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
compile()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
dump_list(char * str)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
do_entry(struct use_item * item_ptr)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
elim_cancellations(short Booleans[],short Numbers[],short Strings[])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
change_cancellations(short Booleans[])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
enqueue(long offset)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
dequeue(struct use_item * ptr)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
invalid_term_name(char * name)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
dump_structure(short Booleans[],short Numbers[],short Strings[])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
write_object(FILE * fp,short Booleans[],short Numbers[],short Strings[])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
save_str(char * string)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
init_structure(short Booleans[],short Numbers[],short Strings[])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
handle_use(struct use_item * item_ptr,long entry_offset,short Booleans[],short Numbers[],short Strings[])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