|
|
1.1 root 1: /*
2: * getflds - break a line into fields
3: *
4: * General strategy: ptrs is a pointer to an array of
5: * character pointers. This array is used to hold the
6: * results of each call to getflds. Expandptrs() uses
7: * realloc to grow this array as needed. Each pointer in
8: * the array points into the buffer addressed by str,
9: * so all the strings returned by getflds are really
10: * contiguous. Expandstr() uses realloc to grow this buffer
11: * as needed; after it has done so it must relocate all
12: * the pointers into the buffer because it may have moved.
13: *
14: * Both expandstrs and expandptrs return nonzero for failure.
15: *
16: * Ptrs and str are initially null. In the (unlikely)
17: * event that an attempt to grow one of them fails, the
18: * corresponding pointer is set back to null.
19: */
20:
21: #include <stdio.h>
22: #include <setjmp.h>
23:
24: /* how many elements to expand str and ptrs at a time */
25: #define STRCHUNK 512
26: #define PTRCHUNK 128
27:
28: char *malloc(), *realloc();
29: static char **ptrs = NULL, *str = NULL;
30: static unsigned ptrsize = 0, strsize = 0;
31:
32: static
33: expandptrs()
34: {
35: ptrsize += PTRCHUNK;
36: ptrs = (char **) (ptrs? realloc (ptrs, ptrsize * sizeof (char *)):
37: malloc (ptrsize * sizeof (char *)));
38: if (ptrs == NULL) {
39: ptrsize = 0;
40: return 1;
41: }
42: return 0;
43: }
44:
45: static
46: expandstr()
47: {
48: register char *newstr;
49: register unsigned n;
50:
51: strsize += STRCHUNK;
52: newstr = str? realloc (str, strsize): malloc (strsize);
53: if (newstr == NULL) {
54: str = NULL;
55: strsize = 0;
56: return 1;
57: }
58:
59: /* relocate the ptrs array */
60: for (n = 0; n < ptrsize; n++)
61: ptrs[n] = newstr + (ptrs[n] - str);
62:
63: str = newstr;
64: return 0;
65: }
66:
67: char **
68: getflds (f)
69: register FILE *f;
70: {
71: register int c;
72: register unsigned nptr = 0, nstr = 0;
73:
74: /* try to read the first character of the line */
75: c = getc (f);
76:
77: /* a line beginning with # is a comment */
78: while (c == '#') {
79: do c = getc (f);
80: while (c != '\n' && c != EOF);
81: if (c == '\n')
82: c = getc (f);
83: }
84:
85: /* EOF at the beginning of the line is real */
86: if (c == EOF)
87: return NULL;
88:
89: /* one iteration per field */
90: do {
91: /* 0 outside a quoted string, otherwise the type of quote */
92: register quote = 0;
93:
94: /* skip leading white space */
95: while (c == ' ' || c == '\t')
96: c = getc (f);
97:
98: /* maybe it wan't a field after all */
99: if (c == '\n' || c == EOF)
100: break;
101:
102: /* make room for the field pointer and plant it */
103: if (nptr >= ptrsize)
104: if (expandptrs())
105: return NULL;
106: ptrs[nptr++] = str + nstr;
107:
108: /* one iteration per character or escape sequence */
109: while ((c != ' ' && c != '\t' || quote) && c != '\n' && c != EOF) {
110:
111: /* check for escape sequence */
112: if (c == '\\') {
113: c = getc (f);
114: switch (c) {
115:
116: /* C escapes for newline, etc. */
117: case 'b': c = '\b'; break;
118: case 'f': c = '\f'; break;
119: case 'n': c = '\n'; break;
120: case 'r': c = '\r'; break;
121: case 't': c = '\t'; break;
122: case 'v': c = '\v'; break;
123:
124: /* these characters stand for themselves */
125: case '\'': case '"': case '#':
126: case ' ': case '\t': case '\\':
127: break;
128:
129: /* backslash, newline is ignored */
130: case '\n':
131: c = getc (f);
132: continue;
133:
134: /* backslash, octal digits */
135: case '0': case '1': case '2': case '3':
136: case '4': case '5': case '6': case '7':
137: {
138: register r = c - '0';
139: register n = 2;
140: do {
141: c = getc (f);
142: if (c < '0' || c > '7') {
143: ungetc (c, f);
144: break;
145: }
146: r = (r<<3) + c - '0';
147: } while (--n > 0);
148: c = r;
149: }
150: break;
151:
152: /* else treat the backslash as an ordinary char */
153: default:
154: ungetc (c, f);
155: c = '\\';
156: break;
157: }
158:
159: /* not a backslash, check for a quote */
160: } else if (c == '\'' || c == '"') {
161:
162: /* beginning of a quoted string */
163: if (!quote) {
164: quote = c;
165: c = getc (f);
166: continue;
167:
168: /* end of a quoted string */
169: } else if (c == quote) {
170: quote = 0;
171: c = getc (f);
172: continue;
173: }
174:
175: /*
176: * otherwise we're inside a quoted string
177: * and we've seen the "other" quote, which
178: * is now just an ordinary character.
179: */
180: }
181:
182: /* we have a character; put it in the string */
183: if (nstr >= strsize)
184: if (expandstr())
185: return NULL;
186: str[nstr++] = c;
187: c = getc (f);
188: }
189:
190: /* end of field; plant a null char at the end of the string */
191: if (nstr >= strsize)
192: if (expandstr())
193: return NULL;
194: str[nstr++] = '\0';
195:
196: } while (c != '\n' && c != EOF);
197:
198: /* end of line; put a null pointer at the end of the array */
199: if (nptr >= ptrsize)
200: if (expandptrs())
201: return NULL;
202: ptrs[nptr++] = NULL;
203:
204: return ptrs;
205: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.