xref: /haiku/src/libs/util/fparseln.c (revision 70b0887a483a2d66a3bca1e712446ba5f717368b)
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