|
|
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: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.