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