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
isescaped(const char * sp,const char * p,int esc)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 *
fparseln(FILE * fp,size_t * size,size_t * lineno,const char str[3],int flags)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
main(int argc,char ** argv)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