]>
Commit | Line | Data |
---|---|---|
5f0e6fc7 | 1 | /* Common code for file-based database parsers in nss_files module. |
74015205 | 2 | Copyright (C) 1996, 1997, 1998 Free Software Foundation, Inc. |
2303f5fd UD |
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 not, | |
17 | write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, | |
18 | Boston, MA 02111-1307, USA. */ | |
5f0e6fc7 RM |
19 | |
20 | #include <ctype.h> | |
21 | #include <errno.h> | |
22 | #include <string.h> | |
23 | #include <stdlib.h> | |
24 | ||
adc6ff7f RM |
25 | /* These symbols are defined by the including source file: |
26 | ||
27 | ENTNAME -- database name of the structure and functions (hostent, pwent). | |
28 | STRUCTURE -- struct name, define only if not ENTNAME (passwd, group). | |
29 | DATABASE -- string of the database file's name ("hosts", "passwd"). | |
30 | ||
31 | ENTDATA -- if defined, `struct ENTDATA' is used by the parser to store | |
32 | things pointed to by the resultant `struct STRUCTURE'. | |
33 | ||
34 | NEED_H_ERRNO - defined iff an arg `int *herrnop' is used. | |
35 | ||
36 | Also see files-XXX.c. */ | |
5f0e6fc7 RM |
37 | |
38 | #define CONCAT(a,b) CONCAT1(a,b) | |
39 | #define CONCAT1(a,b) a##b | |
40 | ||
41 | #ifndef STRUCTURE | |
26761c28 | 42 | # define STRUCTURE ENTNAME |
5f0e6fc7 RM |
43 | #endif |
44 | ||
45 | ||
46 | struct parser_data | |
47 | { | |
3776d592 RM |
48 | #ifdef ENTDATA |
49 | struct ENTDATA entdata; | |
26761c28 | 50 | # define ENTDATA_DECL(data) struct ENTDATA *const entdata = &data->entdata; |
3776d592 | 51 | #else |
26761c28 | 52 | # define ENTDATA_DECL(data) |
3776d592 | 53 | #endif |
5f0e6fc7 RM |
54 | char linebuffer[0]; |
55 | }; | |
56 | ||
3776d592 RM |
57 | #ifdef ENTDATA |
58 | /* The function can't be exported, because the entdata structure | |
59 | is defined only in files-foo.c. */ | |
26761c28 | 60 | # define parser_stclass static inline |
3776d592 RM |
61 | #else |
62 | /* Export the line parser function so it can be used in nss_db. */ | |
26761c28 UD |
63 | # define parser_stclass /* Global */ |
64 | # define parse_line CONCAT(_nss_files_parse_,ENTNAME) | |
3776d592 RM |
65 | #endif |
66 | ||
96bda0ea RM |
67 | |
68 | #ifdef EXTERN_PARSER | |
69 | ||
70 | /* The parser is defined in a different module. */ | |
71 | extern int parse_line (char *line, struct STRUCTURE *result, | |
d71b808a | 72 | struct parser_data *data, size_t datalen, int *errnop); |
96bda0ea | 73 | |
26761c28 | 74 | # define LINE_PARSER(EOLSET, BODY) /* Do nothing */ |
96bda0ea RM |
75 | |
76 | #else | |
77 | ||
78 | /* Define a line parsing function. */ | |
79 | ||
26761c28 | 80 | # define LINE_PARSER(EOLSET, BODY) \ |
3776d592 | 81 | parser_stclass int \ |
5f0e6fc7 | 82 | parse_line (char *line, struct STRUCTURE *result, \ |
d71b808a | 83 | struct parser_data *data, size_t datalen, int *errnop) \ |
5f0e6fc7 | 84 | { \ |
ffee1316 RM |
85 | ENTDATA_DECL (data) \ |
86 | char *p = strpbrk (line, EOLSET "\n"); \ | |
26761c28 | 87 | if (p != NULL) \ |
ffee1316 | 88 | *p = '\0'; \ |
5f0e6fc7 RM |
89 | BODY; \ |
90 | TRAILING_LIST_PARSER; \ | |
91 | return 1; \ | |
92 | } | |
93 | ||
94 | ||
26761c28 | 95 | # define STRING_FIELD(variable, terminator_p, swallow) \ |
5f0e6fc7 RM |
96 | { \ |
97 | variable = line; \ | |
adc6ff7f | 98 | while (*line != '\0' && !terminator_p (*line)) \ |
5f0e6fc7 | 99 | ++line; \ |
adc6ff7f RM |
100 | if (*line != '\0') \ |
101 | { \ | |
102 | *line = '\0'; \ | |
103 | do \ | |
104 | ++line; \ | |
105 | while (swallow && terminator_p (*line)); \ | |
106 | } \ | |
5f0e6fc7 RM |
107 | } |
108 | ||
26761c28 | 109 | # define INT_FIELD(variable, terminator_p, swallow, base, convert) \ |
5f0e6fc7 RM |
110 | { \ |
111 | char *endp; \ | |
112 | variable = convert (strtol (line, &endp, base)); \ | |
113 | if (endp == line) \ | |
114 | return 0; \ | |
115 | else if (terminator_p (*endp)) \ | |
116 | do \ | |
117 | ++endp; \ | |
118 | while (swallow && terminator_p (*endp)); \ | |
119 | else if (*endp != '\0') \ | |
120 | return 0; \ | |
121 | line = endp; \ | |
122 | } | |
123 | ||
26761c28 | 124 | # define INT_FIELD_MAYBE_NULL(variable, terminator_p, swallow, base, convert, default) \ |
569c558c UD |
125 | { \ |
126 | char *endp; \ | |
127 | if (*line == '\0') \ | |
128 | /* We expect some more input, so don't allow the string to end here. */ \ | |
129 | return 0; \ | |
130 | variable = convert (strtol (line, &endp, base)); \ | |
131 | if (endp == line) \ | |
132 | variable = default; \ | |
133 | if (terminator_p (*endp)) \ | |
134 | do \ | |
135 | ++endp; \ | |
136 | while (swallow && terminator_p (*endp)); \ | |
137 | else if (*endp != '\0') \ | |
138 | return 0; \ | |
139 | line = endp; \ | |
140 | } | |
141 | ||
26761c28 | 142 | # define ISCOLON(c) ((c) == ':') |
5f0e6fc7 RM |
143 | |
144 | ||
26761c28 UD |
145 | # ifndef TRAILING_LIST_MEMBER |
146 | # define TRAILING_LIST_PARSER /* Nothing to do. */ | |
147 | # else | |
5f0e6fc7 | 148 | |
26761c28 | 149 | # define TRAILING_LIST_PARSER \ |
5f0e6fc7 | 150 | { \ |
d71b808a | 151 | char **list = parse_list (line, data, datalen, errnop); \ |
5f0e6fc7 RM |
152 | if (list) \ |
153 | result->TRAILING_LIST_MEMBER = list; \ | |
154 | else \ | |
22d57dd3 | 155 | return -1; /* -1 indicates we ran out of space. */ \ |
5f0e6fc7 RM |
156 | } |
157 | ||
158 | static inline char ** | |
d71b808a | 159 | parse_list (char *line, struct parser_data *data, size_t datalen, int *errnop) |
5f0e6fc7 RM |
160 | { |
161 | char *eol, **list, **p; | |
162 | ||
dbe31b9a RM |
163 | if (line >= data->linebuffer && line < (char *) data + datalen) |
164 | /* Find the end of the line buffer, we will use the space in DATA after | |
165 | it for storing the vector of pointers. */ | |
166 | eol = strchr (line, '\0') + 1; | |
167 | else | |
168 | /* LINE does not point within DATA->linebuffer, so that space is | |
169 | not being used for scratch space right now. We can use all of | |
170 | it for the pointer vector storage. */ | |
171 | eol = data->linebuffer; | |
5f0e6fc7 | 172 | /* Adjust the pointer so it is aligned for storing pointers. */ |
3776d592 RM |
173 | eol += __alignof__ (char *) - 1; |
174 | eol -= (eol - (char *) 0) % __alignof__ (char *); | |
5f0e6fc7 RM |
175 | /* We will start the storage here for the vector of pointers. */ |
176 | list = (char **) eol; | |
177 | ||
178 | p = list; | |
179 | while (1) | |
180 | { | |
181 | char *elt; | |
182 | ||
f8b87ef0 | 183 | if ((size_t) ((char *) &p[1] - (char *) data) > datalen) |
5f0e6fc7 RM |
184 | { |
185 | /* We cannot fit another pointer in the buffer. */ | |
d71b808a | 186 | *errnop = ERANGE; |
5f0e6fc7 RM |
187 | return NULL; |
188 | } | |
189 | if (*line == '\0') | |
190 | break; | |
191 | ||
22d57dd3 UD |
192 | /* Skip leading white space. This might not be portable but useful. */ |
193 | while (isspace (*line)) | |
194 | ++line; | |
195 | ||
5f0e6fc7 RM |
196 | elt = line; |
197 | while (1) | |
198 | { | |
22d57dd3 | 199 | if (*line == '\0' || TRAILING_LIST_SEPARATOR_P (*line)) |
5f0e6fc7 | 200 | { |
22d57dd3 | 201 | /* End of the next entry. */ |
5f0e6fc7 | 202 | if (line > elt) |
22d57dd3 | 203 | /* We really found some data. */ |
5f0e6fc7 | 204 | *p++ = elt; |
22d57dd3 UD |
205 | |
206 | /* Terminate string if necessary. */ | |
207 | if (*line != '\0') | |
208 | *line++ = '\0'; | |
5f0e6fc7 RM |
209 | break; |
210 | } | |
22d57dd3 | 211 | ++line; |
5f0e6fc7 RM |
212 | } |
213 | } | |
214 | *p = NULL; | |
215 | ||
216 | return list; | |
217 | } | |
218 | ||
26761c28 | 219 | # endif /* TRAILING_LIST_MEMBER */ |
96bda0ea RM |
220 | #endif /* EXTERN_PARSER */ |
221 | ||
222 | ||
5f0e6fc7 RM |
223 | #define LOOKUP_NAME(nameelt, aliaselt) \ |
224 | { \ | |
225 | char **ap; \ | |
226 | if (! strcmp (name, result->nameelt)) \ | |
227 | break; \ | |
228 | for (ap = result->aliaselt; *ap; ++ap) \ | |
229 | if (! strcmp (name, *ap)) \ | |
230 | break; \ | |
231 | if (*ap) \ | |
232 | break; \ | |
233 | } | |
234 | ||
74015205 UD |
235 | #define LOOKUP_NAME_CASE(nameelt, aliaselt) \ |
236 | { \ | |
237 | char **ap; \ | |
238 | if (! strcasecmp (name, result->nameelt)) \ | |
239 | break; \ | |
240 | for (ap = result->aliaselt; *ap; ++ap) \ | |
241 | if (! strcasecmp (name, *ap)) \ | |
242 | break; \ | |
243 | if (*ap) \ | |
244 | break; \ | |
245 | } | |
246 | ||
96bda0ea RM |
247 | |
248 | /* This is defined by db-*.c to include "../nss_db/db-XXX.c" instead. */ | |
249 | #ifndef GENERIC | |
26761c28 | 250 | # define GENERIC "files-XXX.c" |
96bda0ea | 251 | #endif |