refactoring the directories, especially for scripts; moved gimp stuff out to db since...
[feisty_meow.git] / nucleus / 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         //hmmm: is this right?
113         /* no break */
114     case ENDIF:
115       if (recursion)
116         return(type);
117       break;
118     case DEFINE:
119       define(line, file);
120       break;
121     case UNDEF:
122       if (!*line) {
123           warning("%s, line %d: incomplete undef == \"%s\"\n",
124         file_red->i_file, filep->f_line, line);
125           break;
126       }
127       undefine(line, file_red);
128       break;
129     case INCLUDE:
130       add_include(filep, file, file_red, line, false, failOK);
131       break;
132     case INCLUDEDOT:
133       add_include(filep, file, file_red, line, true, failOK);
134       break;
135     case ERROR:
136           warning("%s: %d: %s\n", file_red->i_file,
137          filep->f_line, line);
138           break;
139         
140     case PRAGMA:
141     case IDENT:
142     case SCCS:
143     case EJECT:
144     case IMPORT:
145       break;
146     case -1:
147       warning("%s", file_red->i_file);
148       if (file_red != file)
149           warning1(" (reading %s)", file->i_file);
150       warning1(", line %d: unknown directive == \"%s\"\n",
151          filep->f_line, line);
152       break;
153     case -2:
154       warning("%s", file_red->i_file);
155       if (file_red != file)
156           warning1(" (reading %s)", file->i_file);
157       warning1(", line %d: incomplete include == \"%s\"\n",
158          filep->f_line, line);
159       break;
160     }
161   }
162   return(-1);
163 }
164
165 int gobble(register struct filepointer *filep, inclist *file,
166     inclist *file_red)
167 {
168   register char  *line;
169   register int  type;
170
171   while ((line = getline(filep))) {
172     switch(type = deftype(line, filep, file_red, file, false)) {
173     case IF:
174     case IFFALSE:
175     case IFGUESSFALSE:
176     case IFDEF:
177     case IFNDEF:
178       type = gobble(filep, file, file_red);
179       while ((type == ELIF) || (type == ELIFFALSE) ||
180              (type == ELIFGUESSFALSE))
181           type = gobble(filep, file, file_red);
182       if (type == ELSE)
183               (void)gobble(filep, file, file_red);
184       break;
185     case ELSE:
186     case ENDIF:
187       debug(0,("%s, line %d: #%s\n",
188         file->i_file, filep->f_line,
189         directives[type]));
190       return(type);
191     case DEFINE:
192     case UNDEF:
193     case INCLUDE:
194     case INCLUDEDOT:
195     case PRAGMA:
196     case ERROR:
197     case IDENT:
198     case SCCS:
199     case EJECT:
200     case IMPORT:
201       break;
202     case ELIF:
203     case ELIFFALSE:
204     case ELIFGUESSFALSE:
205       return(type);
206     case -1:
207       warning("%s, line %d: unknown directive == \"%s\"\n",
208         file_red->i_file, filep->f_line, line);
209       break;
210     }
211   }
212   return(-1);
213 }
214
215 /*
216  * Decide what type of # directive this line is.
217  */
218 int deftype(register char  *line, register struct filepointer *filep,
219     register inclist *file_red, register inclist *file,
220     int parse_it)
221 {
222   register char  *p;
223   char  *directive, savechar;
224   register int  ret;
225
226   /*
227    * Parse the directive...
228    */
229   directive=line+1;
230   while (*directive == ' ' || *directive == '\t')
231     directive++;
232
233   p = directive;
234   while (*p >= 'a' && *p <= 'z')
235     p++;
236   savechar = *p;
237   *p = '\0';
238   ret = match(directive, directives);
239   *p = savechar;
240
241   /* If we don't recognize this compiler directive or we happen to just
242    * be gobbling up text while waiting for an #endif or #elif or #else
243    * in the case of an #elif we must check the zero_value and return an
244    * ELIF or an ELIFFALSE.
245    */
246
247   if (ret == ELIF && !parse_it)
248   {
249       while (*p == ' ' || *p == '\t')
250     p++;
251       /*
252        * parse an expression.
253        */
254       debug(0,("%s, line %d: #elif %s ",
255        file->i_file, filep->f_line, p));
256       ret = zero_value(p, filep, file_red);
257       if (ret != IF)
258       {
259     debug(0,("false...\n"));
260     if (ret == IFFALSE)
261         return(ELIFFALSE);
262     else
263         return(ELIFGUESSFALSE);
264       }
265       else
266       {
267     debug(0,("true...\n"));
268     return(ELIF);
269       }
270   }
271
272   if (ret < 0 || ! parse_it)
273     return(ret);
274
275   /*
276    * now decide how to parse the directive, and do it.
277    */
278   while (*p == ' ' || *p == '\t')
279     p++;
280   switch (ret) {
281   case IF:
282     /*
283      * parse an expression.
284      */
285     ret = zero_value(p, filep, file_red);
286     debug(0,("%s, line %d: %s #if %s\n",
287        file->i_file, filep->f_line, ret?"false":"true", p));
288     break;
289   case IFDEF:
290   case IFNDEF:
291     debug(0,("%s, line %d: #%s %s\n",
292       file->i_file, filep->f_line, directives[ret], p));
293     //hmmm: no break here either?
294   case UNDEF:
295     /*
296      * separate the name of a single symbol.
297      */
298     while (isalnum(*p) || *p == '_')
299       *line++ = *p++;
300     *line = '\0';
301     break;
302   case INCLUDE:
303     debug(2,("%s, line %d: #include %s\n",
304       file->i_file, filep->f_line, p));
305
306     /* Support ANSI macro substitution */
307     {
308         struct symtab *sym = isdefined(p, file_red, NULL);
309         while (sym) {
310       p = sym->s_value;
311       debug(3,("%s : #includes SYMBOL %s = %s\n",
312              file->i_incstring,
313              sym -> s_name,
314              sym -> s_value));
315       /* mark file as having included a 'soft include' */
316       file->i_included_sym = true; 
317       sym = isdefined(p, file_red, NULL);
318         }
319     }
320
321     /*
322      * Separate the name of the include file.
323      */
324     while (*p && *p != '"' && *p != '<')
325       p++;
326     if (! *p)
327       return(-2);
328     if (*p++ == '"') {
329       ret = INCLUDEDOT;
330       while (*p && *p != '"')
331         *line++ = *p++;
332     } else
333       while (*p && *p != '>')
334         *line++ = *p++;
335     *line = '\0';
336     break;
337   case DEFINE:
338     /*
339      * copy the definition back to the beginning of the line.
340      */
341     strcpy (line, p);
342     break;
343   case ELSE:
344   case ENDIF:
345   case ELIF:
346   case PRAGMA:
347   case ERROR:
348   case IDENT:
349   case SCCS:
350   case EJECT:
351   case IMPORT:
352     debug(0,("%s, line %d: #%s\n",
353       file->i_file, filep->f_line, directives[ret]));
354     /*
355      * nothing to do.
356      */
357     break;
358   }
359   return(ret);
360 }
361
362 symtab *isdefined(register char *symbol, inclist *file,
363     inclist  **srcfile)
364 {
365   register struct symtab  *val;
366
367   if ((val = slookup(symbol, &maininclist))) {
368     debug(1,("%s defined on command line\n", symbol));
369     if (srcfile != NULL) *srcfile = &maininclist;
370     return(val);
371   }
372   if ((val = fdefined(symbol, file, srcfile)))
373     return(val);
374   debug(1,("%s not defined in %s\n", symbol, file->i_file));
375   return(NULL);
376 }
377
378 struct symtab *fdefined(register char *symbol, inclist  *file, inclist  **srcfile)
379 {
380   register inclist  **ip;
381   register struct symtab  *val;
382   register int  i;
383   static int  recurse_lvl = 0;
384
385   if (file->i_defchecked)
386     return(NULL);
387   file->i_defchecked = true;
388   if ((val = slookup(symbol, file)))
389     debug(1,("%s defined in %s as %s\n", symbol, file->i_file, val->s_value));
390   if (val == NULL && file->i_list)
391     {
392     for (ip = file->i_list, i=0; i < file->i_listlen; i++, ip++)
393       if ((val = fdefined(symbol, *ip, srcfile))) {
394         break;
395       }
396     }
397   else if (val != NULL && srcfile != NULL) *srcfile = file;
398   recurse_lvl--;
399   file->i_defchecked = false;
400
401   return(val);
402 }
403
404 /*
405  * Return type based on if the #if expression evaluates to 0
406  */
407 int zero_value(register char  *exp, register struct filepointer *filep,
408     register inclist *file_red)
409 {
410   if (cppsetup(exp, filep, file_red))
411       return(IFFALSE);
412   else
413       return(IF);
414 }
415
416 void define(char  *def, inclist  *file)
417 {
418     char *val;
419
420     /* Separate symbol name and its value */
421     val = def;
422     while (isalnum(*val) || *val == '_')
423   val++;
424     if (*val)
425   *val++ = '\0';
426     while (*val == ' ' || *val == '\t')
427   val++;
428
429     if (!*val)
430   val = (char *)"1";
431     define2(def, val, file);
432 }
433
434 void define2(char  *name, char  *val, inclist  *file)
435 {
436     int first, last, below;
437     register struct symtab *sp = NULL, *dest;
438
439     /* Make space if it's needed */
440     if (file->i_defs == NULL)
441     {
442   file->i_defs = (struct symtab *)
443       malloc(sizeof (struct symtab) * SYMTABINC);
444   file->i_deflen = SYMTABINC;
445   file->i_ndefs = 0;
446     }
447     else if (file->i_ndefs == file->i_deflen)
448   file->i_defs = (struct symtab *)
449       realloc(file->i_defs,
450           sizeof(struct symtab)*(file->i_deflen+=SYMTABINC));
451
452     if (file->i_defs == NULL)
453   fatalerr("malloc()/realloc() failure in insert_defn()\n");
454
455     below = first = 0;
456     last = file->i_ndefs - 1;
457     while (last >= first)
458     {
459   /* Fast inline binary search */
460   register char *s1;
461   register char *s2;
462   register int middle = (first + last) / 2;
463
464   /* Fast inline strchr() */
465   s1 = name;
466   s2 = file->i_defs[middle].s_name;
467   while (*s1++ == *s2++)
468       if (s2[-1] == '\0') break;
469
470   /* If exact match, set sp and break */
471   if (*--s1 == *--s2) 
472   {
473       sp = file->i_defs + middle;
474       break;
475   }
476
477   /* If name > i_defs[middle] ... */
478   if (*s1 > *s2) 
479   {
480       below = first;
481       first = middle + 1;
482   }
483   /* else ... */
484   else
485   {
486       below = last = middle - 1;
487   }
488     }
489
490     /* Search is done.  If we found an exact match to the symbol name,
491        just replace its s_value */
492     if (sp != NULL)
493     {
494   free(sp->s_value);
495   sp->s_value = copy(val);
496   return;
497     }
498
499     sp = file->i_defs + file->i_ndefs++;
500     dest = file->i_defs + below + 1;
501     while (sp > dest)
502     {
503   *sp = sp[-1];
504   sp--;
505     }
506     sp->s_name = copy(name);
507     sp->s_value = copy(val);
508 }
509
510 struct symtab *slookup(register char  *symbol, register inclist  *file)
511 {
512   register int first = 0;
513   register int last = file->i_ndefs - 1;
514
515   if (file) while (last >= first)
516   {
517       /* Fast inline binary search */
518       register char *s1;
519       register char *s2;
520       register int middle = (first + last) / 2;
521
522       /* Fast inline strchr() */
523       s1 = symbol;
524       s2 = file->i_defs[middle].s_name;
525       while (*s1++ == *s2++)
526           if (s2[-1] == '\0') break;
527
528       /* If exact match, we're done */
529       if (*--s1 == *--s2) 
530       {
531           return file->i_defs + middle;
532       }
533
534       /* If symbol > i_defs[middle] ... */
535       if (*s1 > *s2) 
536       {
537           first = middle + 1;
538       }
539       /* else ... */
540       else
541       {
542           last = middle - 1;
543       }
544   }
545   return(NULL);
546 }
547
548 void undefine(char  *symbol, register inclist *file)
549 {
550   register struct symtab *ptr;
551   inclist *srcfile;
552   while ((ptr = isdefined(symbol, file, &srcfile)) != NULL)
553   {
554       srcfile->i_ndefs--;
555       for (; ptr < srcfile->i_defs + srcfile->i_ndefs; ptr++)
556     *ptr = ptr[1];
557   }
558 }