Annotation of coherent/b/STREAMS/conf/bin/src/read.c, revision 1.1

1.1     ! root        1: /*
        !             2:  *-IMPORTS:
        !             3:  *     <sys/compat.h>
        !             4:  *             USE_PROTO
        !             5:  *             LOCAL
        !             6:  *             ARGS ()
        !             7:  *     <limits.h>
        !             8:  *             LONG_MAX
        !             9:  *             LONG_MIN
        !            10:  *             ULONG_MAX
        !            11:  *     <string.h>
        !            12:  *             memchr ()
        !            13:  *     "buildobj.h"
        !            14:  *             BUILD_OK
        !            15:  *             build_t
        !            16:  *             builder_alloc ()
        !            17:  *             build_addchar ()
        !            18:  *             build_begin ()
        !            19:  *             build_end ()
        !            20:  *             build_error ()
        !            21:  *             build_release ()
        !            22:  *     "ehand.h"
        !            23:  *             ehand_t
        !            24:  *             CHAIN_ERROR ()
        !            25:  *             POP_HANDLER ()
        !            26:  *             PUSH_HANDLER ()
        !            27:  *             throw_error ()
        !            28:  *     "input.h"
        !            29:  *             IN_EOF
        !            30:  *             input_t
        !            31:  *     "lex.h"
        !            32:  *             CLASS_FLUSH
        !            33:  *             CLASS_SEP
        !            34:  *             lex_t
        !            35:  *             classify ()
        !            36:  */
        !            37: 
        !            38: #include <sys/compat.h>
        !            39: #include <limits.h>
        !            40: #include <string.h>
        !            41: 
        !            42: #include "buildobj.h"
        !            43: #include "ehand.h"
        !            44: #include "input.h"
        !            45: #include "lex.h"
        !            46: 
        !            47: #include "read.h"
        !            48: 
        !            49: 
        !            50: /*
        !            51:  * Simple glue functions to encapsulate the input system.
        !            52:  */
        !            53: 
        !            54: #if    USE_PROTO
        !            55: int (read_char) (input_t * input)
        !            56: #else
        !            57: int
        !            58: read_char ARGS ((input))
        !            59: input_t              * input;
        !            60: #endif
        !            61: {
        !            62:        if (input == NULL)
        !            63:                throw_error ("NULL parameter passed to read_char ()");
        !            64: 
        !            65:        return (* input->in_read) (input);
        !            66: }
        !            67: 
        !            68: 
        !            69: #if    USE_PROTO
        !            70: void (unread_char) (input_t * input)
        !            71: #else
        !            72: void
        !            73: unread_char ARGS ((input))
        !            74: input_t              * input;
        !            75: #endif
        !            76: {
        !            77:        if (input == NULL)
        !            78:                throw_error ("NULL parameter passed to unread_char ()");
        !            79: 
        !            80:        (* input->in_unread) (input);
        !            81: }
        !            82: 
        !            83: 
        !            84: #if    USE_PROTO
        !            85: void (read_error) (input_t * input)
        !            86: #else
        !            87: void
        !            88: read_error ARGS ((input))
        !            89: input_t              * input;
        !            90: #endif
        !            91: {
        !            92:        if (input == NULL)
        !            93:                throw_error ("NULL parameter passed to read_error ()");
        !            94: 
        !            95:        (* input->in_error) (input);
        !            96: }
        !            97: 
        !            98: 
        !            99: #if    USE_PROTO
        !           100: void (read_close) (input_t * input)
        !           101: #else
        !           102: void
        !           103: read_close ARGS ((input))
        !           104: input_t              * input;
        !           105: #endif
        !           106: {
        !           107:        if (input == NULL)
        !           108:                throw_error ("NULL parameter passed to read_close ()");
        !           109: 
        !           110:        (* input->in_close) (input);
        !           111: }
        !           112: 
        !           113: 
        !           114: /*
        !           115:  * Simple helper to ensure that we don't bump into EOF or EOL too early.
        !           116:  */
        !           117: 
        !           118: #if    USE_PROTO
        !           119: void (check_not_eol) (int ch)
        !           120: #else
        !           121: void
        !           122: check_not_eol ARGS ((ch))
        !           123: int            ch;
        !           124: #endif
        !           125: {
        !           126:        if (ch == '\n')
        !           127:                throw_error ("premature end of line");
        !           128: 
        !           129:        if (ch == READ_EOF)
        !           130:                throw_error ("premature end of input");
        !           131: }
        !           132: 
        !           133: 
        !           134: /*
        !           135:  * We use this function to eat anything that the lexical specification
        !           136:  * considers flushable until we see an end-of-line or end-of-file.
        !           137:  */
        !           138: 
        !           139: #if    USE_PROTO
        !           140: int (expect_eol) (input_t * input, lex_t * lexp, int ch)
        !           141: #else
        !           142: int
        !           143: expect_eol ARGS ((input, lexp, ch))
        !           144: input_t              * input;
        !           145: lex_t        * lexp;
        !           146: int            ch;
        !           147: #endif
        !           148: {
        !           149:        if (ch != '\n' && ch != READ_EOF)
        !           150:                while ((ch = (* input->in_read) (input)) != '\n') {
        !           151: 
        !           152:                        if (ch == IN_EOF)
        !           153:                                return READ_EOF;
        !           154: 
        !           155:                        if (classify (lexp, ch, 1) != CLASS_FLUSH)
        !           156:                                break;
        !           157:                }
        !           158: 
        !           159:        return ch;
        !           160: }
        !           161: 
        !           162: 
        !           163: /*
        !           164:  * Read a token from a file; this function may use the subclassed version to
        !           165:  * support more efficient tokenization if possible.
        !           166:  *
        !           167:  * Note that we don't null-terminate the data or do any other funky stuff. If
        !           168:  * our caller wants to to that, well that's fine, and we don't finish the
        !           169:  * object so that the caller can extend it. Note that by returning the token
        !           170:  * length that we built, this function can be used to incrementally extend
        !           171:  * variable-length data and allow the positions of the subparts to be properly
        !           172:  * recovered.
        !           173:  */
        !           174: 
        !           175: #if    USE_PROTO
        !           176: int (read_token) (input_t * input, lex_t * lexp, build_t * heap,
        !           177:                  token_t * tokenp)
        !           178: #else
        !           179: int
        !           180: read_token ARGS ((input, lexp, heap, tokenp))
        !           181: input_t              * input;
        !           182: lex_t        * lexp;
        !           183: build_t              * heap;
        !           184: token_t              * tokenp;
        !           185: #endif
        !           186: {
        !           187:        int             ch;
        !           188:        int             err;
        !           189: 
        !           190:        if (input == NULL || lexp == NULL || heap == NULL || tokenp == NULL)
        !           191:                throw_error ("invalid parameters in read_token ()");
        !           192: 
        !           193:        if (input->in_readtok != NULL) {
        !           194:                /*
        !           195:                 * Use the subclassed version. Since we won't actually be
        !           196:                 * building the token on the passed-in heap, terminate the
        !           197:                 * current build on that heap.
        !           198:                 */
        !           199: 
        !           200:                build_end (heap, NULL);
        !           201: 
        !           202:                tokenp->tok_heap = NULL;
        !           203:                tokenp->tok_data = (* input->in_readtok) (input, lexp,
        !           204:                                                          & tokenp->tok_len);
        !           205: 
        !           206:                return (* input->in_read) (input);
        !           207:        }
        !           208: 
        !           209: 
        !           210:        tokenp->tok_heap = heap;
        !           211:        tokenp->tok_data = NULL;
        !           212:        tokenp->tok_len = 0;
        !           213: 
        !           214:        for (;;) {
        !           215:                if ((ch = (* input->in_read) (input)) == IN_EOF)
        !           216:                        return ch;
        !           217: 
        !           218:                switch (classify (lexp, ch, tokenp->tok_len == 0)) {
        !           219: 
        !           220:                case CLASS_FLUSH:
        !           221:                        continue;
        !           222: 
        !           223:                case CLASS_SEP:
        !           224:                        return ch;
        !           225: 
        !           226:                default:
        !           227:                        break;
        !           228:                }
        !           229: 
        !           230: 
        !           231:                /*
        !           232:                 * We have read a valid non-separator character, add it to the
        !           233:                 * current input symbol.
        !           234:                 */
        !           235: 
        !           236:                tokenp->tok_len ++;
        !           237: 
        !           238:                if ((err = build_addchar (heap, ch)) != BUILD_OK)
        !           239:                        throw_error ("build_addchar () reported %d (%s)", err,
        !           240:                                     build_error (err));
        !           241:        }
        !           242: }
        !           243: 
        !           244: 
        !           245: /*
        !           246:  * Handy function for clients of read_token () to finish up any build-heap
        !           247:  * allocation in the usual case where read_token () is simply expected to copy
        !           248:  * data to the heap.
        !           249:  *
        !           250:  * If it was adding data to the heap, add a NULL terminator for the usual case
        !           251:  * where we would also like the object to be useable as a string.
        !           252:  */
        !           253: 
        !           254: #if    USE_PROTO
        !           255: void (token_end) (token_t * tok)
        !           256: #else
        !           257: void
        !           258: token_end ARGS ((tok))
        !           259: token_t              * tok;
        !           260: #endif
        !           261: {
        !           262:        char            null;
        !           263: 
        !           264:        if (tok->tok_heap == NULL)
        !           265:                return;
        !           266: 
        !           267:        null = 0;
        !           268: 
        !           269:        if (tok->tok_len != 0 ?
        !           270:                        (build_add (tok->tok_heap, 1, & null) != 0) ||
        !           271:                         (tok->tok_data =
        !           272:                                build_end (tok->tok_heap, NULL)) == NULL :
        !           273:                        build_end (tok->tok_heap, NULL) != NULL)
        !           274:                throw_error ("Error ending token construction");
        !           275: }
        !           276: 
        !           277: 
        !           278: /*
        !           279:  * In the case where a token was able to be scanned in-place, it is often
        !           280:  * necessary to copy it to a heap, even if only temporarily. As with the above
        !           281:  * token_end, we terminate the token as if it was a string.
        !           282:  *
        !           283:  * If the token is actually in a different heap from the one given, we move it
        !           284:  * to the new heap. This works in with some special behaviour in the build
        !           285:  * system where object building can be temporarily suspended, allowing some
        !           286:  * kinds of recursive operations to work on borrowed heap space.
        !           287:  */
        !           288: 
        !           289: #if    USE_PROTO
        !           290: void (token_copy) (token_t * tok, build_t * heap)
        !           291: #else
        !           292: void
        !           293: token_copy ARGS ((tok, heap))
        !           294: token_t              * tok;
        !           295: build_t              * heap;
        !           296: #endif
        !           297: {
        !           298:        char            null;
        !           299:        unsigned char * data;
        !           300:        int             err;
        !           301: 
        !           302:        if (tok->tok_heap == heap)
        !           303:                return;
        !           304: 
        !           305:        null = 0;
        !           306: 
        !           307:        if ((err = build_begin (heap, tok->tok_len, tok->tok_data)) != 0 ||
        !           308:            (err = build_add (heap, 1, & null)) != 0 ||
        !           309:            (err = BUILD_NO_OBJECT,
        !           310:             (data = build_end (heap, NULL)) == NULL))
        !           311:                throw_error ("Cannot copy token data to heap, %s",
        !           312:                             build_error (err));
        !           313: 
        !           314:        if (tok->tok_heap != NULL &&
        !           315:            (err = build_release (heap, tok->tok_data)) != 0)
        !           316:                throw_error ("Cannot release data from old heap, %s",
        !           317:                             build_error (err));
        !           318: 
        !           319:        tok->tok_data = data;
        !           320:        tok->tok_heap = heap;
        !           321: }
        !           322: 
        !           323: 
        !           324: /*
        !           325:  * If a read token has been found to be not needed, it may be discarded with
        !           326:  * this function. If it was copied to a heap, then the heap memory is
        !           327:  * released.
        !           328:  */
        !           329: 
        !           330: #if    USE_PROTO
        !           331: void (token_discard) (token_t * tok)
        !           332: #else
        !           333: void
        !           334: token_discard ARGS ((tok))
        !           335: token_t              * tok;
        !           336: #endif
        !           337: {
        !           338:        int             err;
        !           339: 
        !           340:        if (tok->tok_heap != NULL &&
        !           341:            (err = build_release (tok->tok_heap, tok->tok_data)) != 0)
        !           342:                throw_error ("Cannot release token data, error %s",
        !           343:                             build_error (err));
        !           344: }
        !           345: 
        !           346: 
        !           347: /*
        !           348:  * Simply discard flushable input until the next non-flushable input
        !           349:  * character.
        !           350:  */
        !           351: 
        !           352: #if    USE_PROTO
        !           353: void (read_flush) (input_t * input, lex_t * lexp)
        !           354: #else
        !           355: void
        !           356: read_flush ARGS ((input, lexp))
        !           357: input_t              * input;
        !           358: lex_t        * lexp;
        !           359: #endif
        !           360: {
        !           361:        int             ch;
        !           362: 
        !           363:        while ((ch = (* input->in_read) (input)) != IN_EOF) {
        !           364: 
        !           365:                if (classify (lexp, ch, 1) != CLASS_FLUSH) {
        !           366: 
        !           367:                        (* input->in_unread) (input);
        !           368:                        break;
        !           369:                }
        !           370:        }
        !           371: }
        !           372: 
        !           373: 
        !           374: /*
        !           375:  * To help with the numeric conversions, here we define a simple conversion
        !           376:  * utility that converts a character to a digit independent of character set
        !           377:  * and digit case.
        !           378:  *
        !           379:  * ... a truly general way of doing this would be nice ... maybe some kind of
        !           380:  * virtual-machine interpreter would be up to it ... hmmm.
        !           381:  */
        !           382: 
        !           383: enum {
        !           384:        NOT_DIGIT = -1
        !           385: };
        !           386: 
        !           387: #if    USE_PROTO
        !           388: LOCAL int (char_to_digit) (int ch, int radix)
        !           389: #else
        !           390: LOCAL int
        !           391: char_to_digit ARGS ((ch, radix))
        !           392: int            ch;
        !           393: int            radix;
        !           394: #endif
        !           395: {
        !           396:        static CONST char digits [] = {
        !           397:                '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
        !           398:                'A', 'B', 'C', 'D', 'E', 'F',
        !           399:                'a', 'b', 'c', 'd', 'e', 'f'
        !           400:        };
        !           401:        static CONST char values [sizeof (digits)] = {
        !           402:                0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
        !           403:                10, 11, 12, 13, 14, 15,
        !           404:                10, 11, 12, 13, 14, 15
        !           405:        };
        !           406:        CONST char    * temp;
        !           407: 
        !           408: 
        !           409:        if ((temp = (CONST char *) memchr (digits, ch,
        !           410:                                           sizeof (digits))) == NULL ||
        !           411:            (ch = values [temp - digits]) >= radix)
        !           412:                return -1;
        !           413: 
        !           414:        return ch;
        !           415: }
        !           416: 
        !           417: 
        !           418: /*
        !           419:  * Both read_ulong () and read_long () need to be able to select a radix for
        !           420:  * the number in question based on an explicit radix prefix. This code does
        !           421:  * that for both functions; under certain circumstances, the numeric input
        !           422:  * might be completed by this code.
        !           423:  */
        !           424: 
        !           425: #if    USE_PROTO
        !           426: LOCAL int (choose_radix) (input_t * input, unsigned long * ulongp,
        !           427:                          int * radixp)
        !           428: #else
        !           429: LOCAL int
        !           430: choose_radix ARGS ((input, ulongp, radixp))
        !           431: input_t              * input;
        !           432: unsigned long *        ulongp;
        !           433: int          * radixp;
        !           434: #endif
        !           435: {
        !           436:        int             ch;
        !           437:        int             errflag;
        !           438: 
        !           439:        * ulongp = 0;
        !           440: 
        !           441:        /*
        !           442:         * Perform a radix-selection step, looking for 0, 1-9, 0X, or 0x as
        !           443:         * indications of what radix to read the rest of the number in.
        !           444:         */
        !           445: 
        !           446:        switch (ch = (* input->in_read) (input)) {
        !           447: 
        !           448:        case IN_EOF:
        !           449:                return 1;
        !           450: 
        !           451:        case '0':       /* octal or hexadecimal */
        !           452:                switch (ch = (* input->in_read) (input)) {
        !           453: 
        !           454:                case IN_EOF:
        !           455:                        return 1;
        !           456: 
        !           457:                case 'x':
        !           458:                case 'X':
        !           459:                        /*
        !           460:                         * For the case of radix-16 numbers with an explicit
        !           461:                         * radix in the text, we have a special error case,
        !           462:                         * consisting of an 0x or 0X followed by something
        !           463:                         * that is not a valid digit.
        !           464:                         *
        !           465:                         * The easiest way to test for this is to try
        !           466:                         * converting the first digit right here.
        !           467:                         */
        !           468: 
        !           469:                        * radixp = 16;
        !           470:                        errflag = -1;
        !           471: 
        !           472:                        if ((ch = (* input->in_read) (input))
        !           473:                                                    == IN_EOF)
        !           474:                                return -1;
        !           475:                        break;
        !           476: 
        !           477:                default:
        !           478:                        * radixp = 8;
        !           479:                        errflag = 1;
        !           480:                        break;
        !           481:                }
        !           482:                break;
        !           483: 
        !           484:        default:
        !           485:                * radixp = 10;
        !           486:                errflag = 0;
        !           487:                break;
        !           488:        }
        !           489: 
        !           490: 
        !           491:        /*
        !           492:         * The need for the extra error check required by hexadecimal numbers
        !           493:         * could have made life difficult for the caller in terms of working
        !           494:         * out whether this function actually began reading a number or not.
        !           495:         *
        !           496:         * To simplify this, we ensure that this function always consumes at
        !           497:         * least the first digit. Of course, the actual response to the next
        !           498:         * character not being a valid digit is different in each case, so we
        !           499:         * also deal with that.
        !           500:         */
        !           501: 
        !           502:        if ((ch = char_to_digit (ch, * radixp)) == -1) {
        !           503: 
        !           504:                (* input->in_unread) (input);
        !           505:                return errflag;
        !           506:        }
        !           507: 
        !           508:        * ulongp = ch;
        !           509:        return 0;
        !           510: }
        !           511: 
        !           512: 
        !           513: /*
        !           514:  * Read an unsigned long number from the input. No initial whitespace is
        !           515:  * skipped, no sign character is permitted, and the first value that is not
        !           516:  * valid for a number of the given radix ends conversion.
        !           517:  *
        !           518:  * If "radix" is 0, the usual C radix specifiers are recognized. This version
        !           519:  * of the code has a maximum "radix" value of 16.
        !           520:  *
        !           521:  * A return value of 0 indicates no number was seen, a return value of -1
        !           522:  * indicates an invalid number was seen (such as 0xZ, or a number that is too
        !           523:  * large to be represented accurately with an unsigned long), and a return
        !           524:  * value of 1 indicates a number was successfully read.
        !           525:  */
        !           526: 
        !           527: #if    USE_PROTO
        !           528: int (read_ulong) (input_t * input, unsigned long * ulongp, int radix)
        !           529: #else
        !           530: int
        !           531: read_ulong ARGS ((input, ulongp, radix))
        !           532: input_t              * input;
        !           533: unsigned long *        ulongp;
        !           534: int            radix;
        !           535: #endif
        !           536: {
        !           537:        char            ch;
        !           538:        unsigned long   temp;
        !           539:        unsigned long   radix_max;
        !           540:        int             read_something;
        !           541: 
        !           542:        if (input == NULL || ulongp == NULL || radix < 0 || radix > 16)
        !           543:                throw_error ("Invalid parameter passed to read_ulong ()");
        !           544: 
        !           545:        * ulongp = 0;
        !           546: 
        !           547:        if (radix == 0) {
        !           548: 
        !           549:                switch (ch = choose_radix (input, ulongp, & radix)) {
        !           550: 
        !           551:                case 0:
        !           552:                        break;
        !           553: 
        !           554:                default:
        !           555:                        return ch;
        !           556:                }
        !           557: 
        !           558:                read_something = 1;
        !           559:        } else
        !           560:                read_something = 0;
        !           561: 
        !           562:        /*
        !           563:         * In order to detect overflow portably, we figure out the smallest
        !           564:         * value that will cause overflow when multiplied by the radix, and
        !           565:         * test against that before the multiplication. If the addition of the
        !           566:         * value of "ch" causes overflow, that can be detected by a value of
        !           567:         * "temp" that is smaller after the addition, according to the rules
        !           568:         * of ANSI/ISO unsigned arithmetic. Note that unsigned overflow is
        !           569:         * required to be non-signalling in an ANSI/ISO environment.
        !           570:         */
        !           571: 
        !           572:        temp = * ulongp;
        !           573:        radix_max = ULONG_MAX / radix;
        !           574: 
        !           575:        for (;;) {
        !           576: 
        !           577:                if ((ch = (* input->in_read) (input)) == IN_EOF)
        !           578:                        break;
        !           579: 
        !           580:                if ((ch = char_to_digit (ch, radix)) == -1) {
        !           581: 
        !           582:                        (* input->in_unread) (input);
        !           583:                        break;
        !           584:                }
        !           585: 
        !           586:                if (temp > radix_max) {
        !           587:                        /*
        !           588:                         * Will overflow during the multiplication.
        !           589:                         */
        !           590: 
        !           591:                        read_something = -1;
        !           592:                        temp = ULONG_MAX;
        !           593: 
        !           594:                        continue;
        !           595:                }
        !           596: 
        !           597:                read_something = 1;
        !           598:                temp = (temp * radix) + ch;
        !           599: 
        !           600:                if (temp < ch) {
        !           601:                        /*
        !           602:                         * Overflowed during the addition.
        !           603:                         */
        !           604: 
        !           605:                        read_something = -1;
        !           606:                        temp = ULONG_MAX;
        !           607: 
        !           608:                        continue;
        !           609:                }
        !           610:        }
        !           611: 
        !           612:        * ulongp = temp;
        !           613: 
        !           614:        return read_something;
        !           615: }
        !           616: 
        !           617: 
        !           618: /*
        !           619:  * Read a signed long number from the input. No initial whitespace is skipped,
        !           620:  * and the sign character must immediately precede the digits of the number
        !           621:  * (or the redix specifier), and the first value that is not valid for a
        !           622:  * number of the given radix ends conversion.
        !           623:  *
        !           624:  * If "radix" is 0, the usual C radix specifiers are recognized. This version
        !           625:  * of the code has a maximum "radix" value of 16.
        !           626:  *
        !           627:  * A return value of 0 indicates no number was seen, a return value of -1
        !           628:  * indicates an invalid number was seen (such as 0xZ, or a number that is too
        !           629:  * large to be represented accurately with a signed long), and a return value
        !           630:  * of 1 indicates a number was successfully read.
        !           631:  */
        !           632: 
        !           633: #if    USE_PROTO
        !           634: int (read_long) (input_t * input, long * longp, int radix)
        !           635: #else
        !           636: int
        !           637: read_long ARGS ((input, longp, radix))
        !           638: input_t              * input;
        !           639: long         * longp;
        !           640: int            radix;
        !           641: #endif
        !           642: {
        !           643:        int             ch;
        !           644:        unsigned long   temp;
        !           645:        int             sign;
        !           646: 
        !           647:        /*
        !           648:         * To save time and effort, we simply test for an initial sign flag,
        !           649:         * use read_ulong () to convert a number, and then range check the
        !           650:         * result before converting it to signed form.
        !           651:         */
        !           652: 
        !           653:        switch (ch = (* input->in_read) (input)) {
        !           654: 
        !           655:        case IN_EOF:
        !           656:                return 1;
        !           657: 
        !           658:        case '-':
        !           659:                sign = -1;
        !           660:                break;
        !           661: 
        !           662:        case '+':
        !           663:                sign = 1;
        !           664:                break;
        !           665: 
        !           666:        default:
        !           667:                /*
        !           668:                 * There is no sign character that we can see, return the
        !           669:                 * lookahead character to the input source so that it will be
        !           670:                 * checked by read_ulong ().
        !           671:                 */
        !           672: 
        !           673:                sign = 0;
        !           674:                (* input->in_unread) (input);
        !           675:        }
        !           676: 
        !           677:        ch = read_ulong (input, & temp, radix);
        !           678: 
        !           679: 
        !           680:        /*
        !           681:         * Before we range-check the result that we are going to return, it
        !           682:         * pays to note that the range of signed numbers may well not be
        !           683:         * symmetric. Typically, there are more negative numbers than non-zero
        !           684:         * positive numbers, so that "- LONG_MIN" is not a legal long integer.
        !           685:         *
        !           686:         * Producing a value of LONG_MIN without getting into implementation-
        !           687:         * defined (or undefined, in K&R) territory is tricky because of the
        !           688:         * integral promotions. We'll work around it by subtracting from -1
        !           689:         * rather than zero.
        !           690:         *
        !           691:         * We'd better test that the range of negative integers is at most one
        !           692:         * greater than the range of non-zero positive integers. We can't do
        !           693:         * the test if the preprocessor does arithmetic wrong, though, and
        !           694:         * many do.
        !           695:         */
        !           696: 
        !           697: #if    -23UL > 0
        !           698: # if   (- (LONG_MIN + 0UL)) - 1 > LONG_MAX
        !           699: #  error       There are too many negative integers!
        !           700: # endif
        !           701: #else
        !           702:        /* Your preprocessor does arithmetic wrong */
        !           703: #endif
        !           704: 
        !           705: 
        !           706:        if (sign < 0 && temp != 0) {
        !           707: 
        !           708:                temp -= 1;
        !           709: 
        !           710:                if (temp > - (unsigned long) LONG_MIN - 1) {
        !           711: 
        !           712:                        * longp = LONG_MIN;
        !           713:                        return -1;
        !           714:                } else
        !           715:                        * longp = -1 - (long) temp;
        !           716: 
        !           717:        } else if (temp > LONG_MAX) {
        !           718: 
        !           719:                * longp = LONG_MAX;
        !           720:                return -1;
        !           721:        } else
        !           722:                * longp = temp;
        !           723: 
        !           724: 
        !           725:        /*
        !           726:         * If we saw a sign (of either kind) and nothing else, that's an
        !           727:         * error.
        !           728:         */
        !           729: 
        !           730:        return (sign != 0 && ch == 0) ? -1 : ch;
        !           731: }
        !           732: 
        !           733: 
        !           734: /*
        !           735:  * Read a single unsigned long or a numeric range (indicated by a pair of
        !           736:  * unsigned longs separated by a hyphen without any intervening whitespace).
        !           737:  */
        !           738: 
        !           739: #if    USE_PROTO
        !           740: int (read_ulongs) (input_t * input, lex_t * lexp, unsigned long * number,
        !           741:                   int rangeflag)
        !           742: #else
        !           743: int
        !           744: read_ulongs ARGS ((input, lexp, number, rangeflag))
        !           745: input_t              * input;
        !           746: lex_t        * lexp;
        !           747: unsigned long *        number;
        !           748: int            rangeflag;
        !           749: #endif
        !           750: {
        !           751:        if ((rangeflag != RANGE && rangeflag != NO_RANGE) ||
        !           752:            input == NULL || lexp == NULL || number == NULL)
        !           753:                throw_error ("Invalid parameter to read_ulongs ()");
        !           754: 
        !           755:        /*
        !           756:         * We permit initial whitespace according to the current lexical
        !           757:         * idea of what whitespace is.
        !           758:         */
        !           759: 
        !           760:        read_flush (input, lexp);
        !           761: 
        !           762:        if (read_ulong (input, number, 0) != 1)
        !           763:                throw_error ("Illegal unsigned long number");
        !           764: 
        !           765:        if (rangeflag == RANGE) {
        !           766:                int             ch;
        !           767: 
        !           768:                if ((ch = (* input->in_read) (input)) != IN_EOF &&
        !           769:                    ((* input->in_unread) (input),      /* for effect */
        !           770:                     ch == '-')) {
        !           771:                        /*
        !           772:                         * Read the second part of the range.
        !           773:                         */
        !           774: 
        !           775:                        if (read_ulong (input, number + 1, 0) != 1)
        !           776:                                throw_error ("Illegal second half of unsigned long range");
        !           777:                } else
        !           778:                        number [1] = number [0];
        !           779:        }
        !           780: 
        !           781:        return (* input->in_read) (input);
        !           782: }
        !           783: 
        !           784: 
        !           785: /*
        !           786:  * Read a single integer or a numeric range (indicated by a pair of integers
        !           787:  * separated by a hyphen without any intervening whitespace).
        !           788:  */
        !           789: 
        !           790: #if    USE_PROTO
        !           791: int (read_ints) (input_t * input, lex_t * lexp, int * number, int rangeflag)
        !           792: #else
        !           793: int
        !           794: read_ints ARGS ((input, lexp, number, rangeflag))
        !           795: input_t              * input;
        !           796: lex_t        * lexp;
        !           797: int          * number;
        !           798: int            rangeflag;
        !           799: #endif
        !           800: {
        !           801:        long            value;
        !           802: 
        !           803:        if ((rangeflag != RANGE && rangeflag != NO_RANGE) ||
        !           804:            input == NULL || lexp == NULL || number == NULL)
        !           805:                throw_error ("Invalid parameter to read_ints ()");
        !           806: 
        !           807:        /*
        !           808:         * We permit initial whitespace according to the current lexical
        !           809:         * idea of what whitespace is.
        !           810:         */
        !           811: 
        !           812:        read_flush (input, lexp);
        !           813: 
        !           814:        if (read_long (input, & value, 0) != 1 ||
        !           815: #ifdef __COHERENT__
        !           816:                0)      /* Coherent compiles the test below to bad code */
        !           817: #else
        !           818:            value > INT_MAX || value < INT_MIN)
        !           819: #endif
        !           820:                throw_error ("Illegal integer number");
        !           821: 
        !           822:        number [0] = (int) value;
        !           823: 
        !           824:        if (rangeflag == RANGE) {
        !           825:                int             ch;
        !           826: 
        !           827:                if ((ch = (* input->in_read) (input)) != IN_EOF &&
        !           828:                    ((* input->in_unread) (input),      /* for effect */
        !           829:                     ch == '-')) {
        !           830:                        /*
        !           831:                         * Read the second part of the range.
        !           832:                         */
        !           833: 
        !           834:                        if (read_long (input, & value, 0) != 1 ||
        !           835: #ifdef __COHERENT__
        !           836:                                0)      /* Coherent compiles to bad code */
        !           837: #else
        !           838:                            value > INT_MAX || value < INT_MIN)
        !           839: #endif
        !           840:                                throw_error ("Illegal second half of integer range");
        !           841:                }
        !           842: 
        !           843:                number [1] = (int) value;
        !           844:        }
        !           845: 
        !           846:        return (* input->in_read) (input);
        !           847: }
        !           848: 
        !           849: 
        !           850: /*
        !           851:  * Read a single integer or a numeric range (indicated by a pair of integers
        !           852:  * separated by a hyphen without any intervening whitespace).
        !           853:  */
        !           854: 
        !           855: #if    USE_PROTO
        !           856: int (read_longs) (input_t * input, lex_t * lexp, long * number, int rangeflag)
        !           857: #else
        !           858: int
        !           859: read_longs ARGS ((input, lexp, number, rangeflag))
        !           860: input_t              * input;
        !           861: lex_t        * lexp;
        !           862: long         * number;
        !           863: int            rangeflag;
        !           864: #endif
        !           865: {
        !           866:        if ((rangeflag != RANGE && rangeflag != NO_RANGE) ||
        !           867:            input == NULL || lexp == NULL || number == NULL)
        !           868:                throw_error ("Invalid parameter to read_longs ()");
        !           869: 
        !           870:        /*
        !           871:         * We permit initial whitespace according to the current lexical
        !           872:         * idea of what whitespace is.
        !           873:         */
        !           874: 
        !           875:        read_flush (input, lexp);
        !           876: 
        !           877:        if (read_long (input, number, 0) != 1)
        !           878:                throw_error ("Illegal long-integer number");
        !           879: 
        !           880:        if (rangeflag == RANGE) {
        !           881:                int             ch;
        !           882: 
        !           883:                if ((ch = (* input->in_read) (input)) != IN_EOF &&
        !           884:                    ((* input->in_unread) (input),      /* for effect */
        !           885:                     ch == '-')) {
        !           886:                        /*
        !           887:                         * Read the second part of the range.
        !           888:                         */
        !           889: 
        !           890:                        if (read_long (input, number + 1, 0) != 1)
        !           891:                                throw_error ("Illegal second half of long-integer range");
        !           892:                }
        !           893:        }
        !           894: 
        !           895:        return (* input->in_read) (input);
        !           896: }
        !           897: 
        !           898: 
        !           899: /*
        !           900:  * Read a single unsigned integer or a numeric range (indicated by a pair of
        !           901:  * unsigned integers separated by a hyphen without any intervening
        !           902:  * whitespace).
        !           903:  */
        !           904: 
        !           905: #if    USE_PROTO
        !           906: int (read_uints) (input_t * input, lex_t * lexp, unsigned int * number,
        !           907:                  int rangeflag)
        !           908: #else
        !           909: int
        !           910: read_uints ARGS ((input, lexp, number, rangeflag))
        !           911: input_t              * input;
        !           912: lex_t        * lexp;
        !           913: unsigned int  *        number;
        !           914: int            rangeflag;
        !           915: #endif
        !           916: {
        !           917:        unsigned long   value;
        !           918: 
        !           919:        if ((rangeflag != RANGE && rangeflag != NO_RANGE) ||
        !           920:            input == NULL || lexp == NULL || number == NULL)
        !           921:                throw_error ("Invalid parameter to read_ints ()");
        !           922: 
        !           923:        /*
        !           924:         * We permit initial whitespace according to the current lexical
        !           925:         * idea of what whitespace is.
        !           926:         */
        !           927: 
        !           928:        read_flush (input, lexp);
        !           929: 
        !           930:        if (read_ulong (input, & value, 0) != 1 || value > UINT_MAX)
        !           931:                throw_error ("Illegal unsigned integer number");
        !           932: 
        !           933:        number [0] = (unsigned int) value;
        !           934: 
        !           935:        if (rangeflag == RANGE) {
        !           936:                int             ch;
        !           937: 
        !           938:                if ((ch = (* input->in_read) (input)) != IN_EOF &&
        !           939:                    ((* input->in_unread) (input),      /* for effect */
        !           940:                     ch == '-')) {
        !           941:                        /*
        !           942:                         * Read the second part of the range.
        !           943:                         */
        !           944: 
        !           945:                        if (read_ulong (input, & value, 0) != 1 ||
        !           946:                            value > UINT_MAX)
        !           947:                                throw_error ("Illegal second half of unsigned integer range");
        !           948:                }
        !           949: 
        !           950:                number [1] = (unsigned int) value;
        !           951:        }
        !           952: 
        !           953:        return (* input->in_read) (input);
        !           954: }

unix.superglobalmegacorp.com

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