1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License, Version 1.0 only 6 * (the "License"). You may not use this file except in compliance 7 * with the License. 8 * 9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10 * or http://www.opensolaris.org/os/licensing. 11 * See the License for the specific language governing permissions 12 * and limitations under the License. 13 * 14 * When distributing Covered Code, include this CDDL HEADER in each 15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16 * If applicable, add the following below this CDDL HEADER, with the 17 * fields enclosed by brackets "[]" replaced with your own identifying 18 * information: Portions Copyright [yyyy] [name of copyright owner] 19 * 20 * CDDL HEADER END 21 */ 22 /* 23 * Copyright (c) 1996-1999 by Sun Microsystems, Inc. 24 * All rights reserved. 25 */ 26 /* Copyright (c) 1988 AT&T */ 27 /* All Rights Reserved */ 28 29 30 /* 31 * University Copyright- Copyright (c) 1982, 1986, 1988 32 * The Regents of the University of California 33 * All Rights Reserved 34 * 35 * University Acknowledgment- Portions of this document are derived from 36 * software developed by the University of California, Berkeley, and its 37 * contributors. 38 */ 39 40 #pragma ident "%Z%%M% %I% %E% SMI" 41 42 /* 43 * ******************************************************************* 44 * COPYRIGHT NOTICE * 45 * ******************************************************************** 46 * This software is copyright (C) 1982 by Pavel Curtis * 47 * * 48 * Permission is granted to reproduce and distribute * 49 * this file by any means so long as no fee is charged * 50 * above a nominal handling fee and so long as this * 51 * notice is always included in the copies. * 52 * * 53 * Other rights are reserved except as explicitly granted * 54 * by written permission of the author. * 55 * Pavel Curtis * 56 * Computer Science Dept. * 57 * 405 Upson Hall * 58 * Cornell University * 59 * Ithaca, NY 14853 * 60 * * 61 * Ph- (607) 256-4934 * 62 * * 63 * Pavel.Cornell@Udel-Relay (ARPAnet) * 64 * decvax!cornell!pavel (UUCPnet) * 65 * ******************************************************************** 66 */ 67 68 /* 69 * comp_parse.c -- The high-level (ha!) parts of the compiler, 70 * that is, the routines which drive the scanner, 71 * etc. 72 * 73 * $Log: RCS/comp_parse.v $ 74 * Revision 2.1 82/10/25 14:45:43 pavel 75 * Added Copyright Notice 76 * 77 * Revision 2.0 82/10/24 15:16:39 pavel 78 * Beta-one Test Release 79 * 80 * Revision 1.3 82/08/23 22:29:39 pavel 81 * The REAL Alpha-one Release Version 82 * 83 * Revision 1.2 82/08/19 19:09:53 pavel 84 * Alpha Test Release One 85 * 86 * Revision 1.1 82/08/12 18:37:12 pavel 87 * Initial revision 88 * 89 * 90 */ 91 92 #include <sys/types.h> 93 #include <sys/stat.h> 94 #include <stdio.h> 95 #include <ctype.h> 96 #include <stdlib.h> 97 #include "curses_inc.h" 98 #include "compiler.h" 99 #include "object.h" 100 101 extern char check_only; 102 extern char *progname; 103 104 char *string_table; 105 int next_free; /* next free character in string_table */ 106 unsigned int table_size = 0; /* current string_table size */ 107 short term_names; /* string table offset - current terminal */ 108 int part2 = 0; /* set to allow old compiled defns to be used */ 109 int complete = 0; /* 1 if entry done with no forward uses */ 110 111 struct use_item { 112 long offset; 113 struct use_item *fptr, *bptr; 114 }; 115 116 struct use_header { 117 struct use_item *head, *tail; 118 }; 119 120 struct use_header use_list = {NULL, NULL}; 121 int use_count = 0; 122 123 /* 124 * The use_list is a doubly-linked list with NULLs terminating the lists: 125 * 126 * use_item use_item use_item 127 * --------- --------- --------- 128 * | | | | | | offset 129 * |-------| |-------| |-------| 130 * | ----+-->| ----+-->| NULL | fptr 131 * |-------| |-------| |-------| 132 * | NULL |<--+---- |<--+---- | bptr 133 * --------- --------- --------- 134 * ^ ^ 135 * | ------------------ | 136 * | | | | | 137 * +--+---- | ----+---+ 138 * | | | 139 * ------------------ 140 * head tail 141 * use_list 142 * 143 */ 144 145 146 /* 147 * compile() 148 * 149 * Main loop of the compiler. 150 * 151 * get_token() 152 * if curr_token != NAMES 153 * err_abort() 154 * while (not at end of file) 155 * do an entry 156 * 157 */ 158 159 void 160 compile() 161 { 162 char line[1024]; 163 int token_type; 164 struct use_item *ptr; 165 int old_use_count; 166 167 token_type = get_token(); 168 169 if (token_type != NAMES) 170 err_abort( 171 "File does not start with terminal names in column one"); 172 173 while (token_type != EOF) 174 token_type = do_entry((struct use_item *)NULL); 175 176 DEBUG(2, "Starting handling of forward USE's\n", ""); 177 178 for (part2 = 0; part2 < 2; part2++) { 179 old_use_count = -1; 180 DEBUG(2, "\n\nPART %d\n\n", part2); 181 while (use_list.head != NULL && old_use_count != use_count) { 182 old_use_count = use_count; 183 for (ptr = use_list.tail; ptr != NULL; 184 ptr = ptr->bptr) { 185 fseek(stdin, ptr->offset, 0); 186 reset_input(); 187 if ((token_type = get_token()) != NAMES) 188 syserr_abort( 189 "Token after a seek not NAMES"); 190 (void) do_entry(ptr); 191 if (complete) 192 dequeue(ptr); 193 } 194 195 for (ptr = use_list.head; ptr != NULL; 196 ptr = ptr->fptr) { 197 fseek(stdin, ptr->offset, 0); 198 reset_input(); 199 if ((token_type = get_token()) != NAMES) 200 syserr_abort( 201 "Token after a seek not NAMES"); 202 (void) do_entry(ptr); 203 if (complete) 204 dequeue(ptr); 205 } 206 207 DEBUG(2, 208 "Finished a pass through enqueued forward USE's\n", ""); 209 } 210 } 211 212 if (use_list.head != NULL && !check_only) { 213 fprintf(stderr, 214 "\nError in following up use-links. Either there is\n"); 215 fprintf(stderr, 216 "a loop in the links or they reference non-existant\n"); 217 fprintf(stderr, 218 "terminals. The following is a list of the entries\n"); 219 fprintf(stderr, "involved:\n\n"); 220 221 for (ptr = use_list.head; ptr != NULL; ptr = ptr->fptr) { 222 fseek(stdin, ptr->offset, 0); 223 fgets(line, 1024, stdin); 224 fprintf(stderr, "%s", line); 225 } 226 227 exit(1); 228 } 229 } 230 231 dump_list(str) 232 char *str; 233 { 234 struct use_item *ptr; 235 char line[512]; 236 237 fprintf(stderr, "dump_list %s\n", str); 238 for (ptr = use_list.head; ptr != NULL; ptr = ptr->fptr) { 239 fseek(stdin, ptr->offset, 0); 240 fgets(line, 1024, stdin); 241 fprintf(stderr, "ptr %x off %d bptr %x fptr %x str %s", 242 ptr, ptr->offset, ptr->bptr, ptr->fptr, line); 243 } 244 fprintf(stderr, "\n"); 245 } 246 247 /* 248 * int 249 * do_entry(item_ptr) 250 * 251 * Compile one entry. During the first pass, item_ptr is NULL. In pass 252 * two, item_ptr points to the current entry in the use_list. 253 * 254 * found-forward-use = FALSE 255 * re-initialise internal arrays 256 * save names in string_table 257 * get_token() 258 * while (not EOF and not NAMES) 259 * if found-forward-use 260 * do nothing 261 * else if 'use' 262 * if handle_use() < 0 263 * found-forward-use = TRUE 264 * else 265 * check for existance and type-correctness 266 * enter cap into structure 267 * if STRING 268 * save string in string_table 269 * get_token() 270 * if ! found-forward-use 271 * dump compiled entry into filesystem 272 * 273 */ 274 275 int 276 do_entry(item_ptr) 277 struct use_item *item_ptr; 278 { 279 long entry_offset; 280 register int token_type; 281 register struct name_table_entry *entry_ptr; 282 int found_forward_use = FALSE; 283 short Booleans[MAXBOOLS], 284 Numbers[MAXNUMS], 285 Strings[MAXSTRINGS]; 286 287 init_structure(Booleans, Numbers, Strings); 288 complete = 0; 289 term_names = save_str(curr_token.tk_name); 290 DEBUG(2, "Starting '%s'\n", curr_token.tk_name); 291 entry_offset = curr_file_pos; 292 293 for (token_type = get_token(); 294 token_type != EOF && token_type != NAMES; 295 token_type = get_token()) { 296 if (found_forward_use) 297 /* do nothing */; 298 else if (strcmp(curr_token.tk_name, "use") == 0) { 299 if (handle_use(item_ptr, entry_offset, 300 Booleans, Numbers, Strings) < 0) 301 found_forward_use = TRUE; 302 } else { 303 entry_ptr = find_entry(curr_token.tk_name); 304 305 if (entry_ptr == NOTFOUND) { 306 warning("Unknown Capability - '%s'", 307 curr_token.tk_name); 308 continue; 309 } 310 311 312 if (token_type != CANCEL && 313 entry_ptr->nte_type != token_type) 314 warning("Wrong type used for capability '%s'", 315 curr_token.tk_name); 316 switch (token_type) { 317 case CANCEL: 318 switch (entry_ptr->nte_type) { 319 case BOOLEAN: 320 Booleans[entry_ptr->nte_index] = -2; 321 break; 322 323 case NUMBER: 324 Numbers[entry_ptr->nte_index] = -2; 325 break; 326 327 case STRING: 328 Strings[entry_ptr->nte_index] = -2; 329 break; 330 } 331 break; 332 333 case BOOLEAN: 334 if (Booleans[entry_ptr->nte_index] == 0) 335 Booleans[entry_ptr->nte_index] = TRUE; 336 break; 337 338 case NUMBER: 339 if (Numbers[entry_ptr->nte_index] == -1) 340 Numbers[entry_ptr->nte_index] = 341 curr_token.tk_valnumber; 342 break; 343 344 case STRING: 345 if (Strings[entry_ptr->nte_index] == -1) 346 Strings[entry_ptr->nte_index] = 347 save_str(curr_token.tk_valstring); 348 break; 349 350 default: 351 warning("Unknown token type"); 352 panic_mode(','); 353 continue; 354 } 355 } /* end else cur_token.name != "use" */ 356 357 } /* endwhile (not EOF and not NAMES) */ 358 359 if (found_forward_use) 360 return (token_type); 361 362 dump_structure(Booleans, Numbers, Strings); 363 364 complete = 1; 365 return (token_type); 366 } 367 368 /* 369 Change all cancellations to a non-entry. 370 For booleans, @ -> false 371 For nums, @ -> -1 372 For strings, @ -> -1 373 374 This only has to be done for entries which 375 have to be compatible with the pre-Vr3 format. 376 */ 377 #ifndef NOCANCELCOMPAT 378 elim_cancellations(Booleans, Numbers, Strings) 379 short Booleans[]; 380 short Numbers[]; 381 short Strings[]; 382 { 383 register int i; 384 for (i = 0; i < BoolCount; i++) { 385 if (Booleans[i] == -2) 386 Booleans[i] = FALSE; 387 } 388 389 for (i = 0; i < NumCount; i++) { 390 if (Numbers[i] == -2) 391 Numbers[i] = -1; 392 } 393 394 for (i = 0; i < StrCount; i++) { 395 if (Strings[i] == -2) 396 Strings[i] = -1; 397 } 398 } 399 #endif /* NOCANCELCOMPAT */ 400 /* 401 Change the cancellation signal from the -2 used internally to 402 the 2 used within the binary. 403 */ 404 change_cancellations(Booleans) 405 short Booleans[]; 406 { 407 register int i; 408 for (i = 0; i < BoolCount; i++) { 409 if (Booleans[i] == -2) 410 Booleans[i] = 2; 411 } 412 413 } 414 415 /* 416 * enqueue(offset) 417 * 418 * Put a record of the given offset onto the use-list. 419 * 420 */ 421 422 enqueue(offset) 423 long offset; 424 { 425 struct use_item *item; 426 427 item = (struct use_item *)malloc(sizeof (struct use_item)); 428 429 if (item == NULL) 430 syserr_abort("Not enough memory for use_list element"); 431 432 item->offset = offset; 433 434 if (use_list.head != NULL) { 435 item->bptr = use_list.tail; 436 use_list.tail->fptr = item; 437 item->fptr = NULL; 438 use_list.tail = item; 439 } else { 440 use_list.tail = use_list.head = item; 441 item->fptr = item->bptr = NULL; 442 } 443 444 use_count ++; 445 } 446 447 /* 448 * dequeue(ptr) 449 * 450 * remove the pointed-to item from the use_list 451 * 452 */ 453 454 dequeue(ptr) 455 struct use_item *ptr; 456 { 457 if (ptr->fptr == NULL) 458 use_list.tail = ptr->bptr; 459 else 460 (ptr->fptr)->bptr = ptr->bptr; 461 462 if (ptr->bptr == NULL) 463 use_list.head = ptr->fptr; 464 else 465 (ptr->bptr)->fptr = ptr->fptr; 466 467 use_count --; 468 } 469 470 /* 471 * invalid_term_name(name) 472 * 473 * Look for invalid characters in a term name. These include 474 * space, tab and '/'. 475 * 476 * Generate an error message if given name does not begin with a 477 * digit or letter, then exit. 478 * 479 * return TRUE if name is invalid. 480 * 481 */ 482 483 static int invalid_term_name(name) 484 register char *name; 485 { 486 int error = 0; 487 if (! isdigit(*name) && ! islower(*name) && ! isupper(*name)) 488 error++; 489 490 for (; *name; name++) 491 if (isalnum(*name)) 492 continue; 493 else if (isspace(*name) || (*name == '/')) 494 return (1); 495 if (error) { 496 fprintf(stderr, "%s: Line %d: Illegal terminal name - '%s'\n", 497 progname, curr_line, name); 498 fprintf(stderr, 499 "Terminal names must start with a letter or digit\n"); 500 exit(1); 501 } 502 return (0); 503 } 504 505 /* 506 * dump_structure() 507 * 508 * Save the compiled version of a description in the filesystem. 509 * 510 * make a copy of the name-list 511 * break it up into first-name and all-but-last-name 512 * if necessary 513 * clear CANCELS out of the structure 514 * creat(first-name) 515 * write object information to first-name 516 * close(first-name) 517 * for each valid name 518 * link to first-name 519 * 520 */ 521 522 dump_structure(Booleans, Numbers, Strings) 523 short Booleans[]; 524 short Numbers[]; 525 short Strings[]; 526 { 527 struct stat64 statbuf; 528 FILE *fp; 529 char name_list[1024]; 530 register char *first_name, *other_names, *cur_name; 531 char filename[128 + 2 + 1]; 532 char linkname[128 + 2 + 1]; 533 int len; 534 int alphastart = 0; 535 extern char *strchr(), *strrchr(); 536 537 strcpy(name_list, term_names + string_table); 538 DEBUG(7, "Name list = '%s'\n", name_list); 539 540 first_name = name_list; 541 /* Set othernames to 1 past first '|' in the list. */ 542 /* Null out that '|' in the process. */ 543 other_names = strchr(first_name, '|'); 544 if (other_names) 545 *other_names++ = '\0'; 546 547 if (invalid_term_name(first_name)) 548 warning("'%s': bad first term name.", first_name); 549 550 551 DEBUG(7, "First name = '%s'\n", first_name); 552 DEBUG(7, "Other names = '%s'\n", other_names ? other_names : "NULL"); 553 554 if ((len = strlen(first_name)) > 128) 555 warning("'%s': terminal name too long.", first_name); 556 else if (len == 1) 557 warning("'%s': terminal name too short.", first_name); 558 559 check_dir(first_name[0]); 560 561 sprintf(filename, "%c/%s", first_name[0], first_name); 562 563 if (strlen(filename) > 16) 564 warning("'%s' filename too long, truncating to '%.16s'\n", 565 filename, filename); 566 if (stat64(filename, &statbuf) >= 0 && statbuf.st_mtime >= start_time) { 567 warning("'%s' defined in more than one entry.", first_name); 568 fprintf(stderr, "Entry being used is '%s'.\n", 569 (unsigned)term_names + string_table); 570 } 571 572 if (!check_only) { 573 unlink(filename); 574 fp = fopen(filename, "w"); 575 if (fp == NULL) { 576 perror(filename); 577 syserr_abort("Can't open %s/%s\n", 578 destination, filename); 579 } 580 DEBUG(1, "Created %.16s\n", filename); 581 } else DEBUG(1, "Would have created %.16s\n", filename); 582 583 #ifndef NOCANCELCOMPAT 584 /* if there is no '+' in the name, eliminate */ 585 /* cancellation markings. */ 586 if (strchr(first_name, '+') == 0) 587 elim_cancellations(Booleans, Numbers, Strings); 588 else 589 #endif /* NOCANCELCOMPAT */ 590 change_cancellations(Booleans); 591 592 if (!check_only) { 593 if (write_object(fp, Booleans, Numbers, Strings) < 0) { 594 syserr_abort("Error in writing %s/%s", 595 destination, filename); 596 } 597 fclose(fp); 598 } 599 600 alphastart = isalpha(first_name[0]); 601 602 while (other_names) { 603 cur_name = other_names; 604 other_names = strchr(cur_name, '|'); 605 if (other_names) 606 *other_names++ = '\0'; 607 if (*cur_name == '\0') 608 continue; 609 610 if ((len = strlen(cur_name)) > 128) { 611 warning("'%s': terminal name too long.", cur_name); 612 continue; 613 } else if (len == 1) { 614 warning("'%s': terminal name too short.", first_name); 615 continue; 616 } 617 618 if (invalid_term_name(cur_name)) { 619 if (other_names) 620 warning("'%s': bad term name found in list.", 621 cur_name); 622 continue; 623 } 624 625 check_dir(cur_name[0]); 626 627 sprintf(linkname, "%c/%s", cur_name[0], cur_name); 628 629 if (strlen(linkname) > 16) { 630 if (other_names) { 631 warning( 632 "'%s' linkname too long, truncating to '%.16s'\n", linkname, linkname); 633 } else { 634 continue; 635 } 636 } 637 alphastart |= isalpha(cur_name[0]); 638 639 if (strcmp(first_name, cur_name) == 0) { 640 warning("Terminal name '%s' synonym for itself", 641 first_name); 642 } else { 643 if (!check_only) { 644 if (stat64(linkname, &statbuf) >= 0 && 645 statbuf.st_mtime >= start_time) { 646 warning( 647 "'%s' defined in more than one entry.", cur_name); 648 fprintf(stderr, 649 "Entry being used is '%s'.\n", 650 (unsigned)term_names + 651 string_table); 652 } 653 unlink(linkname); 654 if (link(filename, linkname) < 0) 655 syserr_abort("Can't link %s to %s", 656 filename, linkname); 657 DEBUG(1, "Linked %.16s\n", linkname); 658 } else DEBUG(1, "Would have linked %.16s\n", linkname); 659 } 660 } 661 662 if (!alphastart) { 663 warning("At least one synonym should begin with a letter."); 664 } 665 } 666 667 /* 668 * int 669 * write_object(fp, Booleans, Numbers, Strings) 670 * 671 * Write out the compiled entry to the given file. 672 * Return 0 if OK or -1 if not. 673 * 674 */ 675 676 #define swap(x) (((x >> 8) & 0377) + 256 * (x & 0377)) 677 678 #define might_swap(x) (must_swap() ? swap(x) : (x)) 679 680 681 int 682 write_object(fp, Booleans, Numbers, Strings) 683 FILE *fp; 684 short Booleans[]; 685 short Numbers[]; 686 short Strings[]; 687 { 688 struct header header; 689 char *namelist; 690 short namelen; 691 char zero = '\0'; 692 register int i; 693 char cBooleans[MAXBOOLS]; 694 register int l_next_free; 695 696 namelist = term_names + string_table; 697 namelen = strlen(namelist) + 1; 698 699 l_next_free = next_free; 700 if (l_next_free % 256 == 255) 701 l_next_free++; 702 703 if (must_swap()) { 704 header.magic = swap(MAGIC); 705 header.name_size = swap(namelen); 706 header.bool_count = swap(BoolCount); 707 header.num_count = swap(NumCount); 708 header.str_count = swap(StrCount); 709 header.str_size = swap(l_next_free); 710 } else { 711 header.magic = MAGIC; 712 header.name_size = namelen; 713 header.bool_count = BoolCount; 714 header.num_count = NumCount; 715 header.str_count = StrCount; 716 header.str_size = l_next_free; 717 } 718 719 for (i = 0; i < BoolCount; i++) 720 cBooleans[i] = Booleans[i]; 721 722 if (fwrite(&header, sizeof (header), 1, fp) != 1 || 723 fwrite(namelist, sizeof (char), namelen, fp) != namelen || 724 fwrite(cBooleans, sizeof (char), BoolCount, fp) != 725 BoolCount) 726 return (-1); 727 728 if ((namelen+BoolCount) % 2 != 0 && 729 fwrite(&zero, sizeof (char), 1, fp) != 1) 730 return (-1); 731 732 if (must_swap()) { 733 for (i = 0; i < NumCount; i++) 734 Numbers[i] = swap(Numbers[i]); 735 for (i = 0; i < StrCount; i++) 736 Strings[i] = swap(Strings[i]); 737 } 738 739 if (fwrite((char *)Numbers, sizeof (short), NumCount, fp) != NumCount || 740 fwrite((char *)Strings, sizeof (short), StrCount, fp) 741 != StrCount || 742 fwrite(string_table, sizeof (char), l_next_free, fp) 743 != l_next_free) 744 return (-1); 745 746 return (0); 747 } 748 749 /* 750 * int 751 * save_str(string) 752 * 753 * copy string into next free part of string_table, doing a realloc() 754 * if necessary. return offset of beginning of string from start of 755 * string_table. 756 * 757 */ 758 759 int 760 save_str(string) 761 char *string; 762 { 763 int old_next_free; 764 765 /* Do not let an offset be 255. It reads as -1 in Vr2 binaries. */ 766 if (next_free % 256 == 255) 767 next_free++; 768 769 old_next_free = next_free; 770 771 if (table_size == 0) { 772 if ((string_table = malloc(1024)) == NULL) 773 syserr_abort("Out of memory"); 774 table_size = 1024; 775 DEBUG(5, "Made initial string table allocation. Size is %u\n", 776 table_size); 777 } 778 779 while (table_size <= next_free + strlen(string)) { 780 if ((string_table = realloc(string_table, table_size + 1024)) 781 == NULL) 782 syserr_abort("Out of memory"); 783 table_size += 1024; 784 DEBUG(5, "Extended string table. Size now %u\n", table_size); 785 } 786 787 strcpy(&string_table[next_free], string); 788 DEBUG(7, "Saved string '%s' ", string); 789 DEBUG(7, "at location %d\n", next_free); 790 next_free += strlen(string) + 1; 791 792 return (old_next_free); 793 } 794 795 /* 796 * init_structure(Booleans, Numbers, Strings) 797 * 798 * Initialise the given arrays 799 * Reset the next_free counter to zero. 800 * 801 */ 802 803 init_structure(Booleans, Numbers, Strings) 804 short Booleans[]; 805 short Numbers[], Strings[]; 806 { 807 int i; 808 809 for (i = 0; i < BoolCount; i++) 810 Booleans[i] = FALSE; 811 812 for (i = 0; i < NumCount; i++) 813 Numbers[i] = -1; 814 815 for (i = 0; i < StrCount; i++) 816 Strings[i] = -1; 817 818 next_free = 0; 819 } 820 821 /* 822 * int 823 * handle_use(item_ptr, entry_offset, Booleans, Numbers, Strings) 824 * 825 * Merge the compiled file whose name is in cur_token.valstring 826 * with the current entry. 827 * 828 * if it's a forward use-link 829 * if item_ptr == NULL 830 * queue it up for later handling 831 * else 832 * ignore it (we're already going through the queue) 833 * else it's a backward use-link 834 * read in the object file for that terminal 835 * merge contents with current structure 836 * 837 * Returned value is 0 if it was a backward link and we 838 * successfully read it in, -1 if a forward link. 839 */ 840 841 int 842 handle_use(item_ptr, entry_offset, Booleans, Numbers, Strings) 843 long entry_offset; 844 struct use_item *item_ptr; 845 short Booleans[]; 846 short Numbers[]; 847 short Strings[]; 848 { 849 struct _bool_struct use_bools; 850 struct _num_struct use_nums; 851 struct _str_struct use_strs; 852 struct stat64 statbuf; 853 char filename[50]; 854 int i; 855 char *UB = &use_bools._auto_left_margin; /* first bool */ 856 short *UN = &use_nums._columns; /* first num */ 857 char **US = &use_strs.strs._back_tab; /* first str */ 858 859 if (invalid_term_name(curr_token.tk_valstring)) 860 warning("%s: bad term name", curr_token.tk_valstring); 861 862 sprintf(filename, "%c/%s", curr_token.tk_valstring[0], 863 curr_token.tk_valstring); 864 865 if (stat64(filename, &statbuf) < 0 || 866 part2 == 0 && statbuf.st_mtime < start_time) { 867 DEBUG(2, "Forward USE to %s", curr_token.tk_valstring); 868 869 if (item_ptr == NULL) { 870 DEBUG(2, " (enqueued)\n", ""); 871 enqueue(entry_offset); 872 } else DEBUG(2, " (skipped)\n", ""); 873 874 return (-1); 875 } else { 876 DEBUG(2, "Backward USE to %s\n", curr_token.tk_valstring); 877 if (read_entry(filename, &use_bools, &use_nums, &use_strs) < 0) 878 syserr_abort("Error in re-reading compiled file %s", 879 filename); 880 881 for (i = 0; i < BoolCount; i++) { 882 if (Booleans[i] == FALSE) 883 if (UB[i] == TRUE) /* now true */ 884 Booleans[i] = TRUE; 885 else if (UB[i] > TRUE) /* cancelled */ 886 Booleans[i] = -2; 887 } 888 889 for (i = 0; i < NumCount; i++) { 890 if (Numbers[i] == -1) 891 Numbers[i] = UN[i]; 892 } 893 894 for (i = 0; i < StrCount; i++) { 895 if (Strings[i] == -1) 896 if (US[i] == (char *)-1) 897 Strings[i] = -2; 898 else if (US[i] != (char *)0) 899 Strings[i] = save_str(US[i]); 900 } 901 902 } 903 return (0); 904 } 905