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