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