first check-in of feisty meow codebase. many things broken still due to recent
[feisty_meow.git] / core / tools / dependency_tool / parse.cpp
1 /* $XConsortium: parse.c,v 1.30 94/04/17 20:10:38 gildea Exp $ */
2 /*
3
4 Copyright (c) 1993, 1994  X Consortium
5
6 Permission is hereby granted, free of charge, to any person obtaining a copy
7 of this software and associated documentation files (the "Software"), to deal
8 in the Software without restriction, including without limitation the rights
9 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 copies of the Software, and to permit persons to whom the Software is
11 furnished to do so, subject to the following conditions:
12
13 The above copyright notice and this permission notice shall be included in
14 all copies or substantial portions of the Software.
15
16 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
19 X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
20 AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
21 CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22
23 Except as contained in this notice, the name of the X Consortium shall not be
24 used in advertising or otherwise to promote the sale, use or other dealings
25 in this Software without prior written authorization from the X Consortium.
26
27 */
28
29 #ifdef __WIN32__
30   #pragma warning(disable : 4996)
31 #endif
32
33 #include "def.h"
34
35 #include <string.h>
36
37 extern const char  *directives[];
38 extern inclist  maininclist;
39
40 int find_includes(struct filepointer *filep, inclist *file, inclist *file_red, int recursion, bool failOK)
41 {
42   register char  *line;
43   register int  type;
44   bool recfailOK;
45
46   while ((line = getline(filep))) {
47     switch(type = deftype(line, filep, file_red, file, true)) {
48     case IF:
49     doif:
50       type = find_includes(filep, file,
51         file_red, recursion+1, failOK);
52       while ((type == ELIF) || (type == ELIFFALSE) ||
53              (type == ELIFGUESSFALSE))
54         type = gobble(filep, file, file_red);
55       if (type == ELSE)
56         gobble(filep, file, file_red);
57       break;
58     case IFFALSE:
59     case IFGUESSFALSE:
60         doiffalse:
61       if (type == IFGUESSFALSE || type == ELIFGUESSFALSE)
62           recfailOK = true;
63       else
64           recfailOK = failOK;
65       type = gobble(filep, file, file_red);
66       if (type == ELSE)
67           find_includes(filep, file,
68             file_red, recursion+1, recfailOK);
69       else
70       if (type == ELIF)
71           goto doif;
72       else
73       if ((type == ELIFFALSE) || (type == ELIFGUESSFALSE))
74           goto doiffalse;
75       break;
76     case IFDEF:
77     case IFNDEF:
78       if ((type == IFDEF && isdefined(line, file_red, NULL))
79        || (type == IFNDEF && !isdefined(line, file_red, NULL))) {
80         debug(1,(type == IFNDEF ?
81             "line %d: %s !def'd in %s via %s%s\n" : "",
82             filep->f_line, line,
83             file->i_file, file_red->i_file, ": doit"));
84         type = find_includes(filep, file,
85           file_red, recursion+1, failOK);
86         while (type == ELIF || type == ELIFFALSE || type == ELIFGUESSFALSE)
87           type = gobble(filep, file, file_red);
88         if (type == ELSE)
89           gobble(filep, file, file_red);
90       }
91       else {
92         debug(1,(type == IFDEF ?
93             "line %d: %s !def'd in %s via %s%s\n" : "",
94             filep->f_line, line,
95             file->i_file, file_red->i_file, ": gobble"));
96         type = gobble(filep, file, file_red);
97         if (type == ELSE)
98           find_includes(filep, file,
99             file_red, recursion+1, failOK);
100         else if (type == ELIF)
101               goto doif;
102         else if (type == ELIFFALSE || type == ELIFGUESSFALSE)
103               goto doiffalse;
104       }
105       break;
106     case ELSE:
107     case ELIFFALSE:
108     case ELIFGUESSFALSE:
109     case ELIF:
110       if (!recursion)
111         gobble(filep, file, file_red);
112     case ENDIF:
113       if (recursion)
114         return(type);
115     case DEFINE:
116       define(line, file);
117       break;
118     case UNDEF:
119       if (!*line) {
120           warning("%s, line %d: incomplete undef == \"%s\"\n",
121         file_red->i_file, filep->f_line, line);
122           break;
123       }
124       undefine(line, file_red);
125       break;
126     case INCLUDE:
127       add_include(filep, file, file_red, line, false, failOK);
128       break;
129     case INCLUDEDOT:
130       add_include(filep, file, file_red, line, true, failOK);
131       break;
132     case ERROR:
133           warning("%s: %d: %s\n", file_red->i_file,
134          filep->f_line, line);
135           break;
136         
137     case PRAGMA:
138     case IDENT:
139     case SCCS:
140     case EJECT:
141     case IMPORT:
142       break;
143     case -1:
144       warning("%s", file_red->i_file);
145       if (file_red != file)
146           warning1(" (reading %s)", file->i_file);
147       warning1(", line %d: unknown directive == \"%s\"\n",
148          filep->f_line, line);
149       break;
150     case -2:
151       warning("%s", file_red->i_file);
152       if (file_red != file)
153           warning1(" (reading %s)", file->i_file);
154       warning1(", line %d: incomplete include == \"%s\"\n",
155          filep->f_line, line);
156       break;
157     }
158   }
159   return(-1);
160 }
161
162 int gobble(register struct filepointer *filep, inclist *file,
163     inclist *file_red)
164 {
165   register char  *line;
166   register int  type;
167
168   while ((line = getline(filep))) {
169     switch(type = deftype(line, filep, file_red, file, false)) {
170     case IF:
171     case IFFALSE:
172     case IFGUESSFALSE:
173     case IFDEF:
174     case IFNDEF:
175       type = gobble(filep, file, file_red);
176       while ((type == ELIF) || (type == ELIFFALSE) ||
177              (type == ELIFGUESSFALSE))
178           type = gobble(filep, file, file_red);
179       if (type == ELSE)
180               (void)gobble(filep, file, file_red);
181       break;
182     case ELSE:
183     case ENDIF:
184       debug(0,("%s, line %d: #%s\n",
185         file->i_file, filep->f_line,
186         directives[type]));
187       return(type);
188     case DEFINE:
189     case UNDEF:
190     case INCLUDE:
191     case INCLUDEDOT:
192     case PRAGMA:
193     case ERROR:
194     case IDENT:
195     case SCCS:
196     case EJECT:
197     case IMPORT:
198       break;
199     case ELIF:
200     case ELIFFALSE:
201     case ELIFGUESSFALSE:
202       return(type);
203     case -1:
204       warning("%s, line %d: unknown directive == \"%s\"\n",
205         file_red->i_file, filep->f_line, line);
206       break;
207     }
208   }
209   return(-1);
210 }
211
212 /*
213  * Decide what type of # directive this line is.
214  */
215 int deftype(register char  *line, register struct filepointer *filep,
216     register inclist *file_red, register inclist *file,
217     int parse_it)
218 {
219   register char  *p;
220   char  *directive, savechar;
221   register int  ret;
222
223   /*
224    * Parse the directive...
225    */
226   directive=line+1;
227   while (*directive == ' ' || *directive == '\t')
228     directive++;
229
230   p = directive;
231   while (*p >= 'a' && *p <= 'z')
232     p++;
233   savechar = *p;
234   *p = '\0';
235   ret = match(directive, directives);
236   *p = savechar;
237
238   /* If we don't recognize this compiler directive or we happen to just
239    * be gobbling up text while waiting for an #endif or #elif or #else
240    * in the case of an #elif we must check the zero_value and return an
241    * ELIF or an ELIFFALSE.
242    */
243
244   if (ret == ELIF && !parse_it)
245   {
246       while (*p == ' ' || *p == '\t')
247     p++;
248       /*
249        * parse an expression.
250        */
251       debug(0,("%s, line %d: #elif %s ",
252        file->i_file, filep->f_line, p));
253       ret = zero_value(p, filep, file_red);
254       if (ret != IF)
255       {
256     debug(0,("false...\n"));
257     if (ret == IFFALSE)
258         return(ELIFFALSE);
259     else
260         return(ELIFGUESSFALSE);
261       }
262       else
263       {
264     debug(0,("true...\n"));
265     return(ELIF);
266       }
267   }
268
269   if (ret < 0 || ! parse_it)
270     return(ret);
271
272   /*
273    * now decide how to parse the directive, and do it.
274    */
275   while (*p == ' ' || *p == '\t')
276     p++;
277   switch (ret) {
278   case IF:
279     /*
280      * parse an expression.
281      */
282     ret = zero_value(p, filep, file_red);
283     debug(0,("%s, line %d: %s #if %s\n",
284        file->i_file, filep->f_line, ret?"false":"true", p));
285     break;
286   case IFDEF:
287   case IFNDEF:
288     debug(0,("%s, line %d: #%s %s\n",
289       file->i_file, filep->f_line, directives[ret], p));
290   case UNDEF:
291     /*
292      * separate the name of a single symbol.
293      */
294     while (isalnum(*p) || *p == '_')
295       *line++ = *p++;
296     *line = '\0';
297     break;
298   case INCLUDE:
299     debug(2,("%s, line %d: #include %s\n",
300       file->i_file, filep->f_line, p));
301
302     /* Support ANSI macro substitution */
303     {
304         struct symtab *sym = isdefined(p, file_red, NULL);
305         while (sym) {
306       p = sym->s_value;
307       debug(3,("%s : #includes SYMBOL %s = %s\n",
308              file->i_incstring,
309              sym -> s_name,
310              sym -> s_value));
311       /* mark file as having included a 'soft include' */
312       file->i_included_sym = true; 
313       sym = isdefined(p, file_red, NULL);
314         }
315     }
316
317     /*
318      * Separate the name of the include file.
319      */
320     while (*p && *p != '"' && *p != '<')
321       p++;
322     if (! *p)
323       return(-2);
324     if (*p++ == '"') {
325       ret = INCLUDEDOT;
326       while (*p && *p != '"')
327         *line++ = *p++;
328     } else
329       while (*p && *p != '>')
330         *line++ = *p++;
331     *line = '\0';
332     break;
333   case DEFINE:
334     /*
335      * copy the definition back to the beginning of the line.
336      */
337     strcpy (line, p);
338     break;
339   case ELSE:
340   case ENDIF:
341   case ELIF:
342   case PRAGMA:
343   case ERROR:
344   case IDENT:
345   case SCCS:
346   case EJECT:
347   case IMPORT:
348     debug(0,("%s, line %d: #%s\n",
349       file->i_file, filep->f_line, directives[ret]));
350     /*
351      * nothing to do.
352      */
353     break;
354   }
355   return(ret);
356 }
357
358 symtab *isdefined(register char *symbol, inclist *file,
359     inclist  **srcfile)
360 {
361   register struct symtab  *val;
362
363   if ((val = slookup(symbol, &maininclist))) {
364     debug(1,("%s defined on command line\n", symbol));
365     if (srcfile != NULL) *srcfile = &maininclist;
366     return(val);
367   }
368   if ((val = fdefined(symbol, file, srcfile)))
369     return(val);
370   debug(1,("%s not defined in %s\n", symbol, file->i_file));
371   return(NULL);
372 }
373
374 struct symtab *fdefined(register char *symbol, inclist  *file, inclist  **srcfile)
375 {
376   register inclist  **ip;
377   register struct symtab  *val;
378   register int  i;
379   static int  recurse_lvl = 0;
380
381   if (file->i_defchecked)
382     return(NULL);
383   file->i_defchecked = true;
384   if ((val = slookup(symbol, file)))
385     debug(1,("%s defined in %s as %s\n", symbol, file->i_file, val->s_value));
386   if (val == NULL && file->i_list)
387     {
388     for (ip = file->i_list, i=0; i < file->i_listlen; i++, ip++)
389       if ((val = fdefined(symbol, *ip, srcfile))) {
390         break;
391       }
392     }
393   else if (val != NULL && srcfile != NULL) *srcfile = file;
394   recurse_lvl--;
395   file->i_defchecked = false;
396
397   return(val);
398 }
399
400 /*
401  * Return type based on if the #if expression evaluates to 0
402  */
403 int zero_value(register char  *exp, register struct filepointer *filep,
404     register inclist *file_red)
405 {
406   if (cppsetup(exp, filep, file_red))
407       return(IFFALSE);
408   else
409       return(IF);
410 }
411
412 void define(char  *def, inclist  *file)
413 {
414     char *val;
415
416     /* Separate symbol name and its value */
417     val = def;
418     while (isalnum(*val) || *val == '_')
419   val++;
420     if (*val)
421   *val++ = '\0';
422     while (*val == ' ' || *val == '\t')
423   val++;
424
425     if (!*val)
426   val = (char *)"1";
427     define2(def, val, file);
428 }
429
430 void define2(char  *name, char  *val, inclist  *file)
431 {
432     int first, last, below;
433     register struct symtab *sp = NULL, *dest;
434
435     /* Make space if it's needed */
436     if (file->i_defs == NULL)
437     {
438   file->i_defs = (struct symtab *)
439       malloc(sizeof (struct symtab) * SYMTABINC);
440   file->i_deflen = SYMTABINC;
441   file->i_ndefs = 0;
442     }
443     else if (file->i_ndefs == file->i_deflen)
444   file->i_defs = (struct symtab *)
445       realloc(file->i_defs,
446           sizeof(struct symtab)*(file->i_deflen+=SYMTABINC));
447
448     if (file->i_defs == NULL)
449   fatalerr("malloc()/realloc() failure in insert_defn()\n");
450
451     below = first = 0;
452     last = file->i_ndefs - 1;
453     while (last >= first)
454     {
455   /* Fast inline binary search */
456   register char *s1;
457   register char *s2;
458   register int middle = (first + last) / 2;
459
460   /* Fast inline strchr() */
461   s1 = name;
462   s2 = file->i_defs[middle].s_name;
463   while (*s1++ == *s2++)
464       if (s2[-1] == '\0') break;
465
466   /* If exact match, set sp and break */
467   if (*--s1 == *--s2) 
468   {
469       sp = file->i_defs + middle;
470       break;
471   }
472
473   /* If name > i_defs[middle] ... */
474   if (*s1 > *s2) 
475   {
476       below = first;
477       first = middle + 1;
478   }
479   /* else ... */
480   else
481   {
482       below = last = middle - 1;
483   }
484     }
485
486     /* Search is done.  If we found an exact match to the symbol name,
487        just replace its s_value */
488     if (sp != NULL)
489     {
490   free(sp->s_value);
491   sp->s_value = copy(val);
492   return;
493     }
494
495     sp = file->i_defs + file->i_ndefs++;
496     dest = file->i_defs + below + 1;
497     while (sp > dest)
498     {
499   *sp = sp[-1];
500   sp--;
501     }
502     sp->s_name = copy(name);
503     sp->s_value = copy(val);
504 }
505
506 struct symtab *slookup(register char  *symbol, register inclist  *file)
507 {
508   register int first = 0;
509   register int last = file->i_ndefs - 1;
510
511   if (file) while (last >= first)
512   {
513       /* Fast inline binary search */
514       register char *s1;
515       register char *s2;
516       register int middle = (first + last) / 2;
517
518       /* Fast inline strchr() */
519       s1 = symbol;
520       s2 = file->i_defs[middle].s_name;
521       while (*s1++ == *s2++)
522           if (s2[-1] == '\0') break;
523
524       /* If exact match, we're done */
525       if (*--s1 == *--s2) 
526       {
527           return file->i_defs + middle;
528       }
529
530       /* If symbol > i_defs[middle] ... */
531       if (*s1 > *s2) 
532       {
533           first = middle + 1;
534       }
535       /* else ... */
536       else
537       {
538           last = middle - 1;
539       }
540   }
541   return(NULL);
542 }
543
544 void undefine(char  *symbol, register inclist *file)
545 {
546   register struct symtab *ptr;
547   inclist *srcfile;
548   while ((ptr = isdefined(symbol, file, &srcfile)) != NULL)
549   {
550       srcfile->i_ndefs--;
551       for (; ptr < srcfile->i_defs + srcfile->i_ndefs; ptr++)
552     *ptr = ptr[1];
553   }
554 }