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