18c2ecf20Sopenharmony_ci/* 28c2ecf20Sopenharmony_ci * Copyright (c) 2002 - 2011 Tony Finch <dot@dotat.at> 38c2ecf20Sopenharmony_ci * 48c2ecf20Sopenharmony_ci * Redistribution and use in source and binary forms, with or without 58c2ecf20Sopenharmony_ci * modification, are permitted provided that the following conditions 68c2ecf20Sopenharmony_ci * are met: 78c2ecf20Sopenharmony_ci * 1. Redistributions of source code must retain the above copyright 88c2ecf20Sopenharmony_ci * notice, this list of conditions and the following disclaimer. 98c2ecf20Sopenharmony_ci * 2. Redistributions in binary form must reproduce the above copyright 108c2ecf20Sopenharmony_ci * notice, this list of conditions and the following disclaimer in the 118c2ecf20Sopenharmony_ci * documentation and/or other materials provided with the distribution. 128c2ecf20Sopenharmony_ci * 138c2ecf20Sopenharmony_ci * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 148c2ecf20Sopenharmony_ci * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 158c2ecf20Sopenharmony_ci * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 168c2ecf20Sopenharmony_ci * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 178c2ecf20Sopenharmony_ci * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 188c2ecf20Sopenharmony_ci * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 198c2ecf20Sopenharmony_ci * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 208c2ecf20Sopenharmony_ci * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 218c2ecf20Sopenharmony_ci * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 228c2ecf20Sopenharmony_ci * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 238c2ecf20Sopenharmony_ci * SUCH DAMAGE. 248c2ecf20Sopenharmony_ci */ 258c2ecf20Sopenharmony_ci 268c2ecf20Sopenharmony_ci/* 278c2ecf20Sopenharmony_ci * unifdef - remove ifdef'ed lines 288c2ecf20Sopenharmony_ci * 298c2ecf20Sopenharmony_ci * This code was derived from software contributed to Berkeley by Dave Yost. 308c2ecf20Sopenharmony_ci * It was rewritten to support ANSI C by Tony Finch. The original version 318c2ecf20Sopenharmony_ci * of unifdef carried the 4-clause BSD copyright licence. None of its code 328c2ecf20Sopenharmony_ci * remains in this version (though some of the names remain) so it now 338c2ecf20Sopenharmony_ci * carries a more liberal licence. 348c2ecf20Sopenharmony_ci * 358c2ecf20Sopenharmony_ci * Wishlist: 368c2ecf20Sopenharmony_ci * provide an option which will append the name of the 378c2ecf20Sopenharmony_ci * appropriate symbol after #else's and #endif's 388c2ecf20Sopenharmony_ci * provide an option which will check symbols after 398c2ecf20Sopenharmony_ci * #else's and #endif's to see that they match their 408c2ecf20Sopenharmony_ci * corresponding #ifdef or #ifndef 418c2ecf20Sopenharmony_ci * 428c2ecf20Sopenharmony_ci * These require better buffer handling, which would also make 438c2ecf20Sopenharmony_ci * it possible to handle all "dodgy" directives correctly. 448c2ecf20Sopenharmony_ci */ 458c2ecf20Sopenharmony_ci 468c2ecf20Sopenharmony_ci#include <sys/types.h> 478c2ecf20Sopenharmony_ci#include <sys/stat.h> 488c2ecf20Sopenharmony_ci 498c2ecf20Sopenharmony_ci#include <ctype.h> 508c2ecf20Sopenharmony_ci#include <err.h> 518c2ecf20Sopenharmony_ci#include <errno.h> 528c2ecf20Sopenharmony_ci#include <stdarg.h> 538c2ecf20Sopenharmony_ci#include <stdbool.h> 548c2ecf20Sopenharmony_ci#include <stdio.h> 558c2ecf20Sopenharmony_ci#include <stdlib.h> 568c2ecf20Sopenharmony_ci#include <string.h> 578c2ecf20Sopenharmony_ci#include <unistd.h> 588c2ecf20Sopenharmony_ci 598c2ecf20Sopenharmony_ciconst char copyright[] = 608c2ecf20Sopenharmony_ci "@(#) $Version: unifdef-2.5 $\n" 618c2ecf20Sopenharmony_ci "@(#) $Author: Tony Finch (dot@dotat.at) $\n" 628c2ecf20Sopenharmony_ci "@(#) $URL: http://dotat.at/prog/unifdef $\n" 638c2ecf20Sopenharmony_ci; 648c2ecf20Sopenharmony_ci 658c2ecf20Sopenharmony_ci/* types of input lines: */ 668c2ecf20Sopenharmony_citypedef enum { 678c2ecf20Sopenharmony_ci LT_TRUEI, /* a true #if with ignore flag */ 688c2ecf20Sopenharmony_ci LT_FALSEI, /* a false #if with ignore flag */ 698c2ecf20Sopenharmony_ci LT_IF, /* an unknown #if */ 708c2ecf20Sopenharmony_ci LT_TRUE, /* a true #if */ 718c2ecf20Sopenharmony_ci LT_FALSE, /* a false #if */ 728c2ecf20Sopenharmony_ci LT_ELIF, /* an unknown #elif */ 738c2ecf20Sopenharmony_ci LT_ELTRUE, /* a true #elif */ 748c2ecf20Sopenharmony_ci LT_ELFALSE, /* a false #elif */ 758c2ecf20Sopenharmony_ci LT_ELSE, /* #else */ 768c2ecf20Sopenharmony_ci LT_ENDIF, /* #endif */ 778c2ecf20Sopenharmony_ci LT_DODGY, /* flag: directive is not on one line */ 788c2ecf20Sopenharmony_ci LT_DODGY_LAST = LT_DODGY + LT_ENDIF, 798c2ecf20Sopenharmony_ci LT_PLAIN, /* ordinary line */ 808c2ecf20Sopenharmony_ci LT_EOF, /* end of file */ 818c2ecf20Sopenharmony_ci LT_ERROR, /* unevaluable #if */ 828c2ecf20Sopenharmony_ci LT_COUNT 838c2ecf20Sopenharmony_ci} Linetype; 848c2ecf20Sopenharmony_ci 858c2ecf20Sopenharmony_cistatic char const * const linetype_name[] = { 868c2ecf20Sopenharmony_ci "TRUEI", "FALSEI", "IF", "TRUE", "FALSE", 878c2ecf20Sopenharmony_ci "ELIF", "ELTRUE", "ELFALSE", "ELSE", "ENDIF", 888c2ecf20Sopenharmony_ci "DODGY TRUEI", "DODGY FALSEI", 898c2ecf20Sopenharmony_ci "DODGY IF", "DODGY TRUE", "DODGY FALSE", 908c2ecf20Sopenharmony_ci "DODGY ELIF", "DODGY ELTRUE", "DODGY ELFALSE", 918c2ecf20Sopenharmony_ci "DODGY ELSE", "DODGY ENDIF", 928c2ecf20Sopenharmony_ci "PLAIN", "EOF", "ERROR" 938c2ecf20Sopenharmony_ci}; 948c2ecf20Sopenharmony_ci 958c2ecf20Sopenharmony_ci/* state of #if processing */ 968c2ecf20Sopenharmony_citypedef enum { 978c2ecf20Sopenharmony_ci IS_OUTSIDE, 988c2ecf20Sopenharmony_ci IS_FALSE_PREFIX, /* false #if followed by false #elifs */ 998c2ecf20Sopenharmony_ci IS_TRUE_PREFIX, /* first non-false #(el)if is true */ 1008c2ecf20Sopenharmony_ci IS_PASS_MIDDLE, /* first non-false #(el)if is unknown */ 1018c2ecf20Sopenharmony_ci IS_FALSE_MIDDLE, /* a false #elif after a pass state */ 1028c2ecf20Sopenharmony_ci IS_TRUE_MIDDLE, /* a true #elif after a pass state */ 1038c2ecf20Sopenharmony_ci IS_PASS_ELSE, /* an else after a pass state */ 1048c2ecf20Sopenharmony_ci IS_FALSE_ELSE, /* an else after a true state */ 1058c2ecf20Sopenharmony_ci IS_TRUE_ELSE, /* an else after only false states */ 1068c2ecf20Sopenharmony_ci IS_FALSE_TRAILER, /* #elifs after a true are false */ 1078c2ecf20Sopenharmony_ci IS_COUNT 1088c2ecf20Sopenharmony_ci} Ifstate; 1098c2ecf20Sopenharmony_ci 1108c2ecf20Sopenharmony_cistatic char const * const ifstate_name[] = { 1118c2ecf20Sopenharmony_ci "OUTSIDE", "FALSE_PREFIX", "TRUE_PREFIX", 1128c2ecf20Sopenharmony_ci "PASS_MIDDLE", "FALSE_MIDDLE", "TRUE_MIDDLE", 1138c2ecf20Sopenharmony_ci "PASS_ELSE", "FALSE_ELSE", "TRUE_ELSE", 1148c2ecf20Sopenharmony_ci "FALSE_TRAILER" 1158c2ecf20Sopenharmony_ci}; 1168c2ecf20Sopenharmony_ci 1178c2ecf20Sopenharmony_ci/* state of comment parser */ 1188c2ecf20Sopenharmony_citypedef enum { 1198c2ecf20Sopenharmony_ci NO_COMMENT = false, /* outside a comment */ 1208c2ecf20Sopenharmony_ci C_COMMENT, /* in a comment like this one */ 1218c2ecf20Sopenharmony_ci CXX_COMMENT, /* between // and end of line */ 1228c2ecf20Sopenharmony_ci STARTING_COMMENT, /* just after slash-backslash-newline */ 1238c2ecf20Sopenharmony_ci FINISHING_COMMENT, /* star-backslash-newline in a C comment */ 1248c2ecf20Sopenharmony_ci CHAR_LITERAL, /* inside '' */ 1258c2ecf20Sopenharmony_ci STRING_LITERAL /* inside "" */ 1268c2ecf20Sopenharmony_ci} Comment_state; 1278c2ecf20Sopenharmony_ci 1288c2ecf20Sopenharmony_cistatic char const * const comment_name[] = { 1298c2ecf20Sopenharmony_ci "NO", "C", "CXX", "STARTING", "FINISHING", "CHAR", "STRING" 1308c2ecf20Sopenharmony_ci}; 1318c2ecf20Sopenharmony_ci 1328c2ecf20Sopenharmony_ci/* state of preprocessor line parser */ 1338c2ecf20Sopenharmony_citypedef enum { 1348c2ecf20Sopenharmony_ci LS_START, /* only space and comments on this line */ 1358c2ecf20Sopenharmony_ci LS_HASH, /* only space, comments, and a hash */ 1368c2ecf20Sopenharmony_ci LS_DIRTY /* this line can't be a preprocessor line */ 1378c2ecf20Sopenharmony_ci} Line_state; 1388c2ecf20Sopenharmony_ci 1398c2ecf20Sopenharmony_cistatic char const * const linestate_name[] = { 1408c2ecf20Sopenharmony_ci "START", "HASH", "DIRTY" 1418c2ecf20Sopenharmony_ci}; 1428c2ecf20Sopenharmony_ci 1438c2ecf20Sopenharmony_ci/* 1448c2ecf20Sopenharmony_ci * Minimum translation limits from ISO/IEC 9899:1999 5.2.4.1 1458c2ecf20Sopenharmony_ci */ 1468c2ecf20Sopenharmony_ci#define MAXDEPTH 64 /* maximum #if nesting */ 1478c2ecf20Sopenharmony_ci#define MAXLINE 4096 /* maximum length of line */ 1488c2ecf20Sopenharmony_ci#define MAXSYMS 4096 /* maximum number of symbols */ 1498c2ecf20Sopenharmony_ci 1508c2ecf20Sopenharmony_ci/* 1518c2ecf20Sopenharmony_ci * Sometimes when editing a keyword the replacement text is longer, so 1528c2ecf20Sopenharmony_ci * we leave some space at the end of the tline buffer to accommodate this. 1538c2ecf20Sopenharmony_ci */ 1548c2ecf20Sopenharmony_ci#define EDITSLOP 10 1558c2ecf20Sopenharmony_ci 1568c2ecf20Sopenharmony_ci/* 1578c2ecf20Sopenharmony_ci * For temporary filenames 1588c2ecf20Sopenharmony_ci */ 1598c2ecf20Sopenharmony_ci#define TEMPLATE "unifdef.XXXXXX" 1608c2ecf20Sopenharmony_ci 1618c2ecf20Sopenharmony_ci/* 1628c2ecf20Sopenharmony_ci * Globals. 1638c2ecf20Sopenharmony_ci */ 1648c2ecf20Sopenharmony_ci 1658c2ecf20Sopenharmony_cistatic bool compblank; /* -B: compress blank lines */ 1668c2ecf20Sopenharmony_cistatic bool lnblank; /* -b: blank deleted lines */ 1678c2ecf20Sopenharmony_cistatic bool complement; /* -c: do the complement */ 1688c2ecf20Sopenharmony_cistatic bool debugging; /* -d: debugging reports */ 1698c2ecf20Sopenharmony_cistatic bool iocccok; /* -e: fewer IOCCC errors */ 1708c2ecf20Sopenharmony_cistatic bool strictlogic; /* -K: keep ambiguous #ifs */ 1718c2ecf20Sopenharmony_cistatic bool killconsts; /* -k: eval constant #ifs */ 1728c2ecf20Sopenharmony_cistatic bool lnnum; /* -n: add #line directives */ 1738c2ecf20Sopenharmony_cistatic bool symlist; /* -s: output symbol list */ 1748c2ecf20Sopenharmony_cistatic bool symdepth; /* -S: output symbol depth */ 1758c2ecf20Sopenharmony_cistatic bool text; /* -t: this is a text file */ 1768c2ecf20Sopenharmony_ci 1778c2ecf20Sopenharmony_cistatic const char *symname[MAXSYMS]; /* symbol name */ 1788c2ecf20Sopenharmony_cistatic const char *value[MAXSYMS]; /* -Dsym=value */ 1798c2ecf20Sopenharmony_cistatic bool ignore[MAXSYMS]; /* -iDsym or -iUsym */ 1808c2ecf20Sopenharmony_cistatic int nsyms; /* number of symbols */ 1818c2ecf20Sopenharmony_ci 1828c2ecf20Sopenharmony_cistatic FILE *input; /* input file pointer */ 1838c2ecf20Sopenharmony_cistatic const char *filename; /* input file name */ 1848c2ecf20Sopenharmony_cistatic int linenum; /* current line number */ 1858c2ecf20Sopenharmony_cistatic FILE *output; /* output file pointer */ 1868c2ecf20Sopenharmony_cistatic const char *ofilename; /* output file name */ 1878c2ecf20Sopenharmony_cistatic bool overwriting; /* output overwrites input */ 1888c2ecf20Sopenharmony_cistatic char tempname[FILENAME_MAX]; /* used when overwriting */ 1898c2ecf20Sopenharmony_ci 1908c2ecf20Sopenharmony_cistatic char tline[MAXLINE+EDITSLOP];/* input buffer plus space */ 1918c2ecf20Sopenharmony_cistatic char *keyword; /* used for editing #elif's */ 1928c2ecf20Sopenharmony_ci 1938c2ecf20Sopenharmony_cistatic const char *newline; /* input file format */ 1948c2ecf20Sopenharmony_cistatic const char newline_unix[] = "\n"; 1958c2ecf20Sopenharmony_cistatic const char newline_crlf[] = "\r\n"; 1968c2ecf20Sopenharmony_ci 1978c2ecf20Sopenharmony_cistatic Comment_state incomment; /* comment parser state */ 1988c2ecf20Sopenharmony_cistatic Line_state linestate; /* #if line parser state */ 1998c2ecf20Sopenharmony_cistatic Ifstate ifstate[MAXDEPTH]; /* #if processor state */ 2008c2ecf20Sopenharmony_cistatic bool ignoring[MAXDEPTH]; /* ignore comments state */ 2018c2ecf20Sopenharmony_cistatic int stifline[MAXDEPTH]; /* start of current #if */ 2028c2ecf20Sopenharmony_cistatic int depth; /* current #if nesting */ 2038c2ecf20Sopenharmony_cistatic int delcount; /* count of deleted lines */ 2048c2ecf20Sopenharmony_cistatic unsigned blankcount; /* count of blank lines */ 2058c2ecf20Sopenharmony_cistatic unsigned blankmax; /* maximum recent blankcount */ 2068c2ecf20Sopenharmony_cistatic bool constexpr; /* constant #if expression */ 2078c2ecf20Sopenharmony_cistatic bool zerosyms = true; /* to format symdepth output */ 2088c2ecf20Sopenharmony_cistatic bool firstsym; /* ditto */ 2098c2ecf20Sopenharmony_ci 2108c2ecf20Sopenharmony_cistatic int exitstat; /* program exit status */ 2118c2ecf20Sopenharmony_ci 2128c2ecf20Sopenharmony_cistatic void addsym(bool, bool, char *); 2138c2ecf20Sopenharmony_cistatic void closeout(void); 2148c2ecf20Sopenharmony_cistatic void debug(const char *, ...); 2158c2ecf20Sopenharmony_cistatic void done(void); 2168c2ecf20Sopenharmony_cistatic void error(const char *); 2178c2ecf20Sopenharmony_cistatic int findsym(const char *); 2188c2ecf20Sopenharmony_cistatic void flushline(bool); 2198c2ecf20Sopenharmony_cistatic Linetype parseline(void); 2208c2ecf20Sopenharmony_cistatic Linetype ifeval(const char **); 2218c2ecf20Sopenharmony_cistatic void ignoreoff(void); 2228c2ecf20Sopenharmony_cistatic void ignoreon(void); 2238c2ecf20Sopenharmony_cistatic void keywordedit(const char *); 2248c2ecf20Sopenharmony_cistatic void nest(void); 2258c2ecf20Sopenharmony_cistatic void process(void); 2268c2ecf20Sopenharmony_cistatic const char *skipargs(const char *); 2278c2ecf20Sopenharmony_cistatic const char *skipcomment(const char *); 2288c2ecf20Sopenharmony_cistatic const char *skipsym(const char *); 2298c2ecf20Sopenharmony_cistatic void state(Ifstate); 2308c2ecf20Sopenharmony_cistatic int strlcmp(const char *, const char *, size_t); 2318c2ecf20Sopenharmony_cistatic void unnest(void); 2328c2ecf20Sopenharmony_cistatic void usage(void); 2338c2ecf20Sopenharmony_cistatic void version(void); 2348c2ecf20Sopenharmony_ci 2358c2ecf20Sopenharmony_ci#define endsym(c) (!isalnum((unsigned char)c) && c != '_') 2368c2ecf20Sopenharmony_ci 2378c2ecf20Sopenharmony_ci/* 2388c2ecf20Sopenharmony_ci * The main program. 2398c2ecf20Sopenharmony_ci */ 2408c2ecf20Sopenharmony_ciint 2418c2ecf20Sopenharmony_cimain(int argc, char *argv[]) 2428c2ecf20Sopenharmony_ci{ 2438c2ecf20Sopenharmony_ci int opt; 2448c2ecf20Sopenharmony_ci 2458c2ecf20Sopenharmony_ci while ((opt = getopt(argc, argv, "i:D:U:I:o:bBcdeKklnsStV")) != -1) 2468c2ecf20Sopenharmony_ci switch (opt) { 2478c2ecf20Sopenharmony_ci case 'i': /* treat stuff controlled by these symbols as text */ 2488c2ecf20Sopenharmony_ci /* 2498c2ecf20Sopenharmony_ci * For strict backwards-compatibility the U or D 2508c2ecf20Sopenharmony_ci * should be immediately after the -i but it doesn't 2518c2ecf20Sopenharmony_ci * matter much if we relax that requirement. 2528c2ecf20Sopenharmony_ci */ 2538c2ecf20Sopenharmony_ci opt = *optarg++; 2548c2ecf20Sopenharmony_ci if (opt == 'D') 2558c2ecf20Sopenharmony_ci addsym(true, true, optarg); 2568c2ecf20Sopenharmony_ci else if (opt == 'U') 2578c2ecf20Sopenharmony_ci addsym(true, false, optarg); 2588c2ecf20Sopenharmony_ci else 2598c2ecf20Sopenharmony_ci usage(); 2608c2ecf20Sopenharmony_ci break; 2618c2ecf20Sopenharmony_ci case 'D': /* define a symbol */ 2628c2ecf20Sopenharmony_ci addsym(false, true, optarg); 2638c2ecf20Sopenharmony_ci break; 2648c2ecf20Sopenharmony_ci case 'U': /* undef a symbol */ 2658c2ecf20Sopenharmony_ci addsym(false, false, optarg); 2668c2ecf20Sopenharmony_ci break; 2678c2ecf20Sopenharmony_ci case 'I': /* no-op for compatibility with cpp */ 2688c2ecf20Sopenharmony_ci break; 2698c2ecf20Sopenharmony_ci case 'b': /* blank deleted lines instead of omitting them */ 2708c2ecf20Sopenharmony_ci case 'l': /* backwards compatibility */ 2718c2ecf20Sopenharmony_ci lnblank = true; 2728c2ecf20Sopenharmony_ci break; 2738c2ecf20Sopenharmony_ci case 'B': /* compress blank lines around removed section */ 2748c2ecf20Sopenharmony_ci compblank = true; 2758c2ecf20Sopenharmony_ci break; 2768c2ecf20Sopenharmony_ci case 'c': /* treat -D as -U and vice versa */ 2778c2ecf20Sopenharmony_ci complement = true; 2788c2ecf20Sopenharmony_ci break; 2798c2ecf20Sopenharmony_ci case 'd': 2808c2ecf20Sopenharmony_ci debugging = true; 2818c2ecf20Sopenharmony_ci break; 2828c2ecf20Sopenharmony_ci case 'e': /* fewer errors from dodgy lines */ 2838c2ecf20Sopenharmony_ci iocccok = true; 2848c2ecf20Sopenharmony_ci break; 2858c2ecf20Sopenharmony_ci case 'K': /* keep ambiguous #ifs */ 2868c2ecf20Sopenharmony_ci strictlogic = true; 2878c2ecf20Sopenharmony_ci break; 2888c2ecf20Sopenharmony_ci case 'k': /* process constant #ifs */ 2898c2ecf20Sopenharmony_ci killconsts = true; 2908c2ecf20Sopenharmony_ci break; 2918c2ecf20Sopenharmony_ci case 'n': /* add #line directive after deleted lines */ 2928c2ecf20Sopenharmony_ci lnnum = true; 2938c2ecf20Sopenharmony_ci break; 2948c2ecf20Sopenharmony_ci case 'o': /* output to a file */ 2958c2ecf20Sopenharmony_ci ofilename = optarg; 2968c2ecf20Sopenharmony_ci break; 2978c2ecf20Sopenharmony_ci case 's': /* only output list of symbols that control #ifs */ 2988c2ecf20Sopenharmony_ci symlist = true; 2998c2ecf20Sopenharmony_ci break; 3008c2ecf20Sopenharmony_ci case 'S': /* list symbols with their nesting depth */ 3018c2ecf20Sopenharmony_ci symlist = symdepth = true; 3028c2ecf20Sopenharmony_ci break; 3038c2ecf20Sopenharmony_ci case 't': /* don't parse C comments */ 3048c2ecf20Sopenharmony_ci text = true; 3058c2ecf20Sopenharmony_ci break; 3068c2ecf20Sopenharmony_ci case 'V': /* print version */ 3078c2ecf20Sopenharmony_ci version(); 3088c2ecf20Sopenharmony_ci default: 3098c2ecf20Sopenharmony_ci usage(); 3108c2ecf20Sopenharmony_ci } 3118c2ecf20Sopenharmony_ci argc -= optind; 3128c2ecf20Sopenharmony_ci argv += optind; 3138c2ecf20Sopenharmony_ci if (compblank && lnblank) 3148c2ecf20Sopenharmony_ci errx(2, "-B and -b are mutually exclusive"); 3158c2ecf20Sopenharmony_ci if (argc > 1) { 3168c2ecf20Sopenharmony_ci errx(2, "can only do one file"); 3178c2ecf20Sopenharmony_ci } else if (argc == 1 && strcmp(*argv, "-") != 0) { 3188c2ecf20Sopenharmony_ci filename = *argv; 3198c2ecf20Sopenharmony_ci input = fopen(filename, "rb"); 3208c2ecf20Sopenharmony_ci if (input == NULL) 3218c2ecf20Sopenharmony_ci err(2, "can't open %s", filename); 3228c2ecf20Sopenharmony_ci } else { 3238c2ecf20Sopenharmony_ci filename = "[stdin]"; 3248c2ecf20Sopenharmony_ci input = stdin; 3258c2ecf20Sopenharmony_ci } 3268c2ecf20Sopenharmony_ci if (ofilename == NULL) { 3278c2ecf20Sopenharmony_ci ofilename = "[stdout]"; 3288c2ecf20Sopenharmony_ci output = stdout; 3298c2ecf20Sopenharmony_ci } else { 3308c2ecf20Sopenharmony_ci struct stat ist, ost; 3318c2ecf20Sopenharmony_ci if (stat(ofilename, &ost) == 0 && 3328c2ecf20Sopenharmony_ci fstat(fileno(input), &ist) == 0) 3338c2ecf20Sopenharmony_ci overwriting = (ist.st_dev == ost.st_dev 3348c2ecf20Sopenharmony_ci && ist.st_ino == ost.st_ino); 3358c2ecf20Sopenharmony_ci if (overwriting) { 3368c2ecf20Sopenharmony_ci const char *dirsep; 3378c2ecf20Sopenharmony_ci int ofd; 3388c2ecf20Sopenharmony_ci 3398c2ecf20Sopenharmony_ci dirsep = strrchr(ofilename, '/'); 3408c2ecf20Sopenharmony_ci if (dirsep != NULL) 3418c2ecf20Sopenharmony_ci snprintf(tempname, sizeof(tempname), 3428c2ecf20Sopenharmony_ci "%.*s/" TEMPLATE, 3438c2ecf20Sopenharmony_ci (int)(dirsep - ofilename), ofilename); 3448c2ecf20Sopenharmony_ci else 3458c2ecf20Sopenharmony_ci snprintf(tempname, sizeof(tempname), 3468c2ecf20Sopenharmony_ci TEMPLATE); 3478c2ecf20Sopenharmony_ci ofd = mkstemp(tempname); 3488c2ecf20Sopenharmony_ci if (ofd != -1) 3498c2ecf20Sopenharmony_ci output = fdopen(ofd, "wb+"); 3508c2ecf20Sopenharmony_ci if (output == NULL) 3518c2ecf20Sopenharmony_ci err(2, "can't create temporary file"); 3528c2ecf20Sopenharmony_ci fchmod(ofd, ist.st_mode & (S_IRWXU|S_IRWXG|S_IRWXO)); 3538c2ecf20Sopenharmony_ci } else { 3548c2ecf20Sopenharmony_ci output = fopen(ofilename, "wb"); 3558c2ecf20Sopenharmony_ci if (output == NULL) 3568c2ecf20Sopenharmony_ci err(2, "can't open %s", ofilename); 3578c2ecf20Sopenharmony_ci } 3588c2ecf20Sopenharmony_ci } 3598c2ecf20Sopenharmony_ci process(); 3608c2ecf20Sopenharmony_ci abort(); /* bug */ 3618c2ecf20Sopenharmony_ci} 3628c2ecf20Sopenharmony_ci 3638c2ecf20Sopenharmony_cistatic void 3648c2ecf20Sopenharmony_civersion(void) 3658c2ecf20Sopenharmony_ci{ 3668c2ecf20Sopenharmony_ci const char *c = copyright; 3678c2ecf20Sopenharmony_ci for (;;) { 3688c2ecf20Sopenharmony_ci while (*++c != '$') 3698c2ecf20Sopenharmony_ci if (*c == '\0') 3708c2ecf20Sopenharmony_ci exit(0); 3718c2ecf20Sopenharmony_ci while (*++c != '$') 3728c2ecf20Sopenharmony_ci putc(*c, stderr); 3738c2ecf20Sopenharmony_ci putc('\n', stderr); 3748c2ecf20Sopenharmony_ci } 3758c2ecf20Sopenharmony_ci} 3768c2ecf20Sopenharmony_ci 3778c2ecf20Sopenharmony_cistatic void 3788c2ecf20Sopenharmony_ciusage(void) 3798c2ecf20Sopenharmony_ci{ 3808c2ecf20Sopenharmony_ci fprintf(stderr, "usage: unifdef [-bBcdeKknsStV] [-Ipath]" 3818c2ecf20Sopenharmony_ci " [-Dsym[=val]] [-Usym] [-iDsym[=val]] [-iUsym] ... [file]\n"); 3828c2ecf20Sopenharmony_ci exit(2); 3838c2ecf20Sopenharmony_ci} 3848c2ecf20Sopenharmony_ci 3858c2ecf20Sopenharmony_ci/* 3868c2ecf20Sopenharmony_ci * A state transition function alters the global #if processing state 3878c2ecf20Sopenharmony_ci * in a particular way. The table below is indexed by the current 3888c2ecf20Sopenharmony_ci * processing state and the type of the current line. 3898c2ecf20Sopenharmony_ci * 3908c2ecf20Sopenharmony_ci * Nesting is handled by keeping a stack of states; some transition 3918c2ecf20Sopenharmony_ci * functions increase or decrease the depth. They also maintain the 3928c2ecf20Sopenharmony_ci * ignore state on a stack. In some complicated cases they have to 3938c2ecf20Sopenharmony_ci * alter the preprocessor directive, as follows. 3948c2ecf20Sopenharmony_ci * 3958c2ecf20Sopenharmony_ci * When we have processed a group that starts off with a known-false 3968c2ecf20Sopenharmony_ci * #if/#elif sequence (which has therefore been deleted) followed by a 3978c2ecf20Sopenharmony_ci * #elif that we don't understand and therefore must keep, we edit the 3988c2ecf20Sopenharmony_ci * latter into a #if to keep the nesting correct. We use memcpy() to 3998c2ecf20Sopenharmony_ci * overwrite the 4 byte token "elif" with "if " without a '\0' byte. 4008c2ecf20Sopenharmony_ci * 4018c2ecf20Sopenharmony_ci * When we find a true #elif in a group, the following block will 4028c2ecf20Sopenharmony_ci * always be kept and the rest of the sequence after the next #elif or 4038c2ecf20Sopenharmony_ci * #else will be discarded. We edit the #elif into a #else and the 4048c2ecf20Sopenharmony_ci * following directive to #endif since this has the desired behaviour. 4058c2ecf20Sopenharmony_ci * 4068c2ecf20Sopenharmony_ci * "Dodgy" directives are split across multiple lines, the most common 4078c2ecf20Sopenharmony_ci * example being a multi-line comment hanging off the right of the 4088c2ecf20Sopenharmony_ci * directive. We can handle them correctly only if there is no change 4098c2ecf20Sopenharmony_ci * from printing to dropping (or vice versa) caused by that directive. 4108c2ecf20Sopenharmony_ci * If the directive is the first of a group we have a choice between 4118c2ecf20Sopenharmony_ci * failing with an error, or passing it through unchanged instead of 4128c2ecf20Sopenharmony_ci * evaluating it. The latter is not the default to avoid questions from 4138c2ecf20Sopenharmony_ci * users about unifdef unexpectedly leaving behind preprocessor directives. 4148c2ecf20Sopenharmony_ci */ 4158c2ecf20Sopenharmony_citypedef void state_fn(void); 4168c2ecf20Sopenharmony_ci 4178c2ecf20Sopenharmony_ci/* report an error */ 4188c2ecf20Sopenharmony_cistatic void Eelif (void) { error("Inappropriate #elif"); } 4198c2ecf20Sopenharmony_cistatic void Eelse (void) { error("Inappropriate #else"); } 4208c2ecf20Sopenharmony_cistatic void Eendif(void) { error("Inappropriate #endif"); } 4218c2ecf20Sopenharmony_cistatic void Eeof (void) { error("Premature EOF"); } 4228c2ecf20Sopenharmony_cistatic void Eioccc(void) { error("Obfuscated preprocessor control line"); } 4238c2ecf20Sopenharmony_ci/* plain line handling */ 4248c2ecf20Sopenharmony_cistatic void print (void) { flushline(true); } 4258c2ecf20Sopenharmony_cistatic void drop (void) { flushline(false); } 4268c2ecf20Sopenharmony_ci/* output lacks group's start line */ 4278c2ecf20Sopenharmony_cistatic void Strue (void) { drop(); ignoreoff(); state(IS_TRUE_PREFIX); } 4288c2ecf20Sopenharmony_cistatic void Sfalse(void) { drop(); ignoreoff(); state(IS_FALSE_PREFIX); } 4298c2ecf20Sopenharmony_cistatic void Selse (void) { drop(); state(IS_TRUE_ELSE); } 4308c2ecf20Sopenharmony_ci/* print/pass this block */ 4318c2ecf20Sopenharmony_cistatic void Pelif (void) { print(); ignoreoff(); state(IS_PASS_MIDDLE); } 4328c2ecf20Sopenharmony_cistatic void Pelse (void) { print(); state(IS_PASS_ELSE); } 4338c2ecf20Sopenharmony_cistatic void Pendif(void) { print(); unnest(); } 4348c2ecf20Sopenharmony_ci/* discard this block */ 4358c2ecf20Sopenharmony_cistatic void Dfalse(void) { drop(); ignoreoff(); state(IS_FALSE_TRAILER); } 4368c2ecf20Sopenharmony_cistatic void Delif (void) { drop(); ignoreoff(); state(IS_FALSE_MIDDLE); } 4378c2ecf20Sopenharmony_cistatic void Delse (void) { drop(); state(IS_FALSE_ELSE); } 4388c2ecf20Sopenharmony_cistatic void Dendif(void) { drop(); unnest(); } 4398c2ecf20Sopenharmony_ci/* first line of group */ 4408c2ecf20Sopenharmony_cistatic void Fdrop (void) { nest(); Dfalse(); } 4418c2ecf20Sopenharmony_cistatic void Fpass (void) { nest(); Pelif(); } 4428c2ecf20Sopenharmony_cistatic void Ftrue (void) { nest(); Strue(); } 4438c2ecf20Sopenharmony_cistatic void Ffalse(void) { nest(); Sfalse(); } 4448c2ecf20Sopenharmony_ci/* variable pedantry for obfuscated lines */ 4458c2ecf20Sopenharmony_cistatic void Oiffy (void) { if (!iocccok) Eioccc(); Fpass(); ignoreon(); } 4468c2ecf20Sopenharmony_cistatic void Oif (void) { if (!iocccok) Eioccc(); Fpass(); } 4478c2ecf20Sopenharmony_cistatic void Oelif (void) { if (!iocccok) Eioccc(); Pelif(); } 4488c2ecf20Sopenharmony_ci/* ignore comments in this block */ 4498c2ecf20Sopenharmony_cistatic void Idrop (void) { Fdrop(); ignoreon(); } 4508c2ecf20Sopenharmony_cistatic void Itrue (void) { Ftrue(); ignoreon(); } 4518c2ecf20Sopenharmony_cistatic void Ifalse(void) { Ffalse(); ignoreon(); } 4528c2ecf20Sopenharmony_ci/* modify this line */ 4538c2ecf20Sopenharmony_cistatic void Mpass (void) { memcpy(keyword, "if ", 4); Pelif(); } 4548c2ecf20Sopenharmony_cistatic void Mtrue (void) { keywordedit("else"); state(IS_TRUE_MIDDLE); } 4558c2ecf20Sopenharmony_cistatic void Melif (void) { keywordedit("endif"); state(IS_FALSE_TRAILER); } 4568c2ecf20Sopenharmony_cistatic void Melse (void) { keywordedit("endif"); state(IS_FALSE_ELSE); } 4578c2ecf20Sopenharmony_ci 4588c2ecf20Sopenharmony_cistatic state_fn * const trans_table[IS_COUNT][LT_COUNT] = { 4598c2ecf20Sopenharmony_ci/* IS_OUTSIDE */ 4608c2ecf20Sopenharmony_ci{ Itrue, Ifalse,Fpass, Ftrue, Ffalse,Eelif, Eelif, Eelif, Eelse, Eendif, 4618c2ecf20Sopenharmony_ci Oiffy, Oiffy, Fpass, Oif, Oif, Eelif, Eelif, Eelif, Eelse, Eendif, 4628c2ecf20Sopenharmony_ci print, done, abort }, 4638c2ecf20Sopenharmony_ci/* IS_FALSE_PREFIX */ 4648c2ecf20Sopenharmony_ci{ Idrop, Idrop, Fdrop, Fdrop, Fdrop, Mpass, Strue, Sfalse,Selse, Dendif, 4658c2ecf20Sopenharmony_ci Idrop, Idrop, Fdrop, Fdrop, Fdrop, Mpass, Eioccc,Eioccc,Eioccc,Eioccc, 4668c2ecf20Sopenharmony_ci drop, Eeof, abort }, 4678c2ecf20Sopenharmony_ci/* IS_TRUE_PREFIX */ 4688c2ecf20Sopenharmony_ci{ Itrue, Ifalse,Fpass, Ftrue, Ffalse,Dfalse,Dfalse,Dfalse,Delse, Dendif, 4698c2ecf20Sopenharmony_ci Oiffy, Oiffy, Fpass, Oif, Oif, Eioccc,Eioccc,Eioccc,Eioccc,Eioccc, 4708c2ecf20Sopenharmony_ci print, Eeof, abort }, 4718c2ecf20Sopenharmony_ci/* IS_PASS_MIDDLE */ 4728c2ecf20Sopenharmony_ci{ Itrue, Ifalse,Fpass, Ftrue, Ffalse,Pelif, Mtrue, Delif, Pelse, Pendif, 4738c2ecf20Sopenharmony_ci Oiffy, Oiffy, Fpass, Oif, Oif, Pelif, Oelif, Oelif, Pelse, Pendif, 4748c2ecf20Sopenharmony_ci print, Eeof, abort }, 4758c2ecf20Sopenharmony_ci/* IS_FALSE_MIDDLE */ 4768c2ecf20Sopenharmony_ci{ Idrop, Idrop, Fdrop, Fdrop, Fdrop, Pelif, Mtrue, Delif, Pelse, Pendif, 4778c2ecf20Sopenharmony_ci Idrop, Idrop, Fdrop, Fdrop, Fdrop, Eioccc,Eioccc,Eioccc,Eioccc,Eioccc, 4788c2ecf20Sopenharmony_ci drop, Eeof, abort }, 4798c2ecf20Sopenharmony_ci/* IS_TRUE_MIDDLE */ 4808c2ecf20Sopenharmony_ci{ Itrue, Ifalse,Fpass, Ftrue, Ffalse,Melif, Melif, Melif, Melse, Pendif, 4818c2ecf20Sopenharmony_ci Oiffy, Oiffy, Fpass, Oif, Oif, Eioccc,Eioccc,Eioccc,Eioccc,Pendif, 4828c2ecf20Sopenharmony_ci print, Eeof, abort }, 4838c2ecf20Sopenharmony_ci/* IS_PASS_ELSE */ 4848c2ecf20Sopenharmony_ci{ Itrue, Ifalse,Fpass, Ftrue, Ffalse,Eelif, Eelif, Eelif, Eelse, Pendif, 4858c2ecf20Sopenharmony_ci Oiffy, Oiffy, Fpass, Oif, Oif, Eelif, Eelif, Eelif, Eelse, Pendif, 4868c2ecf20Sopenharmony_ci print, Eeof, abort }, 4878c2ecf20Sopenharmony_ci/* IS_FALSE_ELSE */ 4888c2ecf20Sopenharmony_ci{ Idrop, Idrop, Fdrop, Fdrop, Fdrop, Eelif, Eelif, Eelif, Eelse, Dendif, 4898c2ecf20Sopenharmony_ci Idrop, Idrop, Fdrop, Fdrop, Fdrop, Eelif, Eelif, Eelif, Eelse, Eioccc, 4908c2ecf20Sopenharmony_ci drop, Eeof, abort }, 4918c2ecf20Sopenharmony_ci/* IS_TRUE_ELSE */ 4928c2ecf20Sopenharmony_ci{ Itrue, Ifalse,Fpass, Ftrue, Ffalse,Eelif, Eelif, Eelif, Eelse, Dendif, 4938c2ecf20Sopenharmony_ci Oiffy, Oiffy, Fpass, Oif, Oif, Eelif, Eelif, Eelif, Eelse, Eioccc, 4948c2ecf20Sopenharmony_ci print, Eeof, abort }, 4958c2ecf20Sopenharmony_ci/* IS_FALSE_TRAILER */ 4968c2ecf20Sopenharmony_ci{ Idrop, Idrop, Fdrop, Fdrop, Fdrop, Dfalse,Dfalse,Dfalse,Delse, Dendif, 4978c2ecf20Sopenharmony_ci Idrop, Idrop, Fdrop, Fdrop, Fdrop, Dfalse,Dfalse,Dfalse,Delse, Eioccc, 4988c2ecf20Sopenharmony_ci drop, Eeof, abort } 4998c2ecf20Sopenharmony_ci/*TRUEI FALSEI IF TRUE FALSE ELIF ELTRUE ELFALSE ELSE ENDIF 5008c2ecf20Sopenharmony_ci TRUEI FALSEI IF TRUE FALSE ELIF ELTRUE ELFALSE ELSE ENDIF (DODGY) 5018c2ecf20Sopenharmony_ci PLAIN EOF ERROR */ 5028c2ecf20Sopenharmony_ci}; 5038c2ecf20Sopenharmony_ci 5048c2ecf20Sopenharmony_ci/* 5058c2ecf20Sopenharmony_ci * State machine utility functions 5068c2ecf20Sopenharmony_ci */ 5078c2ecf20Sopenharmony_cistatic void 5088c2ecf20Sopenharmony_ciignoreoff(void) 5098c2ecf20Sopenharmony_ci{ 5108c2ecf20Sopenharmony_ci if (depth == 0) 5118c2ecf20Sopenharmony_ci abort(); /* bug */ 5128c2ecf20Sopenharmony_ci ignoring[depth] = ignoring[depth-1]; 5138c2ecf20Sopenharmony_ci} 5148c2ecf20Sopenharmony_cistatic void 5158c2ecf20Sopenharmony_ciignoreon(void) 5168c2ecf20Sopenharmony_ci{ 5178c2ecf20Sopenharmony_ci ignoring[depth] = true; 5188c2ecf20Sopenharmony_ci} 5198c2ecf20Sopenharmony_cistatic void 5208c2ecf20Sopenharmony_cikeywordedit(const char *replacement) 5218c2ecf20Sopenharmony_ci{ 5228c2ecf20Sopenharmony_ci snprintf(keyword, tline + sizeof(tline) - keyword, 5238c2ecf20Sopenharmony_ci "%s%s", replacement, newline); 5248c2ecf20Sopenharmony_ci print(); 5258c2ecf20Sopenharmony_ci} 5268c2ecf20Sopenharmony_cistatic void 5278c2ecf20Sopenharmony_cinest(void) 5288c2ecf20Sopenharmony_ci{ 5298c2ecf20Sopenharmony_ci if (depth > MAXDEPTH-1) 5308c2ecf20Sopenharmony_ci abort(); /* bug */ 5318c2ecf20Sopenharmony_ci if (depth == MAXDEPTH-1) 5328c2ecf20Sopenharmony_ci error("Too many levels of nesting"); 5338c2ecf20Sopenharmony_ci depth += 1; 5348c2ecf20Sopenharmony_ci stifline[depth] = linenum; 5358c2ecf20Sopenharmony_ci} 5368c2ecf20Sopenharmony_cistatic void 5378c2ecf20Sopenharmony_ciunnest(void) 5388c2ecf20Sopenharmony_ci{ 5398c2ecf20Sopenharmony_ci if (depth == 0) 5408c2ecf20Sopenharmony_ci abort(); /* bug */ 5418c2ecf20Sopenharmony_ci depth -= 1; 5428c2ecf20Sopenharmony_ci} 5438c2ecf20Sopenharmony_cistatic void 5448c2ecf20Sopenharmony_cistate(Ifstate is) 5458c2ecf20Sopenharmony_ci{ 5468c2ecf20Sopenharmony_ci ifstate[depth] = is; 5478c2ecf20Sopenharmony_ci} 5488c2ecf20Sopenharmony_ci 5498c2ecf20Sopenharmony_ci/* 5508c2ecf20Sopenharmony_ci * Write a line to the output or not, according to command line options. 5518c2ecf20Sopenharmony_ci */ 5528c2ecf20Sopenharmony_cistatic void 5538c2ecf20Sopenharmony_ciflushline(bool keep) 5548c2ecf20Sopenharmony_ci{ 5558c2ecf20Sopenharmony_ci if (symlist) 5568c2ecf20Sopenharmony_ci return; 5578c2ecf20Sopenharmony_ci if (keep ^ complement) { 5588c2ecf20Sopenharmony_ci bool blankline = tline[strspn(tline, " \t\r\n")] == '\0'; 5598c2ecf20Sopenharmony_ci if (blankline && compblank && blankcount != blankmax) { 5608c2ecf20Sopenharmony_ci delcount += 1; 5618c2ecf20Sopenharmony_ci blankcount += 1; 5628c2ecf20Sopenharmony_ci } else { 5638c2ecf20Sopenharmony_ci if (lnnum && delcount > 0) 5648c2ecf20Sopenharmony_ci printf("#line %d%s", linenum, newline); 5658c2ecf20Sopenharmony_ci fputs(tline, output); 5668c2ecf20Sopenharmony_ci delcount = 0; 5678c2ecf20Sopenharmony_ci blankmax = blankcount = blankline ? blankcount + 1 : 0; 5688c2ecf20Sopenharmony_ci } 5698c2ecf20Sopenharmony_ci } else { 5708c2ecf20Sopenharmony_ci if (lnblank) 5718c2ecf20Sopenharmony_ci fputs(newline, output); 5728c2ecf20Sopenharmony_ci exitstat = 1; 5738c2ecf20Sopenharmony_ci delcount += 1; 5748c2ecf20Sopenharmony_ci blankcount = 0; 5758c2ecf20Sopenharmony_ci } 5768c2ecf20Sopenharmony_ci if (debugging) 5778c2ecf20Sopenharmony_ci fflush(output); 5788c2ecf20Sopenharmony_ci} 5798c2ecf20Sopenharmony_ci 5808c2ecf20Sopenharmony_ci/* 5818c2ecf20Sopenharmony_ci * The driver for the state machine. 5828c2ecf20Sopenharmony_ci */ 5838c2ecf20Sopenharmony_cistatic void 5848c2ecf20Sopenharmony_ciprocess(void) 5858c2ecf20Sopenharmony_ci{ 5868c2ecf20Sopenharmony_ci /* When compressing blank lines, act as if the file 5878c2ecf20Sopenharmony_ci is preceded by a large number of blank lines. */ 5888c2ecf20Sopenharmony_ci blankmax = blankcount = 1000; 5898c2ecf20Sopenharmony_ci for (;;) { 5908c2ecf20Sopenharmony_ci Linetype lineval = parseline(); 5918c2ecf20Sopenharmony_ci trans_table[ifstate[depth]][lineval](); 5928c2ecf20Sopenharmony_ci debug("process line %d %s -> %s depth %d", 5938c2ecf20Sopenharmony_ci linenum, linetype_name[lineval], 5948c2ecf20Sopenharmony_ci ifstate_name[ifstate[depth]], depth); 5958c2ecf20Sopenharmony_ci } 5968c2ecf20Sopenharmony_ci} 5978c2ecf20Sopenharmony_ci 5988c2ecf20Sopenharmony_ci/* 5998c2ecf20Sopenharmony_ci * Flush the output and handle errors. 6008c2ecf20Sopenharmony_ci */ 6018c2ecf20Sopenharmony_cistatic void 6028c2ecf20Sopenharmony_cicloseout(void) 6038c2ecf20Sopenharmony_ci{ 6048c2ecf20Sopenharmony_ci if (symdepth && !zerosyms) 6058c2ecf20Sopenharmony_ci printf("\n"); 6068c2ecf20Sopenharmony_ci if (fclose(output) == EOF) { 6078c2ecf20Sopenharmony_ci warn("couldn't write to %s", ofilename); 6088c2ecf20Sopenharmony_ci if (overwriting) { 6098c2ecf20Sopenharmony_ci unlink(tempname); 6108c2ecf20Sopenharmony_ci errx(2, "%s unchanged", filename); 6118c2ecf20Sopenharmony_ci } else { 6128c2ecf20Sopenharmony_ci exit(2); 6138c2ecf20Sopenharmony_ci } 6148c2ecf20Sopenharmony_ci } 6158c2ecf20Sopenharmony_ci} 6168c2ecf20Sopenharmony_ci 6178c2ecf20Sopenharmony_ci/* 6188c2ecf20Sopenharmony_ci * Clean up and exit. 6198c2ecf20Sopenharmony_ci */ 6208c2ecf20Sopenharmony_cistatic void 6218c2ecf20Sopenharmony_cidone(void) 6228c2ecf20Sopenharmony_ci{ 6238c2ecf20Sopenharmony_ci if (incomment) 6248c2ecf20Sopenharmony_ci error("EOF in comment"); 6258c2ecf20Sopenharmony_ci closeout(); 6268c2ecf20Sopenharmony_ci if (overwriting && rename(tempname, ofilename) == -1) { 6278c2ecf20Sopenharmony_ci warn("couldn't rename temporary file"); 6288c2ecf20Sopenharmony_ci unlink(tempname); 6298c2ecf20Sopenharmony_ci errx(2, "%s unchanged", ofilename); 6308c2ecf20Sopenharmony_ci } 6318c2ecf20Sopenharmony_ci exit(exitstat); 6328c2ecf20Sopenharmony_ci} 6338c2ecf20Sopenharmony_ci 6348c2ecf20Sopenharmony_ci/* 6358c2ecf20Sopenharmony_ci * Parse a line and determine its type. We keep the preprocessor line 6368c2ecf20Sopenharmony_ci * parser state between calls in the global variable linestate, with 6378c2ecf20Sopenharmony_ci * help from skipcomment(). 6388c2ecf20Sopenharmony_ci */ 6398c2ecf20Sopenharmony_cistatic Linetype 6408c2ecf20Sopenharmony_ciparseline(void) 6418c2ecf20Sopenharmony_ci{ 6428c2ecf20Sopenharmony_ci const char *cp; 6438c2ecf20Sopenharmony_ci int cursym; 6448c2ecf20Sopenharmony_ci int kwlen; 6458c2ecf20Sopenharmony_ci Linetype retval; 6468c2ecf20Sopenharmony_ci Comment_state wascomment; 6478c2ecf20Sopenharmony_ci 6488c2ecf20Sopenharmony_ci linenum++; 6498c2ecf20Sopenharmony_ci if (fgets(tline, MAXLINE, input) == NULL) 6508c2ecf20Sopenharmony_ci return (LT_EOF); 6518c2ecf20Sopenharmony_ci if (newline == NULL) { 6528c2ecf20Sopenharmony_ci if (strrchr(tline, '\n') == strrchr(tline, '\r') + 1) 6538c2ecf20Sopenharmony_ci newline = newline_crlf; 6548c2ecf20Sopenharmony_ci else 6558c2ecf20Sopenharmony_ci newline = newline_unix; 6568c2ecf20Sopenharmony_ci } 6578c2ecf20Sopenharmony_ci retval = LT_PLAIN; 6588c2ecf20Sopenharmony_ci wascomment = incomment; 6598c2ecf20Sopenharmony_ci cp = skipcomment(tline); 6608c2ecf20Sopenharmony_ci if (linestate == LS_START) { 6618c2ecf20Sopenharmony_ci if (*cp == '#') { 6628c2ecf20Sopenharmony_ci linestate = LS_HASH; 6638c2ecf20Sopenharmony_ci firstsym = true; 6648c2ecf20Sopenharmony_ci cp = skipcomment(cp + 1); 6658c2ecf20Sopenharmony_ci } else if (*cp != '\0') 6668c2ecf20Sopenharmony_ci linestate = LS_DIRTY; 6678c2ecf20Sopenharmony_ci } 6688c2ecf20Sopenharmony_ci if (!incomment && linestate == LS_HASH) { 6698c2ecf20Sopenharmony_ci keyword = tline + (cp - tline); 6708c2ecf20Sopenharmony_ci cp = skipsym(cp); 6718c2ecf20Sopenharmony_ci kwlen = cp - keyword; 6728c2ecf20Sopenharmony_ci /* no way can we deal with a continuation inside a keyword */ 6738c2ecf20Sopenharmony_ci if (strncmp(cp, "\\\r\n", 3) == 0 || 6748c2ecf20Sopenharmony_ci strncmp(cp, "\\\n", 2) == 0) 6758c2ecf20Sopenharmony_ci Eioccc(); 6768c2ecf20Sopenharmony_ci if (strlcmp("ifdef", keyword, kwlen) == 0 || 6778c2ecf20Sopenharmony_ci strlcmp("ifndef", keyword, kwlen) == 0) { 6788c2ecf20Sopenharmony_ci cp = skipcomment(cp); 6798c2ecf20Sopenharmony_ci if ((cursym = findsym(cp)) < 0) 6808c2ecf20Sopenharmony_ci retval = LT_IF; 6818c2ecf20Sopenharmony_ci else { 6828c2ecf20Sopenharmony_ci retval = (keyword[2] == 'n') 6838c2ecf20Sopenharmony_ci ? LT_FALSE : LT_TRUE; 6848c2ecf20Sopenharmony_ci if (value[cursym] == NULL) 6858c2ecf20Sopenharmony_ci retval = (retval == LT_TRUE) 6868c2ecf20Sopenharmony_ci ? LT_FALSE : LT_TRUE; 6878c2ecf20Sopenharmony_ci if (ignore[cursym]) 6888c2ecf20Sopenharmony_ci retval = (retval == LT_TRUE) 6898c2ecf20Sopenharmony_ci ? LT_TRUEI : LT_FALSEI; 6908c2ecf20Sopenharmony_ci } 6918c2ecf20Sopenharmony_ci cp = skipsym(cp); 6928c2ecf20Sopenharmony_ci } else if (strlcmp("if", keyword, kwlen) == 0) 6938c2ecf20Sopenharmony_ci retval = ifeval(&cp); 6948c2ecf20Sopenharmony_ci else if (strlcmp("elif", keyword, kwlen) == 0) 6958c2ecf20Sopenharmony_ci retval = ifeval(&cp) - LT_IF + LT_ELIF; 6968c2ecf20Sopenharmony_ci else if (strlcmp("else", keyword, kwlen) == 0) 6978c2ecf20Sopenharmony_ci retval = LT_ELSE; 6988c2ecf20Sopenharmony_ci else if (strlcmp("endif", keyword, kwlen) == 0) 6998c2ecf20Sopenharmony_ci retval = LT_ENDIF; 7008c2ecf20Sopenharmony_ci else { 7018c2ecf20Sopenharmony_ci linestate = LS_DIRTY; 7028c2ecf20Sopenharmony_ci retval = LT_PLAIN; 7038c2ecf20Sopenharmony_ci } 7048c2ecf20Sopenharmony_ci cp = skipcomment(cp); 7058c2ecf20Sopenharmony_ci if (*cp != '\0') { 7068c2ecf20Sopenharmony_ci linestate = LS_DIRTY; 7078c2ecf20Sopenharmony_ci if (retval == LT_TRUE || retval == LT_FALSE || 7088c2ecf20Sopenharmony_ci retval == LT_TRUEI || retval == LT_FALSEI) 7098c2ecf20Sopenharmony_ci retval = LT_IF; 7108c2ecf20Sopenharmony_ci if (retval == LT_ELTRUE || retval == LT_ELFALSE) 7118c2ecf20Sopenharmony_ci retval = LT_ELIF; 7128c2ecf20Sopenharmony_ci } 7138c2ecf20Sopenharmony_ci if (retval != LT_PLAIN && (wascomment || incomment)) { 7148c2ecf20Sopenharmony_ci retval += LT_DODGY; 7158c2ecf20Sopenharmony_ci if (incomment) 7168c2ecf20Sopenharmony_ci linestate = LS_DIRTY; 7178c2ecf20Sopenharmony_ci } 7188c2ecf20Sopenharmony_ci /* skipcomment normally changes the state, except 7198c2ecf20Sopenharmony_ci if the last line of the file lacks a newline, or 7208c2ecf20Sopenharmony_ci if there is too much whitespace in a directive */ 7218c2ecf20Sopenharmony_ci if (linestate == LS_HASH) { 7228c2ecf20Sopenharmony_ci size_t len = cp - tline; 7238c2ecf20Sopenharmony_ci if (fgets(tline + len, MAXLINE - len, input) == NULL) { 7248c2ecf20Sopenharmony_ci /* append the missing newline */ 7258c2ecf20Sopenharmony_ci strcpy(tline + len, newline); 7268c2ecf20Sopenharmony_ci cp += strlen(newline); 7278c2ecf20Sopenharmony_ci linestate = LS_START; 7288c2ecf20Sopenharmony_ci } else { 7298c2ecf20Sopenharmony_ci linestate = LS_DIRTY; 7308c2ecf20Sopenharmony_ci } 7318c2ecf20Sopenharmony_ci } 7328c2ecf20Sopenharmony_ci } 7338c2ecf20Sopenharmony_ci if (linestate == LS_DIRTY) { 7348c2ecf20Sopenharmony_ci while (*cp != '\0') 7358c2ecf20Sopenharmony_ci cp = skipcomment(cp + 1); 7368c2ecf20Sopenharmony_ci } 7378c2ecf20Sopenharmony_ci debug("parser line %d state %s comment %s line", linenum, 7388c2ecf20Sopenharmony_ci comment_name[incomment], linestate_name[linestate]); 7398c2ecf20Sopenharmony_ci return (retval); 7408c2ecf20Sopenharmony_ci} 7418c2ecf20Sopenharmony_ci 7428c2ecf20Sopenharmony_ci/* 7438c2ecf20Sopenharmony_ci * These are the binary operators that are supported by the expression 7448c2ecf20Sopenharmony_ci * evaluator. 7458c2ecf20Sopenharmony_ci */ 7468c2ecf20Sopenharmony_cistatic Linetype op_strict(int *p, int v, Linetype at, Linetype bt) { 7478c2ecf20Sopenharmony_ci if(at == LT_IF || bt == LT_IF) return (LT_IF); 7488c2ecf20Sopenharmony_ci return (*p = v, v ? LT_TRUE : LT_FALSE); 7498c2ecf20Sopenharmony_ci} 7508c2ecf20Sopenharmony_cistatic Linetype op_lt(int *p, Linetype at, int a, Linetype bt, int b) { 7518c2ecf20Sopenharmony_ci return op_strict(p, a < b, at, bt); 7528c2ecf20Sopenharmony_ci} 7538c2ecf20Sopenharmony_cistatic Linetype op_gt(int *p, Linetype at, int a, Linetype bt, int b) { 7548c2ecf20Sopenharmony_ci return op_strict(p, a > b, at, bt); 7558c2ecf20Sopenharmony_ci} 7568c2ecf20Sopenharmony_cistatic Linetype op_le(int *p, Linetype at, int a, Linetype bt, int b) { 7578c2ecf20Sopenharmony_ci return op_strict(p, a <= b, at, bt); 7588c2ecf20Sopenharmony_ci} 7598c2ecf20Sopenharmony_cistatic Linetype op_ge(int *p, Linetype at, int a, Linetype bt, int b) { 7608c2ecf20Sopenharmony_ci return op_strict(p, a >= b, at, bt); 7618c2ecf20Sopenharmony_ci} 7628c2ecf20Sopenharmony_cistatic Linetype op_eq(int *p, Linetype at, int a, Linetype bt, int b) { 7638c2ecf20Sopenharmony_ci return op_strict(p, a == b, at, bt); 7648c2ecf20Sopenharmony_ci} 7658c2ecf20Sopenharmony_cistatic Linetype op_ne(int *p, Linetype at, int a, Linetype bt, int b) { 7668c2ecf20Sopenharmony_ci return op_strict(p, a != b, at, bt); 7678c2ecf20Sopenharmony_ci} 7688c2ecf20Sopenharmony_cistatic Linetype op_or(int *p, Linetype at, int a, Linetype bt, int b) { 7698c2ecf20Sopenharmony_ci if (!strictlogic && (at == LT_TRUE || bt == LT_TRUE)) 7708c2ecf20Sopenharmony_ci return (*p = 1, LT_TRUE); 7718c2ecf20Sopenharmony_ci return op_strict(p, a || b, at, bt); 7728c2ecf20Sopenharmony_ci} 7738c2ecf20Sopenharmony_cistatic Linetype op_and(int *p, Linetype at, int a, Linetype bt, int b) { 7748c2ecf20Sopenharmony_ci if (!strictlogic && (at == LT_FALSE || bt == LT_FALSE)) 7758c2ecf20Sopenharmony_ci return (*p = 0, LT_FALSE); 7768c2ecf20Sopenharmony_ci return op_strict(p, a && b, at, bt); 7778c2ecf20Sopenharmony_ci} 7788c2ecf20Sopenharmony_ci 7798c2ecf20Sopenharmony_ci/* 7808c2ecf20Sopenharmony_ci * An evaluation function takes three arguments, as follows: (1) a pointer to 7818c2ecf20Sopenharmony_ci * an element of the precedence table which lists the operators at the current 7828c2ecf20Sopenharmony_ci * level of precedence; (2) a pointer to an integer which will receive the 7838c2ecf20Sopenharmony_ci * value of the expression; and (3) a pointer to a char* that points to the 7848c2ecf20Sopenharmony_ci * expression to be evaluated and that is updated to the end of the expression 7858c2ecf20Sopenharmony_ci * when evaluation is complete. The function returns LT_FALSE if the value of 7868c2ecf20Sopenharmony_ci * the expression is zero, LT_TRUE if it is non-zero, LT_IF if the expression 7878c2ecf20Sopenharmony_ci * depends on an unknown symbol, or LT_ERROR if there is a parse failure. 7888c2ecf20Sopenharmony_ci */ 7898c2ecf20Sopenharmony_cistruct ops; 7908c2ecf20Sopenharmony_ci 7918c2ecf20Sopenharmony_citypedef Linetype eval_fn(const struct ops *, int *, const char **); 7928c2ecf20Sopenharmony_ci 7938c2ecf20Sopenharmony_cistatic eval_fn eval_table, eval_unary; 7948c2ecf20Sopenharmony_ci 7958c2ecf20Sopenharmony_ci/* 7968c2ecf20Sopenharmony_ci * The precedence table. Expressions involving binary operators are evaluated 7978c2ecf20Sopenharmony_ci * in a table-driven way by eval_table. When it evaluates a subexpression it 7988c2ecf20Sopenharmony_ci * calls the inner function with its first argument pointing to the next 7998c2ecf20Sopenharmony_ci * element of the table. Innermost expressions have special non-table-driven 8008c2ecf20Sopenharmony_ci * handling. 8018c2ecf20Sopenharmony_ci */ 8028c2ecf20Sopenharmony_cistatic const struct ops { 8038c2ecf20Sopenharmony_ci eval_fn *inner; 8048c2ecf20Sopenharmony_ci struct op { 8058c2ecf20Sopenharmony_ci const char *str; 8068c2ecf20Sopenharmony_ci Linetype (*fn)(int *, Linetype, int, Linetype, int); 8078c2ecf20Sopenharmony_ci } op[5]; 8088c2ecf20Sopenharmony_ci} eval_ops[] = { 8098c2ecf20Sopenharmony_ci { eval_table, { { "||", op_or } } }, 8108c2ecf20Sopenharmony_ci { eval_table, { { "&&", op_and } } }, 8118c2ecf20Sopenharmony_ci { eval_table, { { "==", op_eq }, 8128c2ecf20Sopenharmony_ci { "!=", op_ne } } }, 8138c2ecf20Sopenharmony_ci { eval_unary, { { "<=", op_le }, 8148c2ecf20Sopenharmony_ci { ">=", op_ge }, 8158c2ecf20Sopenharmony_ci { "<", op_lt }, 8168c2ecf20Sopenharmony_ci { ">", op_gt } } } 8178c2ecf20Sopenharmony_ci}; 8188c2ecf20Sopenharmony_ci 8198c2ecf20Sopenharmony_ci/* 8208c2ecf20Sopenharmony_ci * Function for evaluating the innermost parts of expressions, 8218c2ecf20Sopenharmony_ci * viz. !expr (expr) number defined(symbol) symbol 8228c2ecf20Sopenharmony_ci * We reset the constexpr flag in the last two cases. 8238c2ecf20Sopenharmony_ci */ 8248c2ecf20Sopenharmony_cistatic Linetype 8258c2ecf20Sopenharmony_cieval_unary(const struct ops *ops, int *valp, const char **cpp) 8268c2ecf20Sopenharmony_ci{ 8278c2ecf20Sopenharmony_ci const char *cp; 8288c2ecf20Sopenharmony_ci char *ep; 8298c2ecf20Sopenharmony_ci int sym; 8308c2ecf20Sopenharmony_ci bool defparen; 8318c2ecf20Sopenharmony_ci Linetype lt; 8328c2ecf20Sopenharmony_ci 8338c2ecf20Sopenharmony_ci cp = skipcomment(*cpp); 8348c2ecf20Sopenharmony_ci if (*cp == '!') { 8358c2ecf20Sopenharmony_ci debug("eval%d !", ops - eval_ops); 8368c2ecf20Sopenharmony_ci cp++; 8378c2ecf20Sopenharmony_ci lt = eval_unary(ops, valp, &cp); 8388c2ecf20Sopenharmony_ci if (lt == LT_ERROR) 8398c2ecf20Sopenharmony_ci return (LT_ERROR); 8408c2ecf20Sopenharmony_ci if (lt != LT_IF) { 8418c2ecf20Sopenharmony_ci *valp = !*valp; 8428c2ecf20Sopenharmony_ci lt = *valp ? LT_TRUE : LT_FALSE; 8438c2ecf20Sopenharmony_ci } 8448c2ecf20Sopenharmony_ci } else if (*cp == '(') { 8458c2ecf20Sopenharmony_ci cp++; 8468c2ecf20Sopenharmony_ci debug("eval%d (", ops - eval_ops); 8478c2ecf20Sopenharmony_ci lt = eval_table(eval_ops, valp, &cp); 8488c2ecf20Sopenharmony_ci if (lt == LT_ERROR) 8498c2ecf20Sopenharmony_ci return (LT_ERROR); 8508c2ecf20Sopenharmony_ci cp = skipcomment(cp); 8518c2ecf20Sopenharmony_ci if (*cp++ != ')') 8528c2ecf20Sopenharmony_ci return (LT_ERROR); 8538c2ecf20Sopenharmony_ci } else if (isdigit((unsigned char)*cp)) { 8548c2ecf20Sopenharmony_ci debug("eval%d number", ops - eval_ops); 8558c2ecf20Sopenharmony_ci *valp = strtol(cp, &ep, 0); 8568c2ecf20Sopenharmony_ci if (ep == cp) 8578c2ecf20Sopenharmony_ci return (LT_ERROR); 8588c2ecf20Sopenharmony_ci lt = *valp ? LT_TRUE : LT_FALSE; 8598c2ecf20Sopenharmony_ci cp = skipsym(cp); 8608c2ecf20Sopenharmony_ci } else if (strncmp(cp, "defined", 7) == 0 && endsym(cp[7])) { 8618c2ecf20Sopenharmony_ci cp = skipcomment(cp+7); 8628c2ecf20Sopenharmony_ci debug("eval%d defined", ops - eval_ops); 8638c2ecf20Sopenharmony_ci if (*cp == '(') { 8648c2ecf20Sopenharmony_ci cp = skipcomment(cp+1); 8658c2ecf20Sopenharmony_ci defparen = true; 8668c2ecf20Sopenharmony_ci } else { 8678c2ecf20Sopenharmony_ci defparen = false; 8688c2ecf20Sopenharmony_ci } 8698c2ecf20Sopenharmony_ci sym = findsym(cp); 8708c2ecf20Sopenharmony_ci if (sym < 0) { 8718c2ecf20Sopenharmony_ci lt = LT_IF; 8728c2ecf20Sopenharmony_ci } else { 8738c2ecf20Sopenharmony_ci *valp = (value[sym] != NULL); 8748c2ecf20Sopenharmony_ci lt = *valp ? LT_TRUE : LT_FALSE; 8758c2ecf20Sopenharmony_ci } 8768c2ecf20Sopenharmony_ci cp = skipsym(cp); 8778c2ecf20Sopenharmony_ci cp = skipcomment(cp); 8788c2ecf20Sopenharmony_ci if (defparen && *cp++ != ')') 8798c2ecf20Sopenharmony_ci return (LT_ERROR); 8808c2ecf20Sopenharmony_ci constexpr = false; 8818c2ecf20Sopenharmony_ci } else if (!endsym(*cp)) { 8828c2ecf20Sopenharmony_ci debug("eval%d symbol", ops - eval_ops); 8838c2ecf20Sopenharmony_ci sym = findsym(cp); 8848c2ecf20Sopenharmony_ci cp = skipsym(cp); 8858c2ecf20Sopenharmony_ci if (sym < 0) { 8868c2ecf20Sopenharmony_ci lt = LT_IF; 8878c2ecf20Sopenharmony_ci cp = skipargs(cp); 8888c2ecf20Sopenharmony_ci } else if (value[sym] == NULL) { 8898c2ecf20Sopenharmony_ci *valp = 0; 8908c2ecf20Sopenharmony_ci lt = LT_FALSE; 8918c2ecf20Sopenharmony_ci } else { 8928c2ecf20Sopenharmony_ci *valp = strtol(value[sym], &ep, 0); 8938c2ecf20Sopenharmony_ci if (*ep != '\0' || ep == value[sym]) 8948c2ecf20Sopenharmony_ci return (LT_ERROR); 8958c2ecf20Sopenharmony_ci lt = *valp ? LT_TRUE : LT_FALSE; 8968c2ecf20Sopenharmony_ci cp = skipargs(cp); 8978c2ecf20Sopenharmony_ci } 8988c2ecf20Sopenharmony_ci constexpr = false; 8998c2ecf20Sopenharmony_ci } else { 9008c2ecf20Sopenharmony_ci debug("eval%d bad expr", ops - eval_ops); 9018c2ecf20Sopenharmony_ci return (LT_ERROR); 9028c2ecf20Sopenharmony_ci } 9038c2ecf20Sopenharmony_ci 9048c2ecf20Sopenharmony_ci *cpp = cp; 9058c2ecf20Sopenharmony_ci debug("eval%d = %d", ops - eval_ops, *valp); 9068c2ecf20Sopenharmony_ci return (lt); 9078c2ecf20Sopenharmony_ci} 9088c2ecf20Sopenharmony_ci 9098c2ecf20Sopenharmony_ci/* 9108c2ecf20Sopenharmony_ci * Table-driven evaluation of binary operators. 9118c2ecf20Sopenharmony_ci */ 9128c2ecf20Sopenharmony_cistatic Linetype 9138c2ecf20Sopenharmony_cieval_table(const struct ops *ops, int *valp, const char **cpp) 9148c2ecf20Sopenharmony_ci{ 9158c2ecf20Sopenharmony_ci const struct op *op; 9168c2ecf20Sopenharmony_ci const char *cp; 9178c2ecf20Sopenharmony_ci int val; 9188c2ecf20Sopenharmony_ci Linetype lt, rt; 9198c2ecf20Sopenharmony_ci 9208c2ecf20Sopenharmony_ci debug("eval%d", ops - eval_ops); 9218c2ecf20Sopenharmony_ci cp = *cpp; 9228c2ecf20Sopenharmony_ci lt = ops->inner(ops+1, valp, &cp); 9238c2ecf20Sopenharmony_ci if (lt == LT_ERROR) 9248c2ecf20Sopenharmony_ci return (LT_ERROR); 9258c2ecf20Sopenharmony_ci for (;;) { 9268c2ecf20Sopenharmony_ci cp = skipcomment(cp); 9278c2ecf20Sopenharmony_ci for (op = ops->op; op->str != NULL; op++) 9288c2ecf20Sopenharmony_ci if (strncmp(cp, op->str, strlen(op->str)) == 0) 9298c2ecf20Sopenharmony_ci break; 9308c2ecf20Sopenharmony_ci if (op->str == NULL) 9318c2ecf20Sopenharmony_ci break; 9328c2ecf20Sopenharmony_ci cp += strlen(op->str); 9338c2ecf20Sopenharmony_ci debug("eval%d %s", ops - eval_ops, op->str); 9348c2ecf20Sopenharmony_ci rt = ops->inner(ops+1, &val, &cp); 9358c2ecf20Sopenharmony_ci if (rt == LT_ERROR) 9368c2ecf20Sopenharmony_ci return (LT_ERROR); 9378c2ecf20Sopenharmony_ci lt = op->fn(valp, lt, *valp, rt, val); 9388c2ecf20Sopenharmony_ci } 9398c2ecf20Sopenharmony_ci 9408c2ecf20Sopenharmony_ci *cpp = cp; 9418c2ecf20Sopenharmony_ci debug("eval%d = %d", ops - eval_ops, *valp); 9428c2ecf20Sopenharmony_ci debug("eval%d lt = %s", ops - eval_ops, linetype_name[lt]); 9438c2ecf20Sopenharmony_ci return (lt); 9448c2ecf20Sopenharmony_ci} 9458c2ecf20Sopenharmony_ci 9468c2ecf20Sopenharmony_ci/* 9478c2ecf20Sopenharmony_ci * Evaluate the expression on a #if or #elif line. If we can work out 9488c2ecf20Sopenharmony_ci * the result we return LT_TRUE or LT_FALSE accordingly, otherwise we 9498c2ecf20Sopenharmony_ci * return just a generic LT_IF. 9508c2ecf20Sopenharmony_ci */ 9518c2ecf20Sopenharmony_cistatic Linetype 9528c2ecf20Sopenharmony_ciifeval(const char **cpp) 9538c2ecf20Sopenharmony_ci{ 9548c2ecf20Sopenharmony_ci int ret; 9558c2ecf20Sopenharmony_ci int val = 0; 9568c2ecf20Sopenharmony_ci 9578c2ecf20Sopenharmony_ci debug("eval %s", *cpp); 9588c2ecf20Sopenharmony_ci constexpr = killconsts ? false : true; 9598c2ecf20Sopenharmony_ci ret = eval_table(eval_ops, &val, cpp); 9608c2ecf20Sopenharmony_ci debug("eval = %d", val); 9618c2ecf20Sopenharmony_ci return (constexpr ? LT_IF : ret == LT_ERROR ? LT_IF : ret); 9628c2ecf20Sopenharmony_ci} 9638c2ecf20Sopenharmony_ci 9648c2ecf20Sopenharmony_ci/* 9658c2ecf20Sopenharmony_ci * Skip over comments, strings, and character literals and stop at the 9668c2ecf20Sopenharmony_ci * next character position that is not whitespace. Between calls we keep 9678c2ecf20Sopenharmony_ci * the comment state in the global variable incomment, and we also adjust 9688c2ecf20Sopenharmony_ci * the global variable linestate when we see a newline. 9698c2ecf20Sopenharmony_ci * XXX: doesn't cope with the buffer splitting inside a state transition. 9708c2ecf20Sopenharmony_ci */ 9718c2ecf20Sopenharmony_cistatic const char * 9728c2ecf20Sopenharmony_ciskipcomment(const char *cp) 9738c2ecf20Sopenharmony_ci{ 9748c2ecf20Sopenharmony_ci if (text || ignoring[depth]) { 9758c2ecf20Sopenharmony_ci for (; isspace((unsigned char)*cp); cp++) 9768c2ecf20Sopenharmony_ci if (*cp == '\n') 9778c2ecf20Sopenharmony_ci linestate = LS_START; 9788c2ecf20Sopenharmony_ci return (cp); 9798c2ecf20Sopenharmony_ci } 9808c2ecf20Sopenharmony_ci while (*cp != '\0') 9818c2ecf20Sopenharmony_ci /* don't reset to LS_START after a line continuation */ 9828c2ecf20Sopenharmony_ci if (strncmp(cp, "\\\r\n", 3) == 0) 9838c2ecf20Sopenharmony_ci cp += 3; 9848c2ecf20Sopenharmony_ci else if (strncmp(cp, "\\\n", 2) == 0) 9858c2ecf20Sopenharmony_ci cp += 2; 9868c2ecf20Sopenharmony_ci else switch (incomment) { 9878c2ecf20Sopenharmony_ci case NO_COMMENT: 9888c2ecf20Sopenharmony_ci if (strncmp(cp, "/\\\r\n", 4) == 0) { 9898c2ecf20Sopenharmony_ci incomment = STARTING_COMMENT; 9908c2ecf20Sopenharmony_ci cp += 4; 9918c2ecf20Sopenharmony_ci } else if (strncmp(cp, "/\\\n", 3) == 0) { 9928c2ecf20Sopenharmony_ci incomment = STARTING_COMMENT; 9938c2ecf20Sopenharmony_ci cp += 3; 9948c2ecf20Sopenharmony_ci } else if (strncmp(cp, "/*", 2) == 0) { 9958c2ecf20Sopenharmony_ci incomment = C_COMMENT; 9968c2ecf20Sopenharmony_ci cp += 2; 9978c2ecf20Sopenharmony_ci } else if (strncmp(cp, "//", 2) == 0) { 9988c2ecf20Sopenharmony_ci incomment = CXX_COMMENT; 9998c2ecf20Sopenharmony_ci cp += 2; 10008c2ecf20Sopenharmony_ci } else if (strncmp(cp, "\'", 1) == 0) { 10018c2ecf20Sopenharmony_ci incomment = CHAR_LITERAL; 10028c2ecf20Sopenharmony_ci linestate = LS_DIRTY; 10038c2ecf20Sopenharmony_ci cp += 1; 10048c2ecf20Sopenharmony_ci } else if (strncmp(cp, "\"", 1) == 0) { 10058c2ecf20Sopenharmony_ci incomment = STRING_LITERAL; 10068c2ecf20Sopenharmony_ci linestate = LS_DIRTY; 10078c2ecf20Sopenharmony_ci cp += 1; 10088c2ecf20Sopenharmony_ci } else if (strncmp(cp, "\n", 1) == 0) { 10098c2ecf20Sopenharmony_ci linestate = LS_START; 10108c2ecf20Sopenharmony_ci cp += 1; 10118c2ecf20Sopenharmony_ci } else if (strchr(" \r\t", *cp) != NULL) { 10128c2ecf20Sopenharmony_ci cp += 1; 10138c2ecf20Sopenharmony_ci } else 10148c2ecf20Sopenharmony_ci return (cp); 10158c2ecf20Sopenharmony_ci continue; 10168c2ecf20Sopenharmony_ci case CXX_COMMENT: 10178c2ecf20Sopenharmony_ci if (strncmp(cp, "\n", 1) == 0) { 10188c2ecf20Sopenharmony_ci incomment = NO_COMMENT; 10198c2ecf20Sopenharmony_ci linestate = LS_START; 10208c2ecf20Sopenharmony_ci } 10218c2ecf20Sopenharmony_ci cp += 1; 10228c2ecf20Sopenharmony_ci continue; 10238c2ecf20Sopenharmony_ci case CHAR_LITERAL: 10248c2ecf20Sopenharmony_ci case STRING_LITERAL: 10258c2ecf20Sopenharmony_ci if ((incomment == CHAR_LITERAL && cp[0] == '\'') || 10268c2ecf20Sopenharmony_ci (incomment == STRING_LITERAL && cp[0] == '\"')) { 10278c2ecf20Sopenharmony_ci incomment = NO_COMMENT; 10288c2ecf20Sopenharmony_ci cp += 1; 10298c2ecf20Sopenharmony_ci } else if (cp[0] == '\\') { 10308c2ecf20Sopenharmony_ci if (cp[1] == '\0') 10318c2ecf20Sopenharmony_ci cp += 1; 10328c2ecf20Sopenharmony_ci else 10338c2ecf20Sopenharmony_ci cp += 2; 10348c2ecf20Sopenharmony_ci } else if (strncmp(cp, "\n", 1) == 0) { 10358c2ecf20Sopenharmony_ci if (incomment == CHAR_LITERAL) 10368c2ecf20Sopenharmony_ci error("unterminated char literal"); 10378c2ecf20Sopenharmony_ci else 10388c2ecf20Sopenharmony_ci error("unterminated string literal"); 10398c2ecf20Sopenharmony_ci } else 10408c2ecf20Sopenharmony_ci cp += 1; 10418c2ecf20Sopenharmony_ci continue; 10428c2ecf20Sopenharmony_ci case C_COMMENT: 10438c2ecf20Sopenharmony_ci if (strncmp(cp, "*\\\r\n", 4) == 0) { 10448c2ecf20Sopenharmony_ci incomment = FINISHING_COMMENT; 10458c2ecf20Sopenharmony_ci cp += 4; 10468c2ecf20Sopenharmony_ci } else if (strncmp(cp, "*\\\n", 3) == 0) { 10478c2ecf20Sopenharmony_ci incomment = FINISHING_COMMENT; 10488c2ecf20Sopenharmony_ci cp += 3; 10498c2ecf20Sopenharmony_ci } else if (strncmp(cp, "*/", 2) == 0) { 10508c2ecf20Sopenharmony_ci incomment = NO_COMMENT; 10518c2ecf20Sopenharmony_ci cp += 2; 10528c2ecf20Sopenharmony_ci } else 10538c2ecf20Sopenharmony_ci cp += 1; 10548c2ecf20Sopenharmony_ci continue; 10558c2ecf20Sopenharmony_ci case STARTING_COMMENT: 10568c2ecf20Sopenharmony_ci if (*cp == '*') { 10578c2ecf20Sopenharmony_ci incomment = C_COMMENT; 10588c2ecf20Sopenharmony_ci cp += 1; 10598c2ecf20Sopenharmony_ci } else if (*cp == '/') { 10608c2ecf20Sopenharmony_ci incomment = CXX_COMMENT; 10618c2ecf20Sopenharmony_ci cp += 1; 10628c2ecf20Sopenharmony_ci } else { 10638c2ecf20Sopenharmony_ci incomment = NO_COMMENT; 10648c2ecf20Sopenharmony_ci linestate = LS_DIRTY; 10658c2ecf20Sopenharmony_ci } 10668c2ecf20Sopenharmony_ci continue; 10678c2ecf20Sopenharmony_ci case FINISHING_COMMENT: 10688c2ecf20Sopenharmony_ci if (*cp == '/') { 10698c2ecf20Sopenharmony_ci incomment = NO_COMMENT; 10708c2ecf20Sopenharmony_ci cp += 1; 10718c2ecf20Sopenharmony_ci } else 10728c2ecf20Sopenharmony_ci incomment = C_COMMENT; 10738c2ecf20Sopenharmony_ci continue; 10748c2ecf20Sopenharmony_ci default: 10758c2ecf20Sopenharmony_ci abort(); /* bug */ 10768c2ecf20Sopenharmony_ci } 10778c2ecf20Sopenharmony_ci return (cp); 10788c2ecf20Sopenharmony_ci} 10798c2ecf20Sopenharmony_ci 10808c2ecf20Sopenharmony_ci/* 10818c2ecf20Sopenharmony_ci * Skip macro arguments. 10828c2ecf20Sopenharmony_ci */ 10838c2ecf20Sopenharmony_cistatic const char * 10848c2ecf20Sopenharmony_ciskipargs(const char *cp) 10858c2ecf20Sopenharmony_ci{ 10868c2ecf20Sopenharmony_ci const char *ocp = cp; 10878c2ecf20Sopenharmony_ci int level = 0; 10888c2ecf20Sopenharmony_ci cp = skipcomment(cp); 10898c2ecf20Sopenharmony_ci if (*cp != '(') 10908c2ecf20Sopenharmony_ci return (cp); 10918c2ecf20Sopenharmony_ci do { 10928c2ecf20Sopenharmony_ci if (*cp == '(') 10938c2ecf20Sopenharmony_ci level++; 10948c2ecf20Sopenharmony_ci if (*cp == ')') 10958c2ecf20Sopenharmony_ci level--; 10968c2ecf20Sopenharmony_ci cp = skipcomment(cp+1); 10978c2ecf20Sopenharmony_ci } while (level != 0 && *cp != '\0'); 10988c2ecf20Sopenharmony_ci if (level == 0) 10998c2ecf20Sopenharmony_ci return (cp); 11008c2ecf20Sopenharmony_ci else 11018c2ecf20Sopenharmony_ci /* Rewind and re-detect the syntax error later. */ 11028c2ecf20Sopenharmony_ci return (ocp); 11038c2ecf20Sopenharmony_ci} 11048c2ecf20Sopenharmony_ci 11058c2ecf20Sopenharmony_ci/* 11068c2ecf20Sopenharmony_ci * Skip over an identifier. 11078c2ecf20Sopenharmony_ci */ 11088c2ecf20Sopenharmony_cistatic const char * 11098c2ecf20Sopenharmony_ciskipsym(const char *cp) 11108c2ecf20Sopenharmony_ci{ 11118c2ecf20Sopenharmony_ci while (!endsym(*cp)) 11128c2ecf20Sopenharmony_ci ++cp; 11138c2ecf20Sopenharmony_ci return (cp); 11148c2ecf20Sopenharmony_ci} 11158c2ecf20Sopenharmony_ci 11168c2ecf20Sopenharmony_ci/* 11178c2ecf20Sopenharmony_ci * Look for the symbol in the symbol table. If it is found, we return 11188c2ecf20Sopenharmony_ci * the symbol table index, else we return -1. 11198c2ecf20Sopenharmony_ci */ 11208c2ecf20Sopenharmony_cistatic int 11218c2ecf20Sopenharmony_cifindsym(const char *str) 11228c2ecf20Sopenharmony_ci{ 11238c2ecf20Sopenharmony_ci const char *cp; 11248c2ecf20Sopenharmony_ci int symind; 11258c2ecf20Sopenharmony_ci 11268c2ecf20Sopenharmony_ci cp = skipsym(str); 11278c2ecf20Sopenharmony_ci if (cp == str) 11288c2ecf20Sopenharmony_ci return (-1); 11298c2ecf20Sopenharmony_ci if (symlist) { 11308c2ecf20Sopenharmony_ci if (symdepth && firstsym) 11318c2ecf20Sopenharmony_ci printf("%s%3d", zerosyms ? "" : "\n", depth); 11328c2ecf20Sopenharmony_ci firstsym = zerosyms = false; 11338c2ecf20Sopenharmony_ci printf("%s%.*s%s", 11348c2ecf20Sopenharmony_ci symdepth ? " " : "", 11358c2ecf20Sopenharmony_ci (int)(cp-str), str, 11368c2ecf20Sopenharmony_ci symdepth ? "" : "\n"); 11378c2ecf20Sopenharmony_ci /* we don't care about the value of the symbol */ 11388c2ecf20Sopenharmony_ci return (0); 11398c2ecf20Sopenharmony_ci } 11408c2ecf20Sopenharmony_ci for (symind = 0; symind < nsyms; ++symind) { 11418c2ecf20Sopenharmony_ci if (strlcmp(symname[symind], str, cp-str) == 0) { 11428c2ecf20Sopenharmony_ci debug("findsym %s %s", symname[symind], 11438c2ecf20Sopenharmony_ci value[symind] ? value[symind] : ""); 11448c2ecf20Sopenharmony_ci return (symind); 11458c2ecf20Sopenharmony_ci } 11468c2ecf20Sopenharmony_ci } 11478c2ecf20Sopenharmony_ci return (-1); 11488c2ecf20Sopenharmony_ci} 11498c2ecf20Sopenharmony_ci 11508c2ecf20Sopenharmony_ci/* 11518c2ecf20Sopenharmony_ci * Add a symbol to the symbol table. 11528c2ecf20Sopenharmony_ci */ 11538c2ecf20Sopenharmony_cistatic void 11548c2ecf20Sopenharmony_ciaddsym(bool ignorethis, bool definethis, char *sym) 11558c2ecf20Sopenharmony_ci{ 11568c2ecf20Sopenharmony_ci int symind; 11578c2ecf20Sopenharmony_ci char *val; 11588c2ecf20Sopenharmony_ci 11598c2ecf20Sopenharmony_ci symind = findsym(sym); 11608c2ecf20Sopenharmony_ci if (symind < 0) { 11618c2ecf20Sopenharmony_ci if (nsyms >= MAXSYMS) 11628c2ecf20Sopenharmony_ci errx(2, "too many symbols"); 11638c2ecf20Sopenharmony_ci symind = nsyms++; 11648c2ecf20Sopenharmony_ci } 11658c2ecf20Sopenharmony_ci symname[symind] = sym; 11668c2ecf20Sopenharmony_ci ignore[symind] = ignorethis; 11678c2ecf20Sopenharmony_ci val = sym + (skipsym(sym) - sym); 11688c2ecf20Sopenharmony_ci if (definethis) { 11698c2ecf20Sopenharmony_ci if (*val == '=') { 11708c2ecf20Sopenharmony_ci value[symind] = val+1; 11718c2ecf20Sopenharmony_ci *val = '\0'; 11728c2ecf20Sopenharmony_ci } else if (*val == '\0') 11738c2ecf20Sopenharmony_ci value[symind] = "1"; 11748c2ecf20Sopenharmony_ci else 11758c2ecf20Sopenharmony_ci usage(); 11768c2ecf20Sopenharmony_ci } else { 11778c2ecf20Sopenharmony_ci if (*val != '\0') 11788c2ecf20Sopenharmony_ci usage(); 11798c2ecf20Sopenharmony_ci value[symind] = NULL; 11808c2ecf20Sopenharmony_ci } 11818c2ecf20Sopenharmony_ci debug("addsym %s=%s", symname[symind], 11828c2ecf20Sopenharmony_ci value[symind] ? value[symind] : "undef"); 11838c2ecf20Sopenharmony_ci} 11848c2ecf20Sopenharmony_ci 11858c2ecf20Sopenharmony_ci/* 11868c2ecf20Sopenharmony_ci * Compare s with n characters of t. 11878c2ecf20Sopenharmony_ci * The same as strncmp() except that it checks that s[n] == '\0'. 11888c2ecf20Sopenharmony_ci */ 11898c2ecf20Sopenharmony_cistatic int 11908c2ecf20Sopenharmony_cistrlcmp(const char *s, const char *t, size_t n) 11918c2ecf20Sopenharmony_ci{ 11928c2ecf20Sopenharmony_ci while (n-- && *t != '\0') 11938c2ecf20Sopenharmony_ci if (*s != *t) 11948c2ecf20Sopenharmony_ci return ((unsigned char)*s - (unsigned char)*t); 11958c2ecf20Sopenharmony_ci else 11968c2ecf20Sopenharmony_ci ++s, ++t; 11978c2ecf20Sopenharmony_ci return ((unsigned char)*s); 11988c2ecf20Sopenharmony_ci} 11998c2ecf20Sopenharmony_ci 12008c2ecf20Sopenharmony_ci/* 12018c2ecf20Sopenharmony_ci * Diagnostics. 12028c2ecf20Sopenharmony_ci */ 12038c2ecf20Sopenharmony_cistatic void 12048c2ecf20Sopenharmony_cidebug(const char *msg, ...) 12058c2ecf20Sopenharmony_ci{ 12068c2ecf20Sopenharmony_ci va_list ap; 12078c2ecf20Sopenharmony_ci 12088c2ecf20Sopenharmony_ci if (debugging) { 12098c2ecf20Sopenharmony_ci va_start(ap, msg); 12108c2ecf20Sopenharmony_ci vwarnx(msg, ap); 12118c2ecf20Sopenharmony_ci va_end(ap); 12128c2ecf20Sopenharmony_ci } 12138c2ecf20Sopenharmony_ci} 12148c2ecf20Sopenharmony_ci 12158c2ecf20Sopenharmony_cistatic void 12168c2ecf20Sopenharmony_cierror(const char *msg) 12178c2ecf20Sopenharmony_ci{ 12188c2ecf20Sopenharmony_ci if (depth == 0) 12198c2ecf20Sopenharmony_ci warnx("%s: %d: %s", filename, linenum, msg); 12208c2ecf20Sopenharmony_ci else 12218c2ecf20Sopenharmony_ci warnx("%s: %d: %s (#if line %d depth %d)", 12228c2ecf20Sopenharmony_ci filename, linenum, msg, stifline[depth], depth); 12238c2ecf20Sopenharmony_ci closeout(); 12248c2ecf20Sopenharmony_ci errx(2, "output may be truncated"); 12258c2ecf20Sopenharmony_ci} 1226