|
|
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.