Pristine Ack-5.5
[Ack-5.5.git] / util / ego / ic / ic_lib.c
1 /* $Id: ic_lib.c,v 1.7 1994/06/24 10:24:18 ceriel Exp $ */
2 /*
3  * (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
4  * See the copyright notice in the ACK home directory, in the file "Copyright".
5  */
6 /*  I N T E R M E D I A T E   C O D E
7  *
8  *  I C _ L I B . C
9  */
10
11
12 #include <stdio.h>
13 #include <em_spec.h>
14 #include <em_pseu.h>
15 #include <em_mes.h>
16 #include <arch.h>
17 #include "../share/types.h"
18 #include "../share/debug.h"
19 #include "ic.h"
20 #include "ic_lookup.h"
21 #include "ic_io.h"
22 #include "../share/global.h"
23 #include "../share/files.h"
24 #include "ic_lib.h"
25
26
27 STATIC skip_string(n)
28         offset n;
29 {
30         /* Read a string of length n and void it */
31
32         while (n--) {
33                 readchar();
34         }
35 }
36
37
38 STATIC skip_arguments()
39 {
40         /* Skip the arguments of a MES pseudo. The argument
41          * list is terminated by a sp_cend byte.
42          */
43
44         for (;;) {
45                 switch(table2()) {
46                         case sp_scon:
47                                 get_off(); /* void */
48                                 /* fall through !!! */
49                         case sp_icon:
50                         case sp_ucon:
51                         case sp_fcon:
52                                 get_int(); /* void */
53                                 skip_string(get_off());
54                                 break;
55                         case sp_cend:
56                                 return;
57                         default:
58                                 break;
59                 }
60         }
61 }
62
63
64
65 STATIC bool proc_wanted(name)
66         char *name;
67 {
68         /* See if 'name' is the name of an external procedure
69          * that has been used before, but for which no body
70          * has been given so far.
71          */
72
73         proc_p p;
74
75         if (( p = proclookup(name,IMPORTING)) != (proc_p) 0 &&
76            !(p->p_flags1 & PF_BODYSEEN)) {
77                 return TRUE;
78         } else {
79                 return FALSE;
80         }
81 }
82
83
84
85 STATIC bool data_wanted(name)
86         char *name;
87 {
88         /* See if 'name' is the name of an externally visible
89          * data block that has been used before, but for which
90          * no defining occurrence has been given yet.
91          */
92
93         dblock_p db;
94
95         if ((db = symlookup(name,IMPORTING)) != (dblock_p) 0 &&
96            db->d_pseudo == DUNKNOWN) {
97                 return TRUE;
98         } else {
99                 return FALSE;
100         }
101 }
102
103
104
105 STATIC bool wanted_names()
106 {
107         /* Read the names of procedures and data labels,
108          * appearing in a 'MES ms_ext' pseudo. Those are
109          * the names of entities that are imported by
110          * a library module.
111          * If any of them is wanted, return TRUE.
112          * A name is wanted if it is the name of a procedure
113          * or data block for which applied occurrences but
114          * no defining occurrence has been met.
115          */
116
117         for (;;) {
118                 switch(table2()) {
119                         case DLBX:
120                                 if (data_wanted(string)) {
121                                         return TRUE;
122                                 }
123                                 /* A data entity with the name
124                                  * string is available.
125                                  */
126                                 break;
127                         case sp_pnam:
128                                 if (proc_wanted(string)) {
129                                         return TRUE;
130                                 }
131                                 break;
132                         case sp_cend:
133                                 return FALSE;
134                         default:
135                                 error("wrong argument of MES %d", ms_ext);
136                 }
137         }
138 }
139
140
141
142 STATIC FILE *curfile = NULL;
143 STATIC bool useful()
144 {
145         /* Determine if any entity imported by the current
146          * compact EM assembly file  (which will usually be
147          * part of an archive file) is useful to us.
148          * The file must contain (before any other non-MES line)
149          * a 'MES ms_ext' pseudo that has as arguments the names
150          * of the entities imported.
151          */
152
153         for (;;) {
154                 if (table1() != PSEU || tabval != ps_mes) {
155                         error("cannot find MES %d in library file",ms_ext);
156                 }
157                 if (table2() != CSTX1) {
158                         error("message number expected");
159                 }
160                 if (tabval == ms_ext) {
161                         /* This is the one we searched */
162                         return wanted_names();
163                         /* Read the names of the imported entities
164                          * and check if any of them is wanted.
165                          */
166                 } else {
167                         skip_arguments(); /* skip remainder of this MES */
168                 }
169         }
170 }
171
172
173
174 STATIC bool is_archive(name)
175         char *name;
176 {
177         /* See if 'name' is the name of an archive file, i.e. it
178          * should end on ".ma" and should at least be four characters
179          * long (i.e. the name ".ma" is not accepted as an archive name!).
180          */
181
182         register char *p;
183
184         for (p = name; *p; p++);
185         return (p > name+3) && (*--p == 'a') && (*--p == 'm') && (*--p == '.');
186 }
187
188
189
190 STATIC struct ar_hdr hdr;
191
192 STATIC bool read_hdr()
193 {
194         /* Read the header of an archive module */
195
196         char buf[AR_TOTAL];
197         register char *c = buf;
198         register char *p = hdr.ar_name;
199         register int i;
200
201         fread(c, AR_TOTAL, 1, curfile);
202         if (feof(curfile)) return 0;
203         i = 14;
204         while (i--) {
205                 *p++ = *c++;
206         }
207
208 #define get2(c)        (((c)[0]&0377) | ((unsigned) ((c)[1]&0377) << 8))
209
210         hdr.ar_date = ((long) get2(c)) << 16; c += 2;
211         hdr.ar_date |= ((long) get2(c)) & 0xffff; c += 2;
212         hdr.ar_uid = *c++;
213         hdr.ar_gid = *c++;
214         hdr.ar_mode = get2(c); c += 2;
215         hdr.ar_size = (long) get2(c) << 16; c += 2;
216         hdr.ar_size |= (long) get2(c) & 0xffff;
217
218         return 1;
219 }
220
221
222
223 STATIC int argcnt = ARGSTART - 1;
224 STATIC short arstate = NO_ARCHIVE;
225
226
227 FILE *next_file(argc,argv)
228         int argc;
229         char *argv[];
230 {
231         /* See if there are more EM input files. The file names
232          * are given via argv. If a file is an archive file
233          * it is supposed to be a library of EM compact assembly
234          * files. A module (file) contained in this archive file
235          * is only used if it imports at least one procedure or
236          * datalabel for which we have not yet seen a defining
237          * occurrence, although we have seen a used occurrence.
238          */
239
240          long ptr;
241
242          for (;;) {
243                 /* This loop is only exited via a return */
244                 if (arstate == ARCHIVE) {
245                         /* We were reading an archive file */
246                         if (ftell(curfile) & 1) {
247                                 /* modules in an archive file always
248                                  * begin on a word boundary, i.e. at
249                                  * an even address.
250                                  */
251                                 fseek(curfile,1L,1);
252                         }
253                         if (read_hdr()) { /* read header of next module */
254                                 ptr = ftell(curfile); /* file position */
255                                 file_init(curfile,ARCHIVE,hdr.ar_size);
256                                 /* tell i/o package that we're reading
257                                  * an archive module of given length.
258                                  */
259                                 if (useful()) {
260                                         /* re-initialize file, because 'useful'
261                                          * has read some bytes too.
262                                          */
263                                         fseek(curfile,ptr,0); /* start module */
264                                         file_init(curfile,ARCHIVE,hdr.ar_size);
265                                         return curfile;
266                                 } else {
267                                         /* skip this module */
268                                         fseek(curfile,
269                                           ptr+hdr.ar_size,0);
270                                 }
271                         } else {
272                                 /* done with this archive */
273                                 arstate = NO_ARCHIVE;
274                         }
275                 } else {
276                         /* open next file, close old */
277                         if (curfile != NULL) {
278                                 fclose(curfile);
279                         }
280                         argcnt++;
281                         if (argcnt >= argc) {
282                                 /* done with all arguments */
283                                 return NULL;
284                         }
285                         filename = argv[argcnt];
286                         if ((curfile = fopen(filename,"r")) == NULL) {
287                                 error("cannot open %s",filename);
288                         }
289                         if (is_archive(filename)) {
290                                 /* ends on '.ma' */
291                                 arstate = ARCHIVE;
292                                 arch_init(curfile); /* read magic ar number */
293                         } else {
294                                 file_init(curfile,NO_ARCHIVE,0L);
295                                 return curfile;
296                         }
297                 }
298         }
299 }