10eb10989Smrg/*
20eb10989Smrg
30eb10989SmrgCopyright (c) 1993, 1994, 1998 The Open Group
40eb10989Smrg
50eb10989SmrgPermission to use, copy, modify, distribute, and sell this software and its
60eb10989Smrgdocumentation for any purpose is hereby granted without fee, provided that
70eb10989Smrgthe above copyright notice appear in all copies and that both that
80eb10989Smrgcopyright notice and this permission notice appear in supporting
90eb10989Smrgdocumentation.
100eb10989Smrg
110eb10989SmrgThe above copyright notice and this permission notice shall be included in
120eb10989Smrgall copies or substantial portions of the Software.
130eb10989Smrg
140eb10989SmrgTHE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
150eb10989SmrgIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
160eb10989SmrgFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
170eb10989SmrgOPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
180eb10989SmrgAN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
190eb10989SmrgCONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
200eb10989Smrg
210eb10989SmrgExcept as contained in this notice, the name of The Open Group shall not be
220eb10989Smrgused in advertising or otherwise to promote the sale, use or other dealings
230eb10989Smrgin this Software without prior written authorization from The Open Group.
240eb10989Smrg
250eb10989Smrg*/
260eb10989Smrg
270eb10989Smrg#include "def.h"
280eb10989Smrg
29fadff096Smrgstatic int deftype(char *line, struct filepointer *filep,
30fadff096Smrg                   struct inclist *file_red, struct inclist *file,
31fadff096Smrg                   int parse_it);
320eb10989Smrgstatic int zero_value(char *filename, char *exp, struct filepointer *filep,
33fadff096Smrg                      struct inclist *file_red);
34fadff096Smrgstatic struct symtab **slookup(const char *symbol, struct inclist *file);
35fadff096Smrgstatic boolean merge2defines(struct inclist *file1, struct inclist *file2);
36fadff096Smrg
37fadff096Smrgstatic const char *const directives[] = {
38fadff096Smrg    "if",
39fadff096Smrg    "ifdef",
40fadff096Smrg    "ifndef",
41fadff096Smrg    "else",
42fadff096Smrg    "endif",
43fadff096Smrg    "define",
44fadff096Smrg    "undef",
45fadff096Smrg    "include",
46fadff096Smrg    "line",
47fadff096Smrg    "pragma",
48fadff096Smrg    "error",
49fadff096Smrg    "ident",
50fadff096Smrg    "sccs",
51fadff096Smrg    "elif",
52fadff096Smrg    "eject",
53fadff096Smrg    "warning",
54fadff096Smrg    "include_next",
55fadff096Smrg    NULL
56fadff096Smrg};
570eb10989Smrg
580eb10989Smrgstatic int
590eb10989Smrggobble(struct filepointer *filep, struct inclist *file,
600eb10989Smrg       struct inclist *file_red)
610eb10989Smrg{
62fadff096Smrg    char *line;
63fadff096Smrg
64fadff096Smrg    while ((line = getnextline(filep))) {
65fadff096Smrg        int   type = deftype(line, filep, file_red, file, FALSE);
66fadff096Smrg
67fadff096Smrg        switch (type) {
68fadff096Smrg        case IF:
69fadff096Smrg        case IFFALSE:
70fadff096Smrg        case IFGUESSFALSE:
71fadff096Smrg        case IFDEF:
72fadff096Smrg        case IFNDEF:
73fadff096Smrg            type = gobble(filep, file, file_red);
74fadff096Smrg            while ((type == ELIF) || (type == ELIFFALSE) ||
75fadff096Smrg                   (type == ELIFGUESSFALSE))
76fadff096Smrg                type = gobble(filep, file, file_red);
77fadff096Smrg            if (type == ELSE)
78fadff096Smrg                (void) gobble(filep, file, file_red);
79fadff096Smrg            break;
80fadff096Smrg        case ELSE:
81fadff096Smrg        case ENDIF:
82fadff096Smrg            debug(0, ("%s, line %d: #%s\n",
83fadff096Smrg                      file->i_file, filep->f_line, directives[type]));
84fadff096Smrg            return (type);
85fadff096Smrg        case DEFINE:
86fadff096Smrg        case UNDEF:
87fadff096Smrg        case INCLUDE:
88fadff096Smrg        case INCLUDEDOT:
89fadff096Smrg        case PRAGMA:
90fadff096Smrg        case ERROR:
91fadff096Smrg        case IDENT:
92fadff096Smrg        case SCCS:
93fadff096Smrg        case EJECT:
94fadff096Smrg        case WARNING:
95fadff096Smrg        case INCLUDENEXT:
96fadff096Smrg        case INCLUDENEXTDOT:
97fadff096Smrg            break;
98fadff096Smrg        case ELIF:
99fadff096Smrg        case ELIFFALSE:
100fadff096Smrg        case ELIFGUESSFALSE:
101fadff096Smrg            return (type);
102fadff096Smrg        case -1:
103fadff096Smrg            warning("%s", file_red->i_file);
104fadff096Smrg            if (file_red != file)
105fadff096Smrg                warning1(" (reading %s)", file->i_file);
106fadff096Smrg            warning1(", line %ld: unknown directive == \"%s\"\n",
107fadff096Smrg                     filep->f_line, line);
108fadff096Smrg            break;
109fadff096Smrg        }
110fadff096Smrg    }
111fadff096Smrg    return (-1);
1120eb10989Smrg}
1130eb10989Smrg
1140eb10989Smrg/*
1150eb10989Smrg * Decide what type of # directive this line is.
1160eb10989Smrg */
117d43532a6Smrgstatic int
118fadff096Smrgdeftype(char *line, struct filepointer *filep,
119fadff096Smrg        struct inclist *file_red, struct inclist *file, int parse_it)
1200eb10989Smrg{
121fadff096Smrg    char *p;
122fadff096Smrg    char *directive, savechar, *q;
123fadff096Smrg    int   ret;
124fadff096Smrg
125fadff096Smrg    /*
126fadff096Smrg     * Parse the directive...
127fadff096Smrg     */
128fadff096Smrg    directive = line + 1;
129fadff096Smrg    while (*directive == ' ' || *directive == '\t')
130fadff096Smrg        directive++;
131fadff096Smrg
132fadff096Smrg    p = directive;
133fadff096Smrg    while ((*p == '_') || (*p >= 'a' && *p <= 'z'))
134fadff096Smrg        p++;
135fadff096Smrg    savechar = *p;
136fadff096Smrg    *p = '\0';
137fadff096Smrg    ret = match(directive, directives);
138fadff096Smrg    *p = savechar;
139fadff096Smrg
140fadff096Smrg    /* If we don't recognize this compiler directive or we happen to just
141fadff096Smrg     * be gobbling up text while waiting for an #endif or #elif or #else
142fadff096Smrg     * in the case of an #elif we must check the zero_value and return an
143fadff096Smrg     * ELIF or an ELIFFALSE.
144fadff096Smrg     */
145fadff096Smrg
146fadff096Smrg    if (ret == ELIF && !parse_it) {
147fadff096Smrg        while (*p == ' ' || *p == '\t')
148fadff096Smrg            p++;
149fadff096Smrg        /*
150fadff096Smrg         * parse an expression.
151fadff096Smrg         */
152fadff096Smrg        debug(0, ("%s, line %d: #elif %s ", file->i_file, filep->f_line, p));
153fadff096Smrg        ret = zero_value(file->i_file, p, filep, file_red);
154fadff096Smrg        if (ret != IF) {
155fadff096Smrg            debug(0, ("false...\n"));
156fadff096Smrg            if (ret == IFFALSE)
157fadff096Smrg                return (ELIFFALSE);
158fadff096Smrg            else
159fadff096Smrg                return (ELIFGUESSFALSE);
160fadff096Smrg        }
161fadff096Smrg        else {
162fadff096Smrg            debug(0, ("true...\n"));
163fadff096Smrg            return (ELIF);
164fadff096Smrg        }
165fadff096Smrg    }
166fadff096Smrg
167fadff096Smrg    if (ret < 0 || !parse_it)
168fadff096Smrg        return (ret);
169fadff096Smrg
170fadff096Smrg    /*
171fadff096Smrg     * now decide how to parse the directive, and do it.
172fadff096Smrg     */
173fadff096Smrg    while (*p == ' ' || *p == '\t')
174fadff096Smrg        p++;
175fadff096Smrg    q = p + strlen(p);
176fadff096Smrg    do {
177fadff096Smrg        q--;
178fadff096Smrg    } while (*q == ' ' || *q == '\t');
179fadff096Smrg    q[1] = '\0';
180fadff096Smrg    switch (ret) {
181fadff096Smrg    case IF:
182fadff096Smrg        /*
183fadff096Smrg         * parse an expression.
184fadff096Smrg         */
185fadff096Smrg        ret = zero_value(file->i_file, p, filep, file_red);
186fadff096Smrg        debug(0, ("%s, line %d: %s #if %s\n",
187fadff096Smrg                  file->i_file, filep->f_line, ret ? "false" : "true", p));
188fadff096Smrg        break;
189fadff096Smrg    case IFDEF:
190fadff096Smrg    case IFNDEF:
191fadff096Smrg        debug(0, ("%s, line %d: #%s %s\n",
192fadff096Smrg                  file->i_file, filep->f_line, directives[ret], p));
193fadff096Smrg    case UNDEF:
194fadff096Smrg        /*
195fadff096Smrg         * separate the name of a single symbol.
196fadff096Smrg         */
197fadff096Smrg        while (isalnum(*p) || *p == '_')
198fadff096Smrg            *line++ = *p++;
199fadff096Smrg        *line = '\0';
200fadff096Smrg        break;
201fadff096Smrg    case INCLUDE:
202fadff096Smrg    case INCLUDENEXT:
203fadff096Smrg        debug(2, ("%s, line %d: #include%s %s\n",
204fadff096Smrg                  file->i_file, filep->f_line,
205fadff096Smrg                  (ret == INCLUDE) ? "" : "_next", p));
206fadff096Smrg
207fadff096Smrg        /* Support ANSI macro substitution */
208fadff096Smrg        while (1) {
209fadff096Smrg            struct symtab **sym;
210fadff096Smrg
211fadff096Smrg            if (!*p || *p == '"' || *p == '<')
212fadff096Smrg                break;
213fadff096Smrg
214fadff096Smrg            sym = isdefined(p, file_red, NULL);
215fadff096Smrg            if (!sym)
216fadff096Smrg                break;
217fadff096Smrg
218fadff096Smrg            p = (*sym)->s_value;
219fadff096Smrg            debug(3, ("%s : #includes SYMBOL %s = %s\n",
220fadff096Smrg                      file->i_incstring, (*sym)->s_name, (*sym)->s_value));
221fadff096Smrg            /* mark file as having included a 'soft include' */
222fadff096Smrg            file->i_flags |= INCLUDED_SYM;
223fadff096Smrg        }
224fadff096Smrg
225fadff096Smrg        /*
226fadff096Smrg         * Separate the name of the include file.
227fadff096Smrg         */
228fadff096Smrg        while (*p && *p != '"' && *p != '<')
229fadff096Smrg            p++;
230fadff096Smrg        if (!*p)
231fadff096Smrg            return (-2);
232fadff096Smrg        if (*p++ == '"') {
233fadff096Smrg            if (ret == INCLUDE)
234fadff096Smrg                ret = INCLUDEDOT;
235fadff096Smrg            else
236fadff096Smrg                ret = INCLUDENEXTDOT;
237fadff096Smrg            while (*p && *p != '"')
238fadff096Smrg                *line++ = *p++;
239fadff096Smrg        }
240fadff096Smrg        else
241fadff096Smrg            while (*p && *p != '>')
242fadff096Smrg                *line++ = *p++;
243fadff096Smrg        *line = '\0';
244fadff096Smrg        break;
245fadff096Smrg    case DEFINE:
246fadff096Smrg        /*
247fadff096Smrg         * copy the definition back to the beginning of the line.
248fadff096Smrg         */
249fadff096Smrg        memmove(line, p, strlen(p) + 1);
250fadff096Smrg        break;
251fadff096Smrg    case ELSE:
252fadff096Smrg    case ENDIF:
253fadff096Smrg    case ELIF:
254fadff096Smrg    case PRAGMA:
255fadff096Smrg    case ERROR:
256fadff096Smrg    case IDENT:
257fadff096Smrg    case SCCS:
258fadff096Smrg    case EJECT:
259fadff096Smrg    case WARNING:
260fadff096Smrg        debug(0, ("%s, line %d: #%s\n",
261fadff096Smrg                  file->i_file, filep->f_line, directives[ret]));
262fadff096Smrg        /*
263fadff096Smrg         * nothing to do.
264fadff096Smrg         */
265fadff096Smrg        break;
266fadff096Smrg    }
267fadff096Smrg    return (ret);
2680eb10989Smrg}
2690eb10989Smrg
270fadff096Smrgstatic struct symtab **
271d43532a6Smrgfdefined(const char *symbol, struct inclist *file, struct inclist **srcfile)
2720eb10989Smrg{
273fadff096Smrg    struct symtab **val;
274fadff096Smrg    static int      recurse_lvl = 0;
275fadff096Smrg
276fadff096Smrg    if (file->i_flags & DEFCHECKED)
277fadff096Smrg        return (NULL);
278fadff096Smrg    debug(2, ("Looking for %s in %s\n", symbol, file->i_file));
279fadff096Smrg    file->i_flags |= DEFCHECKED;
280fadff096Smrg    if ((val = slookup(symbol, file)))
281fadff096Smrg        debug(1, ("%s defined in %s as %s\n",
282fadff096Smrg                  symbol, file->i_file, (*val)->s_value));
283fadff096Smrg    if (val == NULL && file->i_list) {
284fadff096Smrg        struct inclist **ip;
285fadff096Smrg        unsigned int     i;
286fadff096Smrg
287fadff096Smrg        for (ip = file->i_list, i = 0; i < file->i_listlen; i++, ip++) {
288fadff096Smrg            if (file->i_merged[i] == FALSE) {
289fadff096Smrg                val = fdefined(symbol, *ip, srcfile);
290fadff096Smrg                file->i_merged[i] = merge2defines(file, *ip);
291fadff096Smrg                if (val != NULL)
292fadff096Smrg                    break;
293fadff096Smrg            }
294fadff096Smrg        }
295fadff096Smrg    }
296fadff096Smrg    else if (val != NULL && srcfile != NULL)
297fadff096Smrg        *srcfile = file;
298fadff096Smrg    recurse_lvl--;
299fadff096Smrg    file->i_flags &= ~DEFCHECKED;
300fadff096Smrg
301fadff096Smrg    return (val);
3020eb10989Smrg}
3030eb10989Smrg
3040eb10989Smrgstruct symtab **
305d43532a6Smrgisdefined(const char *symbol, struct inclist *file, struct inclist **srcfile)
3060eb10989Smrg{
307fadff096Smrg    struct symtab **val;
308fadff096Smrg
309fadff096Smrg    if ((val = slookup(symbol, &maininclist))) {
310fadff096Smrg        debug(1, ("%s defined on command line\n", symbol));
311fadff096Smrg        if (srcfile != NULL)
312fadff096Smrg            *srcfile = &maininclist;
313fadff096Smrg        return (val);
314fadff096Smrg    }
315fadff096Smrg    if ((val = fdefined(symbol, file, srcfile)))
316fadff096Smrg        return (val);
317fadff096Smrg    debug(1, ("%s not defined in %s\n", symbol, file->i_file));
318fadff096Smrg    return (NULL);
3190eb10989Smrg}
3200eb10989Smrg
3210eb10989Smrg/*
3220eb10989Smrg * Return type based on if the #if expression evaluates to 0
3230eb10989Smrg */
3240eb10989Smrgstatic int
325fadff096Smrgzero_value(char *filename, char *exp,
326fadff096Smrg           struct filepointer *filep, struct inclist *file_red)
3270eb10989Smrg{
328fadff096Smrg    if (cppsetup(filename, exp, filep, file_red))
329fadff096Smrg        return (IFFALSE);
330fadff096Smrg    else
331fadff096Smrg        return (IF);
3320eb10989Smrg}
3330eb10989Smrg
3340eb10989Smrgvoid
335d43532a6Smrgdefine2(const char *name, const char *val, struct inclist *file)
3360eb10989Smrg{
3370eb10989Smrg    int first, last, below;
338fadff096Smrg    struct symtab **sp = NULL, **dest;
3390eb10989Smrg    struct symtab *stab;
3400eb10989Smrg
3410eb10989Smrg    /* Make space if it's needed */
342fadff096Smrg    if (file->i_defs == NULL) {
343fadff096Smrg        file->i_defs = mallocarray(SYMTABINC, sizeof(struct symtab *));
344fadff096Smrg        file->i_ndefs = 0;
3450eb10989Smrg    }
3460eb10989Smrg    else if (!(file->i_ndefs % SYMTABINC))
347fadff096Smrg        file->i_defs = reallocarray(file->i_defs, (file->i_ndefs + SYMTABINC),
348fadff096Smrg                                    sizeof(struct symtab *));
3490eb10989Smrg
3500eb10989Smrg    if (file->i_defs == NULL)
351fadff096Smrg        fatalerr("malloc()/realloc() failure in insert_defn()\n");
3520eb10989Smrg
3530eb10989Smrg    below = first = 0;
3540eb10989Smrg    last = file->i_ndefs - 1;
355fadff096Smrg    while (last >= first) {
356fadff096Smrg        /* Fast inline binary search */
357fadff096Smrg        const char *s1;
358fadff096Smrg        const char *s2;
359fadff096Smrg        int middle = (first + last) / 2;
360fadff096Smrg
361fadff096Smrg        /* Fast inline strcmp() */
362fadff096Smrg        s1 = name;
363fadff096Smrg        s2 = file->i_defs[middle]->s_name;
364fadff096Smrg        while (*s1++ == *s2++)
365fadff096Smrg            if (s2[-1] == '\0')
366fadff096Smrg                break;
367fadff096Smrg
368fadff096Smrg        /* If exact match, set sp and break */
369fadff096Smrg        if (*--s1 == *--s2) {
370fadff096Smrg            sp = file->i_defs + middle;
371fadff096Smrg            break;
372fadff096Smrg        }
373fadff096Smrg
374fadff096Smrg        /* If name > i_defs[middle] ... */
375fadff096Smrg        if (*s1 > *s2) {
376fadff096Smrg            below = first;
377fadff096Smrg            first = middle + 1;
378fadff096Smrg        }
379fadff096Smrg        /* else ... */
380fadff096Smrg        else {
381fadff096Smrg            below = last = middle - 1;
382fadff096Smrg        }
3830eb10989Smrg    }
3840eb10989Smrg
3850eb10989Smrg    /* Search is done.  If we found an exact match to the symbol name,
3860eb10989Smrg       just replace its s_value */
387fadff096Smrg    if (sp != NULL) {
388fadff096Smrg        debug(1, ("redefining %s from %s to %s in file %s\n",
389fadff096Smrg                  name, (*sp)->s_value, val, file->i_file));
390fadff096Smrg        free((*sp)->s_value);
391fadff096Smrg        (*sp)->s_value = strdup(val);
392fadff096Smrg        if ((*sp)->s_value == NULL)
393fadff096Smrg            fatalerr("strdup() failure in %s()\n", __func__);
394fadff096Smrg        return;
3950eb10989Smrg    }
3960eb10989Smrg
3970eb10989Smrg    sp = file->i_defs + file->i_ndefs++;
3980eb10989Smrg    dest = file->i_defs + below + 1;
399fadff096Smrg    while (sp > dest) {
400fadff096Smrg        *sp = sp[-1];
401fadff096Smrg        sp--;
4020eb10989Smrg    }
403fadff096Smrg    stab = malloc(sizeof(struct symtab));
4040eb10989Smrg    if (stab == NULL)
405fadff096Smrg        fatalerr("malloc()/realloc() failure in insert_defn()\n");
4060eb10989Smrg
407fadff096Smrg    debug(1, ("defining %s to %s in file %s\n", name, val, file->i_file));
408d43532a6Smrg    stab->s_name = strdup(name);
409d43532a6Smrg    stab->s_value = strdup(val);
410fadff096Smrg    if ((stab->s_name == NULL) || (stab->s_value == NULL))
411fadff096Smrg        fatalerr("strdup() failure in %s()\n", __func__);
4120eb10989Smrg    *sp = stab;
4130eb10989Smrg}
4140eb10989Smrg
4150eb10989Smrgvoid
4160eb10989Smrgdefine(char *def, struct inclist *file)
4170eb10989Smrg{
4180eb10989Smrg    char *val;
4190eb10989Smrg
4200eb10989Smrg    /* Separate symbol name and its value */
4210eb10989Smrg    val = def;
4220eb10989Smrg    while (isalnum(*val) || *val == '_')
423fadff096Smrg        val++;
4240eb10989Smrg    if (*val)
425fadff096Smrg        *val++ = '\0';
4260eb10989Smrg    while (*val == ' ' || *val == '\t')
427fadff096Smrg        val++;
4280eb10989Smrg
4290eb10989Smrg    if (!*val)
430fadff096Smrg        define2(def, "1", file);
431d43532a6Smrg    else
432fadff096Smrg        define2(def, val, file);
4330eb10989Smrg}
4340eb10989Smrg
4350eb10989Smrgstruct symtab **
436d43532a6Smrgslookup(const char *symbol, struct inclist *file)
4370eb10989Smrg{
438fadff096Smrg    int first = 0;
439fadff096Smrg    int last;
440fadff096Smrg
441fadff096Smrg    if (file == NULL)
442fadff096Smrg        return NULL;
443fadff096Smrg
444fadff096Smrg    last = file->i_ndefs - 1;
445fadff096Smrg
446fadff096Smrg    while (last >= first) {
447fadff096Smrg        /* Fast inline binary search */
448fadff096Smrg        const char *s1;
449fadff096Smrg        const char *s2;
450fadff096Smrg        int middle = (first + last) / 2;
451fadff096Smrg
452fadff096Smrg        /* Fast inline strcmp() */
453fadff096Smrg        s1 = symbol;
454fadff096Smrg        s2 = file->i_defs[middle]->s_name;
455fadff096Smrg        while (*s1++ == *s2++)
456fadff096Smrg            if (s2[-1] == '\0')
457fadff096Smrg                break;
458fadff096Smrg
459fadff096Smrg        /* If exact match, we're done */
460fadff096Smrg        if (*--s1 == *--s2) {
461fadff096Smrg            return file->i_defs + middle;
462fadff096Smrg        }
463fadff096Smrg
464fadff096Smrg        /* If symbol > i_defs[middle] ... */
465fadff096Smrg        if (*s1 > *s2) {
466fadff096Smrg            first = middle + 1;
467fadff096Smrg        }
468fadff096Smrg        /* else ... */
469fadff096Smrg        else {
470fadff096Smrg            last = middle - 1;
471fadff096Smrg        }
472fadff096Smrg    }
473fadff096Smrg    return (NULL);
4740eb10989Smrg}
4750eb10989Smrg
476fadff096Smrgstatic boolean
4770eb10989Smrgmerge2defines(struct inclist *file1, struct inclist *file2)
4780eb10989Smrg{
479fadff096Smrg    if ((file1 == NULL) || (file2 == NULL) || !(file2->i_flags & FINISHED))
480fadff096Smrg        return 0;
481fadff096Smrg
482fadff096Smrg    for (unsigned int i = 0; i < file2->i_listlen; i++)
483fadff096Smrg        if (file2->i_merged[i] == FALSE)
484fadff096Smrg            return 0;
485fadff096Smrg
486fadff096Smrg    {
487fadff096Smrg        int first1 = 0;
488fadff096Smrg        int last1 = file1->i_ndefs - 1;
489fadff096Smrg
490fadff096Smrg        int first2 = 0;
491fadff096Smrg        int last2 = file2->i_ndefs - 1;
492fadff096Smrg
493fadff096Smrg        int first = 0;
494fadff096Smrg        struct symtab **i_defs = NULL;
495fadff096Smrg        int deflen = file1->i_ndefs + file2->i_ndefs;
496fadff096Smrg
497fadff096Smrg        debug(2, ("merging %s into %s\n", file2->i_file, file1->i_file));
498fadff096Smrg
499fadff096Smrg        if (deflen > 0) {
500fadff096Smrg            /* make sure deflen % SYMTABINC == 0 is still true */
501fadff096Smrg            deflen += (SYMTABINC - deflen % SYMTABINC) % SYMTABINC;
502fadff096Smrg            i_defs = mallocarray(deflen, sizeof(struct symtab *));
503fadff096Smrg            if (i_defs == NULL)
504fadff096Smrg                return 0;
505fadff096Smrg        }
506fadff096Smrg
507fadff096Smrg        while ((last1 >= first1) && (last2 >= first2)) {
508fadff096Smrg            const char *s1 = file1->i_defs[first1]->s_name;
509fadff096Smrg            const char *s2 = file2->i_defs[first2]->s_name;
510fadff096Smrg
511fadff096Smrg            if (strcmp(s1, s2) < 0)
512fadff096Smrg                i_defs[first++] = file1->i_defs[first1++];
513fadff096Smrg            else if (strcmp(s1, s2) > 0)
514fadff096Smrg                i_defs[first++] = file2->i_defs[first2++];
515fadff096Smrg            else {              /* equal */
516fadff096Smrg                i_defs[first++] = file2->i_defs[first2++];
517fadff096Smrg                first1++;
518fadff096Smrg            }
519fadff096Smrg        }
520fadff096Smrg        while (last1 >= first1) {
521fadff096Smrg            i_defs[first++] = file1->i_defs[first1++];
522fadff096Smrg        }
523fadff096Smrg        while (last2 >= first2) {
524fadff096Smrg            i_defs[first++] = file2->i_defs[first2++];
525fadff096Smrg        }
526fadff096Smrg
527fadff096Smrg        if (file1->i_defs)
528fadff096Smrg            free(file1->i_defs);
529fadff096Smrg        file1->i_defs = i_defs;
530fadff096Smrg        file1->i_ndefs = first;
531fadff096Smrg
532fadff096Smrg        return 1;
533fadff096Smrg    }
5340eb10989Smrg}
5350eb10989Smrg
5360eb10989Smrgvoid
537d43532a6Smrgundefine(const char *symbol, struct inclist *file)
5380eb10989Smrg{
539fadff096Smrg    struct symtab **ptr;
540fadff096Smrg    struct inclist *srcfile;
541fadff096Smrg
542fadff096Smrg    while ((ptr = isdefined(symbol, file, &srcfile)) != NULL) {
543fadff096Smrg        srcfile->i_ndefs--;
544fadff096Smrg        for (; ptr < srcfile->i_defs + srcfile->i_ndefs; ptr++)
545fadff096Smrg            *ptr = ptr[1];
546fadff096Smrg    }
5470eb10989Smrg}
5480eb10989Smrg
5490eb10989Smrgint
550d43532a6Smrgfind_includes(struct filepointer *filep, struct inclist *file,
551fadff096Smrg              struct inclist *file_red, int recursion, boolean failOK)
5520eb10989Smrg{
553fadff096Smrg    char *line;
554fadff096Smrg
555fadff096Smrg    while ((line = getnextline(filep))) {
556fadff096Smrg        int type = deftype(line, filep, file_red, file, TRUE);
557fadff096Smrg
558fadff096Smrg        switch (type) {
559fadff096Smrg        case IF:
560fadff096Smrg doif:
561fadff096Smrg            type = find_includes(filep, file, file_red, recursion + 1, failOK);
562fadff096Smrg            while ((type == ELIF) || (type == ELIFFALSE) ||
563fadff096Smrg                   (type == ELIFGUESSFALSE))
564fadff096Smrg                type = gobble(filep, file, file_red);
565fadff096Smrg            if (type == ELSE)
566fadff096Smrg                gobble(filep, file, file_red);
567fadff096Smrg            break;
568fadff096Smrg        case IFFALSE:
569fadff096Smrg        case IFGUESSFALSE:
570fadff096Smrg doiffalse:
571fadff096Smrg        {
572fadff096Smrg            boolean recfailOK;
573fadff096Smrg
574fadff096Smrg            if (type == IFGUESSFALSE || type == ELIFGUESSFALSE)
575fadff096Smrg                recfailOK = TRUE;
576fadff096Smrg            else
577fadff096Smrg                recfailOK = failOK;
578fadff096Smrg            type = gobble(filep, file, file_red);
579fadff096Smrg            if (type == ELSE)
580fadff096Smrg                find_includes(filep, file, file_red, recursion + 1, recfailOK);
581fadff096Smrg            else if (type == ELIF)
582fadff096Smrg                goto doif;
583fadff096Smrg            else if ((type == ELIFFALSE) || (type == ELIFGUESSFALSE))
584fadff096Smrg                goto doiffalse;
585fadff096Smrg        }
586fadff096Smrg            break;
587fadff096Smrg        case IFDEF:
588fadff096Smrg        case IFNDEF:
589fadff096Smrg            if ((type == IFDEF && isdefined(line, file_red, NULL))
590fadff096Smrg                || (type == IFNDEF && !isdefined(line, file_red, NULL))) {
591fadff096Smrg                debug(1, (type == IFNDEF ?
592fadff096Smrg                          "line %d: %s !def'd in %s via %s%s\n" : "",
593fadff096Smrg                          filep->f_line, line,
594fadff096Smrg                          file->i_file, file_red->i_file, ": doit"));
595fadff096Smrg                type = find_includes(filep, file,
596fadff096Smrg                                     file_red, recursion + 1, failOK);
597fadff096Smrg                while (type == ELIF || type == ELIFFALSE ||
598fadff096Smrg                       type == ELIFGUESSFALSE)
599fadff096Smrg                    type = gobble(filep, file, file_red);
600fadff096Smrg                if (type == ELSE)
601fadff096Smrg                    gobble(filep, file, file_red);
602fadff096Smrg            }
603fadff096Smrg            else {
604fadff096Smrg                debug(1, (type == IFDEF ?
605fadff096Smrg                          "line %d: %s !def'd in %s via %s%s\n" : "",
606fadff096Smrg                          filep->f_line, line,
607fadff096Smrg                          file->i_file, file_red->i_file, ": gobble"));
608fadff096Smrg                type = gobble(filep, file, file_red);
609fadff096Smrg                if (type == ELSE)
610fadff096Smrg                    find_includes(filep, file, file_red, recursion + 1, failOK);
611fadff096Smrg                else if (type == ELIF)
612fadff096Smrg                    goto doif;
613fadff096Smrg                else if (type == ELIFFALSE || type == ELIFGUESSFALSE)
614fadff096Smrg                    goto doiffalse;
615fadff096Smrg            }
616fadff096Smrg            break;
617fadff096Smrg        case ELSE:
618fadff096Smrg        case ELIFFALSE:
619fadff096Smrg        case ELIFGUESSFALSE:
620fadff096Smrg        case ELIF:
621fadff096Smrg            if (!recursion)
622fadff096Smrg                gobble(filep, file, file_red);
623fadff096Smrg        case ENDIF:
624fadff096Smrg            if (recursion)
625fadff096Smrg                return (type);
626fadff096Smrg        case DEFINE:
627fadff096Smrg            define(line, file);
628fadff096Smrg            break;
629fadff096Smrg        case UNDEF:
630fadff096Smrg            if (!*line) {
631fadff096Smrg                warning("%s", file_red->i_file);
632fadff096Smrg                if (file_red != file)
633fadff096Smrg                    warning1(" (reading %s)", file->i_file);
634fadff096Smrg                warning1(", line %ld: incomplete undef == \"%s\"\n",
635fadff096Smrg                         filep->f_line, line);
636fadff096Smrg                break;
637fadff096Smrg            }
638fadff096Smrg            undefine(line, file_red);
639fadff096Smrg            break;
640fadff096Smrg        case INCLUDE:
641fadff096Smrg        case INCLUDEDOT:
642fadff096Smrg        case INCLUDENEXT:
643fadff096Smrg        case INCLUDENEXTDOT:
644fadff096Smrg        {
645fadff096Smrg            struct inclist *inclist_save = inclistnext;
646fadff096Smrg            const char **includedirs_save = includedirsnext;
647fadff096Smrg
648fadff096Smrg            debug(2, ("%s, reading %s, includes %s\n",
649fadff096Smrg                      file_red->i_file, file->i_file, line));
650fadff096Smrg            add_include(filep, file, file_red, line, type, failOK);
651fadff096Smrg            inclistnext = inclist_save;
652fadff096Smrg            includedirsnext = includedirs_save;
653fadff096Smrg        }
654fadff096Smrg            break;
655fadff096Smrg        case ERROR:
656fadff096Smrg        case WARNING:
657fadff096Smrg            warning("%s", file_red->i_file);
658fadff096Smrg            if (file_red != file)
659fadff096Smrg                warning1(" (reading %s)", file->i_file);
660fadff096Smrg            warning1(", line %ld: %s\n", filep->f_line, line);
661fadff096Smrg            break;
662fadff096Smrg
663fadff096Smrg        case PRAGMA:
664fadff096Smrg        case IDENT:
665fadff096Smrg        case SCCS:
666fadff096Smrg        case EJECT:
667fadff096Smrg            break;
668fadff096Smrg        case -1:
669fadff096Smrg            warning("%s", file_red->i_file);
670fadff096Smrg            if (file_red != file)
671fadff096Smrg                warning1(" (reading %s)", file->i_file);
672fadff096Smrg            warning1(", line %ld: unknown directive == \"%s\"\n",
673fadff096Smrg                     filep->f_line, line);
674fadff096Smrg            break;
675fadff096Smrg        case -2:
676fadff096Smrg            warning("%s", file_red->i_file);
677fadff096Smrg            if (file_red != file)
678fadff096Smrg                warning1(" (reading %s)", file->i_file);
679fadff096Smrg            warning1(", line %ld: incomplete include == \"%s\"\n",
680fadff096Smrg                     filep->f_line, line);
681fadff096Smrg            break;
682fadff096Smrg        }
683fadff096Smrg    }
684fadff096Smrg    file->i_flags |= FINISHED;
685fadff096Smrg    debug(2, ("finished with %s\n", file->i_file));
686fadff096Smrg    return (-1);
6870eb10989Smrg}
688