11f5207b7SJohn Levon /*
21f5207b7SJohn Levon  * Do C preprocessing, based on a token list gathered by
31f5207b7SJohn Levon  * the tokenizer.
41f5207b7SJohn Levon  *
51f5207b7SJohn Levon  * This may not be the smartest preprocessor on the planet.
61f5207b7SJohn Levon  *
71f5207b7SJohn Levon  * Copyright (C) 2003 Transmeta Corp.
81f5207b7SJohn Levon  *               2003-2004 Linus Torvalds
91f5207b7SJohn Levon  *
101f5207b7SJohn Levon  * Permission is hereby granted, free of charge, to any person obtaining a copy
111f5207b7SJohn Levon  * of this software and associated documentation files (the "Software"), to deal
121f5207b7SJohn Levon  * in the Software without restriction, including without limitation the rights
131f5207b7SJohn Levon  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
141f5207b7SJohn Levon  * copies of the Software, and to permit persons to whom the Software is
151f5207b7SJohn Levon  * furnished to do so, subject to the following conditions:
161f5207b7SJohn Levon  *
171f5207b7SJohn Levon  * The above copyright notice and this permission notice shall be included in
181f5207b7SJohn Levon  * all copies or substantial portions of the Software.
191f5207b7SJohn Levon  *
201f5207b7SJohn Levon  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
211f5207b7SJohn Levon  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
221f5207b7SJohn Levon  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
231f5207b7SJohn Levon  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
241f5207b7SJohn Levon  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
251f5207b7SJohn Levon  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
261f5207b7SJohn Levon  * THE SOFTWARE.
271f5207b7SJohn Levon  */
281f5207b7SJohn Levon #include <stdio.h>
291f5207b7SJohn Levon #include <stdlib.h>
301f5207b7SJohn Levon #include <stdarg.h>
311f5207b7SJohn Levon #include <stddef.h>
321f5207b7SJohn Levon #include <string.h>
331f5207b7SJohn Levon #include <ctype.h>
341f5207b7SJohn Levon #include <unistd.h>
351f5207b7SJohn Levon #include <fcntl.h>
361f5207b7SJohn Levon #include <limits.h>
371f5207b7SJohn Levon #include <time.h>
381f5207b7SJohn Levon #include <dirent.h>
391f5207b7SJohn Levon #include <sys/stat.h>
401f5207b7SJohn Levon 
411f5207b7SJohn Levon #include "lib.h"
421f5207b7SJohn Levon #include "allocate.h"
431f5207b7SJohn Levon #include "parse.h"
441f5207b7SJohn Levon #include "token.h"
451f5207b7SJohn Levon #include "symbol.h"
461f5207b7SJohn Levon #include "expression.h"
471f5207b7SJohn Levon #include "scope.h"
481f5207b7SJohn Levon 
491f5207b7SJohn Levon static struct ident_list *macros;	// only needed for -dD
501f5207b7SJohn Levon static int false_nesting = 0;
511f5207b7SJohn Levon static int counter_macro = 0;		// __COUNTER__ expansion
52*c85f09ccSJohn Levon static int include_level = 0;
531f5207b7SJohn Levon 
541f5207b7SJohn Levon #define INCLUDEPATHS 300
551f5207b7SJohn Levon const char *includepath[INCLUDEPATHS+1] = {
561f5207b7SJohn Levon 	"",
571f5207b7SJohn Levon 	"/usr/include",
581f5207b7SJohn Levon 	"/usr/local/include",
591f5207b7SJohn Levon 	NULL
601f5207b7SJohn Levon };
611f5207b7SJohn Levon 
621f5207b7SJohn Levon static const char **quote_includepath = includepath;
631f5207b7SJohn Levon static const char **angle_includepath = includepath + 1;
641f5207b7SJohn Levon static const char **isys_includepath   = includepath + 1;
651f5207b7SJohn Levon static const char **sys_includepath   = includepath + 1;
661f5207b7SJohn Levon static const char **dirafter_includepath = includepath + 3;
671f5207b7SJohn Levon 
681f5207b7SJohn Levon #define dirty_stream(stream)				\
691f5207b7SJohn Levon 	do {						\
701f5207b7SJohn Levon 		if (!stream->dirty) {			\
711f5207b7SJohn Levon 			stream->dirty = 1;		\
721f5207b7SJohn Levon 			if (!stream->ifndef)		\
731f5207b7SJohn Levon 				stream->protect = NULL;	\
741f5207b7SJohn Levon 		}					\
751f5207b7SJohn Levon 	} while(0)
761f5207b7SJohn Levon 
771f5207b7SJohn Levon #define end_group(stream)					\
781f5207b7SJohn Levon 	do {							\
791f5207b7SJohn Levon 		if (stream->ifndef == stream->top_if) {		\
801f5207b7SJohn Levon 			stream->ifndef = NULL;			\
811f5207b7SJohn Levon 			if (!stream->dirty)			\
821f5207b7SJohn Levon 				stream->protect = NULL;		\
831f5207b7SJohn Levon 			else if (stream->protect)		\
841f5207b7SJohn Levon 				stream->dirty = 0;		\
851f5207b7SJohn Levon 		}						\
861f5207b7SJohn Levon 	} while(0)
871f5207b7SJohn Levon 
881f5207b7SJohn Levon #define nesting_error(stream)		\
891f5207b7SJohn Levon 	do {				\
901f5207b7SJohn Levon 		stream->dirty = 1;	\
911f5207b7SJohn Levon 		stream->ifndef = NULL;	\
921f5207b7SJohn Levon 		stream->protect = NULL;	\
931f5207b7SJohn Levon 	} while(0)
941f5207b7SJohn Levon 
951f5207b7SJohn Levon static struct token *alloc_token(struct position *pos)
961f5207b7SJohn Levon {
971f5207b7SJohn Levon 	struct token *token = __alloc_token(0);
981f5207b7SJohn Levon 
991f5207b7SJohn Levon 	token->pos.stream = pos->stream;
1001f5207b7SJohn Levon 	token->pos.line = pos->line;
1011f5207b7SJohn Levon 	token->pos.pos = pos->pos;
1021f5207b7SJohn Levon 	token->pos.whitespace = 1;
1031f5207b7SJohn Levon 	return token;
1041f5207b7SJohn Levon }
1051f5207b7SJohn Levon 
1061f5207b7SJohn Levon /* Expand symbol 'sym' at '*list' */
1071f5207b7SJohn Levon static int expand(struct token **, struct symbol *);
1081f5207b7SJohn Levon 
1091f5207b7SJohn Levon static void replace_with_string(struct token *token, const char *str)
1101f5207b7SJohn Levon {
1111f5207b7SJohn Levon 	int size = strlen(str) + 1;
1121f5207b7SJohn Levon 	struct string *s = __alloc_string(size);
1131f5207b7SJohn Levon 
1141f5207b7SJohn Levon 	s->length = size;
1151f5207b7SJohn Levon 	memcpy(s->data, str, size);
1161f5207b7SJohn Levon 	token_type(token) = TOKEN_STRING;
1171f5207b7SJohn Levon 	token->string = s;
1181f5207b7SJohn Levon }
1191f5207b7SJohn Levon 
1201f5207b7SJohn Levon static void replace_with_integer(struct token *token, unsigned int val)
1211f5207b7SJohn Levon {
1221f5207b7SJohn Levon 	char *buf = __alloc_bytes(11);
1231f5207b7SJohn Levon 	sprintf(buf, "%u", val);
1241f5207b7SJohn Levon 	token_type(token) = TOKEN_NUMBER;
1251f5207b7SJohn Levon 	token->number = buf;
1261f5207b7SJohn Levon }
1271f5207b7SJohn Levon 
1281f5207b7SJohn Levon static struct symbol *lookup_macro(struct ident *ident)
1291f5207b7SJohn Levon {
1301f5207b7SJohn Levon 	struct symbol *sym = lookup_symbol(ident, NS_MACRO | NS_UNDEF);
1311f5207b7SJohn Levon 	if (sym && sym->namespace != NS_MACRO)
1321f5207b7SJohn Levon 		sym = NULL;
1331f5207b7SJohn Levon 	return sym;
1341f5207b7SJohn Levon }
1351f5207b7SJohn Levon 
1361f5207b7SJohn Levon static int token_defined(struct token *token)
1371f5207b7SJohn Levon {
1381f5207b7SJohn Levon 	if (token_type(token) == TOKEN_IDENT) {
1391f5207b7SJohn Levon 		struct symbol *sym = lookup_macro(token->ident);
1401f5207b7SJohn Levon 		if (sym) {
1411f5207b7SJohn Levon 			sym->used_in = file_scope;
1421f5207b7SJohn Levon 			return 1;
1431f5207b7SJohn Levon 		}
1441f5207b7SJohn Levon 		return 0;
1451f5207b7SJohn Levon 	}
1461f5207b7SJohn Levon 
1471f5207b7SJohn Levon 	sparse_error(token->pos, "expected preprocessor identifier");
1481f5207b7SJohn Levon 	return 0;
1491f5207b7SJohn Levon }
1501f5207b7SJohn Levon 
151*c85f09ccSJohn Levon static void replace_with_bool(struct token *token, bool val)
1521f5207b7SJohn Levon {
1531f5207b7SJohn Levon 	static const char *string[] = { "0", "1" };
1541f5207b7SJohn Levon 
1551f5207b7SJohn Levon 	token_type(token) = TOKEN_NUMBER;
156*c85f09ccSJohn Levon 	token->number = string[val];
157*c85f09ccSJohn Levon }
158*c85f09ccSJohn Levon 
159*c85f09ccSJohn Levon static void replace_with_defined(struct token *token)
160*c85f09ccSJohn Levon {
161*c85f09ccSJohn Levon 	replace_with_bool(token, token_defined(token));
162*c85f09ccSJohn Levon }
163*c85f09ccSJohn Levon 
164*c85f09ccSJohn Levon static void replace_with_has_builtin(struct token *token)
165*c85f09ccSJohn Levon {
166*c85f09ccSJohn Levon 	struct symbol *sym = lookup_symbol(token->ident, NS_SYMBOL);
167*c85f09ccSJohn Levon 	replace_with_bool(token, sym && sym->builtin);
168*c85f09ccSJohn Levon }
169*c85f09ccSJohn Levon 
170*c85f09ccSJohn Levon static void replace_with_has_attribute(struct token *token)
171*c85f09ccSJohn Levon {
172*c85f09ccSJohn Levon 	struct symbol *sym = lookup_symbol(token->ident, NS_KEYWORD);
173*c85f09ccSJohn Levon 	replace_with_bool(token, sym && sym->op && sym->op->attribute);
174*c85f09ccSJohn Levon }
175*c85f09ccSJohn Levon 
176*c85f09ccSJohn Levon static void expand_line(struct token *token)
177*c85f09ccSJohn Levon {
178*c85f09ccSJohn Levon 	replace_with_integer(token, token->pos.line);
179*c85f09ccSJohn Levon }
180*c85f09ccSJohn Levon 
181*c85f09ccSJohn Levon static void expand_file(struct token *token)
182*c85f09ccSJohn Levon {
183*c85f09ccSJohn Levon 	replace_with_string(token, stream_name(token->pos.stream));
184*c85f09ccSJohn Levon }
185*c85f09ccSJohn Levon 
186*c85f09ccSJohn Levon static void expand_basefile(struct token *token)
187*c85f09ccSJohn Levon {
188*c85f09ccSJohn Levon 	replace_with_string(token, base_filename);
189*c85f09ccSJohn Levon }
190*c85f09ccSJohn Levon 
191*c85f09ccSJohn Levon static time_t t = 0;
192*c85f09ccSJohn Levon static void expand_date(struct token *token)
193*c85f09ccSJohn Levon {
194*c85f09ccSJohn Levon 	static char buffer[12]; /* __DATE__: 3 + ' ' + 2 + ' ' + 4 + '\0' */
195*c85f09ccSJohn Levon 
196*c85f09ccSJohn Levon 	if (!t)
197*c85f09ccSJohn Levon 		time(&t);
198*c85f09ccSJohn Levon 	strftime(buffer, 12, "%b %e %Y", localtime(&t));
199*c85f09ccSJohn Levon 	replace_with_string(token, buffer);
200*c85f09ccSJohn Levon }
201*c85f09ccSJohn Levon 
202*c85f09ccSJohn Levon static void expand_time(struct token *token)
203*c85f09ccSJohn Levon {
204*c85f09ccSJohn Levon 	static char buffer[9]; /* __TIME__: 2 + ':' + 2 + ':' + 2 + '\0' */
205*c85f09ccSJohn Levon 
206*c85f09ccSJohn Levon 	if (!t)
207*c85f09ccSJohn Levon 		time(&t);
208*c85f09ccSJohn Levon 	strftime(buffer, 9, "%T", localtime(&t));
209*c85f09ccSJohn Levon 	replace_with_string(token, buffer);
210*c85f09ccSJohn Levon }
211*c85f09ccSJohn Levon 
212*c85f09ccSJohn Levon static void expand_counter(struct token *token)
213*c85f09ccSJohn Levon {
214*c85f09ccSJohn Levon 	replace_with_integer(token, counter_macro++);
215*c85f09ccSJohn Levon }
216*c85f09ccSJohn Levon 
217*c85f09ccSJohn Levon static void expand_include_level(struct token *token)
218*c85f09ccSJohn Levon {
219*c85f09ccSJohn Levon 	replace_with_integer(token, include_level - 1);
2201f5207b7SJohn Levon }
2211f5207b7SJohn Levon 
2221f5207b7SJohn Levon static int expand_one_symbol(struct token **list)
2231f5207b7SJohn Levon {
2241f5207b7SJohn Levon 	struct token *token = *list;
2251f5207b7SJohn Levon 	struct symbol *sym;
2261f5207b7SJohn Levon 
2271f5207b7SJohn Levon 	if (token->pos.noexpand)
2281f5207b7SJohn Levon 		return 1;
2291f5207b7SJohn Levon 
2301f5207b7SJohn Levon 	sym = lookup_macro(token->ident);
231*c85f09ccSJohn Levon 	if (!sym)
232*c85f09ccSJohn Levon 		return 1;
233*c85f09ccSJohn Levon 	store_macro_pos(token);
234*c85f09ccSJohn Levon 	if (sym->expander) {
235*c85f09ccSJohn Levon 		sym->expander(token);
236*c85f09ccSJohn Levon 		return 1;
237*c85f09ccSJohn Levon 	} else {
2381f5207b7SJohn Levon 		sym->used_in = file_scope;
2391f5207b7SJohn Levon 		return expand(list, sym);
2401f5207b7SJohn Levon 	}
2411f5207b7SJohn Levon }
2421f5207b7SJohn Levon 
2431f5207b7SJohn Levon static inline struct token *scan_next(struct token **where)
2441f5207b7SJohn Levon {
2451f5207b7SJohn Levon 	struct token *token = *where;
2461f5207b7SJohn Levon 	if (token_type(token) != TOKEN_UNTAINT)
2471f5207b7SJohn Levon 		return token;
2481f5207b7SJohn Levon 	do {
2491f5207b7SJohn Levon 		token->ident->tainted = 0;
2501f5207b7SJohn Levon 		token = token->next;
2511f5207b7SJohn Levon 	} while (token_type(token) == TOKEN_UNTAINT);
2521f5207b7SJohn Levon 	*where = token;
2531f5207b7SJohn Levon 	return token;
2541f5207b7SJohn Levon }
2551f5207b7SJohn Levon 
2561f5207b7SJohn Levon static void expand_list(struct token **list)
2571f5207b7SJohn Levon {
2581f5207b7SJohn Levon 	struct token *next;
2591f5207b7SJohn Levon 	while (!eof_token(next = scan_next(list))) {
2601f5207b7SJohn Levon 		if (token_type(next) != TOKEN_IDENT || expand_one_symbol(list))
2611f5207b7SJohn Levon 			list = &next->next;
2621f5207b7SJohn Levon 	}
2631f5207b7SJohn Levon }
2641f5207b7SJohn Levon 
2651f5207b7SJohn Levon static void preprocessor_line(struct stream *stream, struct token **line);
2661f5207b7SJohn Levon 
2671f5207b7SJohn Levon static struct token *collect_arg(struct token *prev, int vararg, struct position *pos, int count)
2681f5207b7SJohn Levon {
2691f5207b7SJohn Levon 	struct stream *stream = input_streams + prev->pos.stream;
2701f5207b7SJohn Levon 	struct token **p = &prev->next;
2711f5207b7SJohn Levon 	struct token *next;
2721f5207b7SJohn Levon 	int nesting = 0;
2731f5207b7SJohn Levon 
2741f5207b7SJohn Levon 	while (!eof_token(next = scan_next(p))) {
2751f5207b7SJohn Levon 		if (next->pos.newline && match_op(next, '#')) {
2761f5207b7SJohn Levon 			if (!next->pos.noexpand) {
2771f5207b7SJohn Levon 				sparse_error(next->pos,
2781f5207b7SJohn Levon 					     "directive in argument list");
2791f5207b7SJohn Levon 				preprocessor_line(stream, p);
2801f5207b7SJohn Levon 				__free_token(next);	/* Free the '#' token */
2811f5207b7SJohn Levon 				continue;
2821f5207b7SJohn Levon 			}
2831f5207b7SJohn Levon 		}
2841f5207b7SJohn Levon 		switch (token_type(next)) {
2851f5207b7SJohn Levon 		case TOKEN_STREAMEND:
2861f5207b7SJohn Levon 		case TOKEN_STREAMBEGIN:
2871f5207b7SJohn Levon 			*p = &eof_token_entry;
2881f5207b7SJohn Levon 			return next;
2891f5207b7SJohn Levon 		case TOKEN_STRING:
2901f5207b7SJohn Levon 		case TOKEN_WIDE_STRING:
2911f5207b7SJohn Levon 			if (count > 1)
2921f5207b7SJohn Levon 				next->string->immutable = 1;
2931f5207b7SJohn Levon 			break;
2941f5207b7SJohn Levon 		}
2951f5207b7SJohn Levon 		if (false_nesting) {
2961f5207b7SJohn Levon 			*p = next->next;
2971f5207b7SJohn Levon 			__free_token(next);
2981f5207b7SJohn Levon 			continue;
2991f5207b7SJohn Levon 		}
3001f5207b7SJohn Levon 		if (match_op(next, '(')) {
3011f5207b7SJohn Levon 			nesting++;
3021f5207b7SJohn Levon 		} else if (match_op(next, ')')) {
3031f5207b7SJohn Levon 			if (!nesting--)
3041f5207b7SJohn Levon 				break;
3051f5207b7SJohn Levon 		} else if (match_op(next, ',') && !nesting && !vararg) {
3061f5207b7SJohn Levon 			break;
3071f5207b7SJohn Levon 		}
3081f5207b7SJohn Levon 		next->pos.stream = pos->stream;
3091f5207b7SJohn Levon 		next->pos.line = pos->line;
3101f5207b7SJohn Levon 		next->pos.pos = pos->pos;
3111f5207b7SJohn Levon 		p = &next->next;
3121f5207b7SJohn Levon 	}
3131f5207b7SJohn Levon 	*p = &eof_token_entry;
3141f5207b7SJohn Levon 	return next;
3151f5207b7SJohn Levon }
3161f5207b7SJohn Levon 
3171f5207b7SJohn Levon /*
3181f5207b7SJohn Levon  * We store arglist as <counter> [arg1] <number of uses for arg1> ... eof
3191f5207b7SJohn Levon  */
3201f5207b7SJohn Levon 
3211f5207b7SJohn Levon struct arg {
3221f5207b7SJohn Levon 	struct token *arg;
3231f5207b7SJohn Levon 	struct token *expanded;
3241f5207b7SJohn Levon 	struct token *str;
3251f5207b7SJohn Levon 	int n_normal;
3261f5207b7SJohn Levon 	int n_quoted;
3271f5207b7SJohn Levon 	int n_str;
3281f5207b7SJohn Levon };
3291f5207b7SJohn Levon 
3301f5207b7SJohn Levon static int collect_arguments(struct token *start, struct token *arglist, struct arg *args, struct token *what)
3311f5207b7SJohn Levon {
3321f5207b7SJohn Levon 	int wanted = arglist->count.normal;
3331f5207b7SJohn Levon 	struct token *next = NULL;
3341f5207b7SJohn Levon 	int count = 0;
3351f5207b7SJohn Levon 
3361f5207b7SJohn Levon 	arglist = arglist->next;	/* skip counter */
3371f5207b7SJohn Levon 
3381f5207b7SJohn Levon 	if (!wanted) {
3391f5207b7SJohn Levon 		next = collect_arg(start, 0, &what->pos, 0);
3401f5207b7SJohn Levon 		if (eof_token(next))
3411f5207b7SJohn Levon 			goto Eclosing;
3421f5207b7SJohn Levon 		if (!eof_token(start->next) || !match_op(next, ')')) {
3431f5207b7SJohn Levon 			count++;
3441f5207b7SJohn Levon 			goto Emany;
3451f5207b7SJohn Levon 		}
3461f5207b7SJohn Levon 	} else {
3471f5207b7SJohn Levon 		for (count = 0; count < wanted; count++) {
3481f5207b7SJohn Levon 			struct argcount *p = &arglist->next->count;
3491f5207b7SJohn Levon 			next = collect_arg(start, p->vararg, &what->pos, p->normal);
3501f5207b7SJohn Levon 			if (eof_token(next))
3511f5207b7SJohn Levon 				goto Eclosing;
3521f5207b7SJohn Levon 			if (p->vararg && wanted == 1 && eof_token(start->next))
3531f5207b7SJohn Levon 				break;
3541f5207b7SJohn Levon 			arglist = arglist->next->next;
3551f5207b7SJohn Levon 			args[count].arg = start->next;
3561f5207b7SJohn Levon 			args[count].n_normal = p->normal;
3571f5207b7SJohn Levon 			args[count].n_quoted = p->quoted;
3581f5207b7SJohn Levon 			args[count].n_str = p->str;
3591f5207b7SJohn Levon 			if (match_op(next, ')')) {
3601f5207b7SJohn Levon 				count++;
3611f5207b7SJohn Levon 				break;
3621f5207b7SJohn Levon 			}
3631f5207b7SJohn Levon 			start = next;
3641f5207b7SJohn Levon 		}
3651f5207b7SJohn Levon 		if (count == wanted && !match_op(next, ')'))
3661f5207b7SJohn Levon 			goto Emany;
3671f5207b7SJohn Levon 		if (count == wanted - 1) {
3681f5207b7SJohn Levon 			struct argcount *p = &arglist->next->count;
3691f5207b7SJohn Levon 			if (!p->vararg)
3701f5207b7SJohn Levon 				goto Efew;
3711f5207b7SJohn Levon 			args[count].arg = NULL;
3721f5207b7SJohn Levon 			args[count].n_normal = p->normal;
3731f5207b7SJohn Levon 			args[count].n_quoted = p->quoted;
3741f5207b7SJohn Levon 			args[count].n_str = p->str;
3751f5207b7SJohn Levon 		}
3761f5207b7SJohn Levon 		if (count < wanted - 1)
3771f5207b7SJohn Levon 			goto Efew;
3781f5207b7SJohn Levon 	}
3791f5207b7SJohn Levon 	what->next = next->next;
3801f5207b7SJohn Levon 	return 1;
3811f5207b7SJohn Levon 
3821f5207b7SJohn Levon Efew:
3831f5207b7SJohn Levon 	sparse_error(what->pos, "macro \"%s\" requires %d arguments, but only %d given",
3841f5207b7SJohn Levon 		show_token(what), wanted, count);
3851f5207b7SJohn Levon 	goto out;
3861f5207b7SJohn Levon Emany:
3871f5207b7SJohn Levon 	while (match_op(next, ',')) {
3881f5207b7SJohn Levon 		next = collect_arg(next, 0, &what->pos, 0);
3891f5207b7SJohn Levon 		count++;
3901f5207b7SJohn Levon 	}
3911f5207b7SJohn Levon 	if (eof_token(next))
3921f5207b7SJohn Levon 		goto Eclosing;
3931f5207b7SJohn Levon 	sparse_error(what->pos, "macro \"%s\" passed %d arguments, but takes just %d",
3941f5207b7SJohn Levon 		show_token(what), count, wanted);
3951f5207b7SJohn Levon 	goto out;
3961f5207b7SJohn Levon Eclosing:
3971f5207b7SJohn Levon 	sparse_error(what->pos, "unterminated argument list invoking macro \"%s\"",
3981f5207b7SJohn Levon 		show_token(what));
3991f5207b7SJohn Levon out:
4001f5207b7SJohn Levon 	what->next = next->next;
4011f5207b7SJohn Levon 	return 0;
4021f5207b7SJohn Levon }
4031f5207b7SJohn Levon 
4041f5207b7SJohn Levon static struct token *dup_list(struct token *list)
4051f5207b7SJohn Levon {
4061f5207b7SJohn Levon 	struct token *res = NULL;
4071f5207b7SJohn Levon 	struct token **p = &res;
4081f5207b7SJohn Levon 
4091f5207b7SJohn Levon 	while (!eof_token(list)) {
4101f5207b7SJohn Levon 		struct token *newtok = __alloc_token(0);
4111f5207b7SJohn Levon 		*newtok = *list;
4121f5207b7SJohn Levon 		*p = newtok;
4131f5207b7SJohn Levon 		p = &newtok->next;
4141f5207b7SJohn Levon 		list = list->next;
4151f5207b7SJohn Levon 	}
4161f5207b7SJohn Levon 	return res;
4171f5207b7SJohn Levon }
4181f5207b7SJohn Levon 
4191f5207b7SJohn Levon static const char *show_token_sequence(struct token *token, int quote)
4201f5207b7SJohn Levon {
4211f5207b7SJohn Levon 	static char buffer[MAX_STRING];
4221f5207b7SJohn Levon 	char *ptr = buffer;
4231f5207b7SJohn Levon 	int whitespace = 0;
4241f5207b7SJohn Levon 
4251f5207b7SJohn Levon 	if (!token && !quote)
4261f5207b7SJohn Levon 		return "<none>";
4271f5207b7SJohn Levon 	while (!eof_token(token)) {
4281f5207b7SJohn Levon 		const char *val = quote ? quote_token(token) : show_token(token);
4291f5207b7SJohn Levon 		int len = strlen(val);
4301f5207b7SJohn Levon 
4311f5207b7SJohn Levon 		if (ptr + whitespace + len >= buffer + sizeof(buffer)) {
4321f5207b7SJohn Levon 			sparse_error(token->pos, "too long token expansion");
4331f5207b7SJohn Levon 			break;
4341f5207b7SJohn Levon 		}
4351f5207b7SJohn Levon 
4361f5207b7SJohn Levon 		if (whitespace)
4371f5207b7SJohn Levon 			*ptr++ = ' ';
4381f5207b7SJohn Levon 		memcpy(ptr, val, len);
4391f5207b7SJohn Levon 		ptr += len;
4401f5207b7SJohn Levon 		token = token->next;
4411f5207b7SJohn Levon 		whitespace = token->pos.whitespace;
4421f5207b7SJohn Levon 	}
4431f5207b7SJohn Levon 	*ptr = 0;
4441f5207b7SJohn Levon 	return buffer;
4451f5207b7SJohn Levon }
4461f5207b7SJohn Levon 
4471f5207b7SJohn Levon static struct token *stringify(struct token *arg)
4481f5207b7SJohn Levon {
4491f5207b7SJohn Levon 	const char *s = show_token_sequence(arg, 1);
4501f5207b7SJohn Levon 	int size = strlen(s)+1;
4511f5207b7SJohn Levon 	struct token *token = __alloc_token(0);
4521f5207b7SJohn Levon 	struct string *string = __alloc_string(size);
4531f5207b7SJohn Levon 
4541f5207b7SJohn Levon 	memcpy(string->data, s, size);
4551f5207b7SJohn Levon 	string->length = size;
4561f5207b7SJohn Levon 	token->pos = arg->pos;
4571f5207b7SJohn Levon 	token_type(token) = TOKEN_STRING;
4581f5207b7SJohn Levon 	token->string = string;
4591f5207b7SJohn Levon 	token->next = &eof_token_entry;
4601f5207b7SJohn Levon 	return token;
4611f5207b7SJohn Levon }
4621f5207b7SJohn Levon 
4631f5207b7SJohn Levon static void expand_arguments(int count, struct arg *args)
4641f5207b7SJohn Levon {
4651f5207b7SJohn Levon 	int i;
4661f5207b7SJohn Levon 	for (i = 0; i < count; i++) {
4671f5207b7SJohn Levon 		struct token *arg = args[i].arg;
4681f5207b7SJohn Levon 		if (!arg)
4691f5207b7SJohn Levon 			arg = &eof_token_entry;
4701f5207b7SJohn Levon 		if (args[i].n_str)
4711f5207b7SJohn Levon 			args[i].str = stringify(arg);
4721f5207b7SJohn Levon 		if (args[i].n_normal) {
4731f5207b7SJohn Levon 			if (!args[i].n_quoted) {
4741f5207b7SJohn Levon 				args[i].expanded = arg;
4751f5207b7SJohn Levon 				args[i].arg = NULL;
4761f5207b7SJohn Levon 			} else if (eof_token(arg)) {
4771f5207b7SJohn Levon 				args[i].expanded = arg;
4781f5207b7SJohn Levon 			} else {
4791f5207b7SJohn Levon 				args[i].expanded = dup_list(arg);
4801f5207b7SJohn Levon 			}
4811f5207b7SJohn Levon 			expand_list(&args[i].expanded);
4821f5207b7SJohn Levon 		}
4831f5207b7SJohn Levon 	}
4841f5207b7SJohn Levon }
4851f5207b7SJohn Levon 
4861f5207b7SJohn Levon /*
4871f5207b7SJohn Levon  * Possibly valid combinations:
4881f5207b7SJohn Levon  *  - ident + ident -> ident
4891f5207b7SJohn Levon  *  - ident + number -> ident unless number contains '.', '+' or '-'.
4901f5207b7SJohn Levon  *  - 'L' + char constant -> wide char constant
4911f5207b7SJohn Levon  *  - 'L' + string literal -> wide string literal
4921f5207b7SJohn Levon  *  - number + number -> number
4931f5207b7SJohn Levon  *  - number + ident -> number
4941f5207b7SJohn Levon  *  - number + '.' -> number
4951f5207b7SJohn Levon  *  - number + '+' or '-' -> number, if number used to end on [eEpP].
4961f5207b7SJohn Levon  *  - '.' + number -> number, if number used to start with a digit.
4971f5207b7SJohn Levon  *  - special + special -> either special or an error.
4981f5207b7SJohn Levon  */
4991f5207b7SJohn Levon static enum token_type combine(struct token *left, struct token *right, char *p)
5001f5207b7SJohn Levon {
5011f5207b7SJohn Levon 	int len;
5021f5207b7SJohn Levon 	enum token_type t1 = token_type(left), t2 = token_type(right);
5031f5207b7SJohn Levon 
5041f5207b7SJohn Levon 	if (t1 != TOKEN_IDENT && t1 != TOKEN_NUMBER && t1 != TOKEN_SPECIAL)
5051f5207b7SJohn Levon 		return TOKEN_ERROR;
5061f5207b7SJohn Levon 
5071f5207b7SJohn Levon 	if (t1 == TOKEN_IDENT && left->ident == &L_ident) {
5081f5207b7SJohn Levon 		if (t2 >= TOKEN_CHAR && t2 < TOKEN_WIDE_CHAR)
5091f5207b7SJohn Levon 			return t2 + TOKEN_WIDE_CHAR - TOKEN_CHAR;
5101f5207b7SJohn Levon 		if (t2 == TOKEN_STRING)
5111f5207b7SJohn Levon 			return TOKEN_WIDE_STRING;
5121f5207b7SJohn Levon 	}
5131f5207b7SJohn Levon 
5141f5207b7SJohn Levon 	if (t2 != TOKEN_IDENT && t2 != TOKEN_NUMBER && t2 != TOKEN_SPECIAL)
5151f5207b7SJohn Levon 		return TOKEN_ERROR;
5161f5207b7SJohn Levon 
5171f5207b7SJohn Levon 	strcpy(p, show_token(left));
5181f5207b7SJohn Levon 	strcat(p, show_token(right));
5191f5207b7SJohn Levon 	len = strlen(p);
5201f5207b7SJohn Levon 
5211f5207b7SJohn Levon 	if (len >= 256)
5221f5207b7SJohn Levon 		return TOKEN_ERROR;
5231f5207b7SJohn Levon 
5241f5207b7SJohn Levon 	if (t1 == TOKEN_IDENT) {
5251f5207b7SJohn Levon 		if (t2 == TOKEN_SPECIAL)
5261f5207b7SJohn Levon 			return TOKEN_ERROR;
5271f5207b7SJohn Levon 		if (t2 == TOKEN_NUMBER && strpbrk(p, "+-."))
5281f5207b7SJohn Levon 			return TOKEN_ERROR;
5291f5207b7SJohn Levon 		return TOKEN_IDENT;
5301f5207b7SJohn Levon 	}
5311f5207b7SJohn Levon 
5321f5207b7SJohn Levon 	if (t1 == TOKEN_NUMBER) {
5331f5207b7SJohn Levon 		if (t2 == TOKEN_SPECIAL) {
5341f5207b7SJohn Levon 			switch (right->special) {
5351f5207b7SJohn Levon 			case '.':
5361f5207b7SJohn Levon 				break;
5371f5207b7SJohn Levon 			case '+': case '-':
5381f5207b7SJohn Levon 				if (strchr("eEpP", p[len - 2]))
5391f5207b7SJohn Levon 					break;
5401f5207b7SJohn Levon 			default:
5411f5207b7SJohn Levon 				return TOKEN_ERROR;
5421f5207b7SJohn Levon 			}
5431f5207b7SJohn Levon 		}
5441f5207b7SJohn Levon 		return TOKEN_NUMBER;
5451f5207b7SJohn Levon 	}
5461f5207b7SJohn Levon 
5471f5207b7SJohn Levon 	if (p[0] == '.' && isdigit((unsigned char)p[1]))
5481f5207b7SJohn Levon 		return TOKEN_NUMBER;
5491f5207b7SJohn Levon 
5501f5207b7SJohn Levon 	return TOKEN_SPECIAL;
5511f5207b7SJohn Levon }
5521f5207b7SJohn Levon 
5531f5207b7SJohn Levon static int merge(struct token *left, struct token *right)
5541f5207b7SJohn Levon {
5551f5207b7SJohn Levon 	static char buffer[512];
5561f5207b7SJohn Levon 	enum token_type res = combine(left, right, buffer);
5571f5207b7SJohn Levon 	int n;
5581f5207b7SJohn Levon 
5591f5207b7SJohn Levon 	switch (res) {
5601f5207b7SJohn Levon 	case TOKEN_IDENT:
5611f5207b7SJohn Levon 		left->ident = built_in_ident(buffer);
5621f5207b7SJohn Levon 		left->pos.noexpand = 0;
5631f5207b7SJohn Levon 		return 1;
5641f5207b7SJohn Levon 
565*c85f09ccSJohn Levon 	case TOKEN_NUMBER:
5661f5207b7SJohn Levon 		token_type(left) = TOKEN_NUMBER;	/* could be . + num */
567*c85f09ccSJohn Levon 		left->number = xstrdup(buffer);
5681f5207b7SJohn Levon 		return 1;
5691f5207b7SJohn Levon 
5701f5207b7SJohn Levon 	case TOKEN_SPECIAL:
5711f5207b7SJohn Levon 		if (buffer[2] && buffer[3])
5721f5207b7SJohn Levon 			break;
5731f5207b7SJohn Levon 		for (n = SPECIAL_BASE; n < SPECIAL_ARG_SEPARATOR; n++) {
5741f5207b7SJohn Levon 			if (!memcmp(buffer, combinations[n-SPECIAL_BASE], 3)) {
5751f5207b7SJohn Levon 				left->special = n;
5761f5207b7SJohn Levon 				return 1;
5771f5207b7SJohn Levon 			}
5781f5207b7SJohn Levon 		}
5791f5207b7SJohn Levon 		break;
5801f5207b7SJohn Levon 
5811f5207b7SJohn Levon 	case TOKEN_WIDE_CHAR:
5821f5207b7SJohn Levon 	case TOKEN_WIDE_STRING:
5831f5207b7SJohn Levon 		token_type(left) = res;
5841f5207b7SJohn Levon 		left->pos.noexpand = 0;
5851f5207b7SJohn Levon 		left->string = right->string;
5861f5207b7SJohn Levon 		return 1;
5871f5207b7SJohn Levon 
5881f5207b7SJohn Levon 	case TOKEN_WIDE_CHAR_EMBEDDED_0 ... TOKEN_WIDE_CHAR_EMBEDDED_3:
5891f5207b7SJohn Levon 		token_type(left) = res;
5901f5207b7SJohn Levon 		left->pos.noexpand = 0;
5911f5207b7SJohn Levon 		memcpy(left->embedded, right->embedded, 4);
5921f5207b7SJohn Levon 		return 1;
5931f5207b7SJohn Levon 
5941f5207b7SJohn Levon 	default:
5951f5207b7SJohn Levon 		;
5961f5207b7SJohn Levon 	}
5971f5207b7SJohn Levon 	sparse_error(left->pos, "'##' failed: concatenation is not a valid token");
5981f5207b7SJohn Levon 	return 0;
5991f5207b7SJohn Levon }
6001f5207b7SJohn Levon 
6011f5207b7SJohn Levon static struct token *dup_token(struct token *token, struct position *streampos)
6021f5207b7SJohn Levon {
6031f5207b7SJohn Levon 	struct token *alloc = alloc_token(streampos);
6041f5207b7SJohn Levon 	token_type(alloc) = token_type(token);
6051f5207b7SJohn Levon 	alloc->pos.newline = token->pos.newline;
6061f5207b7SJohn Levon 	alloc->pos.whitespace = token->pos.whitespace;
6071f5207b7SJohn Levon 	alloc->number = token->number;
6081f5207b7SJohn Levon 	alloc->pos.noexpand = token->pos.noexpand;
6091f5207b7SJohn Levon 	return alloc;
6101f5207b7SJohn Levon }
6111f5207b7SJohn Levon 
6121f5207b7SJohn Levon static struct token **copy(struct token **where, struct token *list, int *count)
6131f5207b7SJohn Levon {
6141f5207b7SJohn Levon 	int need_copy = --*count;
6151f5207b7SJohn Levon 	while (!eof_token(list)) {
6161f5207b7SJohn Levon 		struct token *token;
6171f5207b7SJohn Levon 		if (need_copy)
6181f5207b7SJohn Levon 			token = dup_token(list, &list->pos);
6191f5207b7SJohn Levon 		else
6201f5207b7SJohn Levon 			token = list;
6211f5207b7SJohn Levon 		if (token_type(token) == TOKEN_IDENT && token->ident->tainted)
6221f5207b7SJohn Levon 			token->pos.noexpand = 1;
6231f5207b7SJohn Levon 		*where = token;
6241f5207b7SJohn Levon 		where = &token->next;
6251f5207b7SJohn Levon 		list = list->next;
6261f5207b7SJohn Levon 	}
6271f5207b7SJohn Levon 	*where = &eof_token_entry;
6281f5207b7SJohn Levon 	return where;
6291f5207b7SJohn Levon }
6301f5207b7SJohn Levon 
6311f5207b7SJohn Levon static int handle_kludge(struct token **p, struct arg *args)
6321f5207b7SJohn Levon {
6331f5207b7SJohn Levon 	struct token *t = (*p)->next->next;
6341f5207b7SJohn Levon 	while (1) {
6351f5207b7SJohn Levon 		struct arg *v = &args[t->argnum];
6361f5207b7SJohn Levon 		if (token_type(t->next) != TOKEN_CONCAT) {
6371f5207b7SJohn Levon 			if (v->arg) {
6381f5207b7SJohn Levon 				/* ignore the first ## */
6391f5207b7SJohn Levon 				*p = (*p)->next;
6401f5207b7SJohn Levon 				return 0;
6411f5207b7SJohn Levon 			}
6421f5207b7SJohn Levon 			/* skip the entire thing */
6431f5207b7SJohn Levon 			*p = t;
6441f5207b7SJohn Levon 			return 1;
6451f5207b7SJohn Levon 		}
6461f5207b7SJohn Levon 		if (v->arg && !eof_token(v->arg))
6471f5207b7SJohn Levon 			return 0; /* no magic */
6481f5207b7SJohn Levon 		t = t->next->next;
6491f5207b7SJohn Levon 	}
6501f5207b7SJohn Levon }
6511f5207b7SJohn Levon 
6521f5207b7SJohn Levon static struct token **substitute(struct token **list, struct token *body, struct arg *args)
6531f5207b7SJohn Levon {
6541f5207b7SJohn Levon 	struct position *base_pos = &(*list)->pos;
6551f5207b7SJohn Levon 	int *count;
6561f5207b7SJohn Levon 	enum {Normal, Placeholder, Concat} state = Normal;
6571f5207b7SJohn Levon 
6581f5207b7SJohn Levon 	for (; !eof_token(body); body = body->next) {
6591f5207b7SJohn Levon 		struct token *added, *arg;
6601f5207b7SJohn Levon 		struct token **tail;
6611f5207b7SJohn Levon 		struct token *t;
6621f5207b7SJohn Levon 
6631f5207b7SJohn Levon 		switch (token_type(body)) {
6641f5207b7SJohn Levon 		case TOKEN_GNU_KLUDGE:
6651f5207b7SJohn Levon 			/*
6661f5207b7SJohn Levon 			 * GNU kludge: if we had <comma>##<vararg>, behaviour
6671f5207b7SJohn Levon 			 * depends on whether we had enough arguments to have
6681f5207b7SJohn Levon 			 * a vararg.  If we did, ## is just ignored.  Otherwise
6691f5207b7SJohn Levon 			 * both , and ## are ignored.  Worse, there can be
6701f5207b7SJohn Levon 			 * an arbitrary number of ##<arg> in between; if all of
6711f5207b7SJohn Levon 			 * those are empty, we act as if they hadn't been there,
6721f5207b7SJohn Levon 			 * otherwise we act as if the kludge didn't exist.
6731f5207b7SJohn Levon 			 */
6741f5207b7SJohn Levon 			t = body;
6751f5207b7SJohn Levon 			if (handle_kludge(&body, args)) {
6761f5207b7SJohn Levon 				if (state == Concat)
6771f5207b7SJohn Levon 					state = Normal;
6781f5207b7SJohn Levon 				else
6791f5207b7SJohn Levon 					state = Placeholder;
6801f5207b7SJohn Levon 				continue;
6811f5207b7SJohn Levon 			}
6821f5207b7SJohn Levon 			added = dup_token(t, base_pos);
6831f5207b7SJohn Levon 			token_type(added) = TOKEN_SPECIAL;
6841f5207b7SJohn Levon 			tail = &added->next;
6851f5207b7SJohn Levon 			break;
6861f5207b7SJohn Levon 
6871f5207b7SJohn Levon 		case TOKEN_STR_ARGUMENT:
6881f5207b7SJohn Levon 			arg = args[body->argnum].str;
6891f5207b7SJohn Levon 			count = &args[body->argnum].n_str;
6901f5207b7SJohn Levon 			goto copy_arg;
6911f5207b7SJohn Levon 
6921f5207b7SJohn Levon 		case TOKEN_QUOTED_ARGUMENT:
6931f5207b7SJohn Levon 			arg = args[body->argnum].arg;
6941f5207b7SJohn Levon 			count = &args[body->argnum].n_quoted;
6951f5207b7SJohn Levon 			if (!arg || eof_token(arg)) {
6961f5207b7SJohn Levon 				if (state == Concat)
6971f5207b7SJohn Levon 					state = Normal;
6981f5207b7SJohn Levon 				else
6991f5207b7SJohn Levon 					state = Placeholder;
7001f5207b7SJohn Levon 				continue;
7011f5207b7SJohn Levon 			}
7021f5207b7SJohn Levon 			goto copy_arg;
7031f5207b7SJohn Levon 
7041f5207b7SJohn Levon 		case TOKEN_MACRO_ARGUMENT:
7051f5207b7SJohn Levon 			arg = args[body->argnum].expanded;
7061f5207b7SJohn Levon 			count = &args[body->argnum].n_normal;
7071f5207b7SJohn Levon 			if (eof_token(arg)) {
7081f5207b7SJohn Levon 				state = Normal;
7091f5207b7SJohn Levon 				continue;
7101f5207b7SJohn Levon 			}
7111f5207b7SJohn Levon 		copy_arg:
7121f5207b7SJohn Levon 			tail = copy(&added, arg, count);
7131f5207b7SJohn Levon 			added->pos.newline = body->pos.newline;
7141f5207b7SJohn Levon 			added->pos.whitespace = body->pos.whitespace;
7151f5207b7SJohn Levon 			break;
7161f5207b7SJohn Levon 
7171f5207b7SJohn Levon 		case TOKEN_CONCAT:
7181f5207b7SJohn Levon 			if (state == Placeholder)
7191f5207b7SJohn Levon 				state = Normal;
7201f5207b7SJohn Levon 			else
7211f5207b7SJohn Levon 				state = Concat;
7221f5207b7SJohn Levon 			continue;
7231f5207b7SJohn Levon 
7241f5207b7SJohn Levon 		case TOKEN_IDENT:
7251f5207b7SJohn Levon 			added = dup_token(body, base_pos);
7261f5207b7SJohn Levon 			if (added->ident->tainted)
7271f5207b7SJohn Levon 				added->pos.noexpand = 1;
7281f5207b7SJohn Levon 			tail = &added->next;
7291f5207b7SJohn Levon 			break;
7301f5207b7SJohn Levon 
7311f5207b7SJohn Levon 		default:
7321f5207b7SJohn Levon 			added = dup_token(body, base_pos);
7331f5207b7SJohn Levon 			tail = &added->next;
7341f5207b7SJohn Levon 			break;
7351f5207b7SJohn Levon 		}
7361f5207b7SJohn Levon 
7371f5207b7SJohn Levon 		/*
7381f5207b7SJohn Levon 		 * if we got to doing real concatenation, we already have
7391f5207b7SJohn Levon 		 * added something into the list, so containing_token() is OK.
7401f5207b7SJohn Levon 		 */
7411f5207b7SJohn Levon 		if (state == Concat && merge(containing_token(list), added)) {
7421f5207b7SJohn Levon 			*list = added->next;
7431f5207b7SJohn Levon 			if (tail != &added->next)
7441f5207b7SJohn Levon 				list = tail;
7451f5207b7SJohn Levon 		} else {
7461f5207b7SJohn Levon 			*list = added;
7471f5207b7SJohn Levon 			list = tail;
7481f5207b7SJohn Levon 		}
7491f5207b7SJohn Levon 		state = Normal;
7501f5207b7SJohn Levon 	}
7511f5207b7SJohn Levon 	*list = &eof_token_entry;
7521f5207b7SJohn Levon 	return list;
7531f5207b7SJohn Levon }
7541f5207b7SJohn Levon 
7551f5207b7SJohn Levon static int expand(struct token **list, struct symbol *sym)
7561f5207b7SJohn Levon {
7571f5207b7SJohn Levon 	struct token *last;
7581f5207b7SJohn Levon 	struct token *token = *list;
7591f5207b7SJohn Levon 	struct ident *expanding = token->ident;
7601f5207b7SJohn Levon 	struct token **tail;
7611f5207b7SJohn Levon 	int nargs = sym->arglist ? sym->arglist->count.normal : 0;
7621f5207b7SJohn Levon 	struct arg args[nargs];
7631f5207b7SJohn Levon 
7641f5207b7SJohn Levon 	if (expanding->tainted) {
7651f5207b7SJohn Levon 		token->pos.noexpand = 1;
7661f5207b7SJohn Levon 		return 1;
7671f5207b7SJohn Levon 	}
7681f5207b7SJohn Levon 
7691f5207b7SJohn Levon 	if (sym->arglist) {
7701f5207b7SJohn Levon 		if (!match_op(scan_next(&token->next), '('))
7711f5207b7SJohn Levon 			return 1;
7721f5207b7SJohn Levon 		if (!collect_arguments(token->next, sym->arglist, args, token))
7731f5207b7SJohn Levon 			return 1;
7741f5207b7SJohn Levon 		expand_arguments(nargs, args);
7751f5207b7SJohn Levon 	}
7761f5207b7SJohn Levon 
7771f5207b7SJohn Levon 	expanding->tainted = 1;
7781f5207b7SJohn Levon 
7791f5207b7SJohn Levon 	last = token->next;
7801f5207b7SJohn Levon 	tail = substitute(list, sym->expansion, args);
7811f5207b7SJohn Levon 	/*
7821f5207b7SJohn Levon 	 * Note that it won't be eof - at least TOKEN_UNTAINT will be there.
7831f5207b7SJohn Levon 	 * We still can lose the newline flag if the sucker expands to nothing,
7841f5207b7SJohn Levon 	 * but the price of dealing with that is probably too high (we'd need
7851f5207b7SJohn Levon 	 * to collect the flags during scan_next())
7861f5207b7SJohn Levon 	 */
7871f5207b7SJohn Levon 	(*list)->pos.newline = token->pos.newline;
7881f5207b7SJohn Levon 	(*list)->pos.whitespace = token->pos.whitespace;
7891f5207b7SJohn Levon 	*tail = last;
7901f5207b7SJohn Levon 
7911f5207b7SJohn Levon 	return 0;
7921f5207b7SJohn Levon }
7931f5207b7SJohn Levon 
7941f5207b7SJohn Levon static const char *token_name_sequence(struct token *token, int endop, struct token *start)
7951f5207b7SJohn Levon {
7961f5207b7SJohn Levon 	static char buffer[256];
7971f5207b7SJohn Levon 	char *ptr = buffer;
7981f5207b7SJohn Levon 
7991f5207b7SJohn Levon 	while (!eof_token(token) && !match_op(token, endop)) {
8001f5207b7SJohn Levon 		int len;
8011f5207b7SJohn Levon 		const char *val = token->string->data;
8021f5207b7SJohn Levon 		if (token_type(token) != TOKEN_STRING)
8031f5207b7SJohn Levon 			val = show_token(token);
8041f5207b7SJohn Levon 		len = strlen(val);
8051f5207b7SJohn Levon 		memcpy(ptr, val, len);
8061f5207b7SJohn Levon 		ptr += len;
8071f5207b7SJohn Levon 		token = token->next;
8081f5207b7SJohn Levon 	}
8091f5207b7SJohn Levon 	*ptr = 0;
8101f5207b7SJohn Levon 	if (endop && !match_op(token, endop))
8111f5207b7SJohn Levon 		sparse_error(start->pos, "expected '>' at end of filename");
8121f5207b7SJohn Levon 	return buffer;
8131f5207b7SJohn Levon }
8141f5207b7SJohn Levon 
8151f5207b7SJohn Levon static int already_tokenized(const char *path)
8161f5207b7SJohn Levon {
8171f5207b7SJohn Levon 	int stream, next;
8181f5207b7SJohn Levon 
8191f5207b7SJohn Levon 	for (stream = *hash_stream(path); stream >= 0 ; stream = next) {
8201f5207b7SJohn Levon 		struct stream *s = input_streams + stream;
8211f5207b7SJohn Levon 
8221f5207b7SJohn Levon 		next = s->next_stream;
8231f5207b7SJohn Levon 		if (s->once) {
8241f5207b7SJohn Levon 			if (strcmp(path, s->name))
8251f5207b7SJohn Levon 				continue;
8261f5207b7SJohn Levon 			return 1;
8271f5207b7SJohn Levon 		}
8281f5207b7SJohn Levon 		if (s->constant != CONSTANT_FILE_YES)
8291f5207b7SJohn Levon 			continue;
8301f5207b7SJohn Levon 		if (strcmp(path, s->name))
8311f5207b7SJohn Levon 			continue;
8321f5207b7SJohn Levon 		if (s->protect && !lookup_macro(s->protect))
8331f5207b7SJohn Levon 			continue;
8341f5207b7SJohn Levon 		return 1;
8351f5207b7SJohn Levon 	}
8361f5207b7SJohn Levon 	return 0;
8371f5207b7SJohn Levon }
8381f5207b7SJohn Levon 
8391f5207b7SJohn Levon /* Handle include of header files.
8401f5207b7SJohn Levon  * The relevant options are made compatible with gcc. The only options that
8411f5207b7SJohn Levon  * are not supported is -withprefix and friends.
8421f5207b7SJohn Levon  *
8431f5207b7SJohn Levon  * Three set of include paths are known:
8441f5207b7SJohn Levon  * quote_includepath:	Path to search when using #include "file.h"
8451f5207b7SJohn Levon  * angle_includepath:	Paths to search when using #include <file.h>
8461f5207b7SJohn Levon  * isys_includepath:	Paths specified with -isystem, come before the
8471f5207b7SJohn Levon  *			built-in system include paths. Gcc would suppress
8481f5207b7SJohn Levon  *			warnings from system headers. Here we separate
8491f5207b7SJohn Levon  *			them from the angle_ ones to keep search ordering.
8501f5207b7SJohn Levon  *
8511f5207b7SJohn Levon  * sys_includepath:	Built-in include paths.
8521f5207b7SJohn Levon  * dirafter_includepath Paths added with -dirafter.
8531f5207b7SJohn Levon  *
8541f5207b7SJohn Levon  * The above is implemented as one array with pointers
8551f5207b7SJohn Levon  *                         +--------------+
8561f5207b7SJohn Levon  * quote_includepath --->  |              |
8571f5207b7SJohn Levon  *                         +--------------+
8581f5207b7SJohn Levon  *                         |              |
8591f5207b7SJohn Levon  *                         +--------------+
8601f5207b7SJohn Levon  * angle_includepath --->  |              |
8611f5207b7SJohn Levon  *                         +--------------+
8621f5207b7SJohn Levon  * isys_includepath  --->  |              |
8631f5207b7SJohn Levon  *                         +--------------+
8641f5207b7SJohn Levon  * sys_includepath   --->  |              |
8651f5207b7SJohn Levon  *                         +--------------+
8661f5207b7SJohn Levon  * dirafter_includepath -> |              |
8671f5207b7SJohn Levon  *                         +--------------+
8681f5207b7SJohn Levon  *
8691f5207b7SJohn Levon  * -I dir insert dir just before isys_includepath and move the rest
8701f5207b7SJohn Levon  * -I- makes all dirs specified with -I before to quote dirs only and
8711f5207b7SJohn Levon  *   angle_includepath is set equal to isys_includepath.
8721f5207b7SJohn Levon  * -nostdinc removes all sys dirs by storing NULL in entry pointed
8731f5207b7SJohn Levon  *   to by * sys_includepath. Note that this will reset all dirs built-in
8741f5207b7SJohn Levon  *   and added before -nostdinc by -isystem and -idirafter.
8751f5207b7SJohn Levon  * -isystem dir adds dir where isys_includepath points adding this dir as
8761f5207b7SJohn Levon  *   first systemdir
8771f5207b7SJohn Levon  * -idirafter dir adds dir to the end of the list
8781f5207b7SJohn Levon  */
8791f5207b7SJohn Levon 
8801f5207b7SJohn Levon static void set_stream_include_path(struct stream *stream)
8811f5207b7SJohn Levon {
8821f5207b7SJohn Levon 	const char *path = stream->path;
8831f5207b7SJohn Levon 	if (!path) {
8841f5207b7SJohn Levon 		const char *p = strrchr(stream->name, '/');
8851f5207b7SJohn Levon 		path = "";
8861f5207b7SJohn Levon 		if (p) {
8871f5207b7SJohn Levon 			int len = p - stream->name + 1;
8881f5207b7SJohn Levon 			char *m = malloc(len+1);
8891f5207b7SJohn Levon 			/* This includes the final "/" */
8901f5207b7SJohn Levon 			memcpy(m, stream->name, len);
8911f5207b7SJohn Levon 			m[len] = 0;
8921f5207b7SJohn Levon 			path = m;
8931f5207b7SJohn Levon 		}
8941f5207b7SJohn Levon 		stream->path = path;
8951f5207b7SJohn Levon 	}
8961f5207b7SJohn Levon 	includepath[0] = path;
8971f5207b7SJohn Levon }
8981f5207b7SJohn Levon 
899*c85f09ccSJohn Levon #ifndef PATH_MAX
900*c85f09ccSJohn Levon #define PATH_MAX 4096	// for Hurd where it's not defined
901*c85f09ccSJohn Levon #endif
902*c85f09ccSJohn Levon 
9031f5207b7SJohn Levon static int try_include(const char *path, const char *filename, int flen, struct token **where, const char **next_path)
9041f5207b7SJohn Levon {
9051f5207b7SJohn Levon 	int fd;
9061f5207b7SJohn Levon 	int plen = strlen(path);
9071f5207b7SJohn Levon 	static char fullname[PATH_MAX];
9081f5207b7SJohn Levon 
9091f5207b7SJohn Levon 	memcpy(fullname, path, plen);
9101f5207b7SJohn Levon 	if (plen && path[plen-1] != '/') {
9111f5207b7SJohn Levon 		fullname[plen] = '/';
9121f5207b7SJohn Levon 		plen++;
9131f5207b7SJohn Levon 	}
9141f5207b7SJohn Levon 	memcpy(fullname+plen, filename, flen);
9151f5207b7SJohn Levon 	if (already_tokenized(fullname))
9161f5207b7SJohn Levon 		return 1;
9171f5207b7SJohn Levon 	fd = open(fullname, O_RDONLY);
9181f5207b7SJohn Levon 	if (fd >= 0) {
919*c85f09ccSJohn Levon 		char *streamname = xmemdup(fullname, plen + flen);
9201f5207b7SJohn Levon 		*where = tokenize(streamname, fd, *where, next_path);
9211f5207b7SJohn Levon 		close(fd);
9221f5207b7SJohn Levon 		return 1;
9231f5207b7SJohn Levon 	}
9241f5207b7SJohn Levon 	return 0;
9251f5207b7SJohn Levon }
9261f5207b7SJohn Levon 
9271f5207b7SJohn Levon static int do_include_path(const char **pptr, struct token **list, struct token *token, const char *filename, int flen)
9281f5207b7SJohn Levon {
9291f5207b7SJohn Levon 	const char *path;
9301f5207b7SJohn Levon 
9311f5207b7SJohn Levon 	while ((path = *pptr++) != NULL) {
9321f5207b7SJohn Levon 		if (!try_include(path, filename, flen, list, pptr))
9331f5207b7SJohn Levon 			continue;
9341f5207b7SJohn Levon 		return 1;
9351f5207b7SJohn Levon 	}
9361f5207b7SJohn Levon 	return 0;
9371f5207b7SJohn Levon }
9381f5207b7SJohn Levon 
9391f5207b7SJohn Levon static int free_preprocessor_line(struct token *token)
9401f5207b7SJohn Levon {
9411f5207b7SJohn Levon 	while (token_type(token) != TOKEN_EOF) {
9421f5207b7SJohn Levon 		struct token *free = token;
9431f5207b7SJohn Levon 		token = token->next;
9441f5207b7SJohn Levon 		__free_token(free);
9451f5207b7SJohn Levon 	};
9461f5207b7SJohn Levon 	return 1;
9471f5207b7SJohn Levon }
9481f5207b7SJohn Levon 
9491f5207b7SJohn Levon const char *find_include(const char *skip, const char *look_for)
9501f5207b7SJohn Levon {
9511f5207b7SJohn Levon 	DIR *dp;
9521f5207b7SJohn Levon 	struct dirent *entry;
9531f5207b7SJohn Levon 	struct stat statbuf;
9541f5207b7SJohn Levon 	const char *ret;
9551f5207b7SJohn Levon 	char cwd[PATH_MAX];
9561f5207b7SJohn Levon 	static char buf[PATH_MAX + 1];
9571f5207b7SJohn Levon 
9581f5207b7SJohn Levon 	dp = opendir(".");
9591f5207b7SJohn Levon 	if (!dp)
9601f5207b7SJohn Levon 		return NULL;
9611f5207b7SJohn Levon 
9621f5207b7SJohn Levon 	if (!getcwd(cwd, sizeof(cwd)))
963*c85f09ccSJohn Levon 		goto close;
9641f5207b7SJohn Levon 
9651f5207b7SJohn Levon 	while ((entry = readdir(dp))) {
9661f5207b7SJohn Levon 		lstat(entry->d_name, &statbuf);
9671f5207b7SJohn Levon 
9681f5207b7SJohn Levon 		if (strcmp(entry->d_name, look_for) == 0) {
9691f5207b7SJohn Levon 			snprintf(buf, sizeof(buf), "%s/%s", cwd, entry->d_name);
970*c85f09ccSJohn Levon 			closedir(dp);
9711f5207b7SJohn Levon 			return buf;
9721f5207b7SJohn Levon 		}
9731f5207b7SJohn Levon 
9741f5207b7SJohn Levon 		if (S_ISDIR(statbuf.st_mode)) {
9751f5207b7SJohn Levon 			/* Found a directory, but ignore . and .. */
9761f5207b7SJohn Levon 			if (strcmp(".", entry->d_name) == 0 ||
9771f5207b7SJohn Levon 			    strcmp("..", entry->d_name) == 0 ||
9781f5207b7SJohn Levon 			    strcmp(skip, entry->d_name) == 0)
9791f5207b7SJohn Levon 				continue;
9801f5207b7SJohn Levon 
9811f5207b7SJohn Levon 			chdir(entry->d_name);
9821f5207b7SJohn Levon 			ret = find_include("", look_for);
9831f5207b7SJohn Levon 			chdir("..");
984*c85f09ccSJohn Levon 			if (ret) {
985*c85f09ccSJohn Levon 				closedir(dp);
9861f5207b7SJohn Levon 				return ret;
987*c85f09ccSJohn Levon 			}
9881f5207b7SJohn Levon 		}
9891f5207b7SJohn Levon 	}
990*c85f09ccSJohn Levon close:
9911f5207b7SJohn Levon 	closedir(dp);
9921f5207b7SJohn Levon 
9931f5207b7SJohn Levon 	return NULL;
9941f5207b7SJohn Levon }
9951f5207b7SJohn Levon 
9961f5207b7SJohn Levon const char *search_dir(const char *stop, const char *look_for)
9971f5207b7SJohn Levon {
9981f5207b7SJohn Levon 	char cwd[PATH_MAX];
9991f5207b7SJohn Levon 	int len;
10001f5207b7SJohn Levon 	const char *ret;
10011f5207b7SJohn Levon 	int cnt = 0;
10021f5207b7SJohn Levon 
10031f5207b7SJohn Levon 	if (!getcwd(cwd, sizeof(cwd)))
10041f5207b7SJohn Levon 		return NULL;
10051f5207b7SJohn Levon 
10061f5207b7SJohn Levon 	len = strlen(cwd);
10071f5207b7SJohn Levon 	while (len >= 0) {
10081f5207b7SJohn Levon 		ret = find_include(cnt++ ? cwd + len + 1 : "", look_for);
10091f5207b7SJohn Levon 		if (ret)
10101f5207b7SJohn Levon 			return ret;
10111f5207b7SJohn Levon 
10121f5207b7SJohn Levon 		if (strcmp(cwd, stop) == 0 ||
10131f5207b7SJohn Levon 		    strcmp(cwd, "/usr/include") == 0 ||
10141f5207b7SJohn Levon 		    strcmp(cwd, "/usr/local/include") == 0 ||
10151f5207b7SJohn Levon 		    strlen(cwd) <= 10 ||  /* heck...  don't search /usr/lib/ */
10161f5207b7SJohn Levon 		    strcmp(cwd, "/") == 0)
10171f5207b7SJohn Levon 			return NULL;
10181f5207b7SJohn Levon 
10191f5207b7SJohn Levon 		while (--len >= 0) {
10201f5207b7SJohn Levon 			if (cwd[len] == '/') {
10211f5207b7SJohn Levon 				cwd[len] = '\0';
10221f5207b7SJohn Levon 				break;
10231f5207b7SJohn Levon 			}
10241f5207b7SJohn Levon 		}
10251f5207b7SJohn Levon 
10261f5207b7SJohn Levon 		chdir("..");
10271f5207b7SJohn Levon 	}
10281f5207b7SJohn Levon 	return NULL;
10291f5207b7SJohn Levon }
10301f5207b7SJohn Levon 
10311f5207b7SJohn Levon static void use_best_guess_header_file(struct token *token, const char *filename, struct token **list)
10321f5207b7SJohn Levon {
10331f5207b7SJohn Levon 	char cwd[PATH_MAX];
10341f5207b7SJohn Levon 	char dir_part[PATH_MAX];
10351f5207b7SJohn Levon 	const char *file_part;
10361f5207b7SJohn Levon 	const char *include_name;
1037*c85f09ccSJohn Levon 	static int cnt;
10381f5207b7SJohn Levon 	int len;
10391f5207b7SJohn Levon 
1040*c85f09ccSJohn Levon 	/* Avoid guessing includes recursively. */
1041*c85f09ccSJohn Levon 	if (cnt++ > 1000)
1042*c85f09ccSJohn Levon 		return;
1043*c85f09ccSJohn Levon 
10441f5207b7SJohn Levon 	if (!filename || filename[0] == '\0')
10451f5207b7SJohn Levon 		return;
10461f5207b7SJohn Levon 
10471f5207b7SJohn Levon 	file_part = filename;
10481f5207b7SJohn Levon 	while ((filename = strchr(filename, '/'))) {
10491f5207b7SJohn Levon 		++filename;
10501f5207b7SJohn Levon 		if (filename[0])
10511f5207b7SJohn Levon 			file_part = filename;
10521f5207b7SJohn Levon 	}
10531f5207b7SJohn Levon 
10541f5207b7SJohn Levon 	snprintf(dir_part, sizeof(dir_part), "%s", stream_name(token->pos.stream));
10551f5207b7SJohn Levon 	len = strlen(dir_part);
10561f5207b7SJohn Levon 	while (--len >= 0) {
10571f5207b7SJohn Levon 		if (dir_part[len] == '/') {
10581f5207b7SJohn Levon 			dir_part[len] = '\0';
10591f5207b7SJohn Levon 			break;
10601f5207b7SJohn Levon 		}
10611f5207b7SJohn Levon 	}
10621f5207b7SJohn Levon 	if (len < 0)
10631f5207b7SJohn Levon 		sprintf(dir_part, ".");
10641f5207b7SJohn Levon 
10651f5207b7SJohn Levon 	if (!getcwd(cwd, sizeof(cwd)))
10661f5207b7SJohn Levon 		return;
10671f5207b7SJohn Levon 
10681f5207b7SJohn Levon 	chdir(dir_part);
10691f5207b7SJohn Levon 	include_name = search_dir(cwd, file_part);
10701f5207b7SJohn Levon 	chdir(cwd);
10711f5207b7SJohn Levon 	if (!include_name)
10721f5207b7SJohn Levon 		return;
10731f5207b7SJohn Levon 	sparse_error(token->pos, "using '%s'", include_name);
10741f5207b7SJohn Levon 
10751f5207b7SJohn Levon 	try_include("", include_name, strlen(include_name), list, includepath);
10761f5207b7SJohn Levon }
10771f5207b7SJohn Levon 
10781f5207b7SJohn Levon static int handle_include_path(struct stream *stream, struct token **list, struct token *token, int how)
10791f5207b7SJohn Levon {
10801f5207b7SJohn Levon 	const char *filename;
10811f5207b7SJohn Levon 	struct token *next;
10821f5207b7SJohn Levon 	const char **path;
10831f5207b7SJohn Levon 	int expect;
10841f5207b7SJohn Levon 	int flen;
10851f5207b7SJohn Levon 
10861f5207b7SJohn Levon 	next = token->next;
10871f5207b7SJohn Levon 	expect = '>';
10881f5207b7SJohn Levon 	if (!match_op(next, '<')) {
10891f5207b7SJohn Levon 		expand_list(&token->next);
10901f5207b7SJohn Levon 		expect = 0;
10911f5207b7SJohn Levon 		next = token;
10921f5207b7SJohn Levon 		if (match_op(token->next, '<')) {
10931f5207b7SJohn Levon 			next = token->next;
10941f5207b7SJohn Levon 			expect = '>';
10951f5207b7SJohn Levon 		}
10961f5207b7SJohn Levon 	}
10971f5207b7SJohn Levon 
10981f5207b7SJohn Levon 	token = next->next;
10991f5207b7SJohn Levon 	filename = token_name_sequence(token, expect, token);
11001f5207b7SJohn Levon 	flen = strlen(filename) + 1;
11011f5207b7SJohn Levon 
11021f5207b7SJohn Levon 	/* Absolute path? */
11031f5207b7SJohn Levon 	if (filename[0] == '/') {
11041f5207b7SJohn Levon 		if (try_include("", filename, flen, list, includepath))
11051f5207b7SJohn Levon 			return 0;
11061f5207b7SJohn Levon 		goto out;
11071f5207b7SJohn Levon 	}
11081f5207b7SJohn Levon 
11091f5207b7SJohn Levon 	switch (how) {
11101f5207b7SJohn Levon 	case 1:
11111f5207b7SJohn Levon 		path = stream->next_path;
11121f5207b7SJohn Levon 		break;
11131f5207b7SJohn Levon 	case 2:
11141f5207b7SJohn Levon 		includepath[0] = "";
11151f5207b7SJohn Levon 		path = includepath;
11161f5207b7SJohn Levon 		break;
11171f5207b7SJohn Levon 	default:
11181f5207b7SJohn Levon 		/* Dir of input file is first dir to search for quoted includes */
11191f5207b7SJohn Levon 		set_stream_include_path(stream);
11201f5207b7SJohn Levon 		path = expect ? angle_includepath : quote_includepath;
11211f5207b7SJohn Levon 		break;
11221f5207b7SJohn Levon 	}
11231f5207b7SJohn Levon 	/* Check the standard include paths.. */
11241f5207b7SJohn Levon 	if (do_include_path(path, list, token, filename, flen))
11251f5207b7SJohn Levon 		return 0;
11261f5207b7SJohn Levon out:
11271f5207b7SJohn Levon 	sparse_error(token->pos, "unable to open '%s'", filename);
11281f5207b7SJohn Levon 	use_best_guess_header_file(token, filename, list);
11291f5207b7SJohn Levon 	return 0;
11301f5207b7SJohn Levon }
11311f5207b7SJohn Levon 
11321f5207b7SJohn Levon static int handle_include(struct stream *stream, struct token **list, struct token *token)
11331f5207b7SJohn Levon {
11341f5207b7SJohn Levon 	return handle_include_path(stream, list, token, 0);
11351f5207b7SJohn Levon }
11361f5207b7SJohn Levon 
11371f5207b7SJohn Levon static int handle_include_next(struct stream *stream, struct token **list, struct token *token)
11381f5207b7SJohn Levon {
11391f5207b7SJohn Levon 	return handle_include_path(stream, list, token, 1);
11401f5207b7SJohn Levon }
11411f5207b7SJohn Levon 
11421f5207b7SJohn Levon static int handle_argv_include(struct stream *stream, struct token **list, struct token *token)
11431f5207b7SJohn Levon {
11441f5207b7SJohn Levon 	return handle_include_path(stream, list, token, 2);
11451f5207b7SJohn Levon }
11461f5207b7SJohn Levon 
11471f5207b7SJohn Levon static int token_different(struct token *t1, struct token *t2)
11481f5207b7SJohn Levon {
11491f5207b7SJohn Levon 	int different;
11501f5207b7SJohn Levon 
11511f5207b7SJohn Levon 	if (token_type(t1) != token_type(t2))
11521f5207b7SJohn Levon 		return 1;
11531f5207b7SJohn Levon 
11541f5207b7SJohn Levon 	switch (token_type(t1)) {
11551f5207b7SJohn Levon 	case TOKEN_IDENT:
11561f5207b7SJohn Levon 		different = t1->ident != t2->ident;
11571f5207b7SJohn Levon 		break;
11581f5207b7SJohn Levon 	case TOKEN_ARG_COUNT:
11591f5207b7SJohn Levon 	case TOKEN_UNTAINT:
11601f5207b7SJohn Levon 	case TOKEN_CONCAT:
11611f5207b7SJohn Levon 	case TOKEN_GNU_KLUDGE:
11621f5207b7SJohn Levon 		different = 0;
11631f5207b7SJohn Levon 		break;
11641f5207b7SJohn Levon 	case TOKEN_NUMBER:
11651f5207b7SJohn Levon 		different = strcmp(t1->number, t2->number);
11661f5207b7SJohn Levon 		break;
11671f5207b7SJohn Levon 	case TOKEN_SPECIAL:
11681f5207b7SJohn Levon 		different = t1->special != t2->special;
11691f5207b7SJohn Levon 		break;
11701f5207b7SJohn Levon 	case TOKEN_MACRO_ARGUMENT:
11711f5207b7SJohn Levon 	case TOKEN_QUOTED_ARGUMENT:
11721f5207b7SJohn Levon 	case TOKEN_STR_ARGUMENT:
11731f5207b7SJohn Levon 		different = t1->argnum != t2->argnum;
11741f5207b7SJohn Levon 		break;
11751f5207b7SJohn Levon 	case TOKEN_CHAR_EMBEDDED_0 ... TOKEN_CHAR_EMBEDDED_3:
11761f5207b7SJohn Levon 	case TOKEN_WIDE_CHAR_EMBEDDED_0 ... TOKEN_WIDE_CHAR_EMBEDDED_3:
11771f5207b7SJohn Levon 		different = memcmp(t1->embedded, t2->embedded, 4);
11781f5207b7SJohn Levon 		break;
11791f5207b7SJohn Levon 	case TOKEN_CHAR:
11801f5207b7SJohn Levon 	case TOKEN_WIDE_CHAR:
11811f5207b7SJohn Levon 	case TOKEN_STRING:
11821f5207b7SJohn Levon 	case TOKEN_WIDE_STRING: {
11831f5207b7SJohn Levon 		struct string *s1, *s2;
11841f5207b7SJohn Levon 
11851f5207b7SJohn Levon 		s1 = t1->string;
11861f5207b7SJohn Levon 		s2 = t2->string;
11871f5207b7SJohn Levon 		different = 1;
11881f5207b7SJohn Levon 		if (s1->length != s2->length)
11891f5207b7SJohn Levon 			break;
11901f5207b7SJohn Levon 		different = memcmp(s1->data, s2->data, s1->length);
11911f5207b7SJohn Levon 		break;
11921f5207b7SJohn Levon 	}
11931f5207b7SJohn Levon 	default:
11941f5207b7SJohn Levon 		different = 1;
11951f5207b7SJohn Levon 		break;
11961f5207b7SJohn Levon 	}
11971f5207b7SJohn Levon 	return different;
11981f5207b7SJohn Levon }
11991f5207b7SJohn Levon 
12001f5207b7SJohn Levon static int token_list_different(struct token *list1, struct token *list2)
12011f5207b7SJohn Levon {
12021f5207b7SJohn Levon 	for (;;) {
12031f5207b7SJohn Levon 		if (list1 == list2)
12041f5207b7SJohn Levon 			return 0;
12051f5207b7SJohn Levon 		if (!list1 || !list2)
12061f5207b7SJohn Levon 			return 1;
12071f5207b7SJohn Levon 		if (token_different(list1, list2))
12081f5207b7SJohn Levon 			return 1;
12091f5207b7SJohn Levon 		list1 = list1->next;
12101f5207b7SJohn Levon 		list2 = list2->next;
12111f5207b7SJohn Levon 	}
12121f5207b7SJohn Levon }
12131f5207b7SJohn Levon 
12141f5207b7SJohn Levon static inline void set_arg_count(struct token *token)
12151f5207b7SJohn Levon {
12161f5207b7SJohn Levon 	token_type(token) = TOKEN_ARG_COUNT;
12171f5207b7SJohn Levon 	token->count.normal = token->count.quoted =
12181f5207b7SJohn Levon 	token->count.str = token->count.vararg = 0;
12191f5207b7SJohn Levon }
12201f5207b7SJohn Levon 
12211f5207b7SJohn Levon static struct token *parse_arguments(struct token *list)
12221f5207b7SJohn Levon {
12231f5207b7SJohn Levon 	struct token *arg = list->next, *next = list;
12241f5207b7SJohn Levon 	struct argcount *count = &list->count;
12251f5207b7SJohn Levon 
12261f5207b7SJohn Levon 	set_arg_count(list);
12271f5207b7SJohn Levon 
12281f5207b7SJohn Levon 	if (match_op(arg, ')')) {
12291f5207b7SJohn Levon 		next = arg->next;
12301f5207b7SJohn Levon 		list->next = &eof_token_entry;
12311f5207b7SJohn Levon 		return next;
12321f5207b7SJohn Levon 	}
12331f5207b7SJohn Levon 
12341f5207b7SJohn Levon 	while (token_type(arg) == TOKEN_IDENT) {
12351f5207b7SJohn Levon 		if (arg->ident == &__VA_ARGS___ident)
12361f5207b7SJohn Levon 			goto Eva_args;
12371f5207b7SJohn Levon 		if (!++count->normal)
12381f5207b7SJohn Levon 			goto Eargs;
12391f5207b7SJohn Levon 		next = arg->next;
12401f5207b7SJohn Levon 
12411f5207b7SJohn Levon 		if (match_op(next, ',')) {
12421f5207b7SJohn Levon 			set_arg_count(next);
12431f5207b7SJohn Levon 			arg = next->next;
12441f5207b7SJohn Levon 			continue;
12451f5207b7SJohn Levon 		}
12461f5207b7SJohn Levon 
12471f5207b7SJohn Levon 		if (match_op(next, ')')) {
12481f5207b7SJohn Levon 			set_arg_count(next);
12491f5207b7SJohn Levon 			next = next->next;
12501f5207b7SJohn Levon 			arg->next->next = &eof_token_entry;
12511f5207b7SJohn Levon 			return next;
12521f5207b7SJohn Levon 		}
12531f5207b7SJohn Levon 
12541f5207b7SJohn Levon 		/* normal cases are finished here */
12551f5207b7SJohn Levon 
12561f5207b7SJohn Levon 		if (match_op(next, SPECIAL_ELLIPSIS)) {
12571f5207b7SJohn Levon 			if (match_op(next->next, ')')) {
12581f5207b7SJohn Levon 				set_arg_count(next);
12591f5207b7SJohn Levon 				next->count.vararg = 1;
12601f5207b7SJohn Levon 				next = next->next;
12611f5207b7SJohn Levon 				arg->next->next = &eof_token_entry;
12621f5207b7SJohn Levon 				return next->next;
12631f5207b7SJohn Levon 			}
12641f5207b7SJohn Levon 
12651f5207b7SJohn Levon 			arg = next;
12661f5207b7SJohn Levon 			goto Enotclosed;
12671f5207b7SJohn Levon 		}
12681f5207b7SJohn Levon 
12691f5207b7SJohn Levon 		if (eof_token(next)) {
12701f5207b7SJohn Levon 			goto Enotclosed;
12711f5207b7SJohn Levon 		} else {
12721f5207b7SJohn Levon 			arg = next;
12731f5207b7SJohn Levon 			goto Ebadstuff;
12741f5207b7SJohn Levon 		}
12751f5207b7SJohn Levon 	}
12761f5207b7SJohn Levon 
12771f5207b7SJohn Levon 	if (match_op(arg, SPECIAL_ELLIPSIS)) {
12781f5207b7SJohn Levon 		next = arg->next;
12791f5207b7SJohn Levon 		token_type(arg) = TOKEN_IDENT;
12801f5207b7SJohn Levon 		arg->ident = &__VA_ARGS___ident;
12811f5207b7SJohn Levon 		if (!match_op(next, ')'))
12821f5207b7SJohn Levon 			goto Enotclosed;
12831f5207b7SJohn Levon 		if (!++count->normal)
12841f5207b7SJohn Levon 			goto Eargs;
12851f5207b7SJohn Levon 		set_arg_count(next);
12861f5207b7SJohn Levon 		next->count.vararg = 1;
12871f5207b7SJohn Levon 		next = next->next;
12881f5207b7SJohn Levon 		arg->next->next = &eof_token_entry;
12891f5207b7SJohn Levon 		return next;
12901f5207b7SJohn Levon 	}
12911f5207b7SJohn Levon 
12921f5207b7SJohn Levon 	if (eof_token(arg)) {
12931f5207b7SJohn Levon 		arg = next;
12941f5207b7SJohn Levon 		goto Enotclosed;
12951f5207b7SJohn Levon 	}
12961f5207b7SJohn Levon 	if (match_op(arg, ','))
12971f5207b7SJohn Levon 		goto Emissing;
12981f5207b7SJohn Levon 	else
12991f5207b7SJohn Levon 		goto Ebadstuff;
13001f5207b7SJohn Levon 
13011f5207b7SJohn Levon 
13021f5207b7SJohn Levon Emissing:
13031f5207b7SJohn Levon 	sparse_error(arg->pos, "parameter name missing");
13041f5207b7SJohn Levon 	return NULL;
13051f5207b7SJohn Levon Ebadstuff:
13061f5207b7SJohn Levon 	sparse_error(arg->pos, "\"%s\" may not appear in macro parameter list",
13071f5207b7SJohn Levon 		show_token(arg));
13081f5207b7SJohn Levon 	return NULL;
13091f5207b7SJohn Levon Enotclosed:
13101f5207b7SJohn Levon 	sparse_error(arg->pos, "missing ')' in macro parameter list");
13111f5207b7SJohn Levon 	return NULL;
13121f5207b7SJohn Levon Eva_args:
13131f5207b7SJohn Levon 	sparse_error(arg->pos, "__VA_ARGS__ can only appear in the expansion of a C99 variadic macro");
13141f5207b7SJohn Levon 	return NULL;
13151f5207b7SJohn Levon Eargs:
13161f5207b7SJohn Levon 	sparse_error(arg->pos, "too many arguments in macro definition");
13171f5207b7SJohn Levon 	return NULL;
13181f5207b7SJohn Levon }
13191f5207b7SJohn Levon 
13201f5207b7SJohn Levon static int try_arg(struct token *token, enum token_type type, struct token *arglist)
13211f5207b7SJohn Levon {
13221f5207b7SJohn Levon 	struct ident *ident = token->ident;
13231f5207b7SJohn Levon 	int nr;
13241f5207b7SJohn Levon 
13251f5207b7SJohn Levon 	if (!arglist || token_type(token) != TOKEN_IDENT)
13261f5207b7SJohn Levon 		return 0;
13271f5207b7SJohn Levon 
13281f5207b7SJohn Levon 	arglist = arglist->next;
13291f5207b7SJohn Levon 
13301f5207b7SJohn Levon 	for (nr = 0; !eof_token(arglist); nr++, arglist = arglist->next->next) {
13311f5207b7SJohn Levon 		if (arglist->ident == ident) {
13321f5207b7SJohn Levon 			struct argcount *count = &arglist->next->count;
13331f5207b7SJohn Levon 			int n;
13341f5207b7SJohn Levon 
13351f5207b7SJohn Levon 			token->argnum = nr;
13361f5207b7SJohn Levon 			token_type(token) = type;
13371f5207b7SJohn Levon 			switch (type) {
13381f5207b7SJohn Levon 			case TOKEN_MACRO_ARGUMENT:
13391f5207b7SJohn Levon 				n = ++count->normal;
13401f5207b7SJohn Levon 				break;
13411f5207b7SJohn Levon 			case TOKEN_QUOTED_ARGUMENT:
13421f5207b7SJohn Levon 				n = ++count->quoted;
13431f5207b7SJohn Levon 				break;
13441f5207b7SJohn Levon 			default:
13451f5207b7SJohn Levon 				n = ++count->str;
13461f5207b7SJohn Levon 			}
13471f5207b7SJohn Levon 			if (n)
13481f5207b7SJohn Levon 				return count->vararg ? 2 : 1;
13491f5207b7SJohn Levon 			/*
13501f5207b7SJohn Levon 			 * XXX - need saner handling of that
13511f5207b7SJohn Levon 			 * (>= 1024 instances of argument)
13521f5207b7SJohn Levon 			 */
13531f5207b7SJohn Levon 			token_type(token) = TOKEN_ERROR;
13541f5207b7SJohn Levon 			return -1;
13551f5207b7SJohn Levon 		}
13561f5207b7SJohn Levon 	}
13571f5207b7SJohn Levon 	return 0;
13581f5207b7SJohn Levon }
13591f5207b7SJohn Levon 
13601f5207b7SJohn Levon static struct token *handle_hash(struct token **p, struct token *arglist)
13611f5207b7SJohn Levon {
13621f5207b7SJohn Levon 	struct token *token = *p;
13631f5207b7SJohn Levon 	if (arglist) {
13641f5207b7SJohn Levon 		struct token *next = token->next;
13651f5207b7SJohn Levon 		if (!try_arg(next, TOKEN_STR_ARGUMENT, arglist))
13661f5207b7SJohn Levon 			goto Equote;
13671f5207b7SJohn Levon 		next->pos.whitespace = token->pos.whitespace;
13681f5207b7SJohn Levon 		__free_token(token);
13691f5207b7SJohn Levon 		token = *p = next;
13701f5207b7SJohn Levon 	} else {
13711f5207b7SJohn Levon 		token->pos.noexpand = 1;
13721f5207b7SJohn Levon 	}
13731f5207b7SJohn Levon 	return token;
13741f5207b7SJohn Levon 
13751f5207b7SJohn Levon Equote:
13761f5207b7SJohn Levon 	sparse_error(token->pos, "'#' is not followed by a macro parameter");
13771f5207b7SJohn Levon 	return NULL;
13781f5207b7SJohn Levon }
13791f5207b7SJohn Levon 
13801f5207b7SJohn Levon /* token->next is ## */
13811f5207b7SJohn Levon static struct token *handle_hashhash(struct token *token, struct token *arglist)
13821f5207b7SJohn Levon {
13831f5207b7SJohn Levon 	struct token *last = token;
13841f5207b7SJohn Levon 	struct token *concat;
13851f5207b7SJohn Levon 	int state = match_op(token, ',');
13861f5207b7SJohn Levon 
13871f5207b7SJohn Levon 	try_arg(token, TOKEN_QUOTED_ARGUMENT, arglist);
13881f5207b7SJohn Levon 
13891f5207b7SJohn Levon 	while (1) {
13901f5207b7SJohn Levon 		struct token *t;
13911f5207b7SJohn Levon 		int is_arg;
13921f5207b7SJohn Levon 
13931f5207b7SJohn Levon 		/* eat duplicate ## */
13941f5207b7SJohn Levon 		concat = token->next;
13951f5207b7SJohn Levon 		while (match_op(t = concat->next, SPECIAL_HASHHASH)) {
13961f5207b7SJohn Levon 			token->next = t;
13971f5207b7SJohn Levon 			__free_token(concat);
13981f5207b7SJohn Levon 			concat = t;
13991f5207b7SJohn Levon 		}
14001f5207b7SJohn Levon 		token_type(concat) = TOKEN_CONCAT;
14011f5207b7SJohn Levon 
14021f5207b7SJohn Levon 		if (eof_token(t))
14031f5207b7SJohn Levon 			goto Econcat;
14041f5207b7SJohn Levon 
14051f5207b7SJohn Levon 		if (match_op(t, '#')) {
14061f5207b7SJohn Levon 			t = handle_hash(&concat->next, arglist);
14071f5207b7SJohn Levon 			if (!t)
14081f5207b7SJohn Levon 				return NULL;
14091f5207b7SJohn Levon 		}
14101f5207b7SJohn Levon 
14111f5207b7SJohn Levon 		is_arg = try_arg(t, TOKEN_QUOTED_ARGUMENT, arglist);
14121f5207b7SJohn Levon 
14131f5207b7SJohn Levon 		if (state == 1 && is_arg) {
14141f5207b7SJohn Levon 			state = is_arg;
14151f5207b7SJohn Levon 		} else {
14161f5207b7SJohn Levon 			last = t;
14171f5207b7SJohn Levon 			state = match_op(t, ',');
14181f5207b7SJohn Levon 		}
14191f5207b7SJohn Levon 
14201f5207b7SJohn Levon 		token = t;
14211f5207b7SJohn Levon 		if (!match_op(token->next, SPECIAL_HASHHASH))
14221f5207b7SJohn Levon 			break;
14231f5207b7SJohn Levon 	}
14241f5207b7SJohn Levon 	/* handle GNU ,##__VA_ARGS__ kludge, in all its weirdness */
14251f5207b7SJohn Levon 	if (state == 2)
14261f5207b7SJohn Levon 		token_type(last) = TOKEN_GNU_KLUDGE;
14271f5207b7SJohn Levon 	return token;
14281f5207b7SJohn Levon 
14291f5207b7SJohn Levon Econcat:
14301f5207b7SJohn Levon 	sparse_error(concat->pos, "'##' cannot appear at the ends of macro expansion");
14311f5207b7SJohn Levon 	return NULL;
14321f5207b7SJohn Levon }
14331f5207b7SJohn Levon 
14341f5207b7SJohn Levon static struct token *parse_expansion(struct token *expansion, struct token *arglist, struct ident *name)
14351f5207b7SJohn Levon {
14361f5207b7SJohn Levon 	struct token *token = expansion;
14371f5207b7SJohn Levon 	struct token **p;
14381f5207b7SJohn Levon 
14391f5207b7SJohn Levon 	if (match_op(token, SPECIAL_HASHHASH))
14401f5207b7SJohn Levon 		goto Econcat;
14411f5207b7SJohn Levon 
14421f5207b7SJohn Levon 	for (p = &expansion; !eof_token(token); p = &token->next, token = *p) {
14431f5207b7SJohn Levon 		if (match_op(token, '#')) {
14441f5207b7SJohn Levon 			token = handle_hash(p, arglist);
14451f5207b7SJohn Levon 			if (!token)
14461f5207b7SJohn Levon 				return NULL;
14471f5207b7SJohn Levon 		}
14481f5207b7SJohn Levon 		if (match_op(token->next, SPECIAL_HASHHASH)) {
14491f5207b7SJohn Levon 			token = handle_hashhash(token, arglist);
14501f5207b7SJohn Levon 			if (!token)
14511f5207b7SJohn Levon 				return NULL;
14521f5207b7SJohn Levon 		} else {
14531f5207b7SJohn Levon 			try_arg(token, TOKEN_MACRO_ARGUMENT, arglist);
14541f5207b7SJohn Levon 		}
14551f5207b7SJohn Levon 		switch (token_type(token)) {
14561f5207b7SJohn Levon 		case TOKEN_ERROR:
14571f5207b7SJohn Levon 			goto Earg;
14581f5207b7SJohn Levon 
14591f5207b7SJohn Levon 		case TOKEN_STRING:
14601f5207b7SJohn Levon 		case TOKEN_WIDE_STRING:
14611f5207b7SJohn Levon 			token->string->immutable = 1;
14621f5207b7SJohn Levon 			break;
14631f5207b7SJohn Levon 		}
14641f5207b7SJohn Levon 	}
14651f5207b7SJohn Levon 	token = alloc_token(&expansion->pos);
14661f5207b7SJohn Levon 	token_type(token) = TOKEN_UNTAINT;
14671f5207b7SJohn Levon 	token->ident = name;
14681f5207b7SJohn Levon 	token->next = *p;
14691f5207b7SJohn Levon 	*p = token;
14701f5207b7SJohn Levon 	return expansion;
14711f5207b7SJohn Levon 
14721f5207b7SJohn Levon Econcat:
14731f5207b7SJohn Levon 	sparse_error(token->pos, "'##' cannot appear at the ends of macro expansion");
14741f5207b7SJohn Levon 	return NULL;
14751f5207b7SJohn Levon Earg:
14761f5207b7SJohn Levon 	sparse_error(token->pos, "too many instances of argument in body");
14771f5207b7SJohn Levon 	return NULL;
14781f5207b7SJohn Levon }
14791f5207b7SJohn Levon 
1480*c85f09ccSJohn Levon static int do_define(struct position pos, struct token *token, struct ident *name,
1481*c85f09ccSJohn Levon 		     struct token *arglist, struct token *expansion, int attr)
14821f5207b7SJohn Levon {
14831f5207b7SJohn Levon 	struct symbol *sym;
1484*c85f09ccSJohn Levon 	int ret = 1;
14851f5207b7SJohn Levon 
14861f5207b7SJohn Levon 	expansion = parse_expansion(expansion, arglist, name);
14871f5207b7SJohn Levon 	if (!expansion)
14881f5207b7SJohn Levon 		return 1;
14891f5207b7SJohn Levon 
14901f5207b7SJohn Levon 	sym = lookup_symbol(name, NS_MACRO | NS_UNDEF);
14911f5207b7SJohn Levon 	if (sym) {
14921f5207b7SJohn Levon 		int clean;
14931f5207b7SJohn Levon 
14941f5207b7SJohn Levon 		if (attr < sym->attr)
14951f5207b7SJohn Levon 			goto out;
14961f5207b7SJohn Levon 
14971f5207b7SJohn Levon 		clean = (attr == sym->attr && sym->namespace == NS_MACRO);
14981f5207b7SJohn Levon 
14991f5207b7SJohn Levon 		if (token_list_different(sym->expansion, expansion) ||
15001f5207b7SJohn Levon 		    token_list_different(sym->arglist, arglist)) {
15011f5207b7SJohn Levon 			ret = 0;
15021f5207b7SJohn Levon 			if ((clean && attr == SYM_ATTR_NORMAL)
15031f5207b7SJohn Levon 					|| sym->used_in == file_scope) {
1504*c85f09ccSJohn Levon 				warning(pos, "preprocessor token %.*s redefined",
15051f5207b7SJohn Levon 						name->len, name->name);
15061f5207b7SJohn Levon 				info(sym->pos, "this was the original definition");
15071f5207b7SJohn Levon 			}
15081f5207b7SJohn Levon 		} else if (clean)
15091f5207b7SJohn Levon 			goto out;
15101f5207b7SJohn Levon 	}
15111f5207b7SJohn Levon 
15121f5207b7SJohn Levon 	if (!sym || sym->scope != file_scope) {
1513*c85f09ccSJohn Levon 		sym = alloc_symbol(pos, SYM_NODE);
15141f5207b7SJohn Levon 		bind_symbol(sym, name, NS_MACRO);
15151f5207b7SJohn Levon 		add_ident(&macros, name);
15161f5207b7SJohn Levon 		ret = 0;
15171f5207b7SJohn Levon 	}
15181f5207b7SJohn Levon 
15191f5207b7SJohn Levon 	if (!ret) {
15201f5207b7SJohn Levon 		sym->expansion = expansion;
15211f5207b7SJohn Levon 		sym->arglist = arglist;
1522*c85f09ccSJohn Levon 		if (token) /* Free the "define" token, but not the rest of the line */
1523*c85f09ccSJohn Levon 			__free_token(token);
15241f5207b7SJohn Levon 	}
15251f5207b7SJohn Levon 
15261f5207b7SJohn Levon 	sym->namespace = NS_MACRO;
15271f5207b7SJohn Levon 	sym->used_in = NULL;
15281f5207b7SJohn Levon 	sym->attr = attr;
15291f5207b7SJohn Levon out:
15301f5207b7SJohn Levon 	return ret;
15311f5207b7SJohn Levon }
15321f5207b7SJohn Levon 
1533*c85f09ccSJohn Levon ///
1534*c85f09ccSJohn Levon // predefine a macro with a printf-formatted value
1535*c85f09ccSJohn Levon // @name: the name of the macro
1536*c85f09ccSJohn Levon // @weak: 0/1 for a normal or a weak define
1537*c85f09ccSJohn Levon // @fmt: the printf format followed by it's arguments.
1538*c85f09ccSJohn Levon //
1539*c85f09ccSJohn Levon // The type of the value is automatically infered:
1540*c85f09ccSJohn Levon // TOKEN_NUMBER if it starts by a digit, TOKEN_IDENT otherwise.
1541*c85f09ccSJohn Levon // If @fmt is null or empty, the macro is defined with an empty definition.
1542*c85f09ccSJohn Levon void predefine(const char *name, int weak, const char *fmt, ...)
1543*c85f09ccSJohn Levon {
1544*c85f09ccSJohn Levon 	struct ident *ident = built_in_ident(name);
1545*c85f09ccSJohn Levon 	struct token *value = &eof_token_entry;
1546*c85f09ccSJohn Levon 	int attr = weak ? SYM_ATTR_WEAK : SYM_ATTR_NORMAL;
1547*c85f09ccSJohn Levon 
1548*c85f09ccSJohn Levon 	if (fmt && fmt[0]) {
1549*c85f09ccSJohn Levon 		static char buf[256];
1550*c85f09ccSJohn Levon 		va_list ap;
1551*c85f09ccSJohn Levon 
1552*c85f09ccSJohn Levon 		va_start(ap, fmt);
1553*c85f09ccSJohn Levon 		vsnprintf(buf, sizeof(buf), fmt, ap);
1554*c85f09ccSJohn Levon 		va_end(ap);
1555*c85f09ccSJohn Levon 
1556*c85f09ccSJohn Levon 		value = __alloc_token(0);
1557*c85f09ccSJohn Levon 		if (isdigit(buf[0])) {
1558*c85f09ccSJohn Levon 			token_type(value) = TOKEN_NUMBER;
1559*c85f09ccSJohn Levon 			value->number = xstrdup(buf);
1560*c85f09ccSJohn Levon 		} else {
1561*c85f09ccSJohn Levon 			token_type(value) = TOKEN_IDENT;
1562*c85f09ccSJohn Levon 			value->ident = built_in_ident(buf);
1563*c85f09ccSJohn Levon 		}
1564*c85f09ccSJohn Levon 		value->pos.whitespace = 1;
1565*c85f09ccSJohn Levon 		value->next = &eof_token_entry;
1566*c85f09ccSJohn Levon 	}
1567*c85f09ccSJohn Levon 
1568*c85f09ccSJohn Levon 	do_define(value->pos, NULL, ident, NULL, value, attr);
1569*c85f09ccSJohn Levon }
1570*c85f09ccSJohn Levon 
1571*c85f09ccSJohn Levon static int do_handle_define(struct stream *stream, struct token **line, struct token *token, int attr)
1572*c85f09ccSJohn Levon {
1573*c85f09ccSJohn Levon 	struct token *arglist, *expansion;
1574*c85f09ccSJohn Levon 	struct token *left = token->next;
1575*c85f09ccSJohn Levon 	struct ident *name;
1576*c85f09ccSJohn Levon 
1577*c85f09ccSJohn Levon 	if (token_type(left) != TOKEN_IDENT) {
1578*c85f09ccSJohn Levon 		sparse_error(token->pos, "expected identifier to 'define'");
1579*c85f09ccSJohn Levon 		return 1;
1580*c85f09ccSJohn Levon 	}
1581*c85f09ccSJohn Levon 
1582*c85f09ccSJohn Levon 	name = left->ident;
1583*c85f09ccSJohn Levon 
1584*c85f09ccSJohn Levon 	arglist = NULL;
1585*c85f09ccSJohn Levon 	expansion = left->next;
1586*c85f09ccSJohn Levon 	if (!expansion->pos.whitespace) {
1587*c85f09ccSJohn Levon 		if (match_op(expansion, '(')) {
1588*c85f09ccSJohn Levon 			arglist = expansion;
1589*c85f09ccSJohn Levon 			expansion = parse_arguments(expansion);
1590*c85f09ccSJohn Levon 			if (!expansion)
1591*c85f09ccSJohn Levon 				return 1;
1592*c85f09ccSJohn Levon 		} else if (!eof_token(expansion)) {
1593*c85f09ccSJohn Levon 			warning(expansion->pos,
1594*c85f09ccSJohn Levon 				"no whitespace before object-like macro body");
1595*c85f09ccSJohn Levon 		}
1596*c85f09ccSJohn Levon 	}
1597*c85f09ccSJohn Levon 
1598*c85f09ccSJohn Levon 	return do_define(left->pos, token, name, arglist, expansion, attr);
1599*c85f09ccSJohn Levon }
1600*c85f09ccSJohn Levon 
16011f5207b7SJohn Levon static int handle_define(struct stream *stream, struct token **line, struct token *token)
16021f5207b7SJohn Levon {
16031f5207b7SJohn Levon 	return do_handle_define(stream, line, token, SYM_ATTR_NORMAL);
16041f5207b7SJohn Levon }
16051f5207b7SJohn Levon 
16061f5207b7SJohn Levon static int handle_weak_define(struct stream *stream, struct token **line, struct token *token)
16071f5207b7SJohn Levon {
16081f5207b7SJohn Levon 	return do_handle_define(stream, line, token, SYM_ATTR_WEAK);
16091f5207b7SJohn Levon }
16101f5207b7SJohn Levon 
16111f5207b7SJohn Levon static int handle_strong_define(struct stream *stream, struct token **line, struct token *token)
16121f5207b7SJohn Levon {
16131f5207b7SJohn Levon 	return do_handle_define(stream, line, token, SYM_ATTR_STRONG);
16141f5207b7SJohn Levon }
16151f5207b7SJohn Levon 
16161f5207b7SJohn Levon static int do_handle_undef(struct stream *stream, struct token **line, struct token *token, int attr)
16171f5207b7SJohn Levon {
16181f5207b7SJohn Levon 	struct token *left = token->next;
16191f5207b7SJohn Levon 	struct symbol *sym;
16201f5207b7SJohn Levon 
16211f5207b7SJohn Levon 	if (token_type(left) != TOKEN_IDENT) {
16221f5207b7SJohn Levon 		sparse_error(token->pos, "expected identifier to 'undef'");
16231f5207b7SJohn Levon 		return 1;
16241f5207b7SJohn Levon 	}
16251f5207b7SJohn Levon 
16261f5207b7SJohn Levon 	sym = lookup_symbol(left->ident, NS_MACRO | NS_UNDEF);
16271f5207b7SJohn Levon 	if (sym) {
16281f5207b7SJohn Levon 		if (attr < sym->attr)
16291f5207b7SJohn Levon 			return 1;
16301f5207b7SJohn Levon 		if (attr == sym->attr && sym->namespace == NS_UNDEF)
16311f5207b7SJohn Levon 			return 1;
16321f5207b7SJohn Levon 	} else if (attr <= SYM_ATTR_NORMAL)
16331f5207b7SJohn Levon 		return 1;
16341f5207b7SJohn Levon 
16351f5207b7SJohn Levon 	if (!sym || sym->scope != file_scope) {
16361f5207b7SJohn Levon 		sym = alloc_symbol(left->pos, SYM_NODE);
16371f5207b7SJohn Levon 		bind_symbol(sym, left->ident, NS_MACRO);
16381f5207b7SJohn Levon 	}
16391f5207b7SJohn Levon 
16401f5207b7SJohn Levon 	sym->namespace = NS_UNDEF;
16411f5207b7SJohn Levon 	sym->used_in = NULL;
16421f5207b7SJohn Levon 	sym->attr = attr;
16431f5207b7SJohn Levon 
16441f5207b7SJohn Levon 	return 1;
16451f5207b7SJohn Levon }
16461f5207b7SJohn Levon 
16471f5207b7SJohn Levon static int handle_undef(struct stream *stream, struct token **line, struct token *token)
16481f5207b7SJohn Levon {
16491f5207b7SJohn Levon 	return do_handle_undef(stream, line, token, SYM_ATTR_NORMAL);
16501f5207b7SJohn Levon }
16511f5207b7SJohn Levon 
16521f5207b7SJohn Levon static int handle_strong_undef(struct stream *stream, struct token **line, struct token *token)
16531f5207b7SJohn Levon {
16541f5207b7SJohn Levon 	return do_handle_undef(stream, line, token, SYM_ATTR_STRONG);
16551f5207b7SJohn Levon }
16561f5207b7SJohn Levon 
1657*c85f09ccSJohn Levon static int preprocessor_if(struct stream *stream, struct token *token, int cond)
16581f5207b7SJohn Levon {
16591f5207b7SJohn Levon 	token_type(token) = false_nesting ? TOKEN_SKIP_GROUPS : TOKEN_IF;
16601f5207b7SJohn Levon 	free_preprocessor_line(token->next);
16611f5207b7SJohn Levon 	token->next = stream->top_if;
16621f5207b7SJohn Levon 	stream->top_if = token;
1663*c85f09ccSJohn Levon 	if (false_nesting || cond != 1)
16641f5207b7SJohn Levon 		false_nesting++;
16651f5207b7SJohn Levon 	return 0;
16661f5207b7SJohn Levon }
16671f5207b7SJohn Levon 
16681f5207b7SJohn Levon static int handle_ifdef(struct stream *stream, struct token **line, struct token *token)
16691f5207b7SJohn Levon {
16701f5207b7SJohn Levon 	struct token *next = token->next;
16711f5207b7SJohn Levon 	int arg;
16721f5207b7SJohn Levon 	if (token_type(next) == TOKEN_IDENT) {
16731f5207b7SJohn Levon 		arg = token_defined(next);
16741f5207b7SJohn Levon 	} else {
16751f5207b7SJohn Levon 		dirty_stream(stream);
16761f5207b7SJohn Levon 		if (!false_nesting)
16771f5207b7SJohn Levon 			sparse_error(token->pos, "expected preprocessor identifier");
16781f5207b7SJohn Levon 		arg = -1;
16791f5207b7SJohn Levon 	}
16801f5207b7SJohn Levon 	return preprocessor_if(stream, token, arg);
16811f5207b7SJohn Levon }
16821f5207b7SJohn Levon 
16831f5207b7SJohn Levon static int handle_ifndef(struct stream *stream, struct token **line, struct token *token)
16841f5207b7SJohn Levon {
16851f5207b7SJohn Levon 	struct token *next = token->next;
16861f5207b7SJohn Levon 	int arg;
16871f5207b7SJohn Levon 	if (token_type(next) == TOKEN_IDENT) {
16881f5207b7SJohn Levon 		if (!stream->dirty && !stream->ifndef) {
16891f5207b7SJohn Levon 			if (!stream->protect) {
16901f5207b7SJohn Levon 				stream->ifndef = token;
16911f5207b7SJohn Levon 				stream->protect = next->ident;
16921f5207b7SJohn Levon 			} else if (stream->protect == next->ident) {
16931f5207b7SJohn Levon 				stream->ifndef = token;
16941f5207b7SJohn Levon 				stream->dirty = 1;
16951f5207b7SJohn Levon 			}
16961f5207b7SJohn Levon 		}
16971f5207b7SJohn Levon 		arg = !token_defined(next);
16981f5207b7SJohn Levon 	} else {
16991f5207b7SJohn Levon 		dirty_stream(stream);
17001f5207b7SJohn Levon 		if (!false_nesting)
17011f5207b7SJohn Levon 			sparse_error(token->pos, "expected preprocessor identifier");
17021f5207b7SJohn Levon 		arg = -1;
17031f5207b7SJohn Levon 	}
17041f5207b7SJohn Levon 
17051f5207b7SJohn Levon 	return preprocessor_if(stream, token, arg);
17061f5207b7SJohn Levon }
17071f5207b7SJohn Levon 
17081f5207b7SJohn Levon static const char *show_token_sequence(struct token *token, int quote);
17091f5207b7SJohn Levon 
17101f5207b7SJohn Levon /*
17111f5207b7SJohn Levon  * Expression handling for #if and #elif; it differs from normal expansion
17121f5207b7SJohn Levon  * due to special treatment of "defined".
17131f5207b7SJohn Levon  */
17141f5207b7SJohn Levon static int expression_value(struct token **where)
17151f5207b7SJohn Levon {
17161f5207b7SJohn Levon 	struct expression *expr;
17171f5207b7SJohn Levon 	struct token *p;
17181f5207b7SJohn Levon 	struct token **list = where, **beginning = NULL;
17191f5207b7SJohn Levon 	long long value;
17201f5207b7SJohn Levon 	int state = 0;
17211f5207b7SJohn Levon 
17221f5207b7SJohn Levon 	while (!eof_token(p = scan_next(list))) {
17231f5207b7SJohn Levon 		switch (state) {
17241f5207b7SJohn Levon 		case 0:
17251f5207b7SJohn Levon 			if (token_type(p) != TOKEN_IDENT)
17261f5207b7SJohn Levon 				break;
17271f5207b7SJohn Levon 			if (p->ident == &defined_ident) {
17281f5207b7SJohn Levon 				state = 1;
17291f5207b7SJohn Levon 				beginning = list;
17301f5207b7SJohn Levon 				break;
1731*c85f09ccSJohn Levon 			} else if (p->ident == &__has_builtin_ident) {
1732*c85f09ccSJohn Levon 				state = 4;
1733*c85f09ccSJohn Levon 				beginning = list;
1734*c85f09ccSJohn Levon 				break;
1735*c85f09ccSJohn Levon 			} else if (p->ident == &__has_attribute_ident) {
1736*c85f09ccSJohn Levon 				state = 6;
1737*c85f09ccSJohn Levon 				beginning = list;
1738*c85f09ccSJohn Levon 				break;
17391f5207b7SJohn Levon 			}
17401f5207b7SJohn Levon 			if (!expand_one_symbol(list))
17411f5207b7SJohn Levon 				continue;
17421f5207b7SJohn Levon 			if (token_type(p) != TOKEN_IDENT)
17431f5207b7SJohn Levon 				break;
17441f5207b7SJohn Levon 			token_type(p) = TOKEN_ZERO_IDENT;
17451f5207b7SJohn Levon 			break;
17461f5207b7SJohn Levon 		case 1:
17471f5207b7SJohn Levon 			if (match_op(p, '(')) {
17481f5207b7SJohn Levon 				state = 2;
17491f5207b7SJohn Levon 			} else {
17501f5207b7SJohn Levon 				state = 0;
17511f5207b7SJohn Levon 				replace_with_defined(p);
17521f5207b7SJohn Levon 				*beginning = p;
17531f5207b7SJohn Levon 			}
17541f5207b7SJohn Levon 			break;
17551f5207b7SJohn Levon 		case 2:
17561f5207b7SJohn Levon 			if (token_type(p) == TOKEN_IDENT)
17571f5207b7SJohn Levon 				state = 3;
17581f5207b7SJohn Levon 			else
17591f5207b7SJohn Levon 				state = 0;
17601f5207b7SJohn Levon 			replace_with_defined(p);
17611f5207b7SJohn Levon 			*beginning = p;
17621f5207b7SJohn Levon 			break;
17631f5207b7SJohn Levon 		case 3:
17641f5207b7SJohn Levon 			state = 0;
17651f5207b7SJohn Levon 			if (!match_op(p, ')'))
17661f5207b7SJohn Levon 				sparse_error(p->pos, "missing ')' after \"defined\"");
17671f5207b7SJohn Levon 			*list = p->next;
17681f5207b7SJohn Levon 			continue;
1769*c85f09ccSJohn Levon 
1770*c85f09ccSJohn Levon 		// __has_builtin(x) or __has_attribute(x)
1771*c85f09ccSJohn Levon 		case 4: case 6:
1772*c85f09ccSJohn Levon 			if (match_op(p, '(')) {
1773*c85f09ccSJohn Levon 				state++;
1774*c85f09ccSJohn Levon 			} else {
1775*c85f09ccSJohn Levon 				sparse_error(p->pos, "missing '(' after \"__has_%s\"",
1776*c85f09ccSJohn Levon 					state == 4 ? "builtin" : "attribute");
1777*c85f09ccSJohn Levon 				state = 0;
1778*c85f09ccSJohn Levon 			}
1779*c85f09ccSJohn Levon 			*beginning = p;
1780*c85f09ccSJohn Levon 			break;
1781*c85f09ccSJohn Levon 		case 5: case 7:
1782*c85f09ccSJohn Levon 			if (token_type(p) != TOKEN_IDENT) {
1783*c85f09ccSJohn Levon 				sparse_error(p->pos, "identifier expected");
1784*c85f09ccSJohn Levon 				state = 0;
1785*c85f09ccSJohn Levon 				break;
1786*c85f09ccSJohn Levon 			}
1787*c85f09ccSJohn Levon 			if (!match_op(p->next, ')'))
1788*c85f09ccSJohn Levon 				sparse_error(p->pos, "missing ')' after \"__has_%s\"",
1789*c85f09ccSJohn Levon 					state == 5 ? "builtin" : "attribute");
1790*c85f09ccSJohn Levon 			if (state == 5)
1791*c85f09ccSJohn Levon 				replace_with_has_builtin(p);
1792*c85f09ccSJohn Levon 			else
1793*c85f09ccSJohn Levon 				replace_with_has_attribute(p);
1794*c85f09ccSJohn Levon 			state = 8;
1795*c85f09ccSJohn Levon 			*beginning = p;
1796*c85f09ccSJohn Levon 			break;
1797*c85f09ccSJohn Levon 		case 8:
1798*c85f09ccSJohn Levon 			state = 0;
1799*c85f09ccSJohn Levon 			*list = p->next;
1800*c85f09ccSJohn Levon 			continue;
18011f5207b7SJohn Levon 		}
18021f5207b7SJohn Levon 		list = &p->next;
18031f5207b7SJohn Levon 	}
18041f5207b7SJohn Levon 
18051f5207b7SJohn Levon 	p = constant_expression(*where, &expr);
18061f5207b7SJohn Levon 	if (!eof_token(p))
18071f5207b7SJohn Levon 		sparse_error(p->pos, "garbage at end: %s", show_token_sequence(p, 0));
18081f5207b7SJohn Levon 	value = get_expression_value(expr);
18091f5207b7SJohn Levon 	return value != 0;
18101f5207b7SJohn Levon }
18111f5207b7SJohn Levon 
18121f5207b7SJohn Levon static int handle_if(struct stream *stream, struct token **line, struct token *token)
18131f5207b7SJohn Levon {
18141f5207b7SJohn Levon 	int value = 0;
18151f5207b7SJohn Levon 	if (!false_nesting)
18161f5207b7SJohn Levon 		value = expression_value(&token->next);
18171f5207b7SJohn Levon 
18181f5207b7SJohn Levon 	dirty_stream(stream);
18191f5207b7SJohn Levon 	return preprocessor_if(stream, token, value);
18201f5207b7SJohn Levon }
18211f5207b7SJohn Levon 
18221f5207b7SJohn Levon static int handle_elif(struct stream * stream, struct token **line, struct token *token)
18231f5207b7SJohn Levon {
18241f5207b7SJohn Levon 	struct token *top_if = stream->top_if;
18251f5207b7SJohn Levon 	end_group(stream);
18261f5207b7SJohn Levon 
18271f5207b7SJohn Levon 	if (!top_if) {
18281f5207b7SJohn Levon 		nesting_error(stream);
18291f5207b7SJohn Levon 		sparse_error(token->pos, "unmatched #elif within stream");
18301f5207b7SJohn Levon 		return 1;
18311f5207b7SJohn Levon 	}
18321f5207b7SJohn Levon 
18331f5207b7SJohn Levon 	if (token_type(top_if) == TOKEN_ELSE) {
18341f5207b7SJohn Levon 		nesting_error(stream);
18351f5207b7SJohn Levon 		sparse_error(token->pos, "#elif after #else");
18361f5207b7SJohn Levon 		if (!false_nesting)
18371f5207b7SJohn Levon 			false_nesting = 1;
18381f5207b7SJohn Levon 		return 1;
18391f5207b7SJohn Levon 	}
18401f5207b7SJohn Levon 
18411f5207b7SJohn Levon 	dirty_stream(stream);
18421f5207b7SJohn Levon 	if (token_type(top_if) != TOKEN_IF)
18431f5207b7SJohn Levon 		return 1;
18441f5207b7SJohn Levon 	if (false_nesting) {
18451f5207b7SJohn Levon 		false_nesting = 0;
18461f5207b7SJohn Levon 		if (!expression_value(&token->next))
18471f5207b7SJohn Levon 			false_nesting = 1;
18481f5207b7SJohn Levon 	} else {
18491f5207b7SJohn Levon 		false_nesting = 1;
18501f5207b7SJohn Levon 		token_type(top_if) = TOKEN_SKIP_GROUPS;
18511f5207b7SJohn Levon 	}
18521f5207b7SJohn Levon 	return 1;
18531f5207b7SJohn Levon }
18541f5207b7SJohn Levon 
18551f5207b7SJohn Levon static int handle_else(struct stream *stream, struct token **line, struct token *token)
18561f5207b7SJohn Levon {
18571f5207b7SJohn Levon 	struct token *top_if = stream->top_if;
18581f5207b7SJohn Levon 	end_group(stream);
18591f5207b7SJohn Levon 
18601f5207b7SJohn Levon 	if (!top_if) {
18611f5207b7SJohn Levon 		nesting_error(stream);
18621f5207b7SJohn Levon 		sparse_error(token->pos, "unmatched #else within stream");
18631f5207b7SJohn Levon 		return 1;
18641f5207b7SJohn Levon 	}
18651f5207b7SJohn Levon 
18661f5207b7SJohn Levon 	if (token_type(top_if) == TOKEN_ELSE) {
18671f5207b7SJohn Levon 		nesting_error(stream);
18681f5207b7SJohn Levon 		sparse_error(token->pos, "#else after #else");
18691f5207b7SJohn Levon 	}
18701f5207b7SJohn Levon 	if (false_nesting) {
18711f5207b7SJohn Levon 		if (token_type(top_if) == TOKEN_IF)
18721f5207b7SJohn Levon 			false_nesting = 0;
18731f5207b7SJohn Levon 	} else {
18741f5207b7SJohn Levon 		false_nesting = 1;
18751f5207b7SJohn Levon 	}
18761f5207b7SJohn Levon 	token_type(top_if) = TOKEN_ELSE;
18771f5207b7SJohn Levon 	return 1;
18781f5207b7SJohn Levon }
18791f5207b7SJohn Levon 
18801f5207b7SJohn Levon static int handle_endif(struct stream *stream, struct token **line, struct token *token)
18811f5207b7SJohn Levon {
18821f5207b7SJohn Levon 	struct token *top_if = stream->top_if;
18831f5207b7SJohn Levon 	end_group(stream);
18841f5207b7SJohn Levon 	if (!top_if) {
18851f5207b7SJohn Levon 		nesting_error(stream);
18861f5207b7SJohn Levon 		sparse_error(token->pos, "unmatched #endif in stream");
18871f5207b7SJohn Levon 		return 1;
18881f5207b7SJohn Levon 	}
18891f5207b7SJohn Levon 	if (false_nesting)
18901f5207b7SJohn Levon 		false_nesting--;
18911f5207b7SJohn Levon 	stream->top_if = top_if->next;
18921f5207b7SJohn Levon 	__free_token(top_if);
18931f5207b7SJohn Levon 	return 1;
18941f5207b7SJohn Levon }
18951f5207b7SJohn Levon 
18961f5207b7SJohn Levon static int handle_warning(struct stream *stream, struct token **line, struct token *token)
18971f5207b7SJohn Levon {
18981f5207b7SJohn Levon 	warning(token->pos, "%s", show_token_sequence(token->next, 0));
18991f5207b7SJohn Levon 	return 1;
19001f5207b7SJohn Levon }
19011f5207b7SJohn Levon 
19021f5207b7SJohn Levon static int handle_error(struct stream *stream, struct token **line, struct token *token)
19031f5207b7SJohn Levon {
19041f5207b7SJohn Levon 	sparse_error(token->pos, "%s", show_token_sequence(token->next, 0));
19051f5207b7SJohn Levon 	return 1;
19061f5207b7SJohn Levon }
19071f5207b7SJohn Levon 
19081f5207b7SJohn Levon static int handle_nostdinc(struct stream *stream, struct token **line, struct token *token)
19091f5207b7SJohn Levon {
19101f5207b7SJohn Levon 	/*
19111f5207b7SJohn Levon 	 * Do we have any non-system includes?
19121f5207b7SJohn Levon 	 * Clear them out if so..
19131f5207b7SJohn Levon 	 */
19141f5207b7SJohn Levon 	*sys_includepath = NULL;
19151f5207b7SJohn Levon 	return 1;
19161f5207b7SJohn Levon }
19171f5207b7SJohn Levon 
19181f5207b7SJohn Levon static inline void update_inc_ptrs(const char ***where)
19191f5207b7SJohn Levon {
19201f5207b7SJohn Levon 
19211f5207b7SJohn Levon 	if (*where <= dirafter_includepath) {
19221f5207b7SJohn Levon 		dirafter_includepath++;
19231f5207b7SJohn Levon 		/* If this was the entry that we prepend, don't
19241f5207b7SJohn Levon 		 * rise the lower entries, even if they are at
19251f5207b7SJohn Levon 		 * the same level. */
19261f5207b7SJohn Levon 		if (where == &dirafter_includepath)
19271f5207b7SJohn Levon 			return;
19281f5207b7SJohn Levon 	}
19291f5207b7SJohn Levon 	if (*where <= sys_includepath) {
19301f5207b7SJohn Levon 		sys_includepath++;
19311f5207b7SJohn Levon 		if (where == &sys_includepath)
19321f5207b7SJohn Levon 			return;
19331f5207b7SJohn Levon 	}
19341f5207b7SJohn Levon 	if (*where <= isys_includepath) {
19351f5207b7SJohn Levon 		isys_includepath++;
19361f5207b7SJohn Levon 		if (where == &isys_includepath)
19371f5207b7SJohn Levon 			return;
19381f5207b7SJohn Levon 	}
19391f5207b7SJohn Levon 
19401f5207b7SJohn Levon 	/* angle_includepath is actually never updated, since we
19411f5207b7SJohn Levon 	 * don't suppport -iquote rught now. May change some day. */
19421f5207b7SJohn Levon 	if (*where <= angle_includepath) {
19431f5207b7SJohn Levon 		angle_includepath++;
19441f5207b7SJohn Levon 		if (where == &angle_includepath)
19451f5207b7SJohn Levon 			return;
19461f5207b7SJohn Levon 	}
19471f5207b7SJohn Levon }
19481f5207b7SJohn Levon 
19491f5207b7SJohn Levon /* Add a path before 'where' and update the pointers associated with the
19501f5207b7SJohn Levon  * includepath array */
19511f5207b7SJohn Levon static void add_path_entry(struct token *token, const char *path,
19521f5207b7SJohn Levon 	const char ***where)
19531f5207b7SJohn Levon {
19541f5207b7SJohn Levon 	const char **dst;
19551f5207b7SJohn Levon 	const char *next;
19561f5207b7SJohn Levon 
19571f5207b7SJohn Levon 	/* Need one free entry.. */
19581f5207b7SJohn Levon 	if (includepath[INCLUDEPATHS-2])
19591f5207b7SJohn Levon 		error_die(token->pos, "too many include path entries");
19601f5207b7SJohn Levon 
19611f5207b7SJohn Levon 	/* check that this is not a duplicate */
19621f5207b7SJohn Levon 	dst = includepath;
19631f5207b7SJohn Levon 	while (*dst) {
19641f5207b7SJohn Levon 		if (strcmp(*dst, path) == 0)
19651f5207b7SJohn Levon 			return;
19661f5207b7SJohn Levon 		dst++;
19671f5207b7SJohn Levon 	}
19681f5207b7SJohn Levon 	next = path;
19691f5207b7SJohn Levon 	dst = *where;
19701f5207b7SJohn Levon 
19711f5207b7SJohn Levon 	update_inc_ptrs(where);
19721f5207b7SJohn Levon 
19731f5207b7SJohn Levon 	/*
19741f5207b7SJohn Levon 	 * Move them all up starting at dst,
19751f5207b7SJohn Levon 	 * insert the new entry..
19761f5207b7SJohn Levon 	 */
19771f5207b7SJohn Levon 	do {
19781f5207b7SJohn Levon 		const char *tmp = *dst;
19791f5207b7SJohn Levon 		*dst = next;
19801f5207b7SJohn Levon 		next = tmp;
19811f5207b7SJohn Levon 		dst++;
19821f5207b7SJohn Levon 	} while (next);
19831f5207b7SJohn Levon }
19841f5207b7SJohn Levon 
19851f5207b7SJohn Levon static int handle_add_include(struct stream *stream, struct token **line, struct token *token)
19861f5207b7SJohn Levon {
19871f5207b7SJohn Levon 	for (;;) {
19881f5207b7SJohn Levon 		token = token->next;
19891f5207b7SJohn Levon 		if (eof_token(token))
19901f5207b7SJohn Levon 			return 1;
19911f5207b7SJohn Levon 		if (token_type(token) != TOKEN_STRING) {
19921f5207b7SJohn Levon 			warning(token->pos, "expected path string");
19931f5207b7SJohn Levon 			return 1;
19941f5207b7SJohn Levon 		}
19951f5207b7SJohn Levon 		add_path_entry(token, token->string->data, &isys_includepath);
19961f5207b7SJohn Levon 	}
19971f5207b7SJohn Levon }
19981f5207b7SJohn Levon 
19991f5207b7SJohn Levon static int handle_add_isystem(struct stream *stream, struct token **line, struct token *token)
20001f5207b7SJohn Levon {
20011f5207b7SJohn Levon 	for (;;) {
20021f5207b7SJohn Levon 		token = token->next;
20031f5207b7SJohn Levon 		if (eof_token(token))
20041f5207b7SJohn Levon 			return 1;
20051f5207b7SJohn Levon 		if (token_type(token) != TOKEN_STRING) {
20061f5207b7SJohn Levon 			sparse_error(token->pos, "expected path string");
20071f5207b7SJohn Levon 			return 1;
20081f5207b7SJohn Levon 		}
20091f5207b7SJohn Levon 		add_path_entry(token, token->string->data, &sys_includepath);
20101f5207b7SJohn Levon 	}
20111f5207b7SJohn Levon }
20121f5207b7SJohn Levon 
20131f5207b7SJohn Levon static int handle_add_system(struct stream *stream, struct token **line, struct token *token)
20141f5207b7SJohn Levon {
20151f5207b7SJohn Levon 	for (;;) {
20161f5207b7SJohn Levon 		token = token->next;
20171f5207b7SJohn Levon 		if (eof_token(token))
20181f5207b7SJohn Levon 			return 1;
20191f5207b7SJohn Levon 		if (token_type(token) != TOKEN_STRING) {
20201f5207b7SJohn Levon 			sparse_error(token->pos, "expected path string");
20211f5207b7SJohn Levon 			return 1;
20221f5207b7SJohn Levon 		}
20231f5207b7SJohn Levon 		add_path_entry(token, token->string->data, &dirafter_includepath);
20241f5207b7SJohn Levon 	}
20251f5207b7SJohn Levon }
20261f5207b7SJohn Levon 
20271f5207b7SJohn Levon /* Add to end on includepath list - no pointer updates */
20281f5207b7SJohn Levon static void add_dirafter_entry(struct token *token, const char *path)
20291f5207b7SJohn Levon {
20301f5207b7SJohn Levon 	const char **dst = includepath;
20311f5207b7SJohn Levon 
20321f5207b7SJohn Levon 	/* Need one free entry.. */
20331f5207b7SJohn Levon 	if (includepath[INCLUDEPATHS-2])
20341f5207b7SJohn Levon 		error_die(token->pos, "too many include path entries");
20351f5207b7SJohn Levon 
20361f5207b7SJohn Levon 	/* Add to the end */
20371f5207b7SJohn Levon 	while (*dst)
20381f5207b7SJohn Levon 		dst++;
20391f5207b7SJohn Levon 	*dst = path;
20401f5207b7SJohn Levon 	dst++;
20411f5207b7SJohn Levon 	*dst = NULL;
20421f5207b7SJohn Levon }
20431f5207b7SJohn Levon 
20441f5207b7SJohn Levon static int handle_add_dirafter(struct stream *stream, struct token **line, struct token *token)
20451f5207b7SJohn Levon {
20461f5207b7SJohn Levon 	for (;;) {
20471f5207b7SJohn Levon 		token = token->next;
20481f5207b7SJohn Levon 		if (eof_token(token))
20491f5207b7SJohn Levon 			return 1;
20501f5207b7SJohn Levon 		if (token_type(token) != TOKEN_STRING) {
20511f5207b7SJohn Levon 			sparse_error(token->pos, "expected path string");
20521f5207b7SJohn Levon 			return 1;
20531f5207b7SJohn Levon 		}
20541f5207b7SJohn Levon 		add_dirafter_entry(token, token->string->data);
20551f5207b7SJohn Levon 	}
20561f5207b7SJohn Levon }
20571f5207b7SJohn Levon 
20581f5207b7SJohn Levon static int handle_split_include(struct stream *stream, struct token **line, struct token *token)
20591f5207b7SJohn Levon {
20601f5207b7SJohn Levon 	/*
20611f5207b7SJohn Levon 	 * -I-
20621f5207b7SJohn Levon 	 *  From info gcc:
20631f5207b7SJohn Levon 	 *  Split the include path.  Any directories specified with `-I'
20641f5207b7SJohn Levon 	 *  options before `-I-' are searched only for headers requested with
20651f5207b7SJohn Levon 	 *  `#include "FILE"'; they are not searched for `#include <FILE>'.
20661f5207b7SJohn Levon 	 *  If additional directories are specified with `-I' options after
20671f5207b7SJohn Levon 	 *  the `-I-', those directories are searched for all `#include'
20681f5207b7SJohn Levon 	 *  directives.
20691f5207b7SJohn Levon 	 *  In addition, `-I-' inhibits the use of the directory of the current
20701f5207b7SJohn Levon 	 *  file directory as the first search directory for `#include "FILE"'.
20711f5207b7SJohn Levon 	 */
20721f5207b7SJohn Levon 	quote_includepath = includepath+1;
20731f5207b7SJohn Levon 	angle_includepath = sys_includepath;
20741f5207b7SJohn Levon 	return 1;
20751f5207b7SJohn Levon }
20761f5207b7SJohn Levon 
20771f5207b7SJohn Levon /*
20781f5207b7SJohn Levon  * We replace "#pragma xxx" with "__pragma__" in the token
20791f5207b7SJohn Levon  * stream. Just as an example.
20801f5207b7SJohn Levon  *
20811f5207b7SJohn Levon  * We'll just #define that away for now, but the theory here
20821f5207b7SJohn Levon  * is that we can use this to insert arbitrary token sequences
20831f5207b7SJohn Levon  * to turn the pragmas into internal front-end sequences for
20841f5207b7SJohn Levon  * when we actually start caring about them.
20851f5207b7SJohn Levon  *
20861f5207b7SJohn Levon  * So eventually this will turn into some kind of extended
20871f5207b7SJohn Levon  * __attribute__() like thing, except called __pragma__(xxx).
20881f5207b7SJohn Levon  */
20891f5207b7SJohn Levon static int handle_pragma(struct stream *stream, struct token **line, struct token *token)
20901f5207b7SJohn Levon {
20911f5207b7SJohn Levon 	struct token *next = *line;
20921f5207b7SJohn Levon 
20931f5207b7SJohn Levon 	if (match_ident(token->next, &once_ident) && eof_token(token->next->next)) {
20941f5207b7SJohn Levon 		stream->once = 1;
20951f5207b7SJohn Levon 		return 1;
20961f5207b7SJohn Levon 	}
20971f5207b7SJohn Levon 	token->ident = &pragma_ident;
20981f5207b7SJohn Levon 	token->pos.newline = 1;
20991f5207b7SJohn Levon 	token->pos.whitespace = 1;
21001f5207b7SJohn Levon 	token->pos.pos = 1;
21011f5207b7SJohn Levon 	*line = token;
21021f5207b7SJohn Levon 	token->next = next;
21031f5207b7SJohn Levon 	return 0;
21041f5207b7SJohn Levon }
21051f5207b7SJohn Levon 
21061f5207b7SJohn Levon /*
21071f5207b7SJohn Levon  * We ignore #line for now.
21081f5207b7SJohn Levon  */
21091f5207b7SJohn Levon static int handle_line(struct stream *stream, struct token **line, struct token *token)
21101f5207b7SJohn Levon {
21111f5207b7SJohn Levon 	return 1;
21121f5207b7SJohn Levon }
21131f5207b7SJohn Levon 
21141f5207b7SJohn Levon static int handle_ident(struct stream *stream, struct token **line, struct token *token)
21151f5207b7SJohn Levon {
21161f5207b7SJohn Levon 	return 1;
21171f5207b7SJohn Levon }
21181f5207b7SJohn Levon 
21191f5207b7SJohn Levon static int handle_nondirective(struct stream *stream, struct token **line, struct token *token)
21201f5207b7SJohn Levon {
21211f5207b7SJohn Levon 	sparse_error(token->pos, "unrecognized preprocessor line '%s'", show_token_sequence(token, 0));
21221f5207b7SJohn Levon 	return 1;
21231f5207b7SJohn Levon }
21241f5207b7SJohn Levon 
21251f5207b7SJohn Levon 
21261f5207b7SJohn Levon static void init_preprocessor(void)
21271f5207b7SJohn Levon {
21281f5207b7SJohn Levon 	int i;
21291f5207b7SJohn Levon 	int stream = init_stream("preprocessor", -1, includepath);
21301f5207b7SJohn Levon 	static struct {
21311f5207b7SJohn Levon 		const char *name;
21321f5207b7SJohn Levon 		int (*handler)(struct stream *, struct token **, struct token *);
21331f5207b7SJohn Levon 	} normal[] = {
21341f5207b7SJohn Levon 		{ "define",		handle_define },
21351f5207b7SJohn Levon 		{ "weak_define",	handle_weak_define },
21361f5207b7SJohn Levon 		{ "strong_define",	handle_strong_define },
21371f5207b7SJohn Levon 		{ "undef",		handle_undef },
21381f5207b7SJohn Levon 		{ "strong_undef",	handle_strong_undef },
21391f5207b7SJohn Levon 		{ "warning",		handle_warning },
21401f5207b7SJohn Levon 		{ "error",		handle_error },
21411f5207b7SJohn Levon 		{ "include",		handle_include },
21421f5207b7SJohn Levon 		{ "include_next",	handle_include_next },
21431f5207b7SJohn Levon 		{ "pragma",		handle_pragma },
21441f5207b7SJohn Levon 		{ "line",		handle_line },
21451f5207b7SJohn Levon 		{ "ident",		handle_ident },
21461f5207b7SJohn Levon 
21471f5207b7SJohn Levon 		// our internal preprocessor tokens
21481f5207b7SJohn Levon 		{ "nostdinc",	   handle_nostdinc },
21491f5207b7SJohn Levon 		{ "add_include",   handle_add_include },
21501f5207b7SJohn Levon 		{ "add_isystem",   handle_add_isystem },
21511f5207b7SJohn Levon 		{ "add_system",    handle_add_system },
21521f5207b7SJohn Levon 		{ "add_dirafter",  handle_add_dirafter },
21531f5207b7SJohn Levon 		{ "split_include", handle_split_include },
21541f5207b7SJohn Levon 		{ "argv_include",  handle_argv_include },
21551f5207b7SJohn Levon 	}, special[] = {
21561f5207b7SJohn Levon 		{ "ifdef",	handle_ifdef },
21571f5207b7SJohn Levon 		{ "ifndef",	handle_ifndef },
21581f5207b7SJohn Levon 		{ "else",	handle_else },
21591f5207b7SJohn Levon 		{ "endif",	handle_endif },
21601f5207b7SJohn Levon 		{ "if",		handle_if },
21611f5207b7SJohn Levon 		{ "elif",	handle_elif },
21621f5207b7SJohn Levon 	};
2163*c85f09ccSJohn Levon 	static struct {
2164*c85f09ccSJohn Levon 		const char *name;
2165*c85f09ccSJohn Levon 		void (*expander)(struct token *);
2166*c85f09ccSJohn Levon 	} dynamic[] = {
2167*c85f09ccSJohn Levon 		{ "__LINE__",		expand_line },
2168*c85f09ccSJohn Levon 		{ "__FILE__",		expand_file },
2169*c85f09ccSJohn Levon 		{ "__BASE_FILE__",	expand_basefile },
2170*c85f09ccSJohn Levon 		{ "__DATE__",		expand_date },
2171*c85f09ccSJohn Levon 		{ "__TIME__",		expand_time },
2172*c85f09ccSJohn Levon 		{ "__COUNTER__",	expand_counter },
2173*c85f09ccSJohn Levon 		{ "__INCLUDE_LEVEL__",	expand_include_level },
2174*c85f09ccSJohn Levon 	};
21751f5207b7SJohn Levon 
21761f5207b7SJohn Levon 	for (i = 0; i < ARRAY_SIZE(normal); i++) {
21771f5207b7SJohn Levon 		struct symbol *sym;
21781f5207b7SJohn Levon 		sym = create_symbol(stream, normal[i].name, SYM_PREPROCESSOR, NS_PREPROCESSOR);
21791f5207b7SJohn Levon 		sym->handler = normal[i].handler;
21801f5207b7SJohn Levon 		sym->normal = 1;
21811f5207b7SJohn Levon 	}
21821f5207b7SJohn Levon 	for (i = 0; i < ARRAY_SIZE(special); i++) {
21831f5207b7SJohn Levon 		struct symbol *sym;
21841f5207b7SJohn Levon 		sym = create_symbol(stream, special[i].name, SYM_PREPROCESSOR, NS_PREPROCESSOR);
21851f5207b7SJohn Levon 		sym->handler = special[i].handler;
21861f5207b7SJohn Levon 		sym->normal = 0;
21871f5207b7SJohn Levon 	}
2188*c85f09ccSJohn Levon 	for (i = 0; i < ARRAY_SIZE(dynamic); i++) {
2189*c85f09ccSJohn Levon 		struct symbol *sym;
2190*c85f09ccSJohn Levon 		sym = create_symbol(stream, dynamic[i].name, SYM_NODE, NS_MACRO);
2191*c85f09ccSJohn Levon 		sym->expander = dynamic[i].expander;
2192*c85f09ccSJohn Levon 	}
21931f5207b7SJohn Levon 
21941f5207b7SJohn Levon 	counter_macro = 0;
21951f5207b7SJohn Levon }
21961f5207b7SJohn Levon 
21971f5207b7SJohn Levon static void handle_preprocessor_line(struct stream *stream, struct token **line, struct token *start)
21981f5207b7SJohn Levon {
21991f5207b7SJohn Levon 	int (*handler)(struct stream *, struct token **, struct token *);
22001f5207b7SJohn Levon 	struct token *token = start->next;
22011f5207b7SJohn Levon 	int is_normal = 1;
22021f5207b7SJohn Levon 
22031f5207b7SJohn Levon 	if (eof_token(token))
22041f5207b7SJohn Levon 		return;
22051f5207b7SJohn Levon 
22061f5207b7SJohn Levon 	if (token_type(token) == TOKEN_IDENT) {
22071f5207b7SJohn Levon 		struct symbol *sym = lookup_symbol(token->ident, NS_PREPROCESSOR);
22081f5207b7SJohn Levon 		if (sym) {
22091f5207b7SJohn Levon 			handler = sym->handler;
22101f5207b7SJohn Levon 			is_normal = sym->normal;
22111f5207b7SJohn Levon 		} else {
22121f5207b7SJohn Levon 			handler = handle_nondirective;
22131f5207b7SJohn Levon 		}
22141f5207b7SJohn Levon 	} else if (token_type(token) == TOKEN_NUMBER) {
22151f5207b7SJohn Levon 		handler = handle_line;
22161f5207b7SJohn Levon 	} else {
22171f5207b7SJohn Levon 		handler = handle_nondirective;
22181f5207b7SJohn Levon 	}
22191f5207b7SJohn Levon 
22201f5207b7SJohn Levon 	if (is_normal) {
22211f5207b7SJohn Levon 		dirty_stream(stream);
22221f5207b7SJohn Levon 		if (false_nesting)
22231f5207b7SJohn Levon 			goto out;
22241f5207b7SJohn Levon 	}
22251f5207b7SJohn Levon 	if (!handler(stream, line, token))	/* all set */
22261f5207b7SJohn Levon 		return;
22271f5207b7SJohn Levon 
22281f5207b7SJohn Levon out:
22291f5207b7SJohn Levon 	free_preprocessor_line(token);
22301f5207b7SJohn Levon }
22311f5207b7SJohn Levon 
22321f5207b7SJohn Levon static void preprocessor_line(struct stream *stream, struct token **line)
22331f5207b7SJohn Levon {
22341f5207b7SJohn Levon 	struct token *start = *line, *next;
22351f5207b7SJohn Levon 	struct token **tp = &start->next;
22361f5207b7SJohn Levon 
22371f5207b7SJohn Levon 	for (;;) {
22381f5207b7SJohn Levon 		next = *tp;
22391f5207b7SJohn Levon 		if (next->pos.newline)
22401f5207b7SJohn Levon 			break;
22411f5207b7SJohn Levon 		tp = &next->next;
22421f5207b7SJohn Levon 	}
22431f5207b7SJohn Levon 	*line = next;
22441f5207b7SJohn Levon 	*tp = &eof_token_entry;
22451f5207b7SJohn Levon 	handle_preprocessor_line(stream, line, start);
22461f5207b7SJohn Levon }
22471f5207b7SJohn Levon 
22481f5207b7SJohn Levon static void do_preprocess(struct token **list)
22491f5207b7SJohn Levon {
22501f5207b7SJohn Levon 	struct token *next;
22511f5207b7SJohn Levon 
22521f5207b7SJohn Levon 	while (!eof_token(next = scan_next(list))) {
22531f5207b7SJohn Levon 		struct stream *stream = input_streams + next->pos.stream;
22541f5207b7SJohn Levon 
22551f5207b7SJohn Levon 		if (next->pos.newline && match_op(next, '#')) {
22561f5207b7SJohn Levon 			if (!next->pos.noexpand) {
22571f5207b7SJohn Levon 				preprocessor_line(stream, list);
22581f5207b7SJohn Levon 				__free_token(next);	/* Free the '#' token */
22591f5207b7SJohn Levon 				continue;
22601f5207b7SJohn Levon 			}
22611f5207b7SJohn Levon 		}
22621f5207b7SJohn Levon 
22631f5207b7SJohn Levon 		switch (token_type(next)) {
22641f5207b7SJohn Levon 		case TOKEN_STREAMEND:
22651f5207b7SJohn Levon 			if (stream->top_if) {
22661f5207b7SJohn Levon 				nesting_error(stream);
22671f5207b7SJohn Levon 				sparse_error(stream->top_if->pos, "unterminated preprocessor conditional");
22681f5207b7SJohn Levon 				stream->top_if = NULL;
22691f5207b7SJohn Levon 				false_nesting = 0;
22701f5207b7SJohn Levon 			}
22711f5207b7SJohn Levon 			if (!stream->dirty)
22721f5207b7SJohn Levon 				stream->constant = CONSTANT_FILE_YES;
22731f5207b7SJohn Levon 			*list = next->next;
2274*c85f09ccSJohn Levon 			include_level--;
22751f5207b7SJohn Levon 			continue;
22761f5207b7SJohn Levon 		case TOKEN_STREAMBEGIN:
22771f5207b7SJohn Levon 			*list = next->next;
2278*c85f09ccSJohn Levon 			include_level++;
22791f5207b7SJohn Levon 			continue;
22801f5207b7SJohn Levon 
22811f5207b7SJohn Levon 		default:
22821f5207b7SJohn Levon 			dirty_stream(stream);
22831f5207b7SJohn Levon 			if (false_nesting) {
22841f5207b7SJohn Levon 				*list = next->next;
22851f5207b7SJohn Levon 				__free_token(next);
22861f5207b7SJohn Levon 				continue;
22871f5207b7SJohn Levon 			}
22881f5207b7SJohn Levon 
22891f5207b7SJohn Levon 			if (token_type(next) != TOKEN_IDENT ||
22901f5207b7SJohn Levon 			    expand_one_symbol(list))
22911f5207b7SJohn Levon 				list = &next->next;
22921f5207b7SJohn Levon 		}
22931f5207b7SJohn Levon 	}
22941f5207b7SJohn Levon }
22951f5207b7SJohn Levon 
22961f5207b7SJohn Levon void init_include_path(void)
22971f5207b7SJohn Levon {
22981f5207b7SJohn Levon 	FILE *fp;
22991f5207b7SJohn Levon 	char path[256];
23001f5207b7SJohn Levon 	char arch[32];
23011f5207b7SJohn Levon 	char os[32];
23021f5207b7SJohn Levon 
23031f5207b7SJohn Levon 	fp = popen("/bin/uname -m", "r");
23041f5207b7SJohn Levon 	if (!fp)
23051f5207b7SJohn Levon 		return;
23061f5207b7SJohn Levon 	if (!fgets(arch, sizeof(arch) - 1, fp))
23071f5207b7SJohn Levon 		return;
23081f5207b7SJohn Levon 	pclose(fp);
23091f5207b7SJohn Levon 	if (arch[strlen(arch) - 1] == '\n')
23101f5207b7SJohn Levon 		arch[strlen(arch) - 1] = '\0';
23111f5207b7SJohn Levon 
23121f5207b7SJohn Levon 	fp = popen("/bin/uname -o", "r");
23131f5207b7SJohn Levon 	if (!fp)
23141f5207b7SJohn Levon 		return;
23151f5207b7SJohn Levon 	fgets(os, sizeof(os) - 1, fp);
23161f5207b7SJohn Levon 	pclose(fp);
23171f5207b7SJohn Levon 
23181f5207b7SJohn Levon 	if (strcmp(os, "GNU/Linux\n") != 0)
23191f5207b7SJohn Levon 		return;
23201f5207b7SJohn Levon 	strcpy(os, "linux-gnu");
23211f5207b7SJohn Levon 
23221f5207b7SJohn Levon 	snprintf(path, sizeof(path), "/usr/include/%s-%s/", arch, os);
23231f5207b7SJohn Levon 	add_pre_buffer("#add_system \"%s/\"\n", path);
23241f5207b7SJohn Levon }
23251f5207b7SJohn Levon 
23261f5207b7SJohn Levon struct token * preprocess(struct token *token)
23271f5207b7SJohn Levon {
23281f5207b7SJohn Levon 	preprocessing = 1;
23291f5207b7SJohn Levon 	init_preprocessor();
23301f5207b7SJohn Levon 	do_preprocess(&token);
23311f5207b7SJohn Levon 
23321f5207b7SJohn Levon 	// Drop all expressions from preprocessing, they're not used any more.
23331f5207b7SJohn Levon 	// This is not true when we have multiple files, though ;/
23341f5207b7SJohn Levon 	// clear_expression_alloc();
23351f5207b7SJohn Levon 	preprocessing = 0;
23361f5207b7SJohn Levon 
23371f5207b7SJohn Levon 	return token;
23381f5207b7SJohn Levon }
23391f5207b7SJohn Levon 
2340*c85f09ccSJohn Levon static int is_VA_ARGS_token(struct token *token)
2341*c85f09ccSJohn Levon {
2342*c85f09ccSJohn Levon 	return (token_type(token) == TOKEN_IDENT) &&
2343*c85f09ccSJohn Levon 		(token->ident == &__VA_ARGS___ident);
2344*c85f09ccSJohn Levon }
2345*c85f09ccSJohn Levon 
23461f5207b7SJohn Levon static void dump_macro(struct symbol *sym)
23471f5207b7SJohn Levon {
23481f5207b7SJohn Levon 	int nargs = sym->arglist ? sym->arglist->count.normal : 0;
23491f5207b7SJohn Levon 	struct token *args[nargs];
23501f5207b7SJohn Levon 	struct token *token;
23511f5207b7SJohn Levon 
23521f5207b7SJohn Levon 	printf("#define %s", show_ident(sym->ident));
23531f5207b7SJohn Levon 	token = sym->arglist;
23541f5207b7SJohn Levon 	if (token) {
23551f5207b7SJohn Levon 		const char *sep = "";
23561f5207b7SJohn Levon 		int narg = 0;
23571f5207b7SJohn Levon 		putchar('(');
23581f5207b7SJohn Levon 		for (; !eof_token(token); token = token->next) {
23591f5207b7SJohn Levon 			if (token_type(token) == TOKEN_ARG_COUNT)
23601f5207b7SJohn Levon 				continue;
2361*c85f09ccSJohn Levon 			if (is_VA_ARGS_token(token))
2362*c85f09ccSJohn Levon 				printf("%s...", sep);
2363*c85f09ccSJohn Levon 			else
2364*c85f09ccSJohn Levon 				printf("%s%s", sep, show_token(token));
23651f5207b7SJohn Levon 			args[narg++] = token;
2366*c85f09ccSJohn Levon 			sep = ",";
23671f5207b7SJohn Levon 		}
23681f5207b7SJohn Levon 		putchar(')');
23691f5207b7SJohn Levon 	}
23701f5207b7SJohn Levon 
23711f5207b7SJohn Levon 	token = sym->expansion;
2372*c85f09ccSJohn Levon 	while (token_type(token) != TOKEN_UNTAINT) {
23731f5207b7SJohn Levon 		struct token *next = token->next;
2374*c85f09ccSJohn Levon 		if (token->pos.whitespace)
2375*c85f09ccSJohn Levon 			putchar(' ');
23761f5207b7SJohn Levon 		switch (token_type(token)) {
2377*c85f09ccSJohn Levon 		case TOKEN_CONCAT:
2378*c85f09ccSJohn Levon 			printf("##");
23791f5207b7SJohn Levon 			break;
2380*c85f09ccSJohn Levon 		case TOKEN_STR_ARGUMENT:
2381*c85f09ccSJohn Levon 			printf("#");
2382*c85f09ccSJohn Levon 			/* fall-through */
2383*c85f09ccSJohn Levon 		case TOKEN_QUOTED_ARGUMENT:
23841f5207b7SJohn Levon 		case TOKEN_MACRO_ARGUMENT:
23851f5207b7SJohn Levon 			token = args[token->argnum];
23861f5207b7SJohn Levon 			/* fall-through */
23871f5207b7SJohn Levon 		default:
23881f5207b7SJohn Levon 			printf("%s", show_token(token));
23891f5207b7SJohn Levon 		}
23901f5207b7SJohn Levon 		token = next;
23911f5207b7SJohn Levon 	}
23921f5207b7SJohn Levon 	putchar('\n');
23931f5207b7SJohn Levon }
23941f5207b7SJohn Levon 
23951f5207b7SJohn Levon void dump_macro_definitions(void)
23961f5207b7SJohn Levon {
23971f5207b7SJohn Levon 	struct ident *name;
23981f5207b7SJohn Levon 
23991f5207b7SJohn Levon 	FOR_EACH_PTR(macros, name) {
24001f5207b7SJohn Levon 		struct symbol *sym = lookup_macro(name);
24011f5207b7SJohn Levon 		if (sym)
24021f5207b7SJohn Levon 			dump_macro(sym);
24031f5207b7SJohn Levon 	} END_FOR_EACH_PTR(name);
24041f5207b7SJohn Levon }
2405