Annotation of coherent/f/etc/conf/bin/src/input.c, revision 1.1.1.1

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 <common/tricks.h>
                     32: #include <sys/compat.h>
                     33: #include <stddef.h>
                     34: #include <stdio.h>
                     35: #include <stdlib.h>
                     36: #include <string.h>
                     37: #include <stdarg.h>
                     38: 
                     39: #include "devadm.h"
                     40: 
                     41: #include "lex.h"
                     42: 
                     43: #include "input.h"
                     44: #include "mkinput.h"
                     45: 
                     46: 
                     47: /*
                     48:  * Structures for dealing with input from a file.
                     49:  *
                     50:  * A new feature added to this for the 'devadm' utility is support for an
                     51:  * output file attached to the input file that can be used to support input
                     52:  * filtering effectively. Comments in the input source are copied to the
                     53:  * output by the lower layer, while higher-level software can perform semantic
                     54:  * processing and then copy the resulting changes out, retaining the relative
                     55:  * ordering of the components. This may cause some reordering (moving comments
                     56:  * at the end of a line to the beginning of a line), but will in general be
                     57:  * benign.
                     58:  */
                     59: 
                     60: typedef struct fileinput filein_t;
                     61: 
                     62: struct fileinput {
                     63:        input_t         fi_input;
                     64: 
                     65:        char          * fi_name;
                     66:        FILE          * fi_infile;      /* input stream */
                     67:        int             fi_inclose;     /* close when stream is closed? */
                     68:        FILE          * fi_outfile;     /* output stream */
                     69:        int             fi_outclose;    /* close when stream is closed? */
                     70:        int             fi_lineno;      /* line number in file */
                     71:        int             fi_colno;       /* current column number */
                     72:        int             fi_prevline;
                     73:        int             fi_prevcol;
                     74:        int             fi_comment;     /* comment character (maybe none) */
                     75:        int             fi_prevchar;    /* previous character */
                     76:        int             fi_outcol;      /* output column number */
                     77: 
                     78:        char            fi_line [64];   /* line buffer for errors */
                     79: };
                     80: 
                     81: #define        ARRAY_LEN(a)    (sizeof (a) / sizeof (* a))
                     82: 
                     83: 
                     84: /*
                     85:  * Structure for processing input from a string.
                     86:  */
                     87: 
                     88: typedef struct strinput        strin_t;
                     89: 
                     90: struct strinput {
                     91:        input_t         si_input;
                     92: 
                     93:        CONST unsigned char
                     94:                      * si_data;        /* data being read */
                     95:        size_t          si_pos;         /* position in input stream */
                     96:        size_t          si_len;         /* length of input stream */
                     97: };
                     98: 
                     99: 
                    100: /*
                    101:  * Send a single character to the filter output.
                    102:  */
                    103: 
                    104: #if    USE_PROTO
                    105: LOCAL int _fi_putc (int ch, filein_t * fi)
                    106: #else
                    107: LOCAL int
                    108: _fi_putc (ch, fi)
                    109: int            ch;
                    110: filein_t      *        fi;
                    111: #endif
                    112: {
                    113:        FILE          * file;
                    114: 
                    115:        if ((file = fi->fi_outfile) == NULL) {
                    116: #if    TRACE
                    117:                if (do_debug == 0)
                    118:                        return 0;
                    119:                file = stderr;
                    120: #else
                    121:                return 0;
                    122: #endif
                    123:        }
                    124: 
                    125:        if (fputc (ch, file) < 0)
                    126:                return -1;
                    127: 
                    128:        switch (ch) {
                    129:        case '\n':
                    130:                fi->fi_outcol = 0;
                    131:                break;
                    132: 
                    133:        case '\t':
                    134:                fi->fi_outcol = ROUND_UP_TO_MULTIPLE (fi->fi_outcol + 1, 8);
                    135:                break;
                    136: 
                    137:        default:
                    138:                fi->fi_outcol ++;
                    139:                break;
                    140:        }
                    141: 
                    142:        return 0;
                    143: }
                    144: 
                    145: 
                    146: /*
                    147:  * Read a character from a file.
                    148:  */
                    149: 
                    150: #if    USE_PROTO
                    151: LOCAL int fi_read (input_t * input)
                    152: #else
                    153: LOCAL int
                    154: fi_read (input)
                    155: input_t              * input;
                    156: #endif
                    157: {
                    158:        filein_t      * fi = (filein_t *) input;
                    159:        int             ch;
                    160: 
                    161:        /*
                    162:         * Get a character from the input file, recording the data for the
                    163:         * purpose of error reporting.
                    164:         */
                    165: 
                    166:        fi->fi_prevcol = fi->fi_colno;
                    167:        fi->fi_prevline = fi->fi_lineno;
                    168: 
                    169: another_line:
                    170:        if ((ch = getc (fi->fi_infile)) == EOF)
                    171:                return IN_EOF;
                    172: 
                    173:        fi->fi_line [fi->fi_colno ++ % ARRAY_LEN (fi->fi_line)] = ch;
                    174: 
                    175:        if (ch == fi->fi_comment) {
                    176:                /*
                    177:                 * Consume data to EOL, then return EOL.
                    178:                 */
                    179: 
                    180:                do {
                    181:                        _fi_putc (ch, fi);
                    182: 
                    183:                        if ((ch = getc (fi->fi_infile)) == EOF)
                    184:                                return IN_EOF;
                    185:                } while (ch != '\n');
                    186: 
                    187:                if (fi->fi_colno > 1)
                    188:                        _fi_putc (ch, fi);
                    189:        }
                    190: 
                    191: 
                    192:        if (ch == '\n') {
                    193: 
                    194:                fi->fi_lineno ++;
                    195: 
                    196:                if (fi->fi_colno == 1) {
                    197: 
                    198:                        _fi_putc (ch, fi);
                    199:                        goto another_line;
                    200:                };
                    201: 
                    202:                fi->fi_colno = 0;
                    203:        }
                    204: 
                    205:        fi->fi_prevchar = ch;
                    206:        return ch;
                    207: }
                    208: 
                    209: 
                    210: /*
                    211:  * Return the last read character to the input stream.
                    212:  */
                    213: 
                    214: #if    USE_PROTO
                    215: LOCAL void fi_unread (input_t * input)
                    216: #else
                    217: LOCAL void
                    218: fi_unread (input)
                    219: input_t              * input;
                    220: #endif
                    221: {
                    222:        filein_t      * fi = (filein_t *) input;
                    223: 
                    224:        if (fi->fi_prevchar != IN_EOF) {
                    225: 
                    226:                ungetc (fi->fi_prevchar, fi->fi_infile);
                    227: 
                    228:                fi->fi_prevchar = IN_EOF;
                    229:                fi->fi_colno = fi->fi_prevcol;
                    230:                fi->fi_lineno = fi->fi_prevline;
                    231:        }
                    232: }
                    233: 
                    234: 
                    235: /*
                    236:  * Close the input file.
                    237:  */
                    238: 
                    239: #if    USE_PROTO
                    240: LOCAL void fi_close (input_t * input)
                    241: #else
                    242: LOCAL void
                    243: fi_close (input)
                    244: input_t              * input;
                    245: #endif
                    246: {
                    247:        filein_t      * fi = (filein_t *) input;
                    248: 
                    249:        if (fi->fi_infile != NULL && fi->fi_inclose)
                    250:                (void) fclose (fi->fi_infile);
                    251:        if (fi->fi_outfile != NULL && fi->fi_outclose)
                    252:                (void) fclose (fi->fi_outfile);
                    253:        free (fi);
                    254: }
                    255: 
                    256: 
                    257: /*
                    258:  * Produce an error report for this input source.
                    259:  */
                    260: 
                    261: #if    USE_PROTO
                    262: LOCAL void fi_error (input_t * input)
                    263: #else
                    264: LOCAL void
                    265: fi_error (input)
                    266: input_t              * input;
                    267: #endif
                    268: {
                    269:        filein_t      * fi = (filein_t *) input;
                    270:        int             col;
                    271:        int             ch;
                    272:        int             end;
                    273: 
                    274:        (void) fprintf (stderr, "Error vicinity : file \"%s\", line %d, column %d\n",
                    275:                        fi->fi_name, fi->fi_prevline, fi->fi_prevcol);
                    276: 
                    277:        col = fi->fi_prevcol < 40 ? 0 : fi->fi_prevcol - 40;
                    278: 
                    279:        if (fi->fi_colno > (end = fi->fi_prevcol))
                    280:                end ++;
                    281: 
                    282:        while (col < end) {
                    283:                /*
                    284:                 * Should think about escaping controls.
                    285:                 */
                    286: 
                    287:                ch = fi->fi_line [col ++ % ARRAY_LEN (fi->fi_line)];
                    288:                (void) putc (ch, stderr);
                    289:        }
                    290: 
                    291: 
                    292:        fputs (" <---\n", stderr);
                    293: }
                    294: 
                    295: 
                    296: /*
                    297:  * Perform columnar formatted output.
                    298:  */
                    299: 
                    300: #if    USE_PROTO
                    301: LOCAL int fi_filter (input_t * input, CONST char * format, ...)
                    302: #else
                    303: LOCAL int
                    304: fi_filter (input, format)
                    305: input_t              * input;
                    306: CONST char    *        format;
                    307: #endif
                    308: {
                    309:        filein_t      * fi = (filein_t *) input;
                    310:        va_list         args;
                    311:        FILE          * file;
                    312: 
                    313:        if ((file = fi->fi_outfile) == NULL) {
                    314: #if    TRACE
                    315:                if (do_debug == 0)
                    316:                        return 0;
                    317:                file = stderr;
                    318: #else
                    319:                return 0;
                    320: #endif
                    321:        }
                    322: 
                    323:        va_start (args, format);
                    324: 
                    325:        while (* format) {
                    326:                char            ch;
                    327:                int             cols;
                    328:                char          * tmp;
                    329:                static char     digits [] = "0123456789";
                    330:                int             long_datum;
                    331: 
                    332:                /*
                    333:                 * We accept either a '%' or '<' sign to introduce a format
                    334:                 * so that we don't clutter things up with too many '%'-signs.
                    335:                 */
                    336: 
                    337:                if (((ch = * format ++) != '%' && ch != '<') ||
                    338:                    * format == ch) {
                    339:                        _fi_putc (ch, fi);
                    340:                        continue;
                    341:                }
                    342: 
                    343:                if ((ch = * format ++) == 0)
                    344:                        return -1;
                    345: 
                    346:                /*
                    347:                 * After a percent-sign, look for a number of tab-columns to
                    348:                 * align the output to.
                    349:                 */
                    350: 
                    351:                cols = 0;
                    352:                while ((tmp = strchr (digits, ch)) != NULL) {
                    353: 
                    354:                        cols = (cols * 10) + (tmp - digits);
                    355:                        if ((ch = * format ++) == 0)
                    356:                                break;
                    357:                }
                    358: 
                    359:                /*
                    360:                 * Dispatch on the format character and record the number of
                    361:                 * characters written (which will be negative on error).
                    362:                 */
                    363: 
                    364:                if ((long_datum = ch == 'l') != 0)
                    365:                        ch = * format ++;
                    366: 
                    367:                switch (ch) {
                    368:                case 'c':
                    369:                        ch = fprintf (file, "%*c", cols,
                    370:                                      va_arg (args, int));
                    371:                        break;
                    372: 
                    373:                case 's':
                    374:                        ch = fprintf (file, "%*s", cols,
                    375:                                      va_arg (args, char *));
                    376:                        break;
                    377: 
                    378:                case 'd':
                    379:                        ch = fprintf (file, "%*ld", cols,
                    380:                                      long_datum ? va_arg (args, long) :
                    381:                                                   (long) va_arg (args, int));
                    382:                        break;
                    383: 
                    384:                case 'x':
                    385:                        ch = fprintf (file, "%*lx", cols,
                    386:                                      long_datum ? va_arg (args, long) :
                    387:                                                   (long) va_arg (args, int));
                    388:                        break;
                    389: 
                    390:                case '>':
                    391:                        /*
                    392:                         * Here is what we add: <{digits}> indicates a column
                    393:                         * number to seek forward to.
                    394:                         */
                    395: 
                    396:                        cols = cols * 8 - fi->fi_outcol;
                    397: 
                    398:                        if (cols <= 0)
                    399:                                _fi_putc (' ', fi);
                    400: 
                    401:                        while (cols > 0) {
                    402:                                _fi_putc ('\t', fi);
                    403:                                cols -= 8;
                    404:                        }
                    405: 
                    406:                        ch = 0;
                    407:                        break;
                    408: 
                    409:                default:
                    410:                        return -1;
                    411:                }
                    412: 
                    413:                if (ch < 0)
                    414:                        return -1;
                    415: 
                    416:                fi->fi_outcol += ch;
                    417:        }
                    418: 
                    419:        va_end (args);
                    420:        return 0;
                    421: }
                    422: 
                    423: 
                    424: /*
                    425:  * Create a source of input from a file. The 'comment' parameter gives the
                    426:  * code of a character which can be used to indicate input sections that are
                    427:  * to be ignored. The 'filter' parameter points to an optional FILE where the
                    428:  * input is going to be copied.
                    429:  */
                    430: 
                    431: #if    USE_PROTO
                    432: input_t * (make_filter) (FILE * infile, CONST char * inname, int inclose,
                    433:                         int comment, FILE * outfile, int outclose)
                    434: #else
                    435: input_t *
                    436: make_filter ARGS ((infile, inname, inclose, comment, outfile, outclose))
                    437: FILE         * infile;
                    438: CONST char    *        inname;
                    439: int            inclose;
                    440: int            comment;
                    441: FILE         * outfile;
                    442: int            outclose;
                    443: #endif
                    444: {
                    445:        filein_t      * fi;
                    446:        size_t          namelen;
                    447: 
                    448:        /* ASSERT that fi_input is the first member of the structure */
                    449: 
                    450:        if (offsetof (filein_t, fi_input) != 0)
                    451:                return NULL;
                    452: 
                    453:        if (inname == NULL)
                    454:                inname = "no name";
                    455: 
                    456:        namelen = strlen (inname) + 1;
                    457: 
                    458:        if ((fi = (filein_t *) malloc (sizeof (* fi) + namelen)) == NULL)
                    459:                return NULL;
                    460: 
                    461:        fi->fi_lineno = 1;
                    462:        fi->fi_colno = 0;
                    463:        fi->fi_infile = infile;
                    464:        fi->fi_inclose = inclose;
                    465:        fi->fi_outfile = outfile;
                    466:        fi->fi_outclose = outclose;
                    467:        fi->fi_name = (char *) (fi + 1);
                    468: 
                    469:        fi->fi_comment = comment;
                    470:        fi->fi_prevchar = IN_EOF;
                    471: 
                    472:        if (namelen > 0)
                    473:                memcpy (fi->fi_name, inname, namelen);
                    474: 
                    475:        fi->fi_input.in_read = fi_read;
                    476:        fi->fi_input.in_unread = fi_unread;
                    477:        fi->fi_input.in_readtok = NULL;
                    478:        fi->fi_input.in_close = fi_close;
                    479:        fi->fi_input.in_error = fi_error;
                    480:        fi->fi_input.in_filter = fi_filter;
                    481: 
                    482:        return & fi->fi_input;
                    483: }
                    484: 
                    485: 
                    486: /*
                    487:  * Return a character from an input string, or EOF when the end-of-string is
                    488:  * reached.
                    489:  */
                    490: 
                    491: #if    USE_PROTO
                    492: LOCAL int si_read (input_t * input)
                    493: #else
                    494: LOCAL int
                    495: si_read (input)
                    496: input_t              * input;
                    497: #endif
                    498: {
                    499:        strin_t       * si = (strin_t *) input;
                    500: 
                    501:        if (si->si_pos >= si->si_len)
                    502:                return IN_EOF;
                    503: 
                    504:        return si->si_data [si->si_pos ++];
                    505: }
                    506: 
                    507: 
                    508: /*
                    509:  * Return a character to the input stream to be read again.
                    510:  */
                    511: 
                    512: #if    USE_PROTO
                    513: LOCAL void si_unread (input_t * input)
                    514: #else
                    515: LOCAL void
                    516: si_unread (input)
                    517: input_t              * input;
                    518: #endif
                    519: {
                    520:        strin_t       * si = (strin_t *) input;
                    521: 
                    522:        if (si->si_pos > 0)
                    523:                si->si_pos --;
                    524: }
                    525: 
                    526: 
                    527: /*
                    528:  * Reading a token, specialized to string input streams.
                    529:  */
                    530: 
                    531: #if    USE_PROTO
                    532: LOCAL CONST unsigned char * si_readtok (input_t * input, lex_t * lexp,
                    533:                                        size_t * lengthp)
                    534: #else
                    535: LOCAL CONST unsigned char *
                    536: si_readtok (input, lexp, lengthp)
                    537: input_t              * input;
                    538: lex_t        * lexp;
                    539: size_t       * lengthp;
                    540: #endif
                    541: {
                    542:        strin_t       * si = (strin_t *) input;
                    543:        int             start = -1;
                    544:        int             ch;
                    545: 
                    546:        for (;;) {
                    547:                if ((ch = si_read (input)) == IN_EOF)
                    548:                        break;
                    549: 
                    550:                switch (classify (lexp, ch, start == -1)) {
                    551: 
                    552:                case CLASS_FLUSH:
                    553:                        continue;
                    554: 
                    555:                case CLASS_SEP:
                    556:                        si_unread (input);
                    557:                        goto separator;
                    558: 
                    559:                default:
                    560:                        break;
                    561:                }
                    562: 
                    563:                if (start == -1)
                    564:                        start = si->si_pos - 1;
                    565:        }
                    566: 
                    567: separator:
                    568:        * lengthp = start == -1 ? 0 : si->si_pos - start;
                    569:        return start == -1 ? NULL : & si->si_data [start];
                    570: }
                    571: 
                    572: 
                    573: /*
                    574:  * Finish with a string input stream.
                    575:  */
                    576: 
                    577: #if    USE_PROTO
                    578: LOCAL void si_close (input_t * input)
                    579: #else
                    580: LOCAL void
                    581: si_close (input)
                    582: input_t              * input;
                    583: #endif
                    584: {
                    585:        free (input);
                    586: }
                    587: 
                    588: 
                    589: /*
                    590:  * Display an error locus in a string input stream.
                    591:  */
                    592: 
                    593: #if    USE_PROTO
                    594: LOCAL void si_error (input_t * input)
                    595: #else
                    596: LOCAL void
                    597: si_error (input)
                    598: input_t              * input;
                    599: #endif
                    600: {
                    601:        strin_t       * si = (strin_t *) input;
                    602:        int             col;
                    603: 
                    604:        col = si->si_pos < 40 ? 0 : si->si_pos - 40;
                    605: 
                    606:        (void) fprintf (stderr, "Error vicinity in input string : %.*s <---\n",
                    607:                        (int) si->si_pos - col, & si->si_data [col]);
                    608: }
                    609: 
                    610: 
                    611: /*
                    612:  * The filtering concept does not really apply to strings yet.
                    613:  */
                    614: 
                    615: #if    USE_PROTO
                    616: LOCAL int si_filter (input_t * NOTUSED (input), CONST char * NOTUSED (format),
                    617:                     ...)
                    618: #else
                    619: LOCAL int
                    620: si_filter (input, format)
                    621: input_t              * input;
                    622: CONST char    *        format;
                    623: #endif
                    624: {
                    625:        return -1;
                    626: }
                    627: 
                    628: 
                    629: /*
                    630:  * Create a source of input from a string. Depending on the "action" code,
                    631:  * the string may or may not be copied or left alone. If the user wants some
                    632:  * clean processing to be done at close time, then another version of this
                    633:  * code should be set in place which allows registration of a close-time
                    634:  * callback (which is messy, so it hasn't been done).
                    635:  */
                    636: 
                    637: #if    USE_PROTO
                    638: input_t * (make_string_input) (CONST unsigned char * str, int copy)
                    639: #else
                    640: input_t *
                    641: make_string_input ARGS ((str, copy))
                    642: CONST unsigned char
                    643:              * str;
                    644: int            copy;
                    645: #endif
                    646: {
                    647:        strin_t       * si;
                    648:        size_t          len;
                    649: 
                    650:        /* ASSERT that si_input is the first member of the structure */
                    651: 
                    652:        if (offsetof (strin_t, si_input) != 0)
                    653:                return NULL;
                    654: 
                    655:        len = strlen ((char *) str);
                    656: 
                    657:        if ((si = (strin_t *) malloc (sizeof (* si) +
                    658:                                      (copy ? len : 0))) == NULL)
                    659:                return NULL;
                    660: 
                    661:        si->si_pos = 0;
                    662:        si->si_len = len;
                    663: 
                    664:        if (copy) {
                    665: 
                    666:                si->si_data = (CONST unsigned char *) (si + 1);
                    667:                memcpy (si + 1, str, len);
                    668:        } else
                    669:                si->si_data = str;
                    670: 
                    671:        si->si_input.in_read = si_read;
                    672:        si->si_input.in_unread = si_unread;
                    673:        si->si_input.in_readtok = si_readtok;
                    674:        si->si_input.in_close = si_close;
                    675:        si->si_input.in_error = si_error;
                    676:        si->si_input.in_filter = si_filter;
                    677: 
                    678:        return & si->si_input;
                    679: }

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.