1 /* lexical analysis of RCS files */ 2 3 /****************************************************************************** 4 * Lexical Analysis. 5 * hashtable, Lexinit, nextlex, getlex, getkey, 6 * getid, getnum, readstring, printstring, savestring, 7 * checkid, fatserror, error, faterror, warn, diagnose 8 * Testprogram: define LEXDB 9 ****************************************************************************** 10 */ 11 12 /* Copyright 1982, 1988, 1989 Walter Tichy 13 Copyright 1990, 1991, 1992, 1993, 1994, 1995 Paul Eggert 14 Distributed under license by the Free Software Foundation, Inc. 15 16 This file is part of RCS. 17 18 RCS is free software; you can redistribute it and/or modify 19 it under the terms of the GNU General Public License as published by 20 the Free Software Foundation; either version 2, or (at your option) 21 any later version. 22 23 RCS is distributed in the hope that it will be useful, 24 but WITHOUT ANY WARRANTY; without even the implied warranty of 25 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 26 GNU General Public License for more details. 27 28 You should have received a copy of the GNU General Public License 29 along with RCS; see the file COPYING. 30 If not, write to the Free Software Foundation, 31 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 32 33 Report problems and direct all questions to: 34 35 rcs-bugs@cs.purdue.edu 36 37 */ 38 39 40 41 /* 42 * $FreeBSD: src/gnu/usr.bin/rcs/lib/rcslex.c,v 1.8 1999/08/27 23:36:47 peter Exp $ 43 * $DragonFly: src/gnu/usr.bin/rcs/lib/rcslex.c,v 1.2 2003/06/17 04:25:47 dillon Exp $ 44 * 45 * Revision 5.19 1995/06/16 06:19:24 eggert 46 * Update FSF address. 47 * 48 * Revision 5.18 1995/06/01 16:23:43 eggert 49 * (map_fd_deallocate,mmap_deallocate,read_deallocate,nothing_to_deallocate): 50 * New functions. 51 * (Iclose): If large_memory and maps_memory, use them to deallocate mapping. 52 * (fd2RILE): Use map_fd if available. 53 * If one mapping method fails, try the next instead of giving up; 54 * if they all fail, fall back on ordinary read. 55 * Work around bug: root mmap over NFS succeeds, but accessing dumps core. 56 * Use MAP_FAILED macro for mmap failure, and `char *' instead of caddr_t. 57 * (advise_access): Use madvise only if this instance used mmap. 58 * (Iopen): Use fdSafer to get safer file descriptor. 59 * (aflush): Moved here from rcsedit.c. 60 * 61 * Revision 5.17 1994/03/20 04:52:58 eggert 62 * Don't worry if madvise fails. Add Orewind. Remove lint. 63 * 64 * Revision 5.16 1993/11/09 17:55:29 eggert 65 * Fix `label: }' typo. 66 * 67 * Revision 5.15 1993/11/03 17:42:27 eggert 68 * Improve quality of diagnostics by putting file names in them more often. 69 * Don't discard ignored phrases. 70 * 71 * Revision 5.14 1992/07/28 16:12:44 eggert 72 * Identifiers may now start with a digit and (unless they are symbolic names) 73 * may contain `.'. Avoid `unsigned'. Statement macro names now end in _. 74 * 75 * Revision 5.13 1992/02/17 23:02:27 eggert 76 * Work around NFS mmap SIGBUS problem. 77 * 78 * Revision 5.12 1992/01/06 02:42:34 eggert 79 * Use OPEN_O_BINARY if mode contains 'b'. 80 * 81 * Revision 5.11 1991/11/03 03:30:44 eggert 82 * Fix porting bug to ancient hosts lacking vfprintf. 83 * 84 * Revision 5.10 1991/10/07 17:32:46 eggert 85 * Support piece tables even if !has_mmap. 86 * 87 * Revision 5.9 1991/09/24 00:28:42 eggert 88 * Don't export errsay(). 89 * 90 * Revision 5.8 1991/08/19 03:13:55 eggert 91 * Add eoflex(), mmap support. Tune. 92 * 93 * Revision 5.7 1991/04/21 11:58:26 eggert 94 * Add MS-DOS support. 95 * 96 * Revision 5.6 1991/02/25 07:12:42 eggert 97 * Work around fputs bug. strsave -> str_save (DG/UX name clash) 98 * 99 * Revision 5.5 1990/12/04 05:18:47 eggert 100 * Use -I for prompts and -q for diagnostics. 101 * 102 * Revision 5.4 1990/11/19 20:05:28 hammer 103 * no longer gives warning about unknown keywords if -q is specified 104 * 105 * Revision 5.3 1990/11/01 05:03:48 eggert 106 * When ignoring unknown phrases, copy them to the output RCS file. 107 * 108 * Revision 5.2 1990/09/04 08:02:27 eggert 109 * Count RCS lines better. 110 * 111 * Revision 5.1 1990/08/29 07:14:03 eggert 112 * Work around buggy compilers with defective argument promotion. 113 * 114 * Revision 5.0 1990/08/22 08:12:55 eggert 115 * Remove compile-time limits; use malloc instead. 116 * Report errno-related errors with perror(). 117 * Ansify and Posixate. Add support for ISO 8859. 118 * Use better hash function. 119 * 120 * Revision 4.6 89/05/01 15:13:07 narten 121 * changed copyright header to reflect current distribution rules 122 * 123 * Revision 4.5 88/08/28 15:01:12 eggert 124 * Don't loop when writing error messages to a full filesystem. 125 * Flush stderr/stdout when mixing output. 126 * Yield exit status compatible with diff(1). 127 * Shrink stdio code size; allow cc -R; remove lint. 128 * 129 * Revision 4.4 87/12/18 11:44:47 narten 130 * fixed to use "varargs" in "fprintf"; this is required if it is to 131 * work on a SPARC machine such as a Sun-4 132 * 133 * Revision 4.3 87/10/18 10:37:18 narten 134 * Updating version numbers. Changes relative to 1.1 actually relative 135 * to version 4.1 136 * 137 * Revision 1.3 87/09/24 14:00:17 narten 138 * Sources now pass through lint (if you ignore printf/sprintf/fprintf 139 * warnings) 140 * 141 * Revision 1.2 87/03/27 14:22:33 jenkins 142 * Port to suns 143 * 144 * Revision 4.1 83/03/25 18:12:51 wft 145 * Only changed $Header to $Id. 146 * 147 * Revision 3.3 82/12/10 16:22:37 wft 148 * Improved error messages, changed exit status on error to 1. 149 * 150 * Revision 3.2 82/11/28 21:27:10 wft 151 * Renamed ctab to map and included EOFILE; ctab is now a macro in rcsbase.h. 152 * Added fflsbuf(), fputs(), and fprintf(), which abort the RCS operations 153 * properly in case there is an IO-error (e.g., file system full). 154 * 155 * Revision 3.1 82/10/11 19:43:56 wft 156 * removed unused label out:; 157 * made sure all calls to getc() return into an integer, not a char. 158 */ 159 160 161 /* 162 #define LEXDB 163 */ 164 /* version LEXDB is for testing the lexical analyzer. The testprogram 165 * reads a stream of lexemes, enters the revision numbers into the 166 * hashtable, and prints the recognized tokens. Keywords are recognized 167 * as identifiers. 168 */ 169 170 171 172 #include "rcsbase.h" 173 174 libId(lexId, "$DragonFly: src/gnu/usr.bin/rcs/lib/rcslex.c,v 1.2 2003/06/17 04:25:47 dillon Exp $") 175 176 static char *checkidentifier P((char*,int,int)); 177 static void errsay P((char const*)); 178 static void fatsay P((char const*)); 179 static void lookup P((char const*)); 180 static void startsay P((const char*,const char*)); 181 static void warnsay P((char const*)); 182 183 static struct hshentry *nexthsh; /*pointer to next hash entry, set by lookup*/ 184 185 enum tokens nexttok; /*next token, set by nextlex */ 186 187 int hshenter; /*if true, next suitable lexeme will be entered */ 188 /*into the symbol table. Handle with care. */ 189 int nextc; /*next input character, initialized by Lexinit */ 190 191 long rcsline; /*current line-number of input */ 192 int nerror; /*counter for errors */ 193 int quietflag; /*indicates quiet mode */ 194 RILE * finptr; /*input file descriptor */ 195 196 FILE * frewrite; /*file descriptor for echoing input */ 197 198 FILE * foutptr; /* copy of frewrite, but 0 to suppress echo */ 199 200 static struct buf tokbuf; /* token buffer */ 201 202 char const * NextString; /* next token */ 203 204 /* 205 * Our hash algorithm is h[0] = 0, h[i+1] = 4*h[i] + c, 206 * so hshsize should be odd. 207 * See B J McKenzie, R Harries & T Bell, Selecting a hashing algorithm, 208 * Software--practice & experience 20, 2 (Feb 1990), 209-224. 209 */ 210 #ifndef hshsize 211 # define hshsize 511 212 #endif 213 214 static struct hshentry *hshtab[hshsize]; /*hashtable */ 215 216 static int ignored_phrases; /* have we ignored phrases in this RCS file? */ 217 218 void 219 warnignore() 220 { 221 if (!ignored_phrases) { 222 ignored_phrases = true; 223 rcswarn("Unknown phrases like `%s ...;' are present.", NextString); 224 } 225 } 226 227 228 229 static void 230 lookup(str) 231 char const *str; 232 /* Function: Looks up the character string pointed to by str in the 233 * hashtable. If the string is not present, a new entry for it is created. 234 * In any case, the address of the corresponding hashtable entry is placed 235 * into nexthsh. 236 */ 237 { 238 register unsigned ihash; /* index into hashtable */ 239 register char const *sp; 240 register struct hshentry *n, **p; 241 242 /* calculate hash code */ 243 sp = str; 244 ihash = 0; 245 while (*sp) 246 ihash = (ihash<<2) + *sp++; 247 ihash %= hshsize; 248 249 for (p = &hshtab[ihash]; ; p = &n->nexthsh) 250 if (!(n = *p)) { 251 /* empty slot found */ 252 *p = n = ftalloc(struct hshentry); 253 n->num = fstr_save(str); 254 n->nexthsh = 0; 255 # ifdef LEXDB 256 VOID printf("\nEntered: %s at %u ", str, ihash); 257 # endif 258 break; 259 } else if (strcmp(str, n->num) == 0) 260 /* match found */ 261 break; 262 nexthsh = n; 263 NextString = n->num; 264 } 265 266 267 268 269 270 271 void 272 Lexinit() 273 /* Function: Initialization of lexical analyzer: 274 * initializes the hashtable, 275 * initializes nextc, nexttok if finptr != 0 276 */ 277 { register int c; 278 279 for (c = hshsize; 0 <= --c; ) { 280 hshtab[c] = 0; 281 } 282 283 nerror = 0; 284 if (finptr) { 285 foutptr = 0; 286 hshenter = true; 287 ignored_phrases = false; 288 rcsline = 1; 289 bufrealloc(&tokbuf, 2); 290 Iget_(finptr, nextc) 291 nextlex(); /*initial token*/ 292 } 293 } 294 295 296 297 298 299 300 301 void 302 nextlex() 303 304 /* Function: Reads the next token and sets nexttok to the next token code. 305 * Only if hshenter is set, a revision number is entered into the 306 * hashtable and a pointer to it is placed into nexthsh. 307 * This is useful for avoiding that dates are placed into the hashtable. 308 * For ID's and NUM's, NextString is set to the character string. 309 * Assumption: nextc contains the next character. 310 */ 311 { register int c; 312 declarecache; 313 register FILE *frew; 314 register char * sp; 315 char const *limit; 316 register enum tokens d; 317 register RILE *fin; 318 319 fin=finptr; frew=foutptr; 320 setupcache(fin); cache(fin); 321 c = nextc; 322 323 for (;;) { switch ((d = ctab[c])) { 324 325 default: 326 fatserror("unknown character `%c'", c); 327 /*NOTREACHED*/ 328 329 case NEWLN: 330 ++rcsline; 331 # ifdef LEXDB 332 afputc('\n',stdout); 333 # endif 334 /* Note: falls into next case */ 335 336 case SPACE: 337 GETC_(frew, c) 338 continue; 339 340 case IDCHAR: 341 case LETTER: 342 case Letter: 343 d = ID; 344 /* fall into */ 345 case DIGIT: 346 case PERIOD: 347 sp = tokbuf.string; 348 limit = sp + tokbuf.size; 349 *sp++ = c; 350 for (;;) { 351 GETC_(frew, c) 352 switch (ctab[c]) { 353 case IDCHAR: 354 case LETTER: 355 case Letter: 356 d = ID; 357 /* fall into */ 358 case DIGIT: 359 case PERIOD: 360 *sp++ = c; 361 if (limit <= sp) 362 sp = bufenlarge(&tokbuf, &limit); 363 continue; 364 365 default: 366 break; 367 } 368 break; 369 } 370 *sp = 0; 371 if (d == DIGIT || d == PERIOD) { 372 d = NUM; 373 if (hshenter) { 374 lookup(tokbuf.string); 375 break; 376 } 377 } 378 NextString = fstr_save(tokbuf.string); 379 break; 380 381 case SBEGIN: /* long string */ 382 d = STRING; 383 /* note: only the initial SBEGIN has been read*/ 384 /* read the string, and reset nextc afterwards*/ 385 break; 386 387 case COLON: 388 case SEMI: 389 GETC_(frew, c) 390 break; 391 } break; } 392 nextc = c; 393 nexttok = d; 394 uncache(fin); 395 } 396 397 int 398 eoflex() 399 /* 400 * Yield true if we look ahead to the end of the input, false otherwise. 401 * nextc becomes undefined at end of file. 402 */ 403 { 404 register int c; 405 declarecache; 406 register FILE *fout; 407 register RILE *fin; 408 409 c = nextc; 410 fin = finptr; 411 fout = foutptr; 412 setupcache(fin); cache(fin); 413 414 for (;;) { 415 switch (ctab[c]) { 416 default: 417 nextc = c; 418 uncache(fin); 419 return false; 420 421 case NEWLN: 422 ++rcsline; 423 /* fall into */ 424 case SPACE: 425 cachegeteof_(c, {uncache(fin);return true;}) 426 break; 427 } 428 if (fout) 429 aputc_(c, fout) 430 } 431 } 432 433 434 int getlex(token) 435 enum tokens token; 436 /* Function: Checks if nexttok is the same as token. If so, 437 * advances the input by calling nextlex and returns true. 438 * otherwise returns false. 439 * Doesn't work for strings and keywords; loses the character string for ids. 440 */ 441 { 442 if (nexttok==token) { 443 nextlex(); 444 return(true); 445 } else return(false); 446 } 447 448 int 449 getkeyopt(key) 450 char const *key; 451 /* Function: If the current token is a keyword identical to key, 452 * advances the input by calling nextlex and returns true; 453 * otherwise returns false. 454 */ 455 { 456 if (nexttok==ID && strcmp(key,NextString) == 0) { 457 /* match found */ 458 ffree1(NextString); 459 nextlex(); 460 return(true); 461 } 462 return(false); 463 } 464 465 void 466 getkey(key) 467 char const *key; 468 /* Check that the current input token is a keyword identical to key, 469 * and advance the input by calling nextlex. 470 */ 471 { 472 if (!getkeyopt(key)) 473 fatserror("missing '%s' keyword", key); 474 } 475 476 void 477 getkeystring(key) 478 char const *key; 479 /* Check that the current input token is a keyword identical to key, 480 * and advance the input by calling nextlex; then look ahead for a string. 481 */ 482 { 483 getkey(key); 484 if (nexttok != STRING) 485 fatserror("missing string after '%s' keyword", key); 486 } 487 488 489 char const * 490 getid() 491 /* Function: Checks if nexttok is an identifier. If so, 492 * advances the input by calling nextlex and returns a pointer 493 * to the identifier; otherwise returns 0. 494 * Treats keywords as identifiers. 495 */ 496 { 497 register char const *name; 498 if (nexttok==ID) { 499 name = NextString; 500 nextlex(); 501 return name; 502 } else 503 return 0; 504 } 505 506 507 struct hshentry * getnum() 508 /* Function: Checks if nexttok is a number. If so, 509 * advances the input by calling nextlex and returns a pointer 510 * to the hashtable entry. Otherwise returns 0. 511 * Doesn't work if hshenter is false. 512 */ 513 { 514 register struct hshentry * num; 515 if (nexttok==NUM) { 516 num=nexthsh; 517 nextlex(); 518 return num; 519 } else 520 return 0; 521 } 522 523 struct cbuf 524 getphrases(key) 525 char const *key; 526 /* 527 * Get a series of phrases that do not start with KEY. Yield resulting buffer. 528 * Stop when the next phrase starts with a token that is not an identifier, 529 * or is KEY. Copy input to foutptr if it is set. Unlike ignorephrases(), 530 * this routine assumes nextlex() has already been invoked before we start. 531 */ 532 { 533 declarecache; 534 register int c; 535 register char const *kn; 536 struct cbuf r; 537 register RILE *fin; 538 register FILE *frew; 539 # if large_memory 540 # define savech_(c) ; 541 # else 542 register char *p; 543 char const *limit; 544 struct buf b; 545 # define savech_(c) {if (limit<=p)p=bufenlarge(&b,&limit); *p++ =(c);} 546 # endif 547 548 if (nexttok!=ID || strcmp(NextString,key) == 0) 549 clear_buf(&r); 550 else { 551 warnignore(); 552 fin = finptr; 553 frew = foutptr; 554 setupcache(fin); cache(fin); 555 # if large_memory 556 r.string = (char const*)cacheptr() - strlen(NextString) - 1; 557 # else 558 bufautobegin(&b); 559 bufscpy(&b, NextString); 560 p = b.string + strlen(b.string); 561 limit = b.string + b.size; 562 # endif 563 ffree1(NextString); 564 c = nextc; 565 for (;;) { 566 for (;;) { 567 savech_(c) 568 switch (ctab[c]) { 569 default: 570 fatserror("unknown character `%c'", c); 571 /*NOTREACHED*/ 572 case NEWLN: 573 ++rcsline; 574 /* fall into */ 575 case COLON: case DIGIT: case LETTER: case Letter: 576 case PERIOD: case SPACE: 577 GETC_(frew, c) 578 continue; 579 case SBEGIN: /* long string */ 580 for (;;) { 581 for (;;) { 582 GETC_(frew, c) 583 savech_(c) 584 switch (c) { 585 case '\n': 586 ++rcsline; 587 /* fall into */ 588 default: 589 continue; 590 591 case SDELIM: 592 break; 593 } 594 break; 595 } 596 GETC_(frew, c) 597 if (c != SDELIM) 598 break; 599 savech_(c) 600 } 601 continue; 602 case SEMI: 603 cacheget_(c) 604 if (ctab[c] == NEWLN) { 605 if (frew) 606 aputc_(c, frew) 607 ++rcsline; 608 savech_(c) 609 cacheget_(c) 610 } 611 # if large_memory 612 r.size = (char const*)cacheptr() - 1 - r.string; 613 # endif 614 for (;;) { 615 switch (ctab[c]) { 616 case NEWLN: 617 ++rcsline; 618 /* fall into */ 619 case SPACE: 620 cacheget_(c) 621 continue; 622 623 default: break; 624 } 625 break; 626 } 627 if (frew) 628 aputc_(c, frew) 629 break; 630 } 631 break; 632 } 633 if (ctab[c] == Letter) { 634 for (kn = key; c && *kn==c; kn++) 635 GETC_(frew, c) 636 if (!*kn) 637 switch (ctab[c]) { 638 case DIGIT: case LETTER: case Letter: 639 case IDCHAR: case PERIOD: 640 break; 641 default: 642 nextc = c; 643 NextString = fstr_save(key); 644 nexttok = ID; 645 uncache(fin); 646 goto returnit; 647 } 648 # if !large_memory 649 { 650 register char const *ki; 651 for (ki=key; ki<kn; ) 652 savech_(*ki++) 653 } 654 # endif 655 } else { 656 nextc = c; 657 uncache(fin); 658 nextlex(); 659 break; 660 } 661 } 662 returnit:; 663 # if !large_memory 664 return bufremember(&b, (size_t)(p - b.string)); 665 # endif 666 } 667 return r; 668 } 669 670 671 void 672 readstring() 673 /* skip over characters until terminating single SDELIM */ 674 /* If foutptr is set, copy every character read to foutptr. */ 675 /* Does not advance nextlex at the end. */ 676 { register int c; 677 declarecache; 678 register FILE *frew; 679 register RILE *fin; 680 fin=finptr; frew=foutptr; 681 setupcache(fin); cache(fin); 682 for (;;) { 683 GETC_(frew, c) 684 switch (c) { 685 case '\n': 686 ++rcsline; 687 break; 688 689 case SDELIM: 690 GETC_(frew, c) 691 if (c != SDELIM) { 692 /* end of string */ 693 nextc = c; 694 uncache(fin); 695 return; 696 } 697 break; 698 } 699 } 700 } 701 702 703 void 704 printstring() 705 /* Function: copy a string to stdout, until terminated with a single SDELIM. 706 * Does not advance nextlex at the end. 707 */ 708 { 709 register int c; 710 declarecache; 711 register FILE *fout; 712 register RILE *fin; 713 fin=finptr; 714 fout = stdout; 715 setupcache(fin); cache(fin); 716 for (;;) { 717 cacheget_(c) 718 switch (c) { 719 case '\n': 720 ++rcsline; 721 break; 722 case SDELIM: 723 cacheget_(c) 724 if (c != SDELIM) { 725 nextc=c; 726 uncache(fin); 727 return; 728 } 729 break; 730 } 731 aputc_(c,fout) 732 } 733 } 734 735 736 737 struct cbuf 738 savestring(target) 739 struct buf *target; 740 /* Copies a string terminated with SDELIM from file finptr to buffer target. 741 * Double SDELIM is replaced with SDELIM. 742 * If foutptr is set, the string is also copied unchanged to foutptr. 743 * Does not advance nextlex at the end. 744 * Yield a copy of *TARGET, except with exact length. 745 */ 746 { 747 register int c; 748 declarecache; 749 register FILE *frew; 750 register char *tp; 751 register RILE *fin; 752 char const *limit; 753 struct cbuf r; 754 755 fin=finptr; frew=foutptr; 756 setupcache(fin); cache(fin); 757 tp = target->string; limit = tp + target->size; 758 for (;;) { 759 GETC_(frew, c) 760 switch (c) { 761 case '\n': 762 ++rcsline; 763 break; 764 case SDELIM: 765 GETC_(frew, c) 766 if (c != SDELIM) { 767 /* end of string */ 768 nextc=c; 769 r.string = target->string; 770 r.size = tp - r.string; 771 uncache(fin); 772 return r; 773 } 774 break; 775 } 776 if (tp == limit) 777 tp = bufenlarge(target, &limit); 778 *tp++ = c; 779 } 780 } 781 782 783 static char * 784 checkidentifier(id, delimiter, dotok) 785 register char *id; 786 int delimiter; 787 register int dotok; 788 /* Function: check whether the string starting at id is an */ 789 /* identifier and return a pointer to the delimiter*/ 790 /* after the identifier. White space, delim and 0 */ 791 /* are legal delimiters. Aborts the program if not*/ 792 /* a legal identifier. Useful for checking commands*/ 793 /* If !delim, the only delimiter is 0. */ 794 /* Allow '.' in identifier only if DOTOK is set. */ 795 { 796 register char *temp; 797 register char c; 798 register char delim = delimiter; 799 int isid = false; 800 801 temp = id; 802 for (;; id++) { 803 switch (ctab[(unsigned char)(c = *id)]) { 804 case IDCHAR: 805 case LETTER: 806 case Letter: 807 isid = true; 808 continue; 809 810 case DIGIT: 811 continue; 812 813 case PERIOD: 814 if (dotok) 815 continue; 816 break; 817 818 default: 819 break; 820 } 821 break; 822 } 823 if ( ! isid 824 || (c && (!delim || (c!=delim && c!=' ' && c!='\t' && c!='\n'))) 825 ) { 826 /* append \0 to end of id before error message */ 827 while ((c = *id) && c!=' ' && c!='\t' && c!='\n' && c!=delim) 828 id++; 829 *id = '\0'; 830 faterror("invalid %s `%s'", 831 dotok ? "identifier" : "symbol", temp 832 ); 833 } 834 return id; 835 } 836 837 char * 838 checkid(id, delimiter) 839 char *id; 840 int delimiter; 841 { 842 return checkidentifier(id, delimiter, true); 843 } 844 845 char * 846 checksym(sym, delimiter) 847 char *sym; 848 int delimiter; 849 { 850 return checkidentifier(sym, delimiter, false); 851 } 852 853 void 854 checksid(id) 855 char *id; 856 /* Check whether the string ID is an identifier. */ 857 { 858 VOID checkid(id, 0); 859 } 860 861 void 862 checkssym(sym) 863 char *sym; 864 { 865 VOID checksym(sym, 0); 866 } 867 868 869 #if !large_memory 870 # define Iclose(f) fclose(f) 871 #else 872 # if !maps_memory 873 static int Iclose P((RILE *)); 874 static int 875 Iclose(f) 876 register RILE *f; 877 { 878 tfree(f->base); 879 f->base = 0; 880 return fclose(f->stream); 881 } 882 # else 883 static int Iclose P((RILE *)); 884 static int 885 Iclose(f) 886 register RILE *f; 887 { 888 (* f->deallocate) (f); 889 f->base = 0; 890 return close(f->fd); 891 } 892 893 # if has_map_fd 894 static void map_fd_deallocate P((RILE *)); 895 static void 896 map_fd_deallocate(f) 897 register RILE *f; 898 { 899 if (vm_deallocate( 900 task_self(), 901 (vm_address_t) f->base, 902 (vm_size_t) (f->lim - f->base) 903 ) != KERN_SUCCESS) 904 efaterror("vm_deallocate"); 905 } 906 # endif 907 # if has_mmap 908 static void mmap_deallocate P((RILE *)); 909 static void 910 mmap_deallocate(f) 911 register RILE *f; 912 { 913 if (munmap((char *) f->base, (size_t) (f->lim - f->base)) != 0) 914 efaterror("munmap"); 915 } 916 # endif 917 static void read_deallocate P((RILE *)); 918 static void 919 read_deallocate(f) 920 RILE *f; 921 { 922 tfree(f->base); 923 } 924 925 static void nothing_to_deallocate P((RILE *)); 926 static void 927 nothing_to_deallocate(f) 928 RILE *f; 929 { 930 } 931 # endif 932 #endif 933 934 935 #if large_memory && maps_memory 936 static RILE *fd2_RILE P((int,char const*,struct stat*)); 937 static RILE * 938 fd2_RILE(fd, name, status) 939 #else 940 static RILE *fd2RILE P((int,char const*,char const*,struct stat*)); 941 static RILE * 942 fd2RILE(fd, name, type, status) 943 char const *type; 944 #endif 945 int fd; 946 char const *name; 947 register struct stat *status; 948 { 949 struct stat st; 950 951 if (!status) 952 status = &st; 953 if (fstat(fd, status) != 0) 954 efaterror(name); 955 if (!S_ISREG(status->st_mode)) { 956 error("`%s' is not a regular file", name); 957 VOID close(fd); 958 errno = EINVAL; 959 return 0; 960 } else { 961 962 # if !(large_memory && maps_memory) 963 FILE *stream; 964 if (!(stream = fdopen(fd, type))) 965 efaterror(name); 966 # endif 967 968 # if !large_memory 969 return stream; 970 # else 971 # define RILES 3 972 { 973 static RILE rilebuf[RILES]; 974 975 register RILE *f; 976 size_t s = status->st_size; 977 978 if (s != status->st_size) 979 faterror("%s: too large", name); 980 for (f = rilebuf; f->base; f++) 981 if (f == rilebuf+RILES) 982 faterror("too many RILEs"); 983 # if maps_memory 984 f->deallocate = nothing_to_deallocate; 985 # endif 986 if (!s) { 987 static unsigned char nothing; 988 f->base = ¬hing; /* Any nonzero address will do. */ 989 } else { 990 f->base = 0; 991 # if has_map_fd 992 map_fd( 993 fd, (vm_offset_t)0, (vm_address_t*) &f->base, 994 TRUE, (vm_size_t)s 995 ); 996 f->deallocate = map_fd_deallocate; 997 # endif 998 # if has_mmap 999 if (!f->base) { 1000 catchmmapints(); 1001 f->base = (unsigned char *) mmap( 1002 (char *)0, s, PROT_READ, MAP_SHARED, 1003 fd, (off_t)0 1004 ); 1005 # ifndef MAP_FAILED 1006 # define MAP_FAILED (-1) 1007 # endif 1008 if (f->base == (unsigned char *) MAP_FAILED) 1009 f->base = 0; 1010 else { 1011 # if has_NFS && mmap_signal 1012 /* 1013 * On many hosts, the superuser 1014 * can mmap an NFS file it can't read. 1015 * So access the first page now, and print 1016 * a nice message if a bus error occurs. 1017 */ 1018 readAccessFilenameBuffer(name, f->base); 1019 # endif 1020 } 1021 f->deallocate = mmap_deallocate; 1022 } 1023 # endif 1024 if (!f->base) { 1025 f->base = tnalloc(unsigned char, s); 1026 # if maps_memory 1027 { 1028 /* 1029 * We can't map the file into memory for some reason. 1030 * Read it into main memory all at once; this is 1031 * the simplest substitute for memory mapping. 1032 */ 1033 char *bufptr = (char *) f->base; 1034 size_t bufsiz = s; 1035 do { 1036 ssize_t r = read(fd, bufptr, bufsiz); 1037 switch (r) { 1038 case -1: 1039 efaterror(name); 1040 1041 case 0: 1042 /* The file must have shrunk! */ 1043 status->st_size = s -= bufsiz; 1044 bufsiz = 0; 1045 break; 1046 1047 default: 1048 bufptr += r; 1049 bufsiz -= r; 1050 break; 1051 } 1052 } while (bufsiz); 1053 if (lseek(fd, (off_t)0, SEEK_SET) == -1) 1054 efaterror(name); 1055 f->deallocate = read_deallocate; 1056 } 1057 # endif 1058 } 1059 } 1060 f->ptr = f->base; 1061 f->lim = f->base + s; 1062 f->fd = fd; 1063 # if !maps_memory 1064 f->readlim = f->base; 1065 f->stream = stream; 1066 # endif 1067 if_advise_access(s, f, MADV_SEQUENTIAL); 1068 return f; 1069 } 1070 # endif 1071 } 1072 } 1073 1074 #if !maps_memory && large_memory 1075 int 1076 Igetmore(f) 1077 register RILE *f; 1078 { 1079 register fread_type r; 1080 register size_t s = f->lim - f->readlim; 1081 1082 if (BUFSIZ < s) 1083 s = BUFSIZ; 1084 if (!(r = Fread(f->readlim, sizeof(*f->readlim), s, f->stream))) { 1085 testIerror(f->stream); 1086 f->lim = f->readlim; /* The file might have shrunk! */ 1087 return 0; 1088 } 1089 f->readlim += r; 1090 return 1; 1091 } 1092 #endif 1093 1094 #if has_madvise && has_mmap && large_memory 1095 void 1096 advise_access(f, advice) 1097 register RILE *f; 1098 int advice; 1099 { 1100 if (f->deallocate == mmap_deallocate) 1101 VOID madvise((char *)f->base, (size_t)(f->lim - f->base), advice); 1102 /* Don't worry if madvise fails; it's only advisory. */ 1103 } 1104 #endif 1105 1106 RILE * 1107 #if large_memory && maps_memory 1108 I_open(name, status) 1109 #else 1110 Iopen(name, type, status) 1111 char const *type; 1112 #endif 1113 char const *name; 1114 struct stat *status; 1115 /* Open NAME for reading, yield its descriptor, and set *STATUS. */ 1116 { 1117 int fd = fdSafer(open(name, O_RDONLY 1118 # if OPEN_O_BINARY 1119 | (strchr(type,'b') ? OPEN_O_BINARY : 0) 1120 # endif 1121 )); 1122 1123 if (fd < 0) 1124 return 0; 1125 # if large_memory && maps_memory 1126 return fd2_RILE(fd, name, status); 1127 # else 1128 return fd2RILE(fd, name, type, status); 1129 # endif 1130 } 1131 1132 1133 static int Oerrloop; 1134 1135 void 1136 Oerror() 1137 { 1138 if (Oerrloop) 1139 exiterr(); 1140 Oerrloop = true; 1141 efaterror("output error"); 1142 } 1143 1144 void Ieof() { fatserror("unexpected end of file"); } 1145 void Ierror() { efaterror("input error"); } 1146 void testIerror(f) FILE *f; { if (ferror(f)) Ierror(); } 1147 void testOerror(o) FILE *o; { if (ferror(o)) Oerror(); } 1148 1149 void Ifclose(f) RILE *f; { if (f && Iclose(f)!=0) Ierror(); } 1150 void Ofclose(f) FILE *f; { if (f && fclose(f)!=0) Oerror(); } 1151 void Izclose(p) RILE **p; { Ifclose(*p); *p = 0; } 1152 void Ozclose(p) FILE **p; { Ofclose(*p); *p = 0; } 1153 1154 #if !large_memory 1155 void 1156 testIeof(f) 1157 FILE *f; 1158 { 1159 testIerror(f); 1160 if (feof(f)) 1161 Ieof(); 1162 } 1163 void Irewind(f) FILE *f; { if (fseek(f,0L,SEEK_SET) != 0) Ierror(); } 1164 #endif 1165 1166 void Orewind(f) FILE *f; { if (fseek(f,0L,SEEK_SET) != 0) Oerror(); } 1167 1168 void aflush(f) FILE *f; { if (fflush(f) != 0) Oerror(); } 1169 void eflush() { if (fflush(stderr)!=0 && !Oerrloop) Oerror(); } 1170 void oflush() 1171 { 1172 if (fflush(workstdout ? workstdout : stdout) != 0 && !Oerrloop) 1173 Oerror(); 1174 } 1175 1176 void 1177 fatcleanup(already_newline) 1178 int already_newline; 1179 { 1180 VOID fprintf(stderr, already_newline+"\n%s aborted\n", cmdid); 1181 exiterr(); 1182 } 1183 1184 static void 1185 startsay(s, t) 1186 const char *s, *t; 1187 { 1188 oflush(); 1189 if (s) 1190 aprintf(stderr, "%s: %s: %s", cmdid, s, t); 1191 else 1192 aprintf(stderr, "%s: %s", cmdid, t); 1193 } 1194 1195 static void 1196 fatsay(s) 1197 char const *s; 1198 { 1199 startsay(s, ""); 1200 } 1201 1202 static void 1203 errsay(s) 1204 char const *s; 1205 { 1206 fatsay(s); 1207 nerror++; 1208 } 1209 1210 static void 1211 warnsay(s) 1212 char const *s; 1213 { 1214 startsay(s, "warning: "); 1215 } 1216 1217 void eerror(s) char const *s; { enerror(errno,s); } 1218 1219 void 1220 enerror(e,s) 1221 int e; 1222 char const *s; 1223 { 1224 errsay((char const*)0); 1225 errno = e; 1226 perror(s); 1227 eflush(); 1228 } 1229 1230 void efaterror(s) char const *s; { enfaterror(errno,s); } 1231 1232 void 1233 enfaterror(e,s) 1234 int e; 1235 char const *s; 1236 { 1237 fatsay((char const*)0); 1238 errno = e; 1239 perror(s); 1240 fatcleanup(true); 1241 } 1242 1243 #if has_prototypes 1244 void 1245 error(char const *format,...) 1246 #else 1247 /*VARARGS1*/ void error(format, va_alist) char const *format; va_dcl 1248 #endif 1249 /* non-fatal error */ 1250 { 1251 va_list args; 1252 errsay((char const*)0); 1253 vararg_start(args, format); 1254 fvfprintf(stderr, format, args); 1255 va_end(args); 1256 afputc('\n',stderr); 1257 eflush(); 1258 } 1259 1260 #if has_prototypes 1261 void 1262 rcserror(char const *format,...) 1263 #else 1264 /*VARARGS1*/ void rcserror(format, va_alist) char const *format; va_dcl 1265 #endif 1266 /* non-fatal RCS file error */ 1267 { 1268 va_list args; 1269 errsay(RCSname); 1270 vararg_start(args, format); 1271 fvfprintf(stderr, format, args); 1272 va_end(args); 1273 afputc('\n',stderr); 1274 eflush(); 1275 } 1276 1277 #if has_prototypes 1278 void 1279 workerror(char const *format,...) 1280 #else 1281 /*VARARGS1*/ void workerror(format, va_alist) char const *format; va_dcl 1282 #endif 1283 /* non-fatal working file error */ 1284 { 1285 va_list args; 1286 errsay(workname); 1287 vararg_start(args, format); 1288 fvfprintf(stderr, format, args); 1289 va_end(args); 1290 afputc('\n',stderr); 1291 eflush(); 1292 } 1293 1294 #if has_prototypes 1295 void 1296 fatserror(char const *format,...) 1297 #else 1298 /*VARARGS1*/ void 1299 fatserror(format, va_alist) char const *format; va_dcl 1300 #endif 1301 /* fatal RCS file syntax error */ 1302 { 1303 va_list args; 1304 oflush(); 1305 VOID fprintf(stderr, "%s: %s:%ld: ", cmdid, RCSname, rcsline); 1306 vararg_start(args, format); 1307 fvfprintf(stderr, format, args); 1308 va_end(args); 1309 fatcleanup(false); 1310 } 1311 1312 #if has_prototypes 1313 void 1314 faterror(char const *format,...) 1315 #else 1316 /*VARARGS1*/ void faterror(format, va_alist) 1317 char const *format; va_dcl 1318 #endif 1319 /* fatal error, terminates program after cleanup */ 1320 { 1321 va_list args; 1322 fatsay((char const*)0); 1323 vararg_start(args, format); 1324 fvfprintf(stderr, format, args); 1325 va_end(args); 1326 fatcleanup(false); 1327 } 1328 1329 #if has_prototypes 1330 void 1331 rcsfaterror(char const *format,...) 1332 #else 1333 /*VARARGS1*/ void rcsfaterror(format, va_alist) 1334 char const *format; va_dcl 1335 #endif 1336 /* fatal RCS file error, terminates program after cleanup */ 1337 { 1338 va_list args; 1339 fatsay(RCSname); 1340 vararg_start(args, format); 1341 fvfprintf(stderr, format, args); 1342 va_end(args); 1343 fatcleanup(false); 1344 } 1345 1346 #if has_prototypes 1347 void 1348 warn(char const *format,...) 1349 #else 1350 /*VARARGS1*/ void warn(format, va_alist) char const *format; va_dcl 1351 #endif 1352 /* warning */ 1353 { 1354 va_list args; 1355 if (!quietflag) { 1356 warnsay((char *)0); 1357 vararg_start(args, format); 1358 fvfprintf(stderr, format, args); 1359 va_end(args); 1360 afputc('\n', stderr); 1361 eflush(); 1362 } 1363 } 1364 1365 #if has_prototypes 1366 void 1367 rcswarn(char const *format,...) 1368 #else 1369 /*VARARGS1*/ void rcswarn(format, va_alist) char const *format; va_dcl 1370 #endif 1371 /* RCS file warning */ 1372 { 1373 va_list args; 1374 if (!quietflag) { 1375 warnsay(RCSname); 1376 vararg_start(args, format); 1377 fvfprintf(stderr, format, args); 1378 va_end(args); 1379 afputc('\n', stderr); 1380 eflush(); 1381 } 1382 } 1383 1384 #if has_prototypes 1385 void 1386 workwarn(char const *format,...) 1387 #else 1388 /*VARARGS1*/ void workwarn(format, va_alist) char const *format; va_dcl 1389 #endif 1390 /* working file warning */ 1391 { 1392 va_list args; 1393 if (!quietflag) { 1394 warnsay(workname); 1395 vararg_start(args, format); 1396 fvfprintf(stderr, format, args); 1397 va_end(args); 1398 afputc('\n', stderr); 1399 eflush(); 1400 } 1401 } 1402 1403 void 1404 redefined(c) 1405 int c; 1406 { 1407 warn("redefinition of -%c option", c); 1408 } 1409 1410 #if has_prototypes 1411 void 1412 diagnose(char const *format,...) 1413 #else 1414 /*VARARGS1*/ void diagnose(format, va_alist) char const *format; va_dcl 1415 #endif 1416 /* prints a diagnostic message */ 1417 /* Unlike the other routines, it does not append a newline. */ 1418 /* This lets some callers suppress the newline, and is faster */ 1419 /* in implementations that flush stderr just at the end of each printf. */ 1420 { 1421 va_list args; 1422 if (!quietflag) { 1423 oflush(); 1424 vararg_start(args, format); 1425 fvfprintf(stderr, format, args); 1426 va_end(args); 1427 eflush(); 1428 } 1429 } 1430 1431 1432 1433 void 1434 afputc(c, f) 1435 /* afputc(c,f); acts like aputc_(c,f) but is smaller and slower. */ 1436 int c; 1437 register FILE *f; 1438 { 1439 aputc_(c,f) 1440 } 1441 1442 1443 void 1444 aputs(s, iop) 1445 char const *s; 1446 FILE *iop; 1447 /* Function: Put string s on file iop, abort on error. 1448 */ 1449 { 1450 #if has_fputs 1451 if (fputs(s, iop) < 0) 1452 Oerror(); 1453 #else 1454 awrite(s, strlen(s), iop); 1455 #endif 1456 } 1457 1458 1459 1460 void 1461 #if has_prototypes 1462 fvfprintf(FILE *stream, char const *format, va_list args) 1463 #else 1464 fvfprintf(stream,format,args) FILE *stream; char *format; va_list args; 1465 #endif 1466 /* like vfprintf, except abort program on error */ 1467 { 1468 #if has_vfprintf 1469 if (vfprintf(stream, format, args) < 0) 1470 Oerror(); 1471 #else 1472 # if has__doprintf 1473 _doprintf(stream, format, args); 1474 # else 1475 # if has__doprnt 1476 _doprnt(format, args, stream); 1477 # else 1478 int *a = (int *)args; 1479 VOID fprintf(stream, format, 1480 a[0], a[1], a[2], a[3], a[4], 1481 a[5], a[6], a[7], a[8], a[9] 1482 ); 1483 # endif 1484 # endif 1485 if (ferror(stream)) 1486 Oerror(); 1487 #endif 1488 } 1489 1490 #if has_prototypes 1491 void 1492 aprintf(FILE *iop, char const *fmt, ...) 1493 #else 1494 /*VARARGS2*/ void 1495 aprintf(iop, fmt, va_alist) 1496 FILE *iop; 1497 char const *fmt; 1498 va_dcl 1499 #endif 1500 /* Function: formatted output. Same as fprintf in stdio, 1501 * but aborts program on error 1502 */ 1503 { 1504 va_list ap; 1505 vararg_start(ap, fmt); 1506 fvfprintf(iop, fmt, ap); 1507 va_end(ap); 1508 } 1509 1510 1511 1512 #ifdef LEXDB 1513 /* test program reading a stream of lexemes and printing the tokens. 1514 */ 1515 1516 1517 1518 int 1519 main(argc,argv) 1520 int argc; char * argv[]; 1521 { 1522 cmdid="lextest"; 1523 if (argc<2) { 1524 aputs("No input file\n",stderr); 1525 exitmain(EXIT_FAILURE); 1526 } 1527 if (!(finptr=Iopen(argv[1], FOPEN_R, (struct stat*)0))) { 1528 faterror("can't open input file %s",argv[1]); 1529 } 1530 Lexinit(); 1531 while (!eoflex()) { 1532 switch (nexttok) { 1533 1534 case ID: 1535 VOID printf("ID: %s",NextString); 1536 break; 1537 1538 case NUM: 1539 if (hshenter) 1540 VOID printf("NUM: %s, index: %d",nexthsh->num, nexthsh-hshtab); 1541 else 1542 VOID printf("NUM, unentered: %s",NextString); 1543 hshenter = !hshenter; /*alternate between dates and numbers*/ 1544 break; 1545 1546 case COLON: 1547 VOID printf("COLON"); break; 1548 1549 case SEMI: 1550 VOID printf("SEMI"); break; 1551 1552 case STRING: 1553 readstring(); 1554 VOID printf("STRING"); break; 1555 1556 case UNKN: 1557 VOID printf("UNKN"); break; 1558 1559 default: 1560 VOID printf("DEFAULT"); break; 1561 } 1562 VOID printf(" | "); 1563 nextlex(); 1564 } 1565 exitmain(EXIT_SUCCESS); 1566 } 1567 1568 void exiterr() { _exit(EXIT_FAILURE); } 1569 1570 1571 #endif 1572