162306a36Sopenharmony_ci/* 262306a36Sopenharmony_ci * Copyright (c) 2002 - 2011 Tony Finch <dot@dotat.at> 362306a36Sopenharmony_ci * 462306a36Sopenharmony_ci * Redistribution and use in source and binary forms, with or without 562306a36Sopenharmony_ci * modification, are permitted provided that the following conditions 662306a36Sopenharmony_ci * are met: 762306a36Sopenharmony_ci * 1. Redistributions of source code must retain the above copyright 862306a36Sopenharmony_ci * notice, this list of conditions and the following disclaimer. 962306a36Sopenharmony_ci * 2. Redistributions in binary form must reproduce the above copyright 1062306a36Sopenharmony_ci * notice, this list of conditions and the following disclaimer in the 1162306a36Sopenharmony_ci * documentation and/or other materials provided with the distribution. 1262306a36Sopenharmony_ci * 1362306a36Sopenharmony_ci * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 1462306a36Sopenharmony_ci * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 1562306a36Sopenharmony_ci * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 1662306a36Sopenharmony_ci * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 1762306a36Sopenharmony_ci * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 1862306a36Sopenharmony_ci * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 1962306a36Sopenharmony_ci * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2062306a36Sopenharmony_ci * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2162306a36Sopenharmony_ci * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2262306a36Sopenharmony_ci * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2362306a36Sopenharmony_ci * SUCH DAMAGE. 2462306a36Sopenharmony_ci */ 2562306a36Sopenharmony_ci 2662306a36Sopenharmony_ci/* 2762306a36Sopenharmony_ci * unifdef - remove ifdef'ed lines 2862306a36Sopenharmony_ci * 2962306a36Sopenharmony_ci * This code was derived from software contributed to Berkeley by Dave Yost. 3062306a36Sopenharmony_ci * It was rewritten to support ANSI C by Tony Finch. The original version 3162306a36Sopenharmony_ci * of unifdef carried the 4-clause BSD copyright licence. None of its code 3262306a36Sopenharmony_ci * remains in this version (though some of the names remain) so it now 3362306a36Sopenharmony_ci * carries a more liberal licence. 3462306a36Sopenharmony_ci * 3562306a36Sopenharmony_ci * Wishlist: 3662306a36Sopenharmony_ci * provide an option which will append the name of the 3762306a36Sopenharmony_ci * appropriate symbol after #else's and #endif's 3862306a36Sopenharmony_ci * provide an option which will check symbols after 3962306a36Sopenharmony_ci * #else's and #endif's to see that they match their 4062306a36Sopenharmony_ci * corresponding #ifdef or #ifndef 4162306a36Sopenharmony_ci * 4262306a36Sopenharmony_ci * These require better buffer handling, which would also make 4362306a36Sopenharmony_ci * it possible to handle all "dodgy" directives correctly. 4462306a36Sopenharmony_ci */ 4562306a36Sopenharmony_ci 4662306a36Sopenharmony_ci#include <sys/types.h> 4762306a36Sopenharmony_ci#include <sys/stat.h> 4862306a36Sopenharmony_ci 4962306a36Sopenharmony_ci#include <ctype.h> 5062306a36Sopenharmony_ci#include <err.h> 5162306a36Sopenharmony_ci#include <errno.h> 5262306a36Sopenharmony_ci#include <stdarg.h> 5362306a36Sopenharmony_ci#include <stdbool.h> 5462306a36Sopenharmony_ci#include <stdio.h> 5562306a36Sopenharmony_ci#include <stdlib.h> 5662306a36Sopenharmony_ci#include <string.h> 5762306a36Sopenharmony_ci#include <unistd.h> 5862306a36Sopenharmony_ci 5962306a36Sopenharmony_ciconst char copyright[] = 6062306a36Sopenharmony_ci "@(#) $Version: unifdef-2.5 $\n" 6162306a36Sopenharmony_ci "@(#) $Author: Tony Finch (dot@dotat.at) $\n" 6262306a36Sopenharmony_ci "@(#) $URL: http://dotat.at/prog/unifdef $\n" 6362306a36Sopenharmony_ci; 6462306a36Sopenharmony_ci 6562306a36Sopenharmony_ci/* types of input lines: */ 6662306a36Sopenharmony_citypedef enum { 6762306a36Sopenharmony_ci LT_TRUEI, /* a true #if with ignore flag */ 6862306a36Sopenharmony_ci LT_FALSEI, /* a false #if with ignore flag */ 6962306a36Sopenharmony_ci LT_IF, /* an unknown #if */ 7062306a36Sopenharmony_ci LT_TRUE, /* a true #if */ 7162306a36Sopenharmony_ci LT_FALSE, /* a false #if */ 7262306a36Sopenharmony_ci LT_ELIF, /* an unknown #elif */ 7362306a36Sopenharmony_ci LT_ELTRUE, /* a true #elif */ 7462306a36Sopenharmony_ci LT_ELFALSE, /* a false #elif */ 7562306a36Sopenharmony_ci LT_ELSE, /* #else */ 7662306a36Sopenharmony_ci LT_ENDIF, /* #endif */ 7762306a36Sopenharmony_ci LT_DODGY, /* flag: directive is not on one line */ 7862306a36Sopenharmony_ci LT_DODGY_LAST = LT_DODGY + LT_ENDIF, 7962306a36Sopenharmony_ci LT_PLAIN, /* ordinary line */ 8062306a36Sopenharmony_ci LT_EOF, /* end of file */ 8162306a36Sopenharmony_ci LT_ERROR, /* unevaluable #if */ 8262306a36Sopenharmony_ci LT_COUNT 8362306a36Sopenharmony_ci} Linetype; 8462306a36Sopenharmony_ci 8562306a36Sopenharmony_cistatic char const * const linetype_name[] = { 8662306a36Sopenharmony_ci "TRUEI", "FALSEI", "IF", "TRUE", "FALSE", 8762306a36Sopenharmony_ci "ELIF", "ELTRUE", "ELFALSE", "ELSE", "ENDIF", 8862306a36Sopenharmony_ci "DODGY TRUEI", "DODGY FALSEI", 8962306a36Sopenharmony_ci "DODGY IF", "DODGY TRUE", "DODGY FALSE", 9062306a36Sopenharmony_ci "DODGY ELIF", "DODGY ELTRUE", "DODGY ELFALSE", 9162306a36Sopenharmony_ci "DODGY ELSE", "DODGY ENDIF", 9262306a36Sopenharmony_ci "PLAIN", "EOF", "ERROR" 9362306a36Sopenharmony_ci}; 9462306a36Sopenharmony_ci 9562306a36Sopenharmony_ci/* state of #if processing */ 9662306a36Sopenharmony_citypedef enum { 9762306a36Sopenharmony_ci IS_OUTSIDE, 9862306a36Sopenharmony_ci IS_FALSE_PREFIX, /* false #if followed by false #elifs */ 9962306a36Sopenharmony_ci IS_TRUE_PREFIX, /* first non-false #(el)if is true */ 10062306a36Sopenharmony_ci IS_PASS_MIDDLE, /* first non-false #(el)if is unknown */ 10162306a36Sopenharmony_ci IS_FALSE_MIDDLE, /* a false #elif after a pass state */ 10262306a36Sopenharmony_ci IS_TRUE_MIDDLE, /* a true #elif after a pass state */ 10362306a36Sopenharmony_ci IS_PASS_ELSE, /* an else after a pass state */ 10462306a36Sopenharmony_ci IS_FALSE_ELSE, /* an else after a true state */ 10562306a36Sopenharmony_ci IS_TRUE_ELSE, /* an else after only false states */ 10662306a36Sopenharmony_ci IS_FALSE_TRAILER, /* #elifs after a true are false */ 10762306a36Sopenharmony_ci IS_COUNT 10862306a36Sopenharmony_ci} Ifstate; 10962306a36Sopenharmony_ci 11062306a36Sopenharmony_cistatic char const * const ifstate_name[] = { 11162306a36Sopenharmony_ci "OUTSIDE", "FALSE_PREFIX", "TRUE_PREFIX", 11262306a36Sopenharmony_ci "PASS_MIDDLE", "FALSE_MIDDLE", "TRUE_MIDDLE", 11362306a36Sopenharmony_ci "PASS_ELSE", "FALSE_ELSE", "TRUE_ELSE", 11462306a36Sopenharmony_ci "FALSE_TRAILER" 11562306a36Sopenharmony_ci}; 11662306a36Sopenharmony_ci 11762306a36Sopenharmony_ci/* state of comment parser */ 11862306a36Sopenharmony_citypedef enum { 11962306a36Sopenharmony_ci NO_COMMENT = false, /* outside a comment */ 12062306a36Sopenharmony_ci C_COMMENT, /* in a comment like this one */ 12162306a36Sopenharmony_ci CXX_COMMENT, /* between // and end of line */ 12262306a36Sopenharmony_ci STARTING_COMMENT, /* just after slash-backslash-newline */ 12362306a36Sopenharmony_ci FINISHING_COMMENT, /* star-backslash-newline in a C comment */ 12462306a36Sopenharmony_ci CHAR_LITERAL, /* inside '' */ 12562306a36Sopenharmony_ci STRING_LITERAL /* inside "" */ 12662306a36Sopenharmony_ci} Comment_state; 12762306a36Sopenharmony_ci 12862306a36Sopenharmony_cistatic char const * const comment_name[] = { 12962306a36Sopenharmony_ci "NO", "C", "CXX", "STARTING", "FINISHING", "CHAR", "STRING" 13062306a36Sopenharmony_ci}; 13162306a36Sopenharmony_ci 13262306a36Sopenharmony_ci/* state of preprocessor line parser */ 13362306a36Sopenharmony_citypedef enum { 13462306a36Sopenharmony_ci LS_START, /* only space and comments on this line */ 13562306a36Sopenharmony_ci LS_HASH, /* only space, comments, and a hash */ 13662306a36Sopenharmony_ci LS_DIRTY /* this line can't be a preprocessor line */ 13762306a36Sopenharmony_ci} Line_state; 13862306a36Sopenharmony_ci 13962306a36Sopenharmony_cistatic char const * const linestate_name[] = { 14062306a36Sopenharmony_ci "START", "HASH", "DIRTY" 14162306a36Sopenharmony_ci}; 14262306a36Sopenharmony_ci 14362306a36Sopenharmony_ci/* 14462306a36Sopenharmony_ci * Minimum translation limits from ISO/IEC 9899:1999 5.2.4.1 14562306a36Sopenharmony_ci */ 14662306a36Sopenharmony_ci#define MAXDEPTH 64 /* maximum #if nesting */ 14762306a36Sopenharmony_ci#define MAXLINE 4096 /* maximum length of line */ 14862306a36Sopenharmony_ci#define MAXSYMS 4096 /* maximum number of symbols */ 14962306a36Sopenharmony_ci 15062306a36Sopenharmony_ci/* 15162306a36Sopenharmony_ci * Sometimes when editing a keyword the replacement text is longer, so 15262306a36Sopenharmony_ci * we leave some space at the end of the tline buffer to accommodate this. 15362306a36Sopenharmony_ci */ 15462306a36Sopenharmony_ci#define EDITSLOP 10 15562306a36Sopenharmony_ci 15662306a36Sopenharmony_ci/* 15762306a36Sopenharmony_ci * For temporary filenames 15862306a36Sopenharmony_ci */ 15962306a36Sopenharmony_ci#define TEMPLATE "unifdef.XXXXXX" 16062306a36Sopenharmony_ci 16162306a36Sopenharmony_ci/* 16262306a36Sopenharmony_ci * Globals. 16362306a36Sopenharmony_ci */ 16462306a36Sopenharmony_ci 16562306a36Sopenharmony_cistatic bool compblank; /* -B: compress blank lines */ 16662306a36Sopenharmony_cistatic bool lnblank; /* -b: blank deleted lines */ 16762306a36Sopenharmony_cistatic bool complement; /* -c: do the complement */ 16862306a36Sopenharmony_cistatic bool debugging; /* -d: debugging reports */ 16962306a36Sopenharmony_cistatic bool iocccok; /* -e: fewer IOCCC errors */ 17062306a36Sopenharmony_cistatic bool strictlogic; /* -K: keep ambiguous #ifs */ 17162306a36Sopenharmony_cistatic bool killconsts; /* -k: eval constant #ifs */ 17262306a36Sopenharmony_cistatic bool lnnum; /* -n: add #line directives */ 17362306a36Sopenharmony_cistatic bool symlist; /* -s: output symbol list */ 17462306a36Sopenharmony_cistatic bool symdepth; /* -S: output symbol depth */ 17562306a36Sopenharmony_cistatic bool text; /* -t: this is a text file */ 17662306a36Sopenharmony_ci 17762306a36Sopenharmony_cistatic const char *symname[MAXSYMS]; /* symbol name */ 17862306a36Sopenharmony_cistatic const char *value[MAXSYMS]; /* -Dsym=value */ 17962306a36Sopenharmony_cistatic bool ignore[MAXSYMS]; /* -iDsym or -iUsym */ 18062306a36Sopenharmony_cistatic int nsyms; /* number of symbols */ 18162306a36Sopenharmony_ci 18262306a36Sopenharmony_cistatic FILE *input; /* input file pointer */ 18362306a36Sopenharmony_cistatic const char *filename; /* input file name */ 18462306a36Sopenharmony_cistatic int linenum; /* current line number */ 18562306a36Sopenharmony_cistatic FILE *output; /* output file pointer */ 18662306a36Sopenharmony_cistatic const char *ofilename; /* output file name */ 18762306a36Sopenharmony_cistatic bool overwriting; /* output overwrites input */ 18862306a36Sopenharmony_cistatic char tempname[FILENAME_MAX]; /* used when overwriting */ 18962306a36Sopenharmony_ci 19062306a36Sopenharmony_cistatic char tline[MAXLINE+EDITSLOP];/* input buffer plus space */ 19162306a36Sopenharmony_cistatic char *keyword; /* used for editing #elif's */ 19262306a36Sopenharmony_ci 19362306a36Sopenharmony_cistatic const char *newline; /* input file format */ 19462306a36Sopenharmony_cistatic const char newline_unix[] = "\n"; 19562306a36Sopenharmony_cistatic const char newline_crlf[] = "\r\n"; 19662306a36Sopenharmony_ci 19762306a36Sopenharmony_cistatic Comment_state incomment; /* comment parser state */ 19862306a36Sopenharmony_cistatic Line_state linestate; /* #if line parser state */ 19962306a36Sopenharmony_cistatic Ifstate ifstate[MAXDEPTH]; /* #if processor state */ 20062306a36Sopenharmony_cistatic bool ignoring[MAXDEPTH]; /* ignore comments state */ 20162306a36Sopenharmony_cistatic int stifline[MAXDEPTH]; /* start of current #if */ 20262306a36Sopenharmony_cistatic int depth; /* current #if nesting */ 20362306a36Sopenharmony_cistatic int delcount; /* count of deleted lines */ 20462306a36Sopenharmony_cistatic unsigned blankcount; /* count of blank lines */ 20562306a36Sopenharmony_cistatic unsigned blankmax; /* maximum recent blankcount */ 20662306a36Sopenharmony_cistatic bool constexpr; /* constant #if expression */ 20762306a36Sopenharmony_cistatic bool zerosyms = true; /* to format symdepth output */ 20862306a36Sopenharmony_cistatic bool firstsym; /* ditto */ 20962306a36Sopenharmony_ci 21062306a36Sopenharmony_cistatic int exitstat; /* program exit status */ 21162306a36Sopenharmony_ci 21262306a36Sopenharmony_cistatic void addsym(bool, bool, char *); 21362306a36Sopenharmony_cistatic void closeout(void); 21462306a36Sopenharmony_cistatic void debug(const char *, ...); 21562306a36Sopenharmony_cistatic void done(void); 21662306a36Sopenharmony_cistatic void error(const char *); 21762306a36Sopenharmony_cistatic int findsym(const char *); 21862306a36Sopenharmony_cistatic void flushline(bool); 21962306a36Sopenharmony_cistatic Linetype parseline(void); 22062306a36Sopenharmony_cistatic Linetype ifeval(const char **); 22162306a36Sopenharmony_cistatic void ignoreoff(void); 22262306a36Sopenharmony_cistatic void ignoreon(void); 22362306a36Sopenharmony_cistatic void keywordedit(const char *); 22462306a36Sopenharmony_cistatic void nest(void); 22562306a36Sopenharmony_cistatic void process(void); 22662306a36Sopenharmony_cistatic const char *skipargs(const char *); 22762306a36Sopenharmony_cistatic const char *skipcomment(const char *); 22862306a36Sopenharmony_cistatic const char *skipsym(const char *); 22962306a36Sopenharmony_cistatic void state(Ifstate); 23062306a36Sopenharmony_cistatic int strlcmp(const char *, const char *, size_t); 23162306a36Sopenharmony_cistatic void unnest(void); 23262306a36Sopenharmony_cistatic void usage(void); 23362306a36Sopenharmony_cistatic void version(void); 23462306a36Sopenharmony_ci 23562306a36Sopenharmony_ci#define endsym(c) (!isalnum((unsigned char)c) && c != '_') 23662306a36Sopenharmony_ci 23762306a36Sopenharmony_ci/* 23862306a36Sopenharmony_ci * The main program. 23962306a36Sopenharmony_ci */ 24062306a36Sopenharmony_ciint 24162306a36Sopenharmony_cimain(int argc, char *argv[]) 24262306a36Sopenharmony_ci{ 24362306a36Sopenharmony_ci int opt; 24462306a36Sopenharmony_ci 24562306a36Sopenharmony_ci while ((opt = getopt(argc, argv, "i:D:U:I:o:bBcdeKklnsStV")) != -1) 24662306a36Sopenharmony_ci switch (opt) { 24762306a36Sopenharmony_ci case 'i': /* treat stuff controlled by these symbols as text */ 24862306a36Sopenharmony_ci /* 24962306a36Sopenharmony_ci * For strict backwards-compatibility the U or D 25062306a36Sopenharmony_ci * should be immediately after the -i but it doesn't 25162306a36Sopenharmony_ci * matter much if we relax that requirement. 25262306a36Sopenharmony_ci */ 25362306a36Sopenharmony_ci opt = *optarg++; 25462306a36Sopenharmony_ci if (opt == 'D') 25562306a36Sopenharmony_ci addsym(true, true, optarg); 25662306a36Sopenharmony_ci else if (opt == 'U') 25762306a36Sopenharmony_ci addsym(true, false, optarg); 25862306a36Sopenharmony_ci else 25962306a36Sopenharmony_ci usage(); 26062306a36Sopenharmony_ci break; 26162306a36Sopenharmony_ci case 'D': /* define a symbol */ 26262306a36Sopenharmony_ci addsym(false, true, optarg); 26362306a36Sopenharmony_ci break; 26462306a36Sopenharmony_ci case 'U': /* undef a symbol */ 26562306a36Sopenharmony_ci addsym(false, false, optarg); 26662306a36Sopenharmony_ci break; 26762306a36Sopenharmony_ci case 'I': /* no-op for compatibility with cpp */ 26862306a36Sopenharmony_ci break; 26962306a36Sopenharmony_ci case 'b': /* blank deleted lines instead of omitting them */ 27062306a36Sopenharmony_ci case 'l': /* backwards compatibility */ 27162306a36Sopenharmony_ci lnblank = true; 27262306a36Sopenharmony_ci break; 27362306a36Sopenharmony_ci case 'B': /* compress blank lines around removed section */ 27462306a36Sopenharmony_ci compblank = true; 27562306a36Sopenharmony_ci break; 27662306a36Sopenharmony_ci case 'c': /* treat -D as -U and vice versa */ 27762306a36Sopenharmony_ci complement = true; 27862306a36Sopenharmony_ci break; 27962306a36Sopenharmony_ci case 'd': 28062306a36Sopenharmony_ci debugging = true; 28162306a36Sopenharmony_ci break; 28262306a36Sopenharmony_ci case 'e': /* fewer errors from dodgy lines */ 28362306a36Sopenharmony_ci iocccok = true; 28462306a36Sopenharmony_ci break; 28562306a36Sopenharmony_ci case 'K': /* keep ambiguous #ifs */ 28662306a36Sopenharmony_ci strictlogic = true; 28762306a36Sopenharmony_ci break; 28862306a36Sopenharmony_ci case 'k': /* process constant #ifs */ 28962306a36Sopenharmony_ci killconsts = true; 29062306a36Sopenharmony_ci break; 29162306a36Sopenharmony_ci case 'n': /* add #line directive after deleted lines */ 29262306a36Sopenharmony_ci lnnum = true; 29362306a36Sopenharmony_ci break; 29462306a36Sopenharmony_ci case 'o': /* output to a file */ 29562306a36Sopenharmony_ci ofilename = optarg; 29662306a36Sopenharmony_ci break; 29762306a36Sopenharmony_ci case 's': /* only output list of symbols that control #ifs */ 29862306a36Sopenharmony_ci symlist = true; 29962306a36Sopenharmony_ci break; 30062306a36Sopenharmony_ci case 'S': /* list symbols with their nesting depth */ 30162306a36Sopenharmony_ci symlist = symdepth = true; 30262306a36Sopenharmony_ci break; 30362306a36Sopenharmony_ci case 't': /* don't parse C comments */ 30462306a36Sopenharmony_ci text = true; 30562306a36Sopenharmony_ci break; 30662306a36Sopenharmony_ci case 'V': /* print version */ 30762306a36Sopenharmony_ci version(); 30862306a36Sopenharmony_ci default: 30962306a36Sopenharmony_ci usage(); 31062306a36Sopenharmony_ci } 31162306a36Sopenharmony_ci argc -= optind; 31262306a36Sopenharmony_ci argv += optind; 31362306a36Sopenharmony_ci if (compblank && lnblank) 31462306a36Sopenharmony_ci errx(2, "-B and -b are mutually exclusive"); 31562306a36Sopenharmony_ci if (argc > 1) { 31662306a36Sopenharmony_ci errx(2, "can only do one file"); 31762306a36Sopenharmony_ci } else if (argc == 1 && strcmp(*argv, "-") != 0) { 31862306a36Sopenharmony_ci filename = *argv; 31962306a36Sopenharmony_ci input = fopen(filename, "rb"); 32062306a36Sopenharmony_ci if (input == NULL) 32162306a36Sopenharmony_ci err(2, "can't open %s", filename); 32262306a36Sopenharmony_ci } else { 32362306a36Sopenharmony_ci filename = "[stdin]"; 32462306a36Sopenharmony_ci input = stdin; 32562306a36Sopenharmony_ci } 32662306a36Sopenharmony_ci if (ofilename == NULL) { 32762306a36Sopenharmony_ci ofilename = "[stdout]"; 32862306a36Sopenharmony_ci output = stdout; 32962306a36Sopenharmony_ci } else { 33062306a36Sopenharmony_ci struct stat ist, ost; 33162306a36Sopenharmony_ci if (stat(ofilename, &ost) == 0 && 33262306a36Sopenharmony_ci fstat(fileno(input), &ist) == 0) 33362306a36Sopenharmony_ci overwriting = (ist.st_dev == ost.st_dev 33462306a36Sopenharmony_ci && ist.st_ino == ost.st_ino); 33562306a36Sopenharmony_ci if (overwriting) { 33662306a36Sopenharmony_ci const char *dirsep; 33762306a36Sopenharmony_ci int ofd; 33862306a36Sopenharmony_ci 33962306a36Sopenharmony_ci dirsep = strrchr(ofilename, '/'); 34062306a36Sopenharmony_ci if (dirsep != NULL) 34162306a36Sopenharmony_ci snprintf(tempname, sizeof(tempname), 34262306a36Sopenharmony_ci "%.*s/" TEMPLATE, 34362306a36Sopenharmony_ci (int)(dirsep - ofilename), ofilename); 34462306a36Sopenharmony_ci else 34562306a36Sopenharmony_ci snprintf(tempname, sizeof(tempname), 34662306a36Sopenharmony_ci TEMPLATE); 34762306a36Sopenharmony_ci ofd = mkstemp(tempname); 34862306a36Sopenharmony_ci if (ofd != -1) 34962306a36Sopenharmony_ci output = fdopen(ofd, "wb+"); 35062306a36Sopenharmony_ci if (output == NULL) 35162306a36Sopenharmony_ci err(2, "can't create temporary file"); 35262306a36Sopenharmony_ci fchmod(ofd, ist.st_mode & (S_IRWXU|S_IRWXG|S_IRWXO)); 35362306a36Sopenharmony_ci } else { 35462306a36Sopenharmony_ci output = fopen(ofilename, "wb"); 35562306a36Sopenharmony_ci if (output == NULL) 35662306a36Sopenharmony_ci err(2, "can't open %s", ofilename); 35762306a36Sopenharmony_ci } 35862306a36Sopenharmony_ci } 35962306a36Sopenharmony_ci process(); 36062306a36Sopenharmony_ci abort(); /* bug */ 36162306a36Sopenharmony_ci} 36262306a36Sopenharmony_ci 36362306a36Sopenharmony_cistatic void 36462306a36Sopenharmony_civersion(void) 36562306a36Sopenharmony_ci{ 36662306a36Sopenharmony_ci const char *c = copyright; 36762306a36Sopenharmony_ci for (;;) { 36862306a36Sopenharmony_ci while (*++c != '$') 36962306a36Sopenharmony_ci if (*c == '\0') 37062306a36Sopenharmony_ci exit(0); 37162306a36Sopenharmony_ci while (*++c != '$') 37262306a36Sopenharmony_ci putc(*c, stderr); 37362306a36Sopenharmony_ci putc('\n', stderr); 37462306a36Sopenharmony_ci } 37562306a36Sopenharmony_ci} 37662306a36Sopenharmony_ci 37762306a36Sopenharmony_cistatic void 37862306a36Sopenharmony_ciusage(void) 37962306a36Sopenharmony_ci{ 38062306a36Sopenharmony_ci fprintf(stderr, "usage: unifdef [-bBcdeKknsStV] [-Ipath]" 38162306a36Sopenharmony_ci " [-Dsym[=val]] [-Usym] [-iDsym[=val]] [-iUsym] ... [file]\n"); 38262306a36Sopenharmony_ci exit(2); 38362306a36Sopenharmony_ci} 38462306a36Sopenharmony_ci 38562306a36Sopenharmony_ci/* 38662306a36Sopenharmony_ci * A state transition function alters the global #if processing state 38762306a36Sopenharmony_ci * in a particular way. The table below is indexed by the current 38862306a36Sopenharmony_ci * processing state and the type of the current line. 38962306a36Sopenharmony_ci * 39062306a36Sopenharmony_ci * Nesting is handled by keeping a stack of states; some transition 39162306a36Sopenharmony_ci * functions increase or decrease the depth. They also maintain the 39262306a36Sopenharmony_ci * ignore state on a stack. In some complicated cases they have to 39362306a36Sopenharmony_ci * alter the preprocessor directive, as follows. 39462306a36Sopenharmony_ci * 39562306a36Sopenharmony_ci * When we have processed a group that starts off with a known-false 39662306a36Sopenharmony_ci * #if/#elif sequence (which has therefore been deleted) followed by a 39762306a36Sopenharmony_ci * #elif that we don't understand and therefore must keep, we edit the 39862306a36Sopenharmony_ci * latter into a #if to keep the nesting correct. We use memcpy() to 39962306a36Sopenharmony_ci * overwrite the 4 byte token "elif" with "if " without a '\0' byte. 40062306a36Sopenharmony_ci * 40162306a36Sopenharmony_ci * When we find a true #elif in a group, the following block will 40262306a36Sopenharmony_ci * always be kept and the rest of the sequence after the next #elif or 40362306a36Sopenharmony_ci * #else will be discarded. We edit the #elif into a #else and the 40462306a36Sopenharmony_ci * following directive to #endif since this has the desired behaviour. 40562306a36Sopenharmony_ci * 40662306a36Sopenharmony_ci * "Dodgy" directives are split across multiple lines, the most common 40762306a36Sopenharmony_ci * example being a multi-line comment hanging off the right of the 40862306a36Sopenharmony_ci * directive. We can handle them correctly only if there is no change 40962306a36Sopenharmony_ci * from printing to dropping (or vice versa) caused by that directive. 41062306a36Sopenharmony_ci * If the directive is the first of a group we have a choice between 41162306a36Sopenharmony_ci * failing with an error, or passing it through unchanged instead of 41262306a36Sopenharmony_ci * evaluating it. The latter is not the default to avoid questions from 41362306a36Sopenharmony_ci * users about unifdef unexpectedly leaving behind preprocessor directives. 41462306a36Sopenharmony_ci */ 41562306a36Sopenharmony_citypedef void state_fn(void); 41662306a36Sopenharmony_ci 41762306a36Sopenharmony_ci/* report an error */ 41862306a36Sopenharmony_cistatic void Eelif (void) { error("Inappropriate #elif"); } 41962306a36Sopenharmony_cistatic void Eelse (void) { error("Inappropriate #else"); } 42062306a36Sopenharmony_cistatic void Eendif(void) { error("Inappropriate #endif"); } 42162306a36Sopenharmony_cistatic void Eeof (void) { error("Premature EOF"); } 42262306a36Sopenharmony_cistatic void Eioccc(void) { error("Obfuscated preprocessor control line"); } 42362306a36Sopenharmony_ci/* plain line handling */ 42462306a36Sopenharmony_cistatic void print (void) { flushline(true); } 42562306a36Sopenharmony_cistatic void drop (void) { flushline(false); } 42662306a36Sopenharmony_ci/* output lacks group's start line */ 42762306a36Sopenharmony_cistatic void Strue (void) { drop(); ignoreoff(); state(IS_TRUE_PREFIX); } 42862306a36Sopenharmony_cistatic void Sfalse(void) { drop(); ignoreoff(); state(IS_FALSE_PREFIX); } 42962306a36Sopenharmony_cistatic void Selse (void) { drop(); state(IS_TRUE_ELSE); } 43062306a36Sopenharmony_ci/* print/pass this block */ 43162306a36Sopenharmony_cistatic void Pelif (void) { print(); ignoreoff(); state(IS_PASS_MIDDLE); } 43262306a36Sopenharmony_cistatic void Pelse (void) { print(); state(IS_PASS_ELSE); } 43362306a36Sopenharmony_cistatic void Pendif(void) { print(); unnest(); } 43462306a36Sopenharmony_ci/* discard this block */ 43562306a36Sopenharmony_cistatic void Dfalse(void) { drop(); ignoreoff(); state(IS_FALSE_TRAILER); } 43662306a36Sopenharmony_cistatic void Delif (void) { drop(); ignoreoff(); state(IS_FALSE_MIDDLE); } 43762306a36Sopenharmony_cistatic void Delse (void) { drop(); state(IS_FALSE_ELSE); } 43862306a36Sopenharmony_cistatic void Dendif(void) { drop(); unnest(); } 43962306a36Sopenharmony_ci/* first line of group */ 44062306a36Sopenharmony_cistatic void Fdrop (void) { nest(); Dfalse(); } 44162306a36Sopenharmony_cistatic void Fpass (void) { nest(); Pelif(); } 44262306a36Sopenharmony_cistatic void Ftrue (void) { nest(); Strue(); } 44362306a36Sopenharmony_cistatic void Ffalse(void) { nest(); Sfalse(); } 44462306a36Sopenharmony_ci/* variable pedantry for obfuscated lines */ 44562306a36Sopenharmony_cistatic void Oiffy (void) { if (!iocccok) Eioccc(); Fpass(); ignoreon(); } 44662306a36Sopenharmony_cistatic void Oif (void) { if (!iocccok) Eioccc(); Fpass(); } 44762306a36Sopenharmony_cistatic void Oelif (void) { if (!iocccok) Eioccc(); Pelif(); } 44862306a36Sopenharmony_ci/* ignore comments in this block */ 44962306a36Sopenharmony_cistatic void Idrop (void) { Fdrop(); ignoreon(); } 45062306a36Sopenharmony_cistatic void Itrue (void) { Ftrue(); ignoreon(); } 45162306a36Sopenharmony_cistatic void Ifalse(void) { Ffalse(); ignoreon(); } 45262306a36Sopenharmony_ci/* modify this line */ 45362306a36Sopenharmony_cistatic void Mpass (void) { memcpy(keyword, "if ", 4); Pelif(); } 45462306a36Sopenharmony_cistatic void Mtrue (void) { keywordedit("else"); state(IS_TRUE_MIDDLE); } 45562306a36Sopenharmony_cistatic void Melif (void) { keywordedit("endif"); state(IS_FALSE_TRAILER); } 45662306a36Sopenharmony_cistatic void Melse (void) { keywordedit("endif"); state(IS_FALSE_ELSE); } 45762306a36Sopenharmony_ci 45862306a36Sopenharmony_cistatic state_fn * const trans_table[IS_COUNT][LT_COUNT] = { 45962306a36Sopenharmony_ci/* IS_OUTSIDE */ 46062306a36Sopenharmony_ci{ Itrue, Ifalse,Fpass, Ftrue, Ffalse,Eelif, Eelif, Eelif, Eelse, Eendif, 46162306a36Sopenharmony_ci Oiffy, Oiffy, Fpass, Oif, Oif, Eelif, Eelif, Eelif, Eelse, Eendif, 46262306a36Sopenharmony_ci print, done, abort }, 46362306a36Sopenharmony_ci/* IS_FALSE_PREFIX */ 46462306a36Sopenharmony_ci{ Idrop, Idrop, Fdrop, Fdrop, Fdrop, Mpass, Strue, Sfalse,Selse, Dendif, 46562306a36Sopenharmony_ci Idrop, Idrop, Fdrop, Fdrop, Fdrop, Mpass, Eioccc,Eioccc,Eioccc,Eioccc, 46662306a36Sopenharmony_ci drop, Eeof, abort }, 46762306a36Sopenharmony_ci/* IS_TRUE_PREFIX */ 46862306a36Sopenharmony_ci{ Itrue, Ifalse,Fpass, Ftrue, Ffalse,Dfalse,Dfalse,Dfalse,Delse, Dendif, 46962306a36Sopenharmony_ci Oiffy, Oiffy, Fpass, Oif, Oif, Eioccc,Eioccc,Eioccc,Eioccc,Eioccc, 47062306a36Sopenharmony_ci print, Eeof, abort }, 47162306a36Sopenharmony_ci/* IS_PASS_MIDDLE */ 47262306a36Sopenharmony_ci{ Itrue, Ifalse,Fpass, Ftrue, Ffalse,Pelif, Mtrue, Delif, Pelse, Pendif, 47362306a36Sopenharmony_ci Oiffy, Oiffy, Fpass, Oif, Oif, Pelif, Oelif, Oelif, Pelse, Pendif, 47462306a36Sopenharmony_ci print, Eeof, abort }, 47562306a36Sopenharmony_ci/* IS_FALSE_MIDDLE */ 47662306a36Sopenharmony_ci{ Idrop, Idrop, Fdrop, Fdrop, Fdrop, Pelif, Mtrue, Delif, Pelse, Pendif, 47762306a36Sopenharmony_ci Idrop, Idrop, Fdrop, Fdrop, Fdrop, Eioccc,Eioccc,Eioccc,Eioccc,Eioccc, 47862306a36Sopenharmony_ci drop, Eeof, abort }, 47962306a36Sopenharmony_ci/* IS_TRUE_MIDDLE */ 48062306a36Sopenharmony_ci{ Itrue, Ifalse,Fpass, Ftrue, Ffalse,Melif, Melif, Melif, Melse, Pendif, 48162306a36Sopenharmony_ci Oiffy, Oiffy, Fpass, Oif, Oif, Eioccc,Eioccc,Eioccc,Eioccc,Pendif, 48262306a36Sopenharmony_ci print, Eeof, abort }, 48362306a36Sopenharmony_ci/* IS_PASS_ELSE */ 48462306a36Sopenharmony_ci{ Itrue, Ifalse,Fpass, Ftrue, Ffalse,Eelif, Eelif, Eelif, Eelse, Pendif, 48562306a36Sopenharmony_ci Oiffy, Oiffy, Fpass, Oif, Oif, Eelif, Eelif, Eelif, Eelse, Pendif, 48662306a36Sopenharmony_ci print, Eeof, abort }, 48762306a36Sopenharmony_ci/* IS_FALSE_ELSE */ 48862306a36Sopenharmony_ci{ Idrop, Idrop, Fdrop, Fdrop, Fdrop, Eelif, Eelif, Eelif, Eelse, Dendif, 48962306a36Sopenharmony_ci Idrop, Idrop, Fdrop, Fdrop, Fdrop, Eelif, Eelif, Eelif, Eelse, Eioccc, 49062306a36Sopenharmony_ci drop, Eeof, abort }, 49162306a36Sopenharmony_ci/* IS_TRUE_ELSE */ 49262306a36Sopenharmony_ci{ Itrue, Ifalse,Fpass, Ftrue, Ffalse,Eelif, Eelif, Eelif, Eelse, Dendif, 49362306a36Sopenharmony_ci Oiffy, Oiffy, Fpass, Oif, Oif, Eelif, Eelif, Eelif, Eelse, Eioccc, 49462306a36Sopenharmony_ci print, Eeof, abort }, 49562306a36Sopenharmony_ci/* IS_FALSE_TRAILER */ 49662306a36Sopenharmony_ci{ Idrop, Idrop, Fdrop, Fdrop, Fdrop, Dfalse,Dfalse,Dfalse,Delse, Dendif, 49762306a36Sopenharmony_ci Idrop, Idrop, Fdrop, Fdrop, Fdrop, Dfalse,Dfalse,Dfalse,Delse, Eioccc, 49862306a36Sopenharmony_ci drop, Eeof, abort } 49962306a36Sopenharmony_ci/*TRUEI FALSEI IF TRUE FALSE ELIF ELTRUE ELFALSE ELSE ENDIF 50062306a36Sopenharmony_ci TRUEI FALSEI IF TRUE FALSE ELIF ELTRUE ELFALSE ELSE ENDIF (DODGY) 50162306a36Sopenharmony_ci PLAIN EOF ERROR */ 50262306a36Sopenharmony_ci}; 50362306a36Sopenharmony_ci 50462306a36Sopenharmony_ci/* 50562306a36Sopenharmony_ci * State machine utility functions 50662306a36Sopenharmony_ci */ 50762306a36Sopenharmony_cistatic void 50862306a36Sopenharmony_ciignoreoff(void) 50962306a36Sopenharmony_ci{ 51062306a36Sopenharmony_ci if (depth == 0) 51162306a36Sopenharmony_ci abort(); /* bug */ 51262306a36Sopenharmony_ci ignoring[depth] = ignoring[depth-1]; 51362306a36Sopenharmony_ci} 51462306a36Sopenharmony_cistatic void 51562306a36Sopenharmony_ciignoreon(void) 51662306a36Sopenharmony_ci{ 51762306a36Sopenharmony_ci ignoring[depth] = true; 51862306a36Sopenharmony_ci} 51962306a36Sopenharmony_cistatic void 52062306a36Sopenharmony_cikeywordedit(const char *replacement) 52162306a36Sopenharmony_ci{ 52262306a36Sopenharmony_ci snprintf(keyword, tline + sizeof(tline) - keyword, 52362306a36Sopenharmony_ci "%s%s", replacement, newline); 52462306a36Sopenharmony_ci print(); 52562306a36Sopenharmony_ci} 52662306a36Sopenharmony_cistatic void 52762306a36Sopenharmony_cinest(void) 52862306a36Sopenharmony_ci{ 52962306a36Sopenharmony_ci if (depth > MAXDEPTH-1) 53062306a36Sopenharmony_ci abort(); /* bug */ 53162306a36Sopenharmony_ci if (depth == MAXDEPTH-1) 53262306a36Sopenharmony_ci error("Too many levels of nesting"); 53362306a36Sopenharmony_ci depth += 1; 53462306a36Sopenharmony_ci stifline[depth] = linenum; 53562306a36Sopenharmony_ci} 53662306a36Sopenharmony_cistatic void 53762306a36Sopenharmony_ciunnest(void) 53862306a36Sopenharmony_ci{ 53962306a36Sopenharmony_ci if (depth == 0) 54062306a36Sopenharmony_ci abort(); /* bug */ 54162306a36Sopenharmony_ci depth -= 1; 54262306a36Sopenharmony_ci} 54362306a36Sopenharmony_cistatic void 54462306a36Sopenharmony_cistate(Ifstate is) 54562306a36Sopenharmony_ci{ 54662306a36Sopenharmony_ci ifstate[depth] = is; 54762306a36Sopenharmony_ci} 54862306a36Sopenharmony_ci 54962306a36Sopenharmony_ci/* 55062306a36Sopenharmony_ci * Write a line to the output or not, according to command line options. 55162306a36Sopenharmony_ci */ 55262306a36Sopenharmony_cistatic void 55362306a36Sopenharmony_ciflushline(bool keep) 55462306a36Sopenharmony_ci{ 55562306a36Sopenharmony_ci if (symlist) 55662306a36Sopenharmony_ci return; 55762306a36Sopenharmony_ci if (keep ^ complement) { 55862306a36Sopenharmony_ci bool blankline = tline[strspn(tline, " \t\r\n")] == '\0'; 55962306a36Sopenharmony_ci if (blankline && compblank && blankcount != blankmax) { 56062306a36Sopenharmony_ci delcount += 1; 56162306a36Sopenharmony_ci blankcount += 1; 56262306a36Sopenharmony_ci } else { 56362306a36Sopenharmony_ci if (lnnum && delcount > 0) 56462306a36Sopenharmony_ci printf("#line %d%s", linenum, newline); 56562306a36Sopenharmony_ci fputs(tline, output); 56662306a36Sopenharmony_ci delcount = 0; 56762306a36Sopenharmony_ci blankmax = blankcount = blankline ? blankcount + 1 : 0; 56862306a36Sopenharmony_ci } 56962306a36Sopenharmony_ci } else { 57062306a36Sopenharmony_ci if (lnblank) 57162306a36Sopenharmony_ci fputs(newline, output); 57262306a36Sopenharmony_ci exitstat = 1; 57362306a36Sopenharmony_ci delcount += 1; 57462306a36Sopenharmony_ci blankcount = 0; 57562306a36Sopenharmony_ci } 57662306a36Sopenharmony_ci if (debugging) 57762306a36Sopenharmony_ci fflush(output); 57862306a36Sopenharmony_ci} 57962306a36Sopenharmony_ci 58062306a36Sopenharmony_ci/* 58162306a36Sopenharmony_ci * The driver for the state machine. 58262306a36Sopenharmony_ci */ 58362306a36Sopenharmony_cistatic void 58462306a36Sopenharmony_ciprocess(void) 58562306a36Sopenharmony_ci{ 58662306a36Sopenharmony_ci /* When compressing blank lines, act as if the file 58762306a36Sopenharmony_ci is preceded by a large number of blank lines. */ 58862306a36Sopenharmony_ci blankmax = blankcount = 1000; 58962306a36Sopenharmony_ci for (;;) { 59062306a36Sopenharmony_ci Linetype lineval = parseline(); 59162306a36Sopenharmony_ci trans_table[ifstate[depth]][lineval](); 59262306a36Sopenharmony_ci debug("process line %d %s -> %s depth %d", 59362306a36Sopenharmony_ci linenum, linetype_name[lineval], 59462306a36Sopenharmony_ci ifstate_name[ifstate[depth]], depth); 59562306a36Sopenharmony_ci } 59662306a36Sopenharmony_ci} 59762306a36Sopenharmony_ci 59862306a36Sopenharmony_ci/* 59962306a36Sopenharmony_ci * Flush the output and handle errors. 60062306a36Sopenharmony_ci */ 60162306a36Sopenharmony_cistatic void 60262306a36Sopenharmony_cicloseout(void) 60362306a36Sopenharmony_ci{ 60462306a36Sopenharmony_ci if (symdepth && !zerosyms) 60562306a36Sopenharmony_ci printf("\n"); 60662306a36Sopenharmony_ci if (fclose(output) == EOF) { 60762306a36Sopenharmony_ci warn("couldn't write to %s", ofilename); 60862306a36Sopenharmony_ci if (overwriting) { 60962306a36Sopenharmony_ci unlink(tempname); 61062306a36Sopenharmony_ci errx(2, "%s unchanged", filename); 61162306a36Sopenharmony_ci } else { 61262306a36Sopenharmony_ci exit(2); 61362306a36Sopenharmony_ci } 61462306a36Sopenharmony_ci } 61562306a36Sopenharmony_ci} 61662306a36Sopenharmony_ci 61762306a36Sopenharmony_ci/* 61862306a36Sopenharmony_ci * Clean up and exit. 61962306a36Sopenharmony_ci */ 62062306a36Sopenharmony_cistatic void 62162306a36Sopenharmony_cidone(void) 62262306a36Sopenharmony_ci{ 62362306a36Sopenharmony_ci if (incomment) 62462306a36Sopenharmony_ci error("EOF in comment"); 62562306a36Sopenharmony_ci closeout(); 62662306a36Sopenharmony_ci if (overwriting && rename(tempname, ofilename) == -1) { 62762306a36Sopenharmony_ci warn("couldn't rename temporary file"); 62862306a36Sopenharmony_ci unlink(tempname); 62962306a36Sopenharmony_ci errx(2, "%s unchanged", ofilename); 63062306a36Sopenharmony_ci } 63162306a36Sopenharmony_ci exit(exitstat); 63262306a36Sopenharmony_ci} 63362306a36Sopenharmony_ci 63462306a36Sopenharmony_ci/* 63562306a36Sopenharmony_ci * Parse a line and determine its type. We keep the preprocessor line 63662306a36Sopenharmony_ci * parser state between calls in the global variable linestate, with 63762306a36Sopenharmony_ci * help from skipcomment(). 63862306a36Sopenharmony_ci */ 63962306a36Sopenharmony_cistatic Linetype 64062306a36Sopenharmony_ciparseline(void) 64162306a36Sopenharmony_ci{ 64262306a36Sopenharmony_ci const char *cp; 64362306a36Sopenharmony_ci int cursym; 64462306a36Sopenharmony_ci int kwlen; 64562306a36Sopenharmony_ci Linetype retval; 64662306a36Sopenharmony_ci Comment_state wascomment; 64762306a36Sopenharmony_ci 64862306a36Sopenharmony_ci linenum++; 64962306a36Sopenharmony_ci if (fgets(tline, MAXLINE, input) == NULL) 65062306a36Sopenharmony_ci return (LT_EOF); 65162306a36Sopenharmony_ci if (newline == NULL) { 65262306a36Sopenharmony_ci if (strrchr(tline, '\n') == strrchr(tline, '\r') + 1) 65362306a36Sopenharmony_ci newline = newline_crlf; 65462306a36Sopenharmony_ci else 65562306a36Sopenharmony_ci newline = newline_unix; 65662306a36Sopenharmony_ci } 65762306a36Sopenharmony_ci retval = LT_PLAIN; 65862306a36Sopenharmony_ci wascomment = incomment; 65962306a36Sopenharmony_ci cp = skipcomment(tline); 66062306a36Sopenharmony_ci if (linestate == LS_START) { 66162306a36Sopenharmony_ci if (*cp == '#') { 66262306a36Sopenharmony_ci linestate = LS_HASH; 66362306a36Sopenharmony_ci firstsym = true; 66462306a36Sopenharmony_ci cp = skipcomment(cp + 1); 66562306a36Sopenharmony_ci } else if (*cp != '\0') 66662306a36Sopenharmony_ci linestate = LS_DIRTY; 66762306a36Sopenharmony_ci } 66862306a36Sopenharmony_ci if (!incomment && linestate == LS_HASH) { 66962306a36Sopenharmony_ci keyword = tline + (cp - tline); 67062306a36Sopenharmony_ci cp = skipsym(cp); 67162306a36Sopenharmony_ci kwlen = cp - keyword; 67262306a36Sopenharmony_ci /* no way can we deal with a continuation inside a keyword */ 67362306a36Sopenharmony_ci if (strncmp(cp, "\\\r\n", 3) == 0 || 67462306a36Sopenharmony_ci strncmp(cp, "\\\n", 2) == 0) 67562306a36Sopenharmony_ci Eioccc(); 67662306a36Sopenharmony_ci if (strlcmp("ifdef", keyword, kwlen) == 0 || 67762306a36Sopenharmony_ci strlcmp("ifndef", keyword, kwlen) == 0) { 67862306a36Sopenharmony_ci cp = skipcomment(cp); 67962306a36Sopenharmony_ci if ((cursym = findsym(cp)) < 0) 68062306a36Sopenharmony_ci retval = LT_IF; 68162306a36Sopenharmony_ci else { 68262306a36Sopenharmony_ci retval = (keyword[2] == 'n') 68362306a36Sopenharmony_ci ? LT_FALSE : LT_TRUE; 68462306a36Sopenharmony_ci if (value[cursym] == NULL) 68562306a36Sopenharmony_ci retval = (retval == LT_TRUE) 68662306a36Sopenharmony_ci ? LT_FALSE : LT_TRUE; 68762306a36Sopenharmony_ci if (ignore[cursym]) 68862306a36Sopenharmony_ci retval = (retval == LT_TRUE) 68962306a36Sopenharmony_ci ? LT_TRUEI : LT_FALSEI; 69062306a36Sopenharmony_ci } 69162306a36Sopenharmony_ci cp = skipsym(cp); 69262306a36Sopenharmony_ci } else if (strlcmp("if", keyword, kwlen) == 0) 69362306a36Sopenharmony_ci retval = ifeval(&cp); 69462306a36Sopenharmony_ci else if (strlcmp("elif", keyword, kwlen) == 0) 69562306a36Sopenharmony_ci retval = ifeval(&cp) - LT_IF + LT_ELIF; 69662306a36Sopenharmony_ci else if (strlcmp("else", keyword, kwlen) == 0) 69762306a36Sopenharmony_ci retval = LT_ELSE; 69862306a36Sopenharmony_ci else if (strlcmp("endif", keyword, kwlen) == 0) 69962306a36Sopenharmony_ci retval = LT_ENDIF; 70062306a36Sopenharmony_ci else { 70162306a36Sopenharmony_ci linestate = LS_DIRTY; 70262306a36Sopenharmony_ci retval = LT_PLAIN; 70362306a36Sopenharmony_ci } 70462306a36Sopenharmony_ci cp = skipcomment(cp); 70562306a36Sopenharmony_ci if (*cp != '\0') { 70662306a36Sopenharmony_ci linestate = LS_DIRTY; 70762306a36Sopenharmony_ci if (retval == LT_TRUE || retval == LT_FALSE || 70862306a36Sopenharmony_ci retval == LT_TRUEI || retval == LT_FALSEI) 70962306a36Sopenharmony_ci retval = LT_IF; 71062306a36Sopenharmony_ci if (retval == LT_ELTRUE || retval == LT_ELFALSE) 71162306a36Sopenharmony_ci retval = LT_ELIF; 71262306a36Sopenharmony_ci } 71362306a36Sopenharmony_ci if (retval != LT_PLAIN && (wascomment || incomment)) { 71462306a36Sopenharmony_ci retval += LT_DODGY; 71562306a36Sopenharmony_ci if (incomment) 71662306a36Sopenharmony_ci linestate = LS_DIRTY; 71762306a36Sopenharmony_ci } 71862306a36Sopenharmony_ci /* skipcomment normally changes the state, except 71962306a36Sopenharmony_ci if the last line of the file lacks a newline, or 72062306a36Sopenharmony_ci if there is too much whitespace in a directive */ 72162306a36Sopenharmony_ci if (linestate == LS_HASH) { 72262306a36Sopenharmony_ci size_t len = cp - tline; 72362306a36Sopenharmony_ci if (fgets(tline + len, MAXLINE - len, input) == NULL) { 72462306a36Sopenharmony_ci /* append the missing newline */ 72562306a36Sopenharmony_ci strcpy(tline + len, newline); 72662306a36Sopenharmony_ci cp += strlen(newline); 72762306a36Sopenharmony_ci linestate = LS_START; 72862306a36Sopenharmony_ci } else { 72962306a36Sopenharmony_ci linestate = LS_DIRTY; 73062306a36Sopenharmony_ci } 73162306a36Sopenharmony_ci } 73262306a36Sopenharmony_ci } 73362306a36Sopenharmony_ci if (linestate == LS_DIRTY) { 73462306a36Sopenharmony_ci while (*cp != '\0') 73562306a36Sopenharmony_ci cp = skipcomment(cp + 1); 73662306a36Sopenharmony_ci } 73762306a36Sopenharmony_ci debug("parser line %d state %s comment %s line", linenum, 73862306a36Sopenharmony_ci comment_name[incomment], linestate_name[linestate]); 73962306a36Sopenharmony_ci return (retval); 74062306a36Sopenharmony_ci} 74162306a36Sopenharmony_ci 74262306a36Sopenharmony_ci/* 74362306a36Sopenharmony_ci * These are the binary operators that are supported by the expression 74462306a36Sopenharmony_ci * evaluator. 74562306a36Sopenharmony_ci */ 74662306a36Sopenharmony_cistatic Linetype op_strict(int *p, int v, Linetype at, Linetype bt) { 74762306a36Sopenharmony_ci if(at == LT_IF || bt == LT_IF) return (LT_IF); 74862306a36Sopenharmony_ci return (*p = v, v ? LT_TRUE : LT_FALSE); 74962306a36Sopenharmony_ci} 75062306a36Sopenharmony_cistatic Linetype op_lt(int *p, Linetype at, int a, Linetype bt, int b) { 75162306a36Sopenharmony_ci return op_strict(p, a < b, at, bt); 75262306a36Sopenharmony_ci} 75362306a36Sopenharmony_cistatic Linetype op_gt(int *p, Linetype at, int a, Linetype bt, int b) { 75462306a36Sopenharmony_ci return op_strict(p, a > b, at, bt); 75562306a36Sopenharmony_ci} 75662306a36Sopenharmony_cistatic Linetype op_le(int *p, Linetype at, int a, Linetype bt, int b) { 75762306a36Sopenharmony_ci return op_strict(p, a <= b, at, bt); 75862306a36Sopenharmony_ci} 75962306a36Sopenharmony_cistatic Linetype op_ge(int *p, Linetype at, int a, Linetype bt, int b) { 76062306a36Sopenharmony_ci return op_strict(p, a >= b, at, bt); 76162306a36Sopenharmony_ci} 76262306a36Sopenharmony_cistatic Linetype op_eq(int *p, Linetype at, int a, Linetype bt, int b) { 76362306a36Sopenharmony_ci return op_strict(p, a == b, at, bt); 76462306a36Sopenharmony_ci} 76562306a36Sopenharmony_cistatic Linetype op_ne(int *p, Linetype at, int a, Linetype bt, int b) { 76662306a36Sopenharmony_ci return op_strict(p, a != b, at, bt); 76762306a36Sopenharmony_ci} 76862306a36Sopenharmony_cistatic Linetype op_or(int *p, Linetype at, int a, Linetype bt, int b) { 76962306a36Sopenharmony_ci if (!strictlogic && (at == LT_TRUE || bt == LT_TRUE)) 77062306a36Sopenharmony_ci return (*p = 1, LT_TRUE); 77162306a36Sopenharmony_ci return op_strict(p, a || b, at, bt); 77262306a36Sopenharmony_ci} 77362306a36Sopenharmony_cistatic Linetype op_and(int *p, Linetype at, int a, Linetype bt, int b) { 77462306a36Sopenharmony_ci if (!strictlogic && (at == LT_FALSE || bt == LT_FALSE)) 77562306a36Sopenharmony_ci return (*p = 0, LT_FALSE); 77662306a36Sopenharmony_ci return op_strict(p, a && b, at, bt); 77762306a36Sopenharmony_ci} 77862306a36Sopenharmony_ci 77962306a36Sopenharmony_ci/* 78062306a36Sopenharmony_ci * An evaluation function takes three arguments, as follows: (1) a pointer to 78162306a36Sopenharmony_ci * an element of the precedence table which lists the operators at the current 78262306a36Sopenharmony_ci * level of precedence; (2) a pointer to an integer which will receive the 78362306a36Sopenharmony_ci * value of the expression; and (3) a pointer to a char* that points to the 78462306a36Sopenharmony_ci * expression to be evaluated and that is updated to the end of the expression 78562306a36Sopenharmony_ci * when evaluation is complete. The function returns LT_FALSE if the value of 78662306a36Sopenharmony_ci * the expression is zero, LT_TRUE if it is non-zero, LT_IF if the expression 78762306a36Sopenharmony_ci * depends on an unknown symbol, or LT_ERROR if there is a parse failure. 78862306a36Sopenharmony_ci */ 78962306a36Sopenharmony_cistruct ops; 79062306a36Sopenharmony_ci 79162306a36Sopenharmony_citypedef Linetype eval_fn(const struct ops *, int *, const char **); 79262306a36Sopenharmony_ci 79362306a36Sopenharmony_cistatic eval_fn eval_table, eval_unary; 79462306a36Sopenharmony_ci 79562306a36Sopenharmony_ci/* 79662306a36Sopenharmony_ci * The precedence table. Expressions involving binary operators are evaluated 79762306a36Sopenharmony_ci * in a table-driven way by eval_table. When it evaluates a subexpression it 79862306a36Sopenharmony_ci * calls the inner function with its first argument pointing to the next 79962306a36Sopenharmony_ci * element of the table. Innermost expressions have special non-table-driven 80062306a36Sopenharmony_ci * handling. 80162306a36Sopenharmony_ci */ 80262306a36Sopenharmony_cistatic const struct ops { 80362306a36Sopenharmony_ci eval_fn *inner; 80462306a36Sopenharmony_ci struct op { 80562306a36Sopenharmony_ci const char *str; 80662306a36Sopenharmony_ci Linetype (*fn)(int *, Linetype, int, Linetype, int); 80762306a36Sopenharmony_ci } op[5]; 80862306a36Sopenharmony_ci} eval_ops[] = { 80962306a36Sopenharmony_ci { eval_table, { { "||", op_or } } }, 81062306a36Sopenharmony_ci { eval_table, { { "&&", op_and } } }, 81162306a36Sopenharmony_ci { eval_table, { { "==", op_eq }, 81262306a36Sopenharmony_ci { "!=", op_ne } } }, 81362306a36Sopenharmony_ci { eval_unary, { { "<=", op_le }, 81462306a36Sopenharmony_ci { ">=", op_ge }, 81562306a36Sopenharmony_ci { "<", op_lt }, 81662306a36Sopenharmony_ci { ">", op_gt } } } 81762306a36Sopenharmony_ci}; 81862306a36Sopenharmony_ci 81962306a36Sopenharmony_ci/* 82062306a36Sopenharmony_ci * Function for evaluating the innermost parts of expressions, 82162306a36Sopenharmony_ci * viz. !expr (expr) number defined(symbol) symbol 82262306a36Sopenharmony_ci * We reset the constexpr flag in the last two cases. 82362306a36Sopenharmony_ci */ 82462306a36Sopenharmony_cistatic Linetype 82562306a36Sopenharmony_cieval_unary(const struct ops *ops, int *valp, const char **cpp) 82662306a36Sopenharmony_ci{ 82762306a36Sopenharmony_ci const char *cp; 82862306a36Sopenharmony_ci char *ep; 82962306a36Sopenharmony_ci int sym; 83062306a36Sopenharmony_ci bool defparen; 83162306a36Sopenharmony_ci Linetype lt; 83262306a36Sopenharmony_ci 83362306a36Sopenharmony_ci cp = skipcomment(*cpp); 83462306a36Sopenharmony_ci if (*cp == '!') { 83562306a36Sopenharmony_ci debug("eval%d !", ops - eval_ops); 83662306a36Sopenharmony_ci cp++; 83762306a36Sopenharmony_ci lt = eval_unary(ops, valp, &cp); 83862306a36Sopenharmony_ci if (lt == LT_ERROR) 83962306a36Sopenharmony_ci return (LT_ERROR); 84062306a36Sopenharmony_ci if (lt != LT_IF) { 84162306a36Sopenharmony_ci *valp = !*valp; 84262306a36Sopenharmony_ci lt = *valp ? LT_TRUE : LT_FALSE; 84362306a36Sopenharmony_ci } 84462306a36Sopenharmony_ci } else if (*cp == '(') { 84562306a36Sopenharmony_ci cp++; 84662306a36Sopenharmony_ci debug("eval%d (", ops - eval_ops); 84762306a36Sopenharmony_ci lt = eval_table(eval_ops, valp, &cp); 84862306a36Sopenharmony_ci if (lt == LT_ERROR) 84962306a36Sopenharmony_ci return (LT_ERROR); 85062306a36Sopenharmony_ci cp = skipcomment(cp); 85162306a36Sopenharmony_ci if (*cp++ != ')') 85262306a36Sopenharmony_ci return (LT_ERROR); 85362306a36Sopenharmony_ci } else if (isdigit((unsigned char)*cp)) { 85462306a36Sopenharmony_ci debug("eval%d number", ops - eval_ops); 85562306a36Sopenharmony_ci *valp = strtol(cp, &ep, 0); 85662306a36Sopenharmony_ci if (ep == cp) 85762306a36Sopenharmony_ci return (LT_ERROR); 85862306a36Sopenharmony_ci lt = *valp ? LT_TRUE : LT_FALSE; 85962306a36Sopenharmony_ci cp = skipsym(cp); 86062306a36Sopenharmony_ci } else if (strncmp(cp, "defined", 7) == 0 && endsym(cp[7])) { 86162306a36Sopenharmony_ci cp = skipcomment(cp+7); 86262306a36Sopenharmony_ci debug("eval%d defined", ops - eval_ops); 86362306a36Sopenharmony_ci if (*cp == '(') { 86462306a36Sopenharmony_ci cp = skipcomment(cp+1); 86562306a36Sopenharmony_ci defparen = true; 86662306a36Sopenharmony_ci } else { 86762306a36Sopenharmony_ci defparen = false; 86862306a36Sopenharmony_ci } 86962306a36Sopenharmony_ci sym = findsym(cp); 87062306a36Sopenharmony_ci if (sym < 0) { 87162306a36Sopenharmony_ci lt = LT_IF; 87262306a36Sopenharmony_ci } else { 87362306a36Sopenharmony_ci *valp = (value[sym] != NULL); 87462306a36Sopenharmony_ci lt = *valp ? LT_TRUE : LT_FALSE; 87562306a36Sopenharmony_ci } 87662306a36Sopenharmony_ci cp = skipsym(cp); 87762306a36Sopenharmony_ci cp = skipcomment(cp); 87862306a36Sopenharmony_ci if (defparen && *cp++ != ')') 87962306a36Sopenharmony_ci return (LT_ERROR); 88062306a36Sopenharmony_ci constexpr = false; 88162306a36Sopenharmony_ci } else if (!endsym(*cp)) { 88262306a36Sopenharmony_ci debug("eval%d symbol", ops - eval_ops); 88362306a36Sopenharmony_ci sym = findsym(cp); 88462306a36Sopenharmony_ci cp = skipsym(cp); 88562306a36Sopenharmony_ci if (sym < 0) { 88662306a36Sopenharmony_ci lt = LT_IF; 88762306a36Sopenharmony_ci cp = skipargs(cp); 88862306a36Sopenharmony_ci } else if (value[sym] == NULL) { 88962306a36Sopenharmony_ci *valp = 0; 89062306a36Sopenharmony_ci lt = LT_FALSE; 89162306a36Sopenharmony_ci } else { 89262306a36Sopenharmony_ci *valp = strtol(value[sym], &ep, 0); 89362306a36Sopenharmony_ci if (*ep != '\0' || ep == value[sym]) 89462306a36Sopenharmony_ci return (LT_ERROR); 89562306a36Sopenharmony_ci lt = *valp ? LT_TRUE : LT_FALSE; 89662306a36Sopenharmony_ci cp = skipargs(cp); 89762306a36Sopenharmony_ci } 89862306a36Sopenharmony_ci constexpr = false; 89962306a36Sopenharmony_ci } else { 90062306a36Sopenharmony_ci debug("eval%d bad expr", ops - eval_ops); 90162306a36Sopenharmony_ci return (LT_ERROR); 90262306a36Sopenharmony_ci } 90362306a36Sopenharmony_ci 90462306a36Sopenharmony_ci *cpp = cp; 90562306a36Sopenharmony_ci debug("eval%d = %d", ops - eval_ops, *valp); 90662306a36Sopenharmony_ci return (lt); 90762306a36Sopenharmony_ci} 90862306a36Sopenharmony_ci 90962306a36Sopenharmony_ci/* 91062306a36Sopenharmony_ci * Table-driven evaluation of binary operators. 91162306a36Sopenharmony_ci */ 91262306a36Sopenharmony_cistatic Linetype 91362306a36Sopenharmony_cieval_table(const struct ops *ops, int *valp, const char **cpp) 91462306a36Sopenharmony_ci{ 91562306a36Sopenharmony_ci const struct op *op; 91662306a36Sopenharmony_ci const char *cp; 91762306a36Sopenharmony_ci int val; 91862306a36Sopenharmony_ci Linetype lt, rt; 91962306a36Sopenharmony_ci 92062306a36Sopenharmony_ci debug("eval%d", ops - eval_ops); 92162306a36Sopenharmony_ci cp = *cpp; 92262306a36Sopenharmony_ci lt = ops->inner(ops+1, valp, &cp); 92362306a36Sopenharmony_ci if (lt == LT_ERROR) 92462306a36Sopenharmony_ci return (LT_ERROR); 92562306a36Sopenharmony_ci for (;;) { 92662306a36Sopenharmony_ci cp = skipcomment(cp); 92762306a36Sopenharmony_ci for (op = ops->op; op->str != NULL; op++) 92862306a36Sopenharmony_ci if (strncmp(cp, op->str, strlen(op->str)) == 0) 92962306a36Sopenharmony_ci break; 93062306a36Sopenharmony_ci if (op->str == NULL) 93162306a36Sopenharmony_ci break; 93262306a36Sopenharmony_ci cp += strlen(op->str); 93362306a36Sopenharmony_ci debug("eval%d %s", ops - eval_ops, op->str); 93462306a36Sopenharmony_ci rt = ops->inner(ops+1, &val, &cp); 93562306a36Sopenharmony_ci if (rt == LT_ERROR) 93662306a36Sopenharmony_ci return (LT_ERROR); 93762306a36Sopenharmony_ci lt = op->fn(valp, lt, *valp, rt, val); 93862306a36Sopenharmony_ci } 93962306a36Sopenharmony_ci 94062306a36Sopenharmony_ci *cpp = cp; 94162306a36Sopenharmony_ci debug("eval%d = %d", ops - eval_ops, *valp); 94262306a36Sopenharmony_ci debug("eval%d lt = %s", ops - eval_ops, linetype_name[lt]); 94362306a36Sopenharmony_ci return (lt); 94462306a36Sopenharmony_ci} 94562306a36Sopenharmony_ci 94662306a36Sopenharmony_ci/* 94762306a36Sopenharmony_ci * Evaluate the expression on a #if or #elif line. If we can work out 94862306a36Sopenharmony_ci * the result we return LT_TRUE or LT_FALSE accordingly, otherwise we 94962306a36Sopenharmony_ci * return just a generic LT_IF. 95062306a36Sopenharmony_ci */ 95162306a36Sopenharmony_cistatic Linetype 95262306a36Sopenharmony_ciifeval(const char **cpp) 95362306a36Sopenharmony_ci{ 95462306a36Sopenharmony_ci int ret; 95562306a36Sopenharmony_ci int val = 0; 95662306a36Sopenharmony_ci 95762306a36Sopenharmony_ci debug("eval %s", *cpp); 95862306a36Sopenharmony_ci constexpr = killconsts ? false : true; 95962306a36Sopenharmony_ci ret = eval_table(eval_ops, &val, cpp); 96062306a36Sopenharmony_ci debug("eval = %d", val); 96162306a36Sopenharmony_ci return (constexpr ? LT_IF : ret == LT_ERROR ? LT_IF : ret); 96262306a36Sopenharmony_ci} 96362306a36Sopenharmony_ci 96462306a36Sopenharmony_ci/* 96562306a36Sopenharmony_ci * Skip over comments, strings, and character literals and stop at the 96662306a36Sopenharmony_ci * next character position that is not whitespace. Between calls we keep 96762306a36Sopenharmony_ci * the comment state in the global variable incomment, and we also adjust 96862306a36Sopenharmony_ci * the global variable linestate when we see a newline. 96962306a36Sopenharmony_ci * XXX: doesn't cope with the buffer splitting inside a state transition. 97062306a36Sopenharmony_ci */ 97162306a36Sopenharmony_cistatic const char * 97262306a36Sopenharmony_ciskipcomment(const char *cp) 97362306a36Sopenharmony_ci{ 97462306a36Sopenharmony_ci if (text || ignoring[depth]) { 97562306a36Sopenharmony_ci for (; isspace((unsigned char)*cp); cp++) 97662306a36Sopenharmony_ci if (*cp == '\n') 97762306a36Sopenharmony_ci linestate = LS_START; 97862306a36Sopenharmony_ci return (cp); 97962306a36Sopenharmony_ci } 98062306a36Sopenharmony_ci while (*cp != '\0') 98162306a36Sopenharmony_ci /* don't reset to LS_START after a line continuation */ 98262306a36Sopenharmony_ci if (strncmp(cp, "\\\r\n", 3) == 0) 98362306a36Sopenharmony_ci cp += 3; 98462306a36Sopenharmony_ci else if (strncmp(cp, "\\\n", 2) == 0) 98562306a36Sopenharmony_ci cp += 2; 98662306a36Sopenharmony_ci else switch (incomment) { 98762306a36Sopenharmony_ci case NO_COMMENT: 98862306a36Sopenharmony_ci if (strncmp(cp, "/\\\r\n", 4) == 0) { 98962306a36Sopenharmony_ci incomment = STARTING_COMMENT; 99062306a36Sopenharmony_ci cp += 4; 99162306a36Sopenharmony_ci } else if (strncmp(cp, "/\\\n", 3) == 0) { 99262306a36Sopenharmony_ci incomment = STARTING_COMMENT; 99362306a36Sopenharmony_ci cp += 3; 99462306a36Sopenharmony_ci } else if (strncmp(cp, "/*", 2) == 0) { 99562306a36Sopenharmony_ci incomment = C_COMMENT; 99662306a36Sopenharmony_ci cp += 2; 99762306a36Sopenharmony_ci } else if (strncmp(cp, "//", 2) == 0) { 99862306a36Sopenharmony_ci incomment = CXX_COMMENT; 99962306a36Sopenharmony_ci cp += 2; 100062306a36Sopenharmony_ci } else if (strncmp(cp, "\'", 1) == 0) { 100162306a36Sopenharmony_ci incomment = CHAR_LITERAL; 100262306a36Sopenharmony_ci linestate = LS_DIRTY; 100362306a36Sopenharmony_ci cp += 1; 100462306a36Sopenharmony_ci } else if (strncmp(cp, "\"", 1) == 0) { 100562306a36Sopenharmony_ci incomment = STRING_LITERAL; 100662306a36Sopenharmony_ci linestate = LS_DIRTY; 100762306a36Sopenharmony_ci cp += 1; 100862306a36Sopenharmony_ci } else if (strncmp(cp, "\n", 1) == 0) { 100962306a36Sopenharmony_ci linestate = LS_START; 101062306a36Sopenharmony_ci cp += 1; 101162306a36Sopenharmony_ci } else if (strchr(" \r\t", *cp) != NULL) { 101262306a36Sopenharmony_ci cp += 1; 101362306a36Sopenharmony_ci } else 101462306a36Sopenharmony_ci return (cp); 101562306a36Sopenharmony_ci continue; 101662306a36Sopenharmony_ci case CXX_COMMENT: 101762306a36Sopenharmony_ci if (strncmp(cp, "\n", 1) == 0) { 101862306a36Sopenharmony_ci incomment = NO_COMMENT; 101962306a36Sopenharmony_ci linestate = LS_START; 102062306a36Sopenharmony_ci } 102162306a36Sopenharmony_ci cp += 1; 102262306a36Sopenharmony_ci continue; 102362306a36Sopenharmony_ci case CHAR_LITERAL: 102462306a36Sopenharmony_ci case STRING_LITERAL: 102562306a36Sopenharmony_ci if ((incomment == CHAR_LITERAL && cp[0] == '\'') || 102662306a36Sopenharmony_ci (incomment == STRING_LITERAL && cp[0] == '\"')) { 102762306a36Sopenharmony_ci incomment = NO_COMMENT; 102862306a36Sopenharmony_ci cp += 1; 102962306a36Sopenharmony_ci } else if (cp[0] == '\\') { 103062306a36Sopenharmony_ci if (cp[1] == '\0') 103162306a36Sopenharmony_ci cp += 1; 103262306a36Sopenharmony_ci else 103362306a36Sopenharmony_ci cp += 2; 103462306a36Sopenharmony_ci } else if (strncmp(cp, "\n", 1) == 0) { 103562306a36Sopenharmony_ci if (incomment == CHAR_LITERAL) 103662306a36Sopenharmony_ci error("unterminated char literal"); 103762306a36Sopenharmony_ci else 103862306a36Sopenharmony_ci error("unterminated string literal"); 103962306a36Sopenharmony_ci } else 104062306a36Sopenharmony_ci cp += 1; 104162306a36Sopenharmony_ci continue; 104262306a36Sopenharmony_ci case C_COMMENT: 104362306a36Sopenharmony_ci if (strncmp(cp, "*\\\r\n", 4) == 0) { 104462306a36Sopenharmony_ci incomment = FINISHING_COMMENT; 104562306a36Sopenharmony_ci cp += 4; 104662306a36Sopenharmony_ci } else if (strncmp(cp, "*\\\n", 3) == 0) { 104762306a36Sopenharmony_ci incomment = FINISHING_COMMENT; 104862306a36Sopenharmony_ci cp += 3; 104962306a36Sopenharmony_ci } else if (strncmp(cp, "*/", 2) == 0) { 105062306a36Sopenharmony_ci incomment = NO_COMMENT; 105162306a36Sopenharmony_ci cp += 2; 105262306a36Sopenharmony_ci } else 105362306a36Sopenharmony_ci cp += 1; 105462306a36Sopenharmony_ci continue; 105562306a36Sopenharmony_ci case STARTING_COMMENT: 105662306a36Sopenharmony_ci if (*cp == '*') { 105762306a36Sopenharmony_ci incomment = C_COMMENT; 105862306a36Sopenharmony_ci cp += 1; 105962306a36Sopenharmony_ci } else if (*cp == '/') { 106062306a36Sopenharmony_ci incomment = CXX_COMMENT; 106162306a36Sopenharmony_ci cp += 1; 106262306a36Sopenharmony_ci } else { 106362306a36Sopenharmony_ci incomment = NO_COMMENT; 106462306a36Sopenharmony_ci linestate = LS_DIRTY; 106562306a36Sopenharmony_ci } 106662306a36Sopenharmony_ci continue; 106762306a36Sopenharmony_ci case FINISHING_COMMENT: 106862306a36Sopenharmony_ci if (*cp == '/') { 106962306a36Sopenharmony_ci incomment = NO_COMMENT; 107062306a36Sopenharmony_ci cp += 1; 107162306a36Sopenharmony_ci } else 107262306a36Sopenharmony_ci incomment = C_COMMENT; 107362306a36Sopenharmony_ci continue; 107462306a36Sopenharmony_ci default: 107562306a36Sopenharmony_ci abort(); /* bug */ 107662306a36Sopenharmony_ci } 107762306a36Sopenharmony_ci return (cp); 107862306a36Sopenharmony_ci} 107962306a36Sopenharmony_ci 108062306a36Sopenharmony_ci/* 108162306a36Sopenharmony_ci * Skip macro arguments. 108262306a36Sopenharmony_ci */ 108362306a36Sopenharmony_cistatic const char * 108462306a36Sopenharmony_ciskipargs(const char *cp) 108562306a36Sopenharmony_ci{ 108662306a36Sopenharmony_ci const char *ocp = cp; 108762306a36Sopenharmony_ci int level = 0; 108862306a36Sopenharmony_ci cp = skipcomment(cp); 108962306a36Sopenharmony_ci if (*cp != '(') 109062306a36Sopenharmony_ci return (cp); 109162306a36Sopenharmony_ci do { 109262306a36Sopenharmony_ci if (*cp == '(') 109362306a36Sopenharmony_ci level++; 109462306a36Sopenharmony_ci if (*cp == ')') 109562306a36Sopenharmony_ci level--; 109662306a36Sopenharmony_ci cp = skipcomment(cp+1); 109762306a36Sopenharmony_ci } while (level != 0 && *cp != '\0'); 109862306a36Sopenharmony_ci if (level == 0) 109962306a36Sopenharmony_ci return (cp); 110062306a36Sopenharmony_ci else 110162306a36Sopenharmony_ci /* Rewind and re-detect the syntax error later. */ 110262306a36Sopenharmony_ci return (ocp); 110362306a36Sopenharmony_ci} 110462306a36Sopenharmony_ci 110562306a36Sopenharmony_ci/* 110662306a36Sopenharmony_ci * Skip over an identifier. 110762306a36Sopenharmony_ci */ 110862306a36Sopenharmony_cistatic const char * 110962306a36Sopenharmony_ciskipsym(const char *cp) 111062306a36Sopenharmony_ci{ 111162306a36Sopenharmony_ci while (!endsym(*cp)) 111262306a36Sopenharmony_ci ++cp; 111362306a36Sopenharmony_ci return (cp); 111462306a36Sopenharmony_ci} 111562306a36Sopenharmony_ci 111662306a36Sopenharmony_ci/* 111762306a36Sopenharmony_ci * Look for the symbol in the symbol table. If it is found, we return 111862306a36Sopenharmony_ci * the symbol table index, else we return -1. 111962306a36Sopenharmony_ci */ 112062306a36Sopenharmony_cistatic int 112162306a36Sopenharmony_cifindsym(const char *str) 112262306a36Sopenharmony_ci{ 112362306a36Sopenharmony_ci const char *cp; 112462306a36Sopenharmony_ci int symind; 112562306a36Sopenharmony_ci 112662306a36Sopenharmony_ci cp = skipsym(str); 112762306a36Sopenharmony_ci if (cp == str) 112862306a36Sopenharmony_ci return (-1); 112962306a36Sopenharmony_ci if (symlist) { 113062306a36Sopenharmony_ci if (symdepth && firstsym) 113162306a36Sopenharmony_ci printf("%s%3d", zerosyms ? "" : "\n", depth); 113262306a36Sopenharmony_ci firstsym = zerosyms = false; 113362306a36Sopenharmony_ci printf("%s%.*s%s", 113462306a36Sopenharmony_ci symdepth ? " " : "", 113562306a36Sopenharmony_ci (int)(cp-str), str, 113662306a36Sopenharmony_ci symdepth ? "" : "\n"); 113762306a36Sopenharmony_ci /* we don't care about the value of the symbol */ 113862306a36Sopenharmony_ci return (0); 113962306a36Sopenharmony_ci } 114062306a36Sopenharmony_ci for (symind = 0; symind < nsyms; ++symind) { 114162306a36Sopenharmony_ci if (strlcmp(symname[symind], str, cp-str) == 0) { 114262306a36Sopenharmony_ci debug("findsym %s %s", symname[symind], 114362306a36Sopenharmony_ci value[symind] ? value[symind] : ""); 114462306a36Sopenharmony_ci return (symind); 114562306a36Sopenharmony_ci } 114662306a36Sopenharmony_ci } 114762306a36Sopenharmony_ci return (-1); 114862306a36Sopenharmony_ci} 114962306a36Sopenharmony_ci 115062306a36Sopenharmony_ci/* 115162306a36Sopenharmony_ci * Add a symbol to the symbol table. 115262306a36Sopenharmony_ci */ 115362306a36Sopenharmony_cistatic void 115462306a36Sopenharmony_ciaddsym(bool ignorethis, bool definethis, char *sym) 115562306a36Sopenharmony_ci{ 115662306a36Sopenharmony_ci int symind; 115762306a36Sopenharmony_ci char *val; 115862306a36Sopenharmony_ci 115962306a36Sopenharmony_ci symind = findsym(sym); 116062306a36Sopenharmony_ci if (symind < 0) { 116162306a36Sopenharmony_ci if (nsyms >= MAXSYMS) 116262306a36Sopenharmony_ci errx(2, "too many symbols"); 116362306a36Sopenharmony_ci symind = nsyms++; 116462306a36Sopenharmony_ci } 116562306a36Sopenharmony_ci symname[symind] = sym; 116662306a36Sopenharmony_ci ignore[symind] = ignorethis; 116762306a36Sopenharmony_ci val = sym + (skipsym(sym) - sym); 116862306a36Sopenharmony_ci if (definethis) { 116962306a36Sopenharmony_ci if (*val == '=') { 117062306a36Sopenharmony_ci value[symind] = val+1; 117162306a36Sopenharmony_ci *val = '\0'; 117262306a36Sopenharmony_ci } else if (*val == '\0') 117362306a36Sopenharmony_ci value[symind] = "1"; 117462306a36Sopenharmony_ci else 117562306a36Sopenharmony_ci usage(); 117662306a36Sopenharmony_ci } else { 117762306a36Sopenharmony_ci if (*val != '\0') 117862306a36Sopenharmony_ci usage(); 117962306a36Sopenharmony_ci value[symind] = NULL; 118062306a36Sopenharmony_ci } 118162306a36Sopenharmony_ci debug("addsym %s=%s", symname[symind], 118262306a36Sopenharmony_ci value[symind] ? value[symind] : "undef"); 118362306a36Sopenharmony_ci} 118462306a36Sopenharmony_ci 118562306a36Sopenharmony_ci/* 118662306a36Sopenharmony_ci * Compare s with n characters of t. 118762306a36Sopenharmony_ci * The same as strncmp() except that it checks that s[n] == '\0'. 118862306a36Sopenharmony_ci */ 118962306a36Sopenharmony_cistatic int 119062306a36Sopenharmony_cistrlcmp(const char *s, const char *t, size_t n) 119162306a36Sopenharmony_ci{ 119262306a36Sopenharmony_ci while (n-- && *t != '\0') 119362306a36Sopenharmony_ci if (*s != *t) 119462306a36Sopenharmony_ci return ((unsigned char)*s - (unsigned char)*t); 119562306a36Sopenharmony_ci else 119662306a36Sopenharmony_ci ++s, ++t; 119762306a36Sopenharmony_ci return ((unsigned char)*s); 119862306a36Sopenharmony_ci} 119962306a36Sopenharmony_ci 120062306a36Sopenharmony_ci/* 120162306a36Sopenharmony_ci * Diagnostics. 120262306a36Sopenharmony_ci */ 120362306a36Sopenharmony_cistatic void 120462306a36Sopenharmony_cidebug(const char *msg, ...) 120562306a36Sopenharmony_ci{ 120662306a36Sopenharmony_ci va_list ap; 120762306a36Sopenharmony_ci 120862306a36Sopenharmony_ci if (debugging) { 120962306a36Sopenharmony_ci va_start(ap, msg); 121062306a36Sopenharmony_ci vwarnx(msg, ap); 121162306a36Sopenharmony_ci va_end(ap); 121262306a36Sopenharmony_ci } 121362306a36Sopenharmony_ci} 121462306a36Sopenharmony_ci 121562306a36Sopenharmony_cistatic void 121662306a36Sopenharmony_cierror(const char *msg) 121762306a36Sopenharmony_ci{ 121862306a36Sopenharmony_ci if (depth == 0) 121962306a36Sopenharmony_ci warnx("%s: %d: %s", filename, linenum, msg); 122062306a36Sopenharmony_ci else 122162306a36Sopenharmony_ci warnx("%s: %d: %s (#if line %d depth %d)", 122262306a36Sopenharmony_ci filename, linenum, msg, stifline[depth], depth); 122362306a36Sopenharmony_ci closeout(); 122462306a36Sopenharmony_ci errx(2, "output may be truncated"); 122562306a36Sopenharmony_ci} 1226