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