bug 313956: expand installer .exe contents to make complete mar. r=ted.
[gecko.git] / config / mkdepend / parse.c
blob968d2c4eabec15ad64f6d52cc86f1b32cf60215f
1 /* $Xorg: parse.c,v 1.6 2001/02/09 02:03:16 xorgcvs Exp $ */
2 /*
4 Copyright (c) 1993, 1994, 1998 The Open Group
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.
12 The above copyright notice and this permission notice shall be included in
13 all copies or substantial portions of the Software.
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.
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.
27 /* $XFree86: xc/config/makedepend/parse.c,v 1.12 2002/02/26 05:09:10 tsi Exp $ */
29 #include "def.h"
31 extern char *directives[];
32 extern struct inclist inclist[ MAXFILES ],
33 *inclistnext,
34 maininclist;
35 extern char *includedirs[ ],
36 **includedirsnext;
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);
45 static int
46 gobble(struct filepointer *filep, struct inclist *file,
47 struct inclist *file_red)
49 char *line;
50 int type;
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;
98 return(-1);
102 * Decide what type of # directive this line is.
104 static int
105 deftype (char *line, struct filepointer *filep,
106 struct inclist *file_red, struct inclist *file, int parse_it)
108 register char *p;
109 char *directive, savechar, *q;
110 register int ret;
113 * Parse the directive...
115 directive=line+1;
116 while (*directive == ' ' || *directive == '\t')
117 directive++;
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;
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.
133 if (ret == ELIF && !parse_it)
135 while (*p == ' ' || *p == '\t')
136 p++;
138 * parse an expression.
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)
145 debug(0,("false...\n"));
146 if (ret == IFFALSE)
147 return(ELIFFALSE);
148 else
149 return(ELIFGUESSFALSE);
151 else
153 debug(0,("true...\n"));
154 return(ELIF);
158 if (ret < 0 || ! parse_it)
159 return(ret);
162 * now decide how to parse the directive, and do it.
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:
174 * parse an expression.
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:
186 * separate the name of a single symbol.
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));
198 /* Support ANSI macro substitution */
199 while (1) {
200 struct symtab **sym;
202 if (!*p || *p == '"' || *p == '<')
203 break;
205 sym = isdefined(p, file_red, NULL);
206 if (!sym)
207 break;
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;
219 * Separate the name of the include file.
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:
239 * copy the definition back to the beginning of the line.
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]));
255 * nothing to do.
257 break;
259 return(ret);
262 struct symtab **
263 fdefined(char *symbol, struct inclist *file, struct inclist **srcfile)
265 struct inclist **ip;
266 struct symtab **val;
267 int i;
268 static int recurse_lvl = 0;
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)
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;
286 else if (val != NULL && srcfile != NULL) *srcfile = file;
287 recurse_lvl--;
288 file->i_flags &= ~DEFCHECKED;
290 return(val);
293 struct symtab **
294 isdefined(char *symbol, struct inclist *file, struct inclist **srcfile)
296 struct symtab **val;
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);
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);
310 * Return type based on if the #if expression evaluates to 0
312 static int
313 zero_value(char *filename,
314 char *exp,
315 struct filepointer *filep,
316 struct inclist *file_red)
318 if (cppsetup(filename, exp, filep, file_red))
319 return(IFFALSE);
320 else
321 return(IF);
324 void
325 define2(char *name, char *val, struct inclist *file)
327 int first, last, below;
328 register struct symtab **sp = NULL, **dest;
329 struct symtab *stab;
331 /* Make space if it's needed */
332 if (file->i_defs == NULL)
334 file->i_defs = (struct symtab **)
335 malloc(sizeof (struct symtab*) * SYMTABINC);
336 file->i_ndefs = 0;
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));
343 if (file->i_defs == NULL)
344 fatalerr("malloc()/realloc() failure in insert_defn()\n");
346 below = first = 0;
347 last = file->i_ndefs - 1;
348 while (last >= first)
350 /* Fast inline binary search */
351 register char *s1;
352 register char *s2;
353 register int middle = (first + last) / 2;
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;
361 /* If exact match, set sp and break */
362 if (*--s1 == *--s2)
364 sp = file->i_defs + middle;
365 break;
368 /* If name > i_defs[middle] ... */
369 if (*s1 > *s2)
371 below = first;
372 first = middle + 1;
374 /* else ... */
375 else
377 below = last = middle - 1;
381 /* Search is done. If we found an exact match to the symbol name,
382 just replace its s_value */
383 if (sp != NULL)
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;
392 sp = file->i_defs + file->i_ndefs++;
393 dest = file->i_defs + below + 1;
394 while (sp > dest)
396 *sp = sp[-1];
397 sp--;
399 stab = (struct symtab *) malloc(sizeof (struct symtab));
400 if (stab == NULL)
401 fatalerr("malloc()/realloc() failure in insert_defn()\n");
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;
409 void
410 define(char *def, struct inclist *file)
412 char *val;
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++;
423 if (!*val)
424 val = "1";
425 define2(def, val, file);
428 struct symtab **
429 slookup(char *symbol, struct inclist *file)
431 register int first = 0;
432 register int last = file->i_ndefs - 1;
434 if (file) while (last >= first)
436 /* Fast inline binary search */
437 register char *s1;
438 register char *s2;
439 register int middle = (first + last) / 2;
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;
447 /* If exact match, we're done */
448 if (*--s1 == *--s2)
450 return file->i_defs + middle;
453 /* If symbol > i_defs[middle] ... */
454 if (*s1 > *s2)
456 first = middle + 1;
458 /* else ... */
459 else
461 last = middle - 1;
464 return(NULL);
467 static int
468 merge2defines(struct inclist *file1, struct inclist *file2)
470 int i;
472 if ((file1==NULL) || (file2==NULL) ||
473 !(file2->i_flags & FINISHED))
474 return 0;
476 for (i=0; i < file2->i_listlen; i++)
477 if (file2->i_merged[i]==FALSE)
478 return 0;
481 int first1 = 0;
482 int last1 = file1->i_ndefs - 1;
484 int first2 = 0;
485 int last2 = file2->i_ndefs - 1;
487 int first=0;
488 struct symtab** i_defs = NULL;
489 int deflen=file1->i_ndefs+file2->i_ndefs;
491 debug(2,("merging %s into %s\n",
492 file2->i_file, file1->i_file));
494 if (deflen>0)
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;
503 while ((last1 >= first1) && (last2 >= first2))
505 char *s1=file1->i_defs[first1]->s_name;
506 char *s2=file2->i_defs[first2]->s_name;
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 */
514 i_defs[first++]=file2->i_defs[first2++];
515 first1++;
518 while (last1 >= first1)
520 i_defs[first++]=file1->i_defs[first1++];
522 while (last2 >= first2)
524 i_defs[first++]=file2->i_defs[first2++];
527 if (file1->i_defs) free(file1->i_defs);
528 file1->i_defs=i_defs;
529 file1->i_ndefs=first;
531 return 1;
535 void
536 undefine(char *symbol, struct inclist *file)
538 register struct symtab **ptr;
539 struct inclist *srcfile;
540 while ((ptr = isdefined(symbol, file, &srcfile)) != NULL)
542 srcfile->i_ndefs--;
543 for (; ptr < srcfile->i_defs + srcfile->i_ndefs; ptr++)
544 *ptr = ptr[1];
549 find_includes(struct filepointer *filep, struct inclist *file,
550 struct inclist *file_red, int recursion, boolean failOK)
552 struct inclist *inclistp;
553 char **includedirsp;
554 register char *line;
555 register int type;
556 boolean recfailOK;
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);
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;
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;
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;
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;
683 file->i_flags |= FINISHED;
684 debug(2,("finished with %s\n", file->i_file));
685 return(-1);