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