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