1 | #ifndef lint |
---|
2 | static char Rcs_Id[] = |
---|
3 | "$Id: fields.c,v 1.2 1997-10-18 16:39:29 ghudson Exp $"; |
---|
4 | #endif |
---|
5 | |
---|
6 | /* |
---|
7 | * $Log: not supported by cvs2svn $ |
---|
8 | * Revision 1.1.1.1 1997/09/03 21:08:08 ghudson |
---|
9 | * Import of ispell 3.1.20 |
---|
10 | * |
---|
11 | * Revision 1.7 1994/01/06 05:26:37 geoff |
---|
12 | * Get rid of all references to System V string routines, for portability |
---|
13 | * (sigh). |
---|
14 | * |
---|
15 | * Revision 1.6 1994/01/05 20:13:43 geoff |
---|
16 | * Add the maxf parameter |
---|
17 | * |
---|
18 | * Revision 1.5 1994/01/04 02:40:21 geoff |
---|
19 | * Make the increments settable (field_line_inc and field_field_inc). |
---|
20 | * Add support for the FLD_NOSHRINK flag. |
---|
21 | * |
---|
22 | * Revision 1.4 1993/09/27 17:48:02 geoff |
---|
23 | * Fix some lint complaints and some parenthesization errors. |
---|
24 | * |
---|
25 | * Revision 1.3 1993/09/09 01:11:11 geoff |
---|
26 | * Add a return value to fieldwrite. Add support for backquotes and for |
---|
27 | * unstripped backslashes. |
---|
28 | * |
---|
29 | * Revision 1.2 1993/08/26 00:02:50 geoff |
---|
30 | * Fix a stupid null-pointer bug |
---|
31 | * |
---|
32 | * Revision 1.1 1993/08/25 21:32:05 geoff |
---|
33 | * Initial revision |
---|
34 | * |
---|
35 | */ |
---|
36 | |
---|
37 | #include <stdio.h> |
---|
38 | #include "config.h" |
---|
39 | #include "fields.h" |
---|
40 | |
---|
41 | field_t * fieldread P ((FILE * file, char * delims, |
---|
42 | int flags, int maxf)); |
---|
43 | /* Read a line with fields from a file */ |
---|
44 | field_t * fieldmake P ((char * line, int allocated, char * delims, |
---|
45 | int flags, int maxf)); |
---|
46 | /* Make a field structure from a line */ |
---|
47 | static field_t * fieldparse P ((field_t * fieldp, char * line, char * delims, |
---|
48 | int flags, int maxf)); |
---|
49 | /* Parse the fields in a line */ |
---|
50 | static int fieldbackch P ((char * str, char ** out, int strip)); |
---|
51 | /* Process backslash sequences */ |
---|
52 | int fieldwrite P ((FILE * file, field_t * fieldp, int delim)); |
---|
53 | /* Write a line with fields to a file */ |
---|
54 | void fieldfree P ((field_t * fieldp)); |
---|
55 | /* Free a field returned by fieldread */ |
---|
56 | |
---|
57 | unsigned int field_field_inc = 20; /* Increment to increase # fields by */ |
---|
58 | unsigned int field_line_inc = 512; /* Incr to increase line length by */ |
---|
59 | |
---|
60 | #ifndef USG |
---|
61 | #define strchr index |
---|
62 | #endif /* USG */ |
---|
63 | |
---|
64 | extern void free (); |
---|
65 | extern char * malloc (); |
---|
66 | extern char * realloc (); |
---|
67 | extern char * strchr (); |
---|
68 | |
---|
69 | /* |
---|
70 | * Read one line of the given file into a buffer, break it up into |
---|
71 | * fields, and return them to the caller. The field_t structure |
---|
72 | * returned must eventually be freed with fieldfree. |
---|
73 | */ |
---|
74 | field_t * fieldread (file, delims, flags, maxf) |
---|
75 | FILE * file; /* File to read lines from */ |
---|
76 | char * delims; /* Characters to use for field delimiters */ |
---|
77 | int flags; /* Option flags; see fields.h */ |
---|
78 | int maxf; /* Maximum number of fields to parse */ |
---|
79 | { |
---|
80 | register char * linebuf; /* Buffer to hold the line read in */ |
---|
81 | int linemax; /* Maximum line buffer size */ |
---|
82 | int linesize; /* Current line buffer size */ |
---|
83 | |
---|
84 | linebuf = (char *) malloc (field_line_inc); |
---|
85 | if (linebuf == NULL) |
---|
86 | return NULL; |
---|
87 | linemax = field_line_inc; |
---|
88 | linesize = 0; |
---|
89 | /* |
---|
90 | * Read in the line. |
---|
91 | */ |
---|
92 | while (fgets (&linebuf[linesize], linemax - linesize, file) |
---|
93 | != NULL) |
---|
94 | { |
---|
95 | linesize += strlen (&linebuf[linesize]); |
---|
96 | if (linebuf[linesize - 1] == '\n') |
---|
97 | break; |
---|
98 | else |
---|
99 | { |
---|
100 | linemax += field_line_inc; |
---|
101 | linebuf = (char *) realloc (linebuf, linemax); |
---|
102 | if (linebuf == NULL) |
---|
103 | return NULL; |
---|
104 | } |
---|
105 | } |
---|
106 | if (linesize == 0) |
---|
107 | { |
---|
108 | free (linebuf); |
---|
109 | return NULL; |
---|
110 | } |
---|
111 | return fieldmake (linebuf, 1, delims, flags, maxf); |
---|
112 | } |
---|
113 | |
---|
114 | field_t * fieldmake (line, allocated, delims, flags, maxf) |
---|
115 | char * line; /* Line to make into a field structure */ |
---|
116 | int allocated; /* NZ if line allocated with malloc */ |
---|
117 | char * delims; /* Characters to use for field delimiters */ |
---|
118 | int flags; /* Option flags; see fields.h */ |
---|
119 | int maxf; /* Maximum number of fields to parse */ |
---|
120 | { |
---|
121 | register field_t * fieldp; /* Structure describing the fields */ |
---|
122 | int linesize; /* Current line buffer size */ |
---|
123 | |
---|
124 | fieldp = (field_t *) malloc (sizeof (field_t)); |
---|
125 | if (fieldp == NULL) |
---|
126 | return NULL; |
---|
127 | fieldp->nfields = 0; |
---|
128 | fieldp->linebuf = allocated ? line : NULL; |
---|
129 | fieldp->fields = NULL; |
---|
130 | fieldp->hadnl = 0; |
---|
131 | linesize = strlen (line); |
---|
132 | if (line[linesize - 1] == '\n') |
---|
133 | { |
---|
134 | line[--linesize] = '\0'; |
---|
135 | fieldp->hadnl = 1; |
---|
136 | } |
---|
137 | /* |
---|
138 | * Shrink the line buffer if necessary. |
---|
139 | */ |
---|
140 | if (allocated && (flags & FLD_NOSHRINK) == 0) |
---|
141 | { |
---|
142 | line = fieldp->linebuf = |
---|
143 | (char *) realloc (fieldp->linebuf, linesize + 1); |
---|
144 | if (fieldp->linebuf == NULL) |
---|
145 | { |
---|
146 | fieldfree (fieldp); |
---|
147 | return NULL; |
---|
148 | } |
---|
149 | } |
---|
150 | return fieldparse (fieldp, line, delims, flags, maxf); |
---|
151 | } |
---|
152 | |
---|
153 | static field_t * fieldparse (fieldp, line, delims, flags, maxf) |
---|
154 | register field_t * fieldp; /* Field structure to parse into */ |
---|
155 | register char * line; /* Line to be parsed */ |
---|
156 | char * delims; /* Characters to use for field delimiters */ |
---|
157 | int flags; /* Option flags; see fields.h */ |
---|
158 | int maxf; /* Maximum number of fields to parse */ |
---|
159 | { |
---|
160 | int fieldmax; /* Max size of fields array */ |
---|
161 | char * lineout; /* Where to store xlated char in line */ |
---|
162 | char quote; /* Quote character in use */ |
---|
163 | |
---|
164 | fieldp->nfields = 0; |
---|
165 | fieldmax = |
---|
166 | (maxf != 0 && maxf < field_field_inc) ? maxf + 2 : field_field_inc; |
---|
167 | fieldp->fields = (char **) malloc (fieldmax * sizeof (char *)); |
---|
168 | if (fieldp->fields == NULL) |
---|
169 | { |
---|
170 | fieldfree (fieldp); |
---|
171 | return NULL; |
---|
172 | } |
---|
173 | if ((flags |
---|
174 | & (FLD_SHQUOTES | FLD_SNGLQUOTES | FLD_BACKQUOTES | FLD_DBLQUOTES)) |
---|
175 | == FLD_SHQUOTES) |
---|
176 | flags |= FLD_SNGLQUOTES | FLD_BACKQUOTES | FLD_DBLQUOTES; |
---|
177 | while (1) |
---|
178 | { |
---|
179 | if (flags & FLD_RUNS) |
---|
180 | { |
---|
181 | while (*line != '\0' && strchr (delims, *line) != NULL) |
---|
182 | line++; /* Skip runs of delimiters */ |
---|
183 | if (*line == '\0') |
---|
184 | break; |
---|
185 | } |
---|
186 | fieldp->fields[fieldp->nfields] = lineout = line; |
---|
187 | /* |
---|
188 | * Skip to the next delimiter. At the end of skipping, "line" will |
---|
189 | * point to either a delimiter or a null byte. |
---|
190 | */ |
---|
191 | if (flags |
---|
192 | & (FLD_SHQUOTES | FLD_SNGLQUOTES | FLD_BACKQUOTES |
---|
193 | | FLD_DBLQUOTES | FLD_BACKSLASH)) |
---|
194 | { |
---|
195 | while (*line != '\0') |
---|
196 | { |
---|
197 | if (strchr (delims, *line) != NULL) |
---|
198 | break; |
---|
199 | else if (((flags & FLD_SNGLQUOTES) && *line == '\'') |
---|
200 | || ((flags & FLD_BACKQUOTES) && *line == '`') |
---|
201 | || ((flags & FLD_DBLQUOTES) && *line == '"')) |
---|
202 | { |
---|
203 | if ((flags & FLD_SHQUOTES) == 0 |
---|
204 | && line != fieldp->fields[fieldp->nfields]) |
---|
205 | quote = '\0'; |
---|
206 | else |
---|
207 | quote = *line; |
---|
208 | } |
---|
209 | else |
---|
210 | quote = '\0'; |
---|
211 | if (quote == '\0') |
---|
212 | { |
---|
213 | if (*line == '\\' && (flags & FLD_BACKSLASH)) |
---|
214 | { |
---|
215 | line++; |
---|
216 | if (*line == '\0') |
---|
217 | break; |
---|
218 | line += fieldbackch (line, &lineout, |
---|
219 | flags & FLD_STRIPQUOTES); |
---|
220 | } |
---|
221 | else |
---|
222 | *lineout++ = *line++; |
---|
223 | } |
---|
224 | else |
---|
225 | { |
---|
226 | /* Process quoted string */ |
---|
227 | if ((flags & FLD_STRIPQUOTES) == 0) |
---|
228 | *lineout++ = quote; |
---|
229 | ++line; |
---|
230 | while (*line != '\0') |
---|
231 | { |
---|
232 | if (*line == quote) |
---|
233 | { |
---|
234 | if ((flags & FLD_STRIPQUOTES) == 0) |
---|
235 | *lineout++ = quote; |
---|
236 | line++; /* Go on past quote */ |
---|
237 | if ((flags & FLD_SHQUOTES) == 0) |
---|
238 | { |
---|
239 | while (*line != '\0' |
---|
240 | && strchr (delims, *line) == NULL) |
---|
241 | line++; /* Skip to delimiter */ |
---|
242 | } |
---|
243 | break; |
---|
244 | } |
---|
245 | else if (*line == '\\') |
---|
246 | { |
---|
247 | if (flags & FLD_BACKSLASH) |
---|
248 | { |
---|
249 | line++; |
---|
250 | if (*line == '\0') |
---|
251 | break; |
---|
252 | else |
---|
253 | line += fieldbackch (line, &lineout, |
---|
254 | flags & FLD_STRIPQUOTES); |
---|
255 | } |
---|
256 | else |
---|
257 | { |
---|
258 | *lineout++ = '\\'; |
---|
259 | if (*++line == '\0') |
---|
260 | break; |
---|
261 | *lineout++ = *line; |
---|
262 | } |
---|
263 | } |
---|
264 | else |
---|
265 | *lineout++ = *line++; |
---|
266 | } |
---|
267 | } |
---|
268 | } |
---|
269 | } |
---|
270 | else |
---|
271 | { |
---|
272 | while (*line != '\0' && strchr (delims, *line) == NULL) |
---|
273 | line++; /* Skip to delimiter */ |
---|
274 | lineout = line; |
---|
275 | } |
---|
276 | fieldp->nfields++; |
---|
277 | if (*line++ == '\0') |
---|
278 | break; |
---|
279 | if (maxf != 0 && fieldp->nfields > maxf) |
---|
280 | break; |
---|
281 | *lineout = '\0'; |
---|
282 | if (fieldp->nfields >= fieldmax) |
---|
283 | { |
---|
284 | fieldmax += field_field_inc; |
---|
285 | fieldp->fields = |
---|
286 | (char **) realloc (fieldp->fields, fieldmax * sizeof (char *)); |
---|
287 | if (fieldp->fields == NULL) |
---|
288 | { |
---|
289 | fieldfree (fieldp); |
---|
290 | return NULL; |
---|
291 | } |
---|
292 | } |
---|
293 | } |
---|
294 | /* |
---|
295 | * Shrink the field pointers and return the field structure. |
---|
296 | */ |
---|
297 | if ((flags & FLD_NOSHRINK) == 0 && fieldp->nfields >= fieldmax) |
---|
298 | { |
---|
299 | fieldp->fields = (char **) realloc (fieldp->fields, |
---|
300 | (fieldp->nfields + 1) * sizeof (char *)); |
---|
301 | if (fieldp->fields == NULL) |
---|
302 | { |
---|
303 | fieldfree (fieldp); |
---|
304 | return NULL; |
---|
305 | } |
---|
306 | } |
---|
307 | fieldp->fields[fieldp->nfields] = NULL; |
---|
308 | return fieldp; |
---|
309 | } |
---|
310 | |
---|
311 | static int fieldbackch (str, out, strip) |
---|
312 | register char * str; /* First char of backslash sequence */ |
---|
313 | register char ** out; /* Where to store result */ |
---|
314 | int strip; /* NZ to convert the sequence */ |
---|
315 | { |
---|
316 | register int ch; /* Character being developed */ |
---|
317 | char * origstr; /* Original value of str */ |
---|
318 | |
---|
319 | if (!strip) |
---|
320 | { |
---|
321 | *(*out)++ = '\\'; |
---|
322 | if (*str != 'x' && *str != 'X' && (*str < '0' || *str > '7')) |
---|
323 | { |
---|
324 | *(*out)++ = *str; |
---|
325 | return *str != '\0'; |
---|
326 | } |
---|
327 | } |
---|
328 | switch (*str) |
---|
329 | { |
---|
330 | case '\0': |
---|
331 | *(*out)++ = '\0'; |
---|
332 | return 0; |
---|
333 | case 'a': |
---|
334 | *(*out)++ = '\007'; |
---|
335 | return 1; |
---|
336 | case 'b': |
---|
337 | *(*out)++ = '\b'; |
---|
338 | return 1; |
---|
339 | case 'f': |
---|
340 | *(*out)++ = '\f'; |
---|
341 | return 1; |
---|
342 | case 'n': |
---|
343 | *(*out)++ = '\n'; |
---|
344 | return 1; |
---|
345 | case 'r': |
---|
346 | *(*out)++ = '\r'; |
---|
347 | return 1; |
---|
348 | case 'v': |
---|
349 | *(*out)++ = '\v'; |
---|
350 | return 1; |
---|
351 | case 'X': |
---|
352 | case 'x': |
---|
353 | /* Hexadecimal sequence */ |
---|
354 | origstr = str++; |
---|
355 | ch = 0; |
---|
356 | if (*str >= '0' && *str <= '9') |
---|
357 | ch = *str++ - '0'; |
---|
358 | else if (*str >= 'a' && *str <= 'f') |
---|
359 | ch = *str++ - 'a' + 0xa; |
---|
360 | else if (*str >= 'A' && *str <= 'F') |
---|
361 | ch = *str++ - 'A' + 0xa; |
---|
362 | if (*str >= '0' && *str <= '9') |
---|
363 | ch = (ch << 4) | (*str++ - '0'); |
---|
364 | else if (*str >= 'a' && *str <= 'f') |
---|
365 | ch = (ch << 4) | (*str++ - 'a' + 0xa); |
---|
366 | else if (*str >= 'A' && *str <= 'F') |
---|
367 | ch = (ch << 4) | (*str++ - 'A' + 0xa); |
---|
368 | break; |
---|
369 | case '0': |
---|
370 | case '1': |
---|
371 | case '2': |
---|
372 | case '3': |
---|
373 | case '4': |
---|
374 | case '5': |
---|
375 | case '6': |
---|
376 | case '7': |
---|
377 | /* Octal sequence */ |
---|
378 | origstr = str; |
---|
379 | ch = *str++ - '0'; |
---|
380 | if (*str >= '0' && *str <= '7') |
---|
381 | ch = (ch << 3) | (*str++ - '0'); |
---|
382 | if (*str >= '0' && *str <= '7') |
---|
383 | ch = (ch << 3) | (*str++ - '0'); |
---|
384 | break; |
---|
385 | default: |
---|
386 | *(*out)++ = *str; |
---|
387 | return 1; |
---|
388 | } |
---|
389 | if (strip) |
---|
390 | { |
---|
391 | *(*out)++ = ch; |
---|
392 | return str - origstr; |
---|
393 | } |
---|
394 | else |
---|
395 | { |
---|
396 | for (ch = 0; origstr < str; ch++) |
---|
397 | *(*out)++ = *origstr++; |
---|
398 | return ch; |
---|
399 | } |
---|
400 | } |
---|
401 | |
---|
402 | int fieldwrite (file, fieldp, delim) |
---|
403 | FILE * file; /* File to write to */ |
---|
404 | register field_t * fieldp; /* Field structure to write */ |
---|
405 | int delim; /* Delimiter to place between fields */ |
---|
406 | { |
---|
407 | int error; /* NZ if an error occurs */ |
---|
408 | register int fieldno; /* Number of field being written */ |
---|
409 | |
---|
410 | error = 0; |
---|
411 | for (fieldno = 0; fieldno < fieldp->nfields; fieldno++) |
---|
412 | { |
---|
413 | if (fieldno != 0) |
---|
414 | error |= putc (delim, file) == EOF; |
---|
415 | error |= fputs (fieldp->fields[fieldno], file) == EOF; |
---|
416 | } |
---|
417 | if (fieldp->hadnl) |
---|
418 | error |= putc ('\n', file) == EOF; |
---|
419 | return error; |
---|
420 | } |
---|
421 | |
---|
422 | void fieldfree (fieldp) |
---|
423 | register field_t * fieldp; /* Field structure to free */ |
---|
424 | { |
---|
425 | |
---|
426 | if (fieldp == NULL) |
---|
427 | return; |
---|
428 | if (fieldp->linebuf != NULL) |
---|
429 | free ((char *) fieldp->linebuf); |
---|
430 | if (fieldp->fields != NULL) |
---|
431 | free ((char *) fieldp->fields); |
---|
432 | free ((char *) fieldp); |
---|
433 | } |
---|