Home | History | Annotate | Download | only in Stdio
      1 /*
      2     Copyright (c) 2010 - 2011, Intel Corporation. All rights reserved.<BR>
      3     This program and the accompanying materials are licensed and made available
      4     under the terms and conditions of the BSD License that accompanies this
      5     distribution.  The full text of the license may be found at
      6     http://opensource.org/licenses/bsd-license.
      7 
      8     THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
      9     WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
     10 
     11  * Copyright (c) 1997 Christos Zoulas.  All rights reserved.
     12  *
     13  * Redistribution and use in source and binary forms, with or without
     14  * modification, are permitted provided that the following conditions
     15  * are met:
     16  * 1. Redistributions of source code must retain the above copyright
     17  *    notice, this list of conditions and the following disclaimer.
     18  * 2. Redistributions in binary form must reproduce the above copyright
     19  *    notice, this list of conditions and the following disclaimer in the
     20  *    documentation and/or other materials provided with the distribution.
     21  * 3. All advertising materials mentioning features or use of this software
     22  *    must display the following acknowledgement:
     23  *  This product includes software developed by Christos Zoulas.
     24  * 4. The name of the author may not be used to endorse or promote products
     25  *    derived from this software without specific prior written permission.
     26  *
     27  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
     28  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
     29  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
     30  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
     31  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
     32  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
     33  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
     34  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     35  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
     36  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     37 
     38     NetBSD: fparseln.c,v 1.5 2004/06/20 22:20:15 jmc Exp
     39 */
     40 #include  <LibConfig.h>
     41 #include <sys/EfiCdefs.h>
     42 
     43 #include "namespace.h"
     44 
     45 #include <assert.h>
     46 #include <errno.h>
     47 #include <stdio.h>
     48 #include <string.h>
     49 #include <stdlib.h>
     50 
     51 #ifdef __weak_alias
     52 __weak_alias(fparseln,_fparseln)
     53 #endif
     54 
     55 #if ! HAVE_FPARSELN
     56 
     57 #ifndef HAVE_NBTOOL_CONFIG_H
     58 #include "reentrant.h"
     59 #include "local.h"
     60 #else
     61 #define FLOCKFILE(fp)
     62 #define FUNLOCKFILE(fp)
     63 #endif
     64 
     65 #if defined(_REENTRANT) && !HAVE_NBTOOL_CONFIG_H
     66 #define __fgetln(f, l) __fgetstr(f, l, '\n')
     67 #else
     68 #define __fgetln(f, l) fgetln(f, l)
     69 #endif
     70 
     71 static int isescaped(const char *, const char *, int);
     72 
     73 /* isescaped():
     74  *  Return true if the character in *p that belongs to a string
     75  *  that starts in *sp, is escaped by the escape character esc.
     76  */
     77 static int
     78 isescaped(const char *sp, const char *p, int esc)
     79 {
     80   const char     *cp;
     81   size_t    ne;
     82 
     83   _DIAGASSERT(sp != NULL);
     84   _DIAGASSERT(p != NULL);
     85 
     86   /* No escape character */
     87   if (esc == '\0')
     88     return 1;
     89 
     90   /* Count the number of escape characters that precede ours */
     91   for (ne = 0, cp = p; --cp >= sp && *cp == esc; ne++)
     92     continue;
     93 
     94   /* Return true if odd number of escape characters */
     95   return (ne & 1) != 0;
     96 }
     97 
     98 
     99 /* fparseln():
    100  *  Read a line from a file parsing continuations ending in \
    101  *  and eliminating trailing newlines, or comments starting with
    102  *  the comment char.
    103  */
    104 char *
    105 fparseln(FILE *fp, size_t *size, size_t *lineno, const char str[3], int flags)
    106 {
    107   static const char dstr[3] = { '\\', '\\', '#' };
    108 
    109   size_t  s, len;
    110   char   *buf;
    111   char   *ptr, *cp;
    112   int cnt;
    113   char  esc, con, nl, com;
    114 
    115   _DIAGASSERT(fp != NULL);
    116   if(fp == NULL) {
    117     errno = EINVAL;
    118     return (NULL);
    119   }
    120 
    121   len = 0;
    122   buf = NULL;
    123   cnt = 1;
    124 
    125   if (str == NULL)
    126     str = dstr;
    127 
    128   esc = str[0];
    129   con = str[1];
    130   com = str[2];
    131   /*
    132    * XXX: it would be cool to be able to specify the newline character,
    133    * but unfortunately, fgetln does not let us
    134    */
    135   nl  = '\n';
    136 
    137   FLOCKFILE(fp);
    138 
    139   while (cnt) {
    140     cnt = 0;
    141 
    142     if (lineno)
    143       (*lineno)++;
    144 
    145     if ((ptr = __fgetln(fp, &s)) == NULL)
    146       break;
    147 
    148     if (s && com) {   /* Check and eliminate comments */
    149       for (cp = ptr; cp < ptr + s; cp++)
    150         if (*cp == com && !isescaped(ptr, cp, esc)) {
    151           s = cp - ptr;
    152           cnt = s == 0 && buf == NULL;
    153           break;
    154         }
    155     }
    156 
    157     if (s && nl) {    /* Check and eliminate newlines */
    158       cp = &ptr[s - 1];
    159 
    160       if (*cp == nl)
    161         s--;  /* forget newline */
    162     }
    163 
    164     if (s && con) {   /* Check and eliminate continuations */
    165       cp = &ptr[s - 1];
    166 
    167       if (*cp == con && !isescaped(ptr, cp, esc)) {
    168         s--;  /* forget escape */
    169         cnt = 1;
    170       }
    171     }
    172 
    173     if (s == 0 && buf != NULL)
    174       continue;
    175 
    176     if ((cp = realloc(buf, len + s + 1)) == NULL) {
    177       FUNLOCKFILE(fp);
    178       free(buf);
    179       return NULL;
    180     }
    181     buf = cp;
    182 
    183     (void) memcpy(buf + len, ptr, s);
    184     len += s;
    185     buf[len] = '\0';
    186   }
    187 
    188   FUNLOCKFILE(fp);
    189 
    190   if ((flags & FPARSELN_UNESCALL) != 0 && esc && buf != NULL &&
    191       strchr(buf, esc) != NULL) {
    192     ptr = cp = buf;
    193     while (cp[0] != '\0') {
    194       int skipesc;
    195 
    196       while (cp[0] != '\0' && cp[0] != esc)
    197         *ptr++ = *cp++;
    198       if (cp[0] == '\0' || cp[1] == '\0')
    199         break;
    200 
    201       skipesc = 0;
    202       if (cp[1] == com)
    203         skipesc += (flags & FPARSELN_UNESCCOMM);
    204       if (cp[1] == con)
    205         skipesc += (flags & FPARSELN_UNESCCONT);
    206       if (cp[1] == esc)
    207         skipesc += (flags & FPARSELN_UNESCESC);
    208       if (cp[1] != com && cp[1] != con && cp[1] != esc)
    209         skipesc = (flags & FPARSELN_UNESCREST);
    210 
    211       if (skipesc)
    212         cp++;
    213       else
    214         *ptr++ = *cp++;
    215       *ptr++ = *cp++;
    216     }
    217     *ptr = '\0';
    218     len = strlen(buf);
    219   }
    220 
    221   if (size)
    222     *size = len;
    223   return buf;
    224 }
    225 
    226 #ifdef TEST
    227 
    228 int main(int, char **);
    229 
    230 int
    231 main(int argc, char **argv)
    232 {
    233   char   *ptr;
    234   size_t  size, line;
    235 
    236   line = 0;
    237   while ((ptr = fparseln(stdin, &size, &line, NULL,
    238       FPARSELN_UNESCALL)) != NULL)
    239     printf("line %d (%d) |%s|\n", line, size, ptr);
    240   return 0;
    241 }
    242 
    243 /*
    244 
    245 # This is a test
    246 line 1
    247 line 2 \
    248 line 3 # Comment
    249 line 4 \# Not comment \\\\
    250 
    251 # And a comment \
    252 line 5 \\\
    253 line 6
    254 
    255 */
    256 
    257 #endif /* TEST */
    258 #endif  /* ! HAVE_FPARSELN */
    259