Tue Jul 2 10:44:37 1996 Roland McGrath <roland@delasyd.gnu.ai.mit.edu>
[kopensolaris-gnu/glibc.git] / nss / nss_files / files-parse.c
1 /* Common code for file-based database parsers in nss_files module.
2 Copyright (C) 1996 Free Software Foundation, Inc.
3 This file is part of the GNU C Library.
4
5 The GNU C Library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Library General Public License as
7 published by the Free Software Foundation; either version 2 of the
8 License, or (at your option) any later version.
9
10 The GNU C Library is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13 Library General Public License for more details.
14
15 You should have received a copy of the GNU Library General Public
16 License along with the GNU C Library; see the file COPYING.LIB.  If
17 not, write to the Free Software Foundation, Inc., 675 Mass Ave,
18 Cambridge, MA 02139, USA.  */
19
20 #include <ctype.h>
21 #include <errno.h>
22 #include <string.h>
23 #include <stdlib.h>
24
25
26 #define CONCAT(a,b) CONCAT1(a,b)
27 #define CONCAT1(a,b) a##b
28
29 #ifndef STRUCTURE
30 #define STRUCTURE ENTNAME
31 #endif
32
33
34 struct parser_data
35   {
36 #ifdef ENTDATA
37     struct ENTDATA entdata;
38 #define ENTDATA_DECL(data) struct ENTDATA *const entdata = &data->entdata;
39 #else
40 #define ENTDATA_DECL(data)
41 #endif
42     char linebuffer[0];
43   };
44
45 #ifdef ENTDATA
46 /* The function can't be exported, because the entdata structure
47    is defined only in files-foo.c.  */
48 #define parser_stclass static inline
49 #else
50 /* Export the line parser function so it can be used in nss_db.  */
51 #define parser_stclass /* Global */
52 #define parse_line CONCAT(_nss_files_parse_,ENTNAME)
53 #endif
54
55
56 #ifdef EXTERN_PARSER
57
58 /* The parser is defined in a different module.  */
59 extern int parse_line (char *line, struct STRUCTURE *result,
60                        struct parser_data *data, int datalen);
61
62 #define LINE_PARSER(EOLSET, BODY) /* Do nothing */
63
64 #else
65
66 /* Define a line parsing function.  */
67
68 #define LINE_PARSER(EOLSET, BODY)                                             \
69 parser_stclass int                                                            \
70 parse_line (char *line, struct STRUCTURE *result,                             \
71             struct parser_data *data, int datalen)                            \
72 {                                                                             \
73   ENTDATA_DECL (data)                                                         \
74   char *p = strpbrk (line, EOLSET "\n");                                      \
75   if (p)                                                                      \
76     *p = '\0';                                                                \
77   BODY;                                                                       \
78   TRAILING_LIST_PARSER;                                                       \
79   return 1;                                                                   \
80 }
81
82
83 #define STRING_FIELD(variable, terminator_p, swallow)                         \
84   {                                                                           \
85     variable = line;                                                          \
86     while (!terminator_p (*line))                                             \
87       if (*++line == '\0')                                                    \
88         return 0;                                                             \
89     *line = '\0';                                                             \
90     do                                                                        \
91       ++line;                                                                 \
92     while (swallow && terminator_p (*line));                                  \
93   }
94
95 #define INT_FIELD(variable, terminator_p, swallow, base, convert)             \
96   {                                                                           \
97     char *endp;                                                               \
98     variable = convert (strtol (line, &endp, base));                          \
99     if (endp == line)                                                         \
100       return 0;                                                               \
101     else if (terminator_p (*endp))                                            \
102       do                                                                      \
103         ++endp;                                                               \
104       while (swallow && terminator_p (*endp));                                \
105     else if (*endp != '\0')                                                   \
106       return 0;                                                               \
107     line = endp;                                                              \
108   }
109
110 #define ISCOLON(c) ((c) == ':')
111
112
113 #ifndef TRAILING_LIST_MEMBER
114 #define TRAILING_LIST_PARSER /* Nothing to do.  */
115 #else
116
117 #define TRAILING_LIST_PARSER                                                  \
118 {                                                                             \
119   char **list = parse_list (line, data, datalen);                             \
120   if (list)                                                                   \
121     result->TRAILING_LIST_MEMBER = list;                                      \
122   else                                                                        \
123     return 0;                                                                 \
124 }
125
126 static inline char **
127 parse_list (char *line, struct parser_data *data, int datalen)
128 {
129   char *eol, **list, **p;
130
131   /* Find the end of the line buffer.  */
132   eol = strchr (data->linebuffer, '\0') + 1;
133   /* Adjust the pointer so it is aligned for storing pointers.  */
134   eol += __alignof__ (char *) - 1;
135   eol -= (eol - (char *) 0) % __alignof__ (char *);
136   /* We will start the storage here for the vector of pointers.  */
137   list = (char **) eol;
138
139   p = list;
140   while (1)
141     {
142       char *elt;
143
144       if ((char *) &p[1] - (char *) data > datalen)
145         {
146           /* We cannot fit another pointer in the buffer.  */
147           errno = ERANGE;
148           return NULL;
149         }
150       if (*line == '\0')
151         break;
152
153       elt = line;
154       while (1)
155         {
156           if (TRAILING_LIST_SEPARATOR_P (*line))
157             {
158               *p++ = elt;
159               *line = '\0';
160               do
161                 ++line;
162               while (TRAILING_LIST_SEPARATOR_P (*line));
163               elt = line;
164             }
165           else if (*line == '\0' || *line == '\n')
166             {
167               /* End of the line.  */
168               if (line > elt)
169                 /* Last element.  */
170                 *p++ = elt;
171               *line = '\0';
172               break;
173             }
174           else
175             ++line;
176         }
177     }
178   *p = NULL;
179
180   return list;
181 }
182
183 #endif  /* EXTERN_PARSER */
184
185
186 #define LOOKUP_NAME(nameelt, aliaselt)                                        \
187 {                                                                             \
188   char **ap;                                                                  \
189   if (! strcmp (name, result->nameelt))                                       \
190     break;                                                                    \
191   for (ap = result->aliaselt; *ap; ++ap)                                      \
192     if (! strcmp (name, *ap))                                                 \
193       break;                                                                  \
194   if (*ap)                                                                    \
195     break;                                                                    \
196 }
197
198 #endif
199
200 /* This is defined by db-*.c to include "../nss_db/db-XXX.c" instead.  */
201 #ifndef GENERIC
202 #define GENERIC "files-XXX.c"
203 #endif