Back to index

glibc  2.9
files-parse.c
Go to the documentation of this file.
00001 /* Common code for file-based database parsers in nss_files module.
00002    Copyright (C) 1996-2000, 2003, 2004 Free Software Foundation, Inc.
00003    This file is part of the GNU C Library.
00004 
00005    The GNU C Library is free software; you can redistribute it and/or
00006    modify it under the terms of the GNU Lesser General Public
00007    License as published by the Free Software Foundation; either
00008    version 2.1 of the License, or (at your option) any later version.
00009 
00010    The GNU C Library is distributed in the hope that it will be useful,
00011    but WITHOUT ANY WARRANTY; without even the implied warranty of
00012    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00013    Lesser General Public License for more details.
00014 
00015    You should have received a copy of the GNU Lesser General Public
00016    License along with the GNU C Library; if not, write to the Free
00017    Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
00018    02111-1307 USA.  */
00019 
00020 #include <ctype.h>
00021 #include <errno.h>
00022 #include <string.h>
00023 #include <stdlib.h>
00024 
00025 /* These symbols are defined by the including source file:
00026 
00027    ENTNAME -- database name of the structure and functions (hostent, pwent).
00028    STRUCTURE -- struct name, define only if not ENTNAME (passwd, group).
00029    DATABASE -- string of the database file's name ("hosts", "passwd").
00030 
00031    ENTDATA -- if defined, `struct ENTDATA' is used by the parser to store
00032               things pointed to by the resultant `struct STRUCTURE'.
00033 
00034    NEED_H_ERRNO - defined iff an arg `int *herrnop' is used.
00035 
00036    EXTRA_ARGS -- defined iff extra parameters must be passed to the parser
00037    EXTRA_ARGS_DECL -- declaration for these extra parameters
00038    EXTRA_ARGS_VALUE -- values to be passed for these parameters
00039 
00040    Also see files-XXX.c.  */
00041 
00042 #ifndef EXTRA_ARGS
00043 # define EXTRA_ARGS
00044 # define EXTRA_ARGS_DECL
00045 # define EXTRA_ARGS_VALUE
00046 #endif
00047 
00048 #define CONCAT(a,b) CONCAT1(a,b)
00049 #define CONCAT1(a,b) a##b
00050 
00051 #ifndef STRUCTURE
00052 # define STRUCTURE ENTNAME
00053 #endif
00054 
00055 
00056 struct parser_data
00057   {
00058 #ifdef ENTDATA
00059     struct ENTDATA entdata;
00060 # define ENTDATA_DECL(data) struct ENTDATA *const entdata = &data->entdata;
00061 #else
00062 # define ENTDATA_DECL(data)
00063 #endif
00064     char linebuffer[0];
00065   };
00066 
00067 #ifdef ENTDATA
00068 /* The function can't be exported, because the entdata structure
00069    is defined only in files-foo.c.  */
00070 # define parser_stclass static
00071 # define nss_files_parse_hidden_def(name)
00072 #else
00073 /* Export the line parser function so it can be used in nss_db.  */
00074 # define parser_stclass /* Global */
00075 # define parse_line CONCAT(_nss_files_parse_,ENTNAME)
00076 # ifdef IS_IN_libc
00077 /* We are defining one of the functions that actually lives in libc
00078    because it is used to implement fget*ent and suchlike.  */
00079 #  define nss_files_parse_hidden_def(name) libc_hidden_def (name)
00080 # else
00081 #  define nss_files_parse_hidden_def(name) libnss_files_hidden_def (name)
00082 # endif
00083 #endif
00084 
00085 
00086 #ifdef EXTERN_PARSER
00087 
00088 /* The parser is defined in a different module.  */
00089 extern int parse_line (char *line, struct STRUCTURE *result,
00090                      struct parser_data *data, size_t datalen, int *errnop
00091                      EXTRA_ARGS_DECL);
00092 
00093 # define LINE_PARSER(EOLSET, BODY) /* Do nothing */
00094 
00095 #else
00096 
00097 /* Define a line parsing function.  */
00098 
00099 # define LINE_PARSER(EOLSET, BODY)                                   \
00100 parser_stclass int                                                   \
00101 parse_line (char *line, struct STRUCTURE *result,                           \
00102            struct parser_data *data, size_t datalen, int *errnop            \
00103            EXTRA_ARGS_DECL)                                          \
00104 {                                                                    \
00105   ENTDATA_DECL (data)                                                       \
00106   char *p = strpbrk (line, EOLSET "\n");                             \
00107   if (p != NULL)                                                     \
00108     *p = '\0';                                                              \
00109   BODY;                                                                     \
00110   TRAILING_LIST_PARSER;                                                     \
00111   return 1;                                                          \
00112 }                                                                    \
00113 nss_files_parse_hidden_def (parse_line)
00114 
00115 
00116 # define STRING_FIELD(variable, terminator_p, swallow)                      \
00117   {                                                                  \
00118     variable = line;                                                 \
00119     while (*line != '\0' && !terminator_p (*line))                          \
00120       ++line;                                                        \
00121     if (*line != '\0')                                                      \
00122       {                                                                     \
00123        *line = '\0';                                                 \
00124        do                                                            \
00125          ++line;                                                     \
00126        while (swallow && terminator_p (*line));                      \
00127       }                                                                     \
00128   }
00129 
00130 # define INT_FIELD(variable, terminator_p, swallow, base, convert)          \
00131   {                                                                  \
00132     char *endp;                                                             \
00133     variable = convert (strtoul (line, &endp, base));                       \
00134     if (endp == line)                                                       \
00135       return 0;                                                             \
00136     else if (terminator_p (*endp))                                   \
00137       do                                                             \
00138        ++endp;                                                              \
00139       while (swallow && terminator_p (*endp));                              \
00140     else if (*endp != '\0')                                          \
00141       return 0;                                                             \
00142     line = endp;                                                     \
00143   }
00144 
00145 # define INT_FIELD_MAYBE_NULL(variable, terminator_p, swallow, base, convert, default)           \
00146   {                                                                  \
00147     char *endp;                                                             \
00148     if (*line == '\0')                                                      \
00149       /* We expect some more input, so don't allow the string to end here. */ \
00150       return 0;                                                             \
00151     variable = convert (strtoul (line, &endp, base));                       \
00152     if (endp == line)                                                       \
00153       variable = default;                                            \
00154     if (terminator_p (*endp))                                               \
00155       do                                                             \
00156        ++endp;                                                              \
00157       while (swallow && terminator_p (*endp));                              \
00158     else if (*endp != '\0')                                          \
00159       return 0;                                                             \
00160     line = endp;                                                     \
00161   }
00162 
00163 # define ISCOLON(c) ((c) == ':')
00164 
00165 
00166 # ifndef TRAILING_LIST_MEMBER
00167 #  define TRAILING_LIST_PARSER /* Nothing to do.  */
00168 # else
00169 
00170 #  define TRAILING_LIST_PARSER                                              \
00171 {                                                                    \
00172   char **list = parse_list (line, data, datalen, errnop);                   \
00173   if (list)                                                          \
00174     result->TRAILING_LIST_MEMBER = list;                             \
00175   else                                                                      \
00176     return -1;              /* -1 indicates we ran out of space.  */        \
00177 }
00178 
00179 static inline char **
00180 __attribute ((always_inline))
00181 parse_list (char *line, struct parser_data *data, size_t datalen, int *errnop)
00182 {
00183   char *eol, **list, **p;
00184 
00185   if (line >= data->linebuffer && line < (char *) data + datalen)
00186     /* Find the end of the line buffer, we will use the space in DATA after
00187        it for storing the vector of pointers.  */
00188     eol = strchr (line, '\0') + 1;
00189   else
00190     /* LINE does not point within DATA->linebuffer, so that space is
00191        not being used for scratch space right now.  We can use all of
00192        it for the pointer vector storage.  */
00193     eol = data->linebuffer;
00194   /* Adjust the pointer so it is aligned for storing pointers.  */
00195   eol += __alignof__ (char *) - 1;
00196   eol -= (eol - (char *) 0) % __alignof__ (char *);
00197   /* We will start the storage here for the vector of pointers.  */
00198   list = (char **) eol;
00199 
00200   p = list;
00201   while (1)
00202     {
00203       char *elt;
00204 
00205       if ((size_t) ((char *) &p[1] - (char *) data) > datalen)
00206        {
00207          /* We cannot fit another pointer in the buffer.  */
00208          *errnop = ERANGE;
00209          return NULL;
00210        }
00211       if (*line == '\0')
00212        break;
00213 
00214       /* Skip leading white space.  This might not be portable but useful.  */
00215       while (isspace (*line))
00216        ++line;
00217 
00218       elt = line;
00219       while (1)
00220        {
00221          if (*line == '\0' || TRAILING_LIST_SEPARATOR_P (*line))
00222            {
00223              /* End of the next entry.  */
00224              if (line > elt)
00225               /* We really found some data.  */
00226               *p++ = elt;
00227 
00228              /* Terminate string if necessary.  */
00229              if (*line != '\0')
00230               *line++ = '\0';
00231              break;
00232            }
00233          ++line;
00234        }
00235     }
00236   *p = NULL;
00237 
00238   return list;
00239 }
00240 
00241 # endif       /* TRAILING_LIST_MEMBER */
00242 #endif /* EXTERN_PARSER */
00243 
00244 
00245 #define LOOKUP_NAME(nameelt, aliaselt)                                      \
00246 {                                                                    \
00247   char **ap;                                                         \
00248   if (! strcmp (name, result->nameelt))                                     \
00249     break;                                                           \
00250   for (ap = result->aliaselt; *ap; ++ap)                             \
00251     if (! strcmp (name, *ap))                                               \
00252       break;                                                         \
00253   if (*ap)                                                           \
00254     break;                                                           \
00255 }
00256 
00257 #define LOOKUP_NAME_CASE(nameelt, aliaselt)                                 \
00258 {                                                                    \
00259   char **ap;                                                         \
00260   if (! __strcasecmp (name, result->nameelt))                               \
00261     break;                                                           \
00262   for (ap = result->aliaselt; *ap; ++ap)                             \
00263     if (! __strcasecmp (name, *ap))                                         \
00264       break;                                                         \
00265   if (*ap)                                                           \
00266     break;                                                           \
00267 }
00268 
00269 
00270 /* This is defined by db-*.c to include "../nss_db/db-XXX.c" instead.  */
00271 #ifndef GENERIC
00272 # define GENERIC "files-XXX.c"
00273 #endif