Annotation of coherent/f/etc/conf/bin/src/input.c, revision 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.