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