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