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(¯os, 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