|
|
1.1 root 1: /*
2: * Input stream abstraction.
3: */
4:
5: /*
6: *-IMPORTS:
7: * <sys/compat.h>
8: * CONST
9: * USE_PROTO
10: * ARGS ()
11: * LOCAL
12: * <stddef.h>
13: * NULL
14: * offsetof ()
15: * <stdio.h>
16: * EOF
17: * FILE
18: * stderr
19: * fprintf ()
20: * fputs ()
21: * getc ()
22: * putc ()
23: * <stdlib.h>
24: * free ()
25: * malloc ()
26: * <string.h>
27: * memcpy ()
28: * strlen ()
29: */
30:
31: #include <sys/compat.h>
32: #include <stddef.h>
33: #include <stdio.h>
34: #include <stdlib.h>
35: #include <string.h>
36:
37: #include "lex.h"
38:
39: #include "input.h"
40: #include "mkinput.h"
41:
42:
43: /*
44: * Structures for dealing with input from a file.
45: */
46:
47: typedef struct fileinput filein_t;
48:
49: struct fileinput {
50: input_t fi_input;
51:
52: char * fi_name;
53: FILE * fi_file; /* input stream */
54: int fi_lineno; /* line number in file */
55: int fi_colno; /* current column number */
56: int fi_prevline;
57: int fi_prevcol;
58: int fi_comment; /* comment character (maybe none) */
59: int fi_prevchar; /* previous character */
60:
61: char fi_line [64]; /* line buffer for errors */
62: };
63:
64: #define ARRAY_LEN(a) (sizeof (a) / sizeof (* a))
65:
66:
67: /*
68: * Structure for processing input from a string.
69: */
70:
71: typedef struct strinput strin_t;
72:
73: struct strinput {
74: input_t si_input;
75:
76: CONST unsigned char
77: * si_data; /* data being read */
78: size_t si_pos; /* position in input stream */
79: size_t si_len; /* length of input stream */
80: };
81:
82:
83: /*
84: * Read a character from a file.
85: */
86:
87: #ifdef USE_PROTO
88: LOCAL int fi_read (input_t * input)
89: #else
90: LOCAL int
91: fi_read (input)
92: input_t * input;
93: #endif
94: {
95: filein_t * fi = (filein_t *) input;
96: int ch;
97:
98: /*
99: * Get a character from the input file, recording the data for the
100: * purpose of error reporting.
101: */
102:
103: fi->fi_prevcol = fi->fi_colno;
104: fi->fi_prevline = fi->fi_lineno;
105:
106: if ((ch = getc (fi->fi_file)) == EOF)
107: return IN_EOF;
108:
109: fi->fi_line [fi->fi_colno ++ % ARRAY_LEN (fi->fi_line)] = ch;
110:
111: if (ch == fi->fi_comment) {
112: /*
113: * Consume data to EOL, then return EOL.
114: */
115:
116: do {
117: if ((ch = getc (fi->fi_file)) == EOF)
118: return IN_EOF;
119: } while (ch != '\n');
120: }
121:
122:
123: if (ch == '\n') {
124:
125: fi->fi_colno = 0;
126: fi->fi_lineno ++;
127: }
128:
129: fi->fi_prevchar = ch;
130: return ch;
131: }
132:
133:
134: /*
135: * Return the last read character to the input stream.
136: */
137:
138: #ifdef USE_PROTO
139: LOCAL void fi_unread (input_t * input)
140: #else
141: LOCAL void
142: fi_unread (input)
143: input_t * input;
144: #endif
145: {
146: filein_t * fi = (filein_t *) input;
147:
148: if (fi->fi_prevchar != IN_EOF) {
149:
150: ungetc (fi->fi_prevchar, fi->fi_file);
151:
152: fi->fi_prevchar = IN_EOF;
153: fi->fi_colno = fi->fi_prevcol;
154: fi->fi_lineno = fi->fi_prevline;
155: }
156: }
157:
158:
159: /*
160: * Close the input file.
161: */
162:
163: #ifdef USE_PROTO
164: LOCAL void fi_close (input_t * input)
165: #else
166: LOCAL void
167: fi_close (input)
168: input_t * input;
169: #endif
170: {
171: filein_t * fi = (filein_t *) input;
172:
173: (void) fclose (fi->fi_file);
174: free (fi);
175: }
176:
177:
178: /*
179: * Produce an error report for this input source.
180: */
181:
182: #ifdef USE_PROTO
183: LOCAL void fi_error (input_t * input)
184: #else
185: LOCAL void
186: fi_error (input)
187: input_t * input;
188: #endif
189: {
190: filein_t * fi = (filein_t *) input;
191: int col;
192: int ch;
193: int end;
194:
195: (void) fprintf (stderr, "Error vicinity : file \"%s\", line %d, column %d\n",
196: fi->fi_name, fi->fi_prevline, fi->fi_prevcol);
197:
198: col = fi->fi_prevcol < 40 ? 0 : fi->fi_prevcol - 40;
199:
200: if (fi->fi_colno > (end = fi->fi_prevcol))
201: end ++;
202:
203: while (col < end) {
204: /*
205: * Should think about escaping controls.
206: */
207:
208: ch = fi->fi_line [col ++ % ARRAY_LEN (fi->fi_line)];
209: (void) putc (ch, stderr);
210: }
211:
212:
213: fputs (" <---\n", stderr);
214: }
215:
216:
217: /*
218: * Create a source of input from a file.
219: */
220:
221: #ifdef USE_PROTO
222: input_t * (make_file_input) (FILE * file, CONST char * name, int comment)
223: #else
224: input_t *
225: make_file_input ARGS ((file, name, comment))
226: FILE * file;
227: CONST char * name;
228: int comment;
229: #endif
230: {
231: filein_t * fi;
232: size_t namelen;
233:
234: /* ASSERT that fi_input is the first member of the structure */
235:
236: if (offsetof (filein_t, fi_input) != 0)
237: return NULL;
238:
239: if (name == NULL)
240: name = "no name";
241:
242: namelen = strlen (name) + 1;
243:
244: if ((fi = (filein_t *) malloc (sizeof (* fi) + namelen)) == NULL)
245: return NULL;
246:
247: fi->fi_lineno = 1;
248: fi->fi_colno = 0;
249: fi->fi_file = file;
250: fi->fi_name = (char *) (fi + 1);
251:
252: fi->fi_comment = comment;
253: fi->fi_prevchar = IN_EOF;
254:
255: if (namelen > 0)
256: memcpy (fi->fi_name, name, namelen);
257:
258: fi->fi_input.in_read = fi_read;
259: fi->fi_input.in_unread = fi_unread;
260: fi->fi_input.in_readtok = NULL;
261: fi->fi_input.in_close = fi_close;
262: fi->fi_input.in_error = fi_error;
263:
264: return & fi->fi_input;
265: }
266:
267:
268: /*
269: * Return a character from an input string, or EOF when the end-of-string is
270: * reached.
271: */
272:
273: #ifdef USE_PROTO
274: LOCAL int si_read (input_t * input)
275: #else
276: LOCAL int
277: si_read (input)
278: input_t * input;
279: #endif
280: {
281: strin_t * si = (strin_t *) input;
282:
283: if (si->si_pos >= si->si_len)
284: return IN_EOF;
285:
286: return si->si_data [si->si_pos ++];
287: }
288:
289:
290: /*
291: * Return a character to the input stream to be read again.
292: */
293:
294: #ifdef USE_PROTO
295: LOCAL void si_unread (input_t * input)
296: #else
297: LOCAL void
298: si_unread (input)
299: input_t * input;
300: #endif
301: {
302: strin_t * si = (strin_t *) input;
303:
304: if (si->si_pos > 0)
305: si->si_pos --;
306: }
307:
308:
309: /*
310: * Reading a token, specialized to string input streams.
311: */
312:
313: #ifdef USE_PROTO
314: LOCAL CONST unsigned char * si_readtok (input_t * input, lex_t * lexp,
315: size_t * lengthp)
316: #else
317: LOCAL CONST unsigned char *
318: si_readtok (input, lexp, lengthp)
319: input_t * input;
320: lex_t * lexp;
321: size_t * lengthp;
322: #endif
323: {
324: strin_t * si = (strin_t *) input;
325: int start = -1;
326: int ch;
327:
328: for (;;) {
329: if ((ch = si_read (input)) == IN_EOF)
330: break;
331:
332: switch (classify (lexp, ch, start == -1)) {
333:
334: case CLASS_FLUSH:
335: continue;
336:
337: case CLASS_SEP:
338: si_unread (input);
339: goto separator;
340:
341: default:
342: break;
343: }
344:
345: if (start == -1)
346: start = si->si_pos - 1;
347: }
348:
349: separator:
350: * lengthp = start == -1 ? 0 : si->si_pos - start;
351: return start == -1 ? NULL : & si->si_data [start];
352: }
353:
354:
355: /*
356: * Finish with a string input stream.
357: */
358:
359: #ifdef USE_PROTO
360: LOCAL void si_close (input_t * input)
361: #else
362: LOCAL void
363: si_close (input)
364: input_t * input;
365: #endif
366: {
367: free (input);
368: }
369:
370:
371: /*
372: * Display an error locus in a string input stream.
373: */
374:
375: #ifdef USE_PROTO
376: LOCAL void si_error (input_t * input)
377: #else
378: LOCAL void
379: si_error (input)
380: input_t * input;
381: #endif
382: {
383: strin_t * si = (strin_t *) input;
384: int col;
385:
386: col = si->si_pos < 40 ? 0 : si->si_pos - 40;
387:
388: (void) fprintf (stderr, "Error vicinity : %.*s <---\n",
389: si->si_pos - col, & si->si_data [col]);
390: }
391:
392:
393: /*
394: * Create a source of input from a string. Depending on the "action" code,
395: * the string may or may not be copied or left alone. If the user wants some
396: * clean processing to be done at close time, then another version of this
397: * code should be set in place which allows registration of a close-time
398: * callback (which is messy, so it hasn't been done).
399: */
400:
401: #ifdef USE_PROTO
402: input_t * (make_string_input) (CONST unsigned char * str, int copy)
403: #else
404: input_t *
405: make_string_input ARGS ((str, copy))
406: CONST unsigned char
407: * str;
408: int copy;
409: #endif
410: {
411: strin_t * si;
412: size_t len;
413:
414: /* ASSERT that si_input is the first member of the structure */
415:
416: if (offsetof (strin_t, si_input) != 0)
417: return NULL;
418:
419: len = strlen ((char *) str);
420:
421: if ((si = (strin_t *) malloc (sizeof (* si) +
422: (copy ? len : 0))) == NULL)
423: return NULL;
424:
425: si->si_pos = 0;
426: si->si_len = len;
427:
428: if (copy) {
429:
430: si->si_data = (CONST unsigned char *) (si + 1);
431: memcpy (si + 1, str, len);
432: } else
433: si->si_data = str;
434:
435: si->si_input.in_read = si_read;
436: si->si_input.in_unread = si_unread;
437: si->si_input.in_readtok = si_readtok;
438: si->si_input.in_close = si_close;
439: si->si_input.in_error = si_error;
440:
441: return & si->si_input;
442: }
443:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.