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 #define LINE_PARSER(EOLSET, BODY)                                             \
56 parser_stclass int                                                            \
57 parse_line (char *line, struct STRUCTURE *result,                             \
58             struct parser_data *data, int datalen)                            \
59 {                                                                             \
60   ENTDATA_DECL (data)                                                         \
61   char *p = strpbrk (line, EOLSET "\n");                                      \
62   if (p)                                                                      \
63     *p = '\0';                                                                \
64   BODY;                                                                       \
65   TRAILING_LIST_PARSER;                                                       \
66   return 1;                                                                   \
67 }
68
69
70 #define STRING_FIELD(variable, terminator_p, swallow)                         \
71   {                                                                           \
72     variable = line;                                                          \
73     while (!terminator_p (*line))                                             \
74       if (*++line == '\0')                                                    \
75         return 0;                                                             \
76     *line = '\0';                                                             \
77     do                                                                        \
78       ++line;                                                                 \
79     while (swallow && terminator_p (*line));                                  \
80   }
81
82 #define INT_FIELD(variable, terminator_p, swallow, base, convert)             \
83   {                                                                           \
84     char *endp;                                                               \
85     variable = convert (strtol (line, &endp, base));                          \
86     if (endp == line)                                                         \
87       return 0;                                                               \
88     else if (terminator_p (*endp))                                            \
89       do                                                                      \
90         ++endp;                                                               \
91       while (swallow && terminator_p (*endp));                                \
92     else if (*endp != '\0')                                                   \
93       return 0;                                                               \
94     line = endp;                                                              \
95   }
96
97 #define ISCOLON(c) ((c) == ':')
98
99
100 #ifndef TRAILING_LIST_MEMBER
101 #define TRAILING_LIST_PARSER /* Nothing to do.  */
102 #else
103
104 #define TRAILING_LIST_PARSER                                                  \
105 {                                                                             \
106   char **list = parse_list (line, data, datalen);                             \
107   if (list)                                                                   \
108     result->TRAILING_LIST_MEMBER = list;                                      \
109   else                                                                        \
110     return 0;                                                                 \
111 }
112
113 static inline char **
114 parse_list (char *line, struct parser_data *data, int datalen)
115 {
116   char *eol, **list, **p;
117
118   /* Find the end of the line buffer.  */
119   eol = strchr (data->linebuffer, '\0') + 1;
120   /* Adjust the pointer so it is aligned for storing pointers.  */
121   eol += __alignof__ (char *) - 1;
122   eol -= (eol - (char *) 0) % __alignof__ (char *);
123   /* We will start the storage here for the vector of pointers.  */
124   list = (char **) eol;
125
126   p = list;
127   while (1)
128     {
129       char *elt;
130
131       if ((char *) &p[1] - (char *) data > datalen)
132         {
133           /* We cannot fit another pointer in the buffer.  */
134           errno = ERANGE;
135           return NULL;
136         }
137       if (*line == '\0')
138         break;
139
140       elt = line;
141       while (1)
142         {
143           if (TRAILING_LIST_SEPARATOR_P (*line))
144             {
145               *p++ = elt;
146               *line = '\0';
147               do
148                 ++line;
149               while (TRAILING_LIST_SEPARATOR_P (*line));
150               elt = line;
151             }
152           else if (*line == '\0' || *line == '\n')
153             {
154               /* End of the line.  */
155               if (line > elt)
156                 /* Last element.  */
157                 *p++ = elt;
158               *line = '\0';
159               break;
160             }
161           else
162             ++line;
163         }
164     }
165   *p = NULL;
166
167   return list;
168 }
169
170 #define LOOKUP_NAME(nameelt, aliaselt)                                        \
171 {                                                                             \
172   char **ap;                                                                  \
173   if (! strcmp (name, result->nameelt))                                       \
174     break;                                                                    \
175   for (ap = result->aliaselt; *ap; ++ap)                                      \
176     if (! strcmp (name, *ap))                                                 \
177       break;                                                                  \
178   if (*ap)                                                                    \
179     break;                                                                    \
180 }
181
182 #endif