c-pp.c 44 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532
  1. /*
  2. ** 2022-11-12:
  3. **
  4. ** The author disclaims copyright to this source code. In place of
  5. ** a legal notice, here is a blessing:
  6. **
  7. ** * May you do good and not evil.
  8. ** * May you find forgiveness for yourself and forgive others.
  9. ** * May you share freely, never taking more than you give.
  10. **
  11. ************************************************************************
  12. **
  13. ** The C-minus Preprocessor: a truly minimal C-like preprocessor.
  14. ** Why? Because C preprocessors _can_ process non-C code but generally make
  15. ** quite a mess of it. The purpose of this application is an extremely
  16. ** minimal preprocessor with only the most basic functionality of a C
  17. ** preprocessor, namely:
  18. **
  19. ** - Limited `#if`, where its one argument is a macro name which
  20. ** resolves to true if it's defined, false if it's not. Likewise,
  21. ** `#ifnot` is the inverse. Includes `#else` and `#elif` and
  22. ** `#elifnot`. Such chains are terminated with `#endif`.
  23. **
  24. ** - `#define` accepts one or more arguments, the names of
  25. ** macros. Each one is implicitly true.
  26. **
  27. ** - `#undef` undefine one or more macros.
  28. **
  29. ** - `#error` treats the rest of the line as a fatal error message.
  30. **
  31. ** - `#include` treats its argument as a filename token (NOT quoted,
  32. ** though support for quoting may be added later). Some effort is
  33. ** made to prevent recursive inclusion, but that support is both
  34. ** somewhat fragile and possibly completely unnecessary.
  35. **
  36. ** - `#pragma` is in place for adding "meta-commands", but it does not
  37. ** yet have any concrete list of documented commands.
  38. **
  39. * - `#stderr` outputs its file name, line number, and the remaininder
  40. ** of that line to stderr.
  41. **
  42. ** - `#//` acts as a single-line comment, noting that there must be as
  43. ** space after the `//` part because `//` is (despite appearances)
  44. ** parsed like a keyword.
  45. **
  46. ** Note that "#" above is symbolic. The keyword delimiter is
  47. ** configurable and defaults to "##". Define CMPP_DEFAULT_DELIM to a
  48. ** string when compiling to define the default at build-time.
  49. **
  50. ** This preprocessor does no expansion of content except within the
  51. ** bounds of its `#keywords`.
  52. **
  53. ** Design note: this code makes use of sqlite3. Though not _strictly_
  54. ** needed in order to implement it, this tool was specifically created
  55. ** for use with the sqlite3 project's own JavaScript code, so there's
  56. ** no reason not to make use of it to do some of the heavy lifting. It
  57. ** does not require any cutting-edge sqlite3 features and should be
  58. ** usable with any version which supports `WITHOUT ROWID`.
  59. **
  60. ** Author(s):
  61. **
  62. ** - Stephan Beal <https://wanderinghorse.net/home/stephan/>
  63. */
  64. #include <stdlib.h>
  65. #include <stdio.h>
  66. #include <errno.h>
  67. #include <string.h>
  68. #include <stdarg.h>
  69. #include <assert.h>
  70. #include <ctype.h>
  71. #include "sqlite3.h"
  72. #if defined(_WIN32) || defined(WIN32)
  73. # include <io.h>
  74. # include <fcntl.h>
  75. # ifndef access
  76. # define access(f,m) _access((f),(m))
  77. # endif
  78. #else
  79. # include <unistd.h>
  80. #endif
  81. #ifndef CMPP_DEFAULT_DELIM
  82. #define CMPP_DEFAULT_DELIM "##"
  83. #endif
  84. #if 1
  85. # define CMPP_NORETURN __attribute__((noreturn))
  86. #else
  87. # define CMPP_NORETURN
  88. #endif
  89. /* Fatally exits the app with the given printf-style message. */
  90. static CMPP_NORETURN void fatalv(char const *zFmt, va_list);
  91. static CMPP_NORETURN void fatal(char const *zFmt, ...);
  92. /** Proxy for free(), for symmetry with cmpp_realloc(). */
  93. static void cmpp_free(void *p);
  94. /** A realloc() proxy which dies fatally on allocation error. */
  95. static void * cmpp_realloc(void * p, unsigned n);
  96. #if 0
  97. /** A malloc() proxy which dies fatally on allocation error. */
  98. static void * cmpp_malloc(unsigned n);
  99. #endif
  100. /*
  101. ** If p is stdin or stderr then this is a no-op, else it is a
  102. ** proxy for fclose(). This is a no-op if p is NULL.
  103. */
  104. static void FILE_close(FILE *p);
  105. /*
  106. ** Works like fopen() but accepts the special name "-" to mean either
  107. ** stdin (if zMode indicates a real-only mode) or stdout. Fails
  108. ** fatally on error.
  109. */
  110. static FILE * FILE_open(char const *zName, const char * zMode);
  111. /*
  112. ** Reads the entire contents of the given file, allocating it in a
  113. ** buffer which gets assigned to `*pOut`. `*nOut` gets assigned the
  114. ** length of the output buffer. Fails fatally on error.
  115. */
  116. static void FILE_slurp(FILE *pFile, unsigned char **pOut,
  117. unsigned * nOut);
  118. /*
  119. ** Intended to be passed an sqlite3 result code. If it's non-0
  120. ** then it emits a fatal error message which contains both the
  121. ** given string and the sqlite3_errmsg() from the application's
  122. ** database instance.
  123. */
  124. static void db_affirm_rc(int rc, const char * zMsg);
  125. /*
  126. ** Proxy for sqlite3_str_finish() which fails fatally if that
  127. ** routine returns NULL.
  128. */
  129. static char * db_str_finish(sqlite3_str *s, int * n);
  130. /*
  131. ** Proxy for sqlite3_str_new() which fails fatally if that
  132. ** routine returns NULL.
  133. */
  134. static sqlite3_str * db_str_new(void);
  135. /* Proxy for sqlite3_finalize(). */
  136. static void db_finalize(sqlite3_stmt *pStmt);
  137. /*
  138. ** Proxy for sqlite3_step() which fails fatally if the result
  139. ** is anything other than SQLITE_ROW or SQLITE_DONE.
  140. */
  141. static int db_step(sqlite3_stmt *pStmt);
  142. /*
  143. ** Proxy for sqlite3_bind_int() which fails fatally on error.
  144. */
  145. static void db_bind_int(sqlite3_stmt *pStmt, int col, int val);
  146. #if 0
  147. /*
  148. ** Proxy for sqlite3_bind_null() which fails fatally on error.
  149. */
  150. static void db_bind_null(sqlite3_stmt *pStmt, int col);
  151. #endif
  152. /*
  153. ** Proxy for sqlite3_bind_text() which fails fatally on error.
  154. */
  155. static void db_bind_text(sqlite3_stmt *pStmt, int col, const char * zStr);
  156. /*
  157. ** Proxy for sqlite3_bind_text() which fails fatally on error.
  158. */
  159. static void db_bind_textn(sqlite3_stmt *pStmt, int col, const char * zStr, int len);
  160. #if 0
  161. /*
  162. ** Proxy for sqlite3_bind_text() which fails fatally on error. It uses
  163. ** sqlite3_str_vappendf() so supports all of its formatting options.
  164. */
  165. static void db_bind_textv(sqlite3_stmt *pStmt, int col, const char * zFmt, ...);
  166. #endif
  167. /*
  168. ** Proxy for sqlite3_free(), to be passed any memory which is allocated
  169. ** by sqlite3_malloc().
  170. */
  171. static void db_free(void *m);
  172. /*
  173. ** Adds the given `#define` macro name to the list of macros, ignoring
  174. ** any duplicates. Fails fatally on error.
  175. */
  176. static void db_define_add(const char * zKey);
  177. /*
  178. ** Returns true if the given key is already in the `#define` list,
  179. ** else false. Fails fatally on db error.
  180. */
  181. static int db_define_has(const char * zName);
  182. /*
  183. ** Removes the given `#define` macro name from the list of
  184. ** macros. Fails fatally on error.
  185. */
  186. static void db_define_rm(const char * zKey);
  187. /*
  188. ** Adds the given filename to the list of being-`#include`d files,
  189. ** using the given source file name and line number of error reporting
  190. ** purposes. If recursion is later detected.
  191. */
  192. static void db_including_add(const char * zKey, const char * zSrc, int srcLine);
  193. /*
  194. ** Adds the given dir to the list of includes. They are checked in the
  195. ** order they are added.
  196. */
  197. static void db_include_dir_add(const char * zKey);
  198. /*
  199. ** Returns a resolved path of PREFIX+'/'+zKey, where PREFIX is one of
  200. ** the `#include` dirs (db_include_dir_add()). If no file match is
  201. ** found, NULL is returned. Memory must eventually be passed to
  202. ** db_free() to free it.
  203. */
  204. static char * db_include_search(const char * zKey);
  205. /*
  206. ** Removes the given key from the `#include` list.
  207. */
  208. static void db_include_rm(const char * zKey);
  209. /*
  210. ** A proxy for sqlite3_prepare() which fails fatally on error.
  211. */
  212. static void db_prepare(sqlite3_stmt **pStmt, const char * zSql, ...);
  213. /*
  214. ** Opens the given file and processes its contents as c-pp, sending
  215. ** all output to the global c-pp output channel. Fails fatally on
  216. ** error.
  217. */
  218. static void cmpp_process_file(const char * zName);
  219. /*
  220. ** Returns the number newline characters between the given starting
  221. ** point and inclusive ending point. Results are undefined if zFrom is
  222. ** greater than zTo.
  223. */
  224. static unsigned count_lines(unsigned char const * zFrom,
  225. unsigned char const *zTo);
  226. /*
  227. ** Wrapper around a FILE handle.
  228. */
  229. struct FileWrapper {
  230. /* File's name. */
  231. char const *zName;
  232. /* FILE handle. */
  233. FILE * pFile;
  234. /* Where FileWrapper_slurp() stores the file's contents. */
  235. unsigned char * zContent;
  236. /* Size of this->zContent, as set by FileWrapper_slurp(). */
  237. unsigned nContent;
  238. };
  239. typedef struct FileWrapper FileWrapper;
  240. #define FileWrapper_empty_m {0,0,0,0}
  241. static const FileWrapper FileWrapper_empty = FileWrapper_empty_m;
  242. /* Proxy for FILE_close(). */
  243. static void FileWrapper_close(FileWrapper * p);
  244. /* Proxy for FILE_open(). */
  245. static void FileWrapper_open(FileWrapper * p, const char * zName, const char *zMode);
  246. /* Proxy for FILE_slurp(). */
  247. static void FileWrapper_slurp(FileWrapper * p);
  248. /*
  249. ** Outputs a printf()-formatted message to stderr.
  250. */
  251. static void g_stderr(char const *zFmt, ...);
  252. /*
  253. ** Outputs a printf()-formatted message to stderr.
  254. */
  255. static void g_stderrv(char const *zFmt, va_list);
  256. #define g_debug(lvl,pfexpr) \
  257. if(lvl<=g.doDebug) g_stderr("%s @ %s:%d: ",g.zArgv0,__FILE__,__LINE__); \
  258. if(lvl<=g.doDebug) g_stderr pfexpr
  259. void fatalv(char const *zFmt, va_list va){
  260. if(zFmt && *zFmt){
  261. vfprintf(stderr, zFmt, va);
  262. }
  263. fputc('\n', stderr);
  264. exit(1);
  265. }
  266. void fatal(char const *zFmt, ...){
  267. va_list va;
  268. va_start(va, zFmt);
  269. fatalv(zFmt, va);
  270. va_end(va);
  271. }
  272. void cmpp_free(void *p){
  273. free(p);
  274. }
  275. void * cmpp_realloc(void * p, unsigned n){
  276. void * const rc = realloc(p, n);
  277. if(!rc) fatal("realloc(P,%u) failed", n);
  278. return rc;
  279. }
  280. #if 0
  281. void * cmpp_malloc(unsigned n){
  282. void * const rc = malloc(n);
  283. if(!rc) fatal("malloc(%u) failed", n);
  284. return rc;
  285. }
  286. #endif
  287. FILE * FILE_open(char const *zName, const char * zMode){
  288. FILE * p;
  289. if('-'==zName[0] && 0==zName[1]){
  290. p = strstr(zMode,"w") ? stdout : stdin;
  291. }else{
  292. p = fopen(zName, zMode);
  293. if(!p) fatal("Cannot open file [%s] with mode [%s]", zName, zMode);
  294. }
  295. return p;
  296. }
  297. void FILE_close(FILE *p){
  298. if(p && p!=stdout && p!=stderr){
  299. fclose(p);
  300. }
  301. }
  302. void FILE_slurp(FILE *pFile, unsigned char **pOut,
  303. unsigned * nOut){
  304. unsigned char zBuf[1024 * 8];
  305. unsigned char * pDest = 0;
  306. unsigned nAlloc = 0;
  307. unsigned nOff = 0;
  308. /* Note that this needs to be able to work on non-seekable streams,
  309. ** thus we read in chunks instead of doing a single alloc and
  310. ** filling it in one go. */
  311. while( !feof(pFile) ){
  312. size_t const n = fread(zBuf, 1, sizeof(zBuf), pFile);
  313. if(n>0){
  314. if(nAlloc < nOff + n + 1){
  315. nAlloc = nOff + n + 1;
  316. pDest = cmpp_realloc(pDest, nAlloc);
  317. }
  318. memcpy(pDest + nOff, zBuf, n);
  319. nOff += n;
  320. }
  321. }
  322. if(pDest) pDest[nOff] = 0;
  323. *pOut = pDest;
  324. *nOut = nOff;
  325. }
  326. void FileWrapper_close(FileWrapper * p){
  327. if(p->pFile) FILE_close(p->pFile);
  328. if(p->zContent) cmpp_free(p->zContent);
  329. *p = FileWrapper_empty;
  330. }
  331. void FileWrapper_open(FileWrapper * p, const char * zName,
  332. const char * zMode){
  333. FileWrapper_close(p);
  334. p->pFile = FILE_open(zName, zMode);
  335. p->zName = zName;
  336. }
  337. void FileWrapper_slurp(FileWrapper * p){
  338. assert(!p->zContent);
  339. assert(p->pFile);
  340. FILE_slurp(p->pFile, &p->zContent, &p->nContent);
  341. }
  342. unsigned count_lines(unsigned char const * zFrom, unsigned char const *zTo){
  343. unsigned ln = 0;
  344. unsigned char const *zPos = zFrom;
  345. assert(zFrom && zTo);
  346. assert(zFrom <= zTo);
  347. for(; zPos < zTo; ++zPos){
  348. switch(*zPos){
  349. case (unsigned)'\n': ++ln; break;
  350. default: break;
  351. }
  352. }
  353. return ln;
  354. }
  355. enum CmppParseState {
  356. TS_Start = 1,
  357. TS_If,
  358. TS_IfPassed,
  359. TS_Else,
  360. TS_Error
  361. };
  362. typedef enum CmppParseState CmppParseState;
  363. enum CmppTokenType {
  364. TT_Invalid = 0,
  365. TT_Comment,
  366. TT_Define,
  367. TT_Elif,
  368. TT_ElifNot,
  369. TT_Else,
  370. TT_EndIf,
  371. TT_Error,
  372. TT_If,
  373. TT_IfNot,
  374. TT_Include,
  375. TT_Line,
  376. TT_Pragma,
  377. TT_Stderr,
  378. TT_Undef
  379. };
  380. typedef enum CmppTokenType CmppTokenType;
  381. struct CmppToken {
  382. CmppTokenType ttype;
  383. /* Line number of this token in the source file. */
  384. unsigned lineNo;
  385. /* Start of the token. */
  386. unsigned char const * zBegin;
  387. /* One-past-the-end byte of the token. */
  388. unsigned char const * zEnd;
  389. };
  390. typedef struct CmppToken CmppToken;
  391. #define CmppToken_empty_m {TT_Invalid,0,0,0}
  392. static const CmppToken CmppToken_empty = CmppToken_empty_m;
  393. /*
  394. ** CmppLevel represents one "level" of tokenization, starting at the
  395. ** top of the main input, incrementing once for each level of `#if`,
  396. ** and decrementing for each `#endif`.
  397. */
  398. typedef struct CmppLevel CmppLevel;
  399. struct CmppLevel {
  400. unsigned short flags;
  401. /*
  402. ** Used for controlling which parts of an if/elif/...endif chain
  403. ** should get output.
  404. */
  405. unsigned short skipLevel;
  406. /* The token which started this level (an 'if' or 'ifnot'). */
  407. CmppToken token;
  408. CmppParseState pstate;
  409. };
  410. #define CmppLevel_empty_m {0U,0U,CmppToken_empty_m,TS_Start}
  411. static const CmppLevel CmppLevel_empty = CmppLevel_empty_m;
  412. enum CmppLevel_Flags {
  413. /* Max depth of nested `#if` constructs in a single tokenizer. */
  414. CmppLevel_Max = 10,
  415. /* Max number of keyword arguments. */
  416. CmppArgs_Max = 10,
  417. /* Flag indicating that output for a CmpLevel should be elided. */
  418. CmppLevel_F_ELIDE = 0x01,
  419. /*
  420. ** Mask of CmppLevel::flags which are inherited when CmppLevel_push()
  421. ** is used.
  422. */
  423. CmppLevel_F_INHERIT_MASK = 0x01
  424. };
  425. typedef struct CmppTokenizer CmppTokenizer;
  426. typedef struct CmppKeyword CmppKeyword;
  427. typedef void (*cmpp_keyword_f)(CmppKeyword const * pKw, CmppTokenizer * t);
  428. struct CmppKeyword {
  429. const char *zName;
  430. unsigned nName;
  431. int bTokenize;
  432. CmppTokenType ttype;
  433. cmpp_keyword_f xCall;
  434. };
  435. static CmppKeyword const * CmppKeyword_search(const char *zName);
  436. static void cmpp_process_keyword(CmppTokenizer * const t);
  437. /*
  438. ** Tokenizer for c-pp input files.
  439. */
  440. struct CmppTokenizer {
  441. const char * zName; /* Input (file) name for error reporting */
  442. unsigned const char * zBegin; /* start of input */
  443. unsigned const char * zEnd; /* one-after-the-end of input */
  444. unsigned const char * zAnchor; /* start of input or end point of
  445. previous token */
  446. unsigned const char * zPos; /* current position */
  447. unsigned int lineNo; /* line # of current pos */
  448. CmppParseState pstate;
  449. CmppToken token; /* current token result */
  450. struct {
  451. unsigned ndx;
  452. CmppLevel stack[CmppLevel_Max];
  453. } level;
  454. /* Args for use in cmpp_keyword_f() impls. */
  455. struct {
  456. CmppKeyword const * pKw;
  457. int argc;
  458. const unsigned char * argv[CmppArgs_Max];
  459. unsigned char lineBuf[1024];
  460. } args;
  461. };
  462. #define CT_level(t) (t)->level.stack[(t)->level.ndx]
  463. #define CT_pstate(t) CT_level(t).pstate
  464. #define CT_skipLevel(t) CT_level(t).skipLevel
  465. #define CLvl_skip(lvl) ((lvl)->skipLevel || ((lvl)->flags & CmppLevel_F_ELIDE))
  466. #define CT_skip(t) CLvl_skip(&CT_level(t))
  467. #define CmppTokenizer_empty_m { \
  468. 0,0,0,0,0,1U/*lineNo*/, \
  469. TS_Start, \
  470. CmppToken_empty_m, \
  471. {/*level*/0U,{CmppLevel_empty_m}}, \
  472. {/*args*/0,0,{0},{0}} \
  473. }
  474. static const CmppTokenizer CmppTokenizer_empty = CmppTokenizer_empty_m;
  475. static void cmpp_t_out(CmppTokenizer * t, void const *z, unsigned int n);
  476. /*static void cmpp_t_outf(CmppTokenizer * t, char const *zFmt, ...);*/
  477. /*
  478. ** Pushes a new level into the given tokenizer. Fails fatally if
  479. ** it's too deep.
  480. */
  481. static void CmppLevel_push(CmppTokenizer * const t);
  482. /*
  483. ** Pops a level from the tokenizer. Fails fatally if the top
  484. ** level is popped.
  485. */
  486. static void CmppLevel_pop(CmppTokenizer * const t);
  487. /*
  488. ** Returns the current level object.
  489. */
  490. static CmppLevel * CmppLevel_get(CmppTokenizer * const t);
  491. /*
  492. ** Global app state singleton. */
  493. static struct Global {
  494. /* main()'s argv[0]. */
  495. const char * zArgv0;
  496. /*
  497. ** Bytes of the keyword delimiter/prefix. Owned
  498. ** elsewhere.
  499. */
  500. const char * zDelim;
  501. /* Byte length of this->zDelim. */
  502. unsigned short nDelim;
  503. /* If true, enables certain debugging output. */
  504. int doDebug;
  505. /* App's db instance. */
  506. sqlite3 * db;
  507. /* Output channel. */
  508. FileWrapper out;
  509. struct {
  510. sqlite3_stmt * defIns;
  511. sqlite3_stmt * defDel;
  512. sqlite3_stmt * defHas;
  513. sqlite3_stmt * inclIns;
  514. sqlite3_stmt * inclDel;
  515. sqlite3_stmt * inclHas;
  516. sqlite3_stmt * inclPathAdd;
  517. sqlite3_stmt * inclSearch;
  518. } stmt;
  519. } g = {
  520. "?",
  521. CMPP_DEFAULT_DELIM/*zDelim*/,
  522. (unsigned short) sizeof(CMPP_DEFAULT_DELIM)-1/*nDelim*/,
  523. 0/*doDebug*/,
  524. 0/*db*/,
  525. FileWrapper_empty_m/*out*/,
  526. {/*stmt*/
  527. 0/*defIns*/, 0/*defDel*/, 0/*defHas*/,
  528. 0/*inclIns*/, 0/*inclDel*/, 0/*inclHas*/,
  529. 0/*inclPathAdd*/
  530. }
  531. };
  532. #if 0
  533. /*
  534. ** Outputs a printf()-formatted message to c-pp's global output
  535. ** channel.
  536. */
  537. static void g_outf(char const *zFmt, ...);
  538. void g_outf(char const *zFmt, ...){
  539. va_list va;
  540. va_start(va, zFmt);
  541. vfprintf(g.out.pFile, zFmt, va);
  542. va_end(va);
  543. }
  544. #endif
  545. #if 0
  546. /* Outputs n bytes from z to c-pp's global output channel. */
  547. static void g_out(void const *z, unsigned int n);
  548. void g_out(void const *z, unsigned int n){
  549. if(1!=fwrite(z, n, 1, g.out.pFile)){
  550. int const err = errno;
  551. fatal("fwrite() output failed with errno #%d", err);
  552. }
  553. }
  554. #endif
  555. void g_stderrv(char const *zFmt, va_list va){
  556. vfprintf(stderr, zFmt, va);
  557. }
  558. void g_stderr(char const *zFmt, ...){
  559. va_list va;
  560. va_start(va, zFmt);
  561. g_stderrv(zFmt, va);
  562. va_end(va);
  563. }
  564. void cmpp_t_out(CmppTokenizer * t, void const *z, unsigned int n){
  565. g_debug(3,("CT_skipLevel() ?= %d\n",CT_skipLevel(t)));
  566. g_debug(3,("CT_skip() ?= %d\n",CT_skip(t)));
  567. if(!CT_skip(t)){
  568. if(1!=fwrite(z, n, 1, g.out.pFile)){
  569. int const err = errno;
  570. fatal("fwrite() output failed with errno #%d", err);
  571. }
  572. }
  573. }
  574. void CmppLevel_push(CmppTokenizer * const t){
  575. CmppLevel * pPrev;
  576. CmppLevel * p;
  577. if(t->level.ndx+1 == (unsigned)CmppLevel_Max){
  578. fatal("%sif nesting level is too deep. Max=%d\n",
  579. g.zDelim, CmppLevel_Max);
  580. }
  581. pPrev = &CT_level(t);
  582. g_debug(3,("push from tokenizer level=%u flags=%04x\n", t->level.ndx, pPrev->flags));
  583. p = &t->level.stack[++t->level.ndx];
  584. *p = CmppLevel_empty;
  585. p->token = t->token;
  586. p->flags = (CmppLevel_F_INHERIT_MASK & pPrev->flags);
  587. if(CLvl_skip(pPrev)) p->flags |= CmppLevel_F_ELIDE;
  588. g_debug(3,("push to tokenizer level=%u flags=%04x\n", t->level.ndx, p->flags));
  589. }
  590. void CmppLevel_pop(CmppTokenizer * const t){
  591. if(!t->level.ndx){
  592. fatal("Internal error: CmppLevel_pop() at the top of the stack");
  593. }
  594. g_debug(3,("pop from tokenizer level=%u, flags=%04x skipLevel?=%d\n", t->level.ndx,
  595. t->level.stack[t->level.ndx].flags, CT_skipLevel(t)));
  596. g_debug(3,("CT_skipLevel() ?= %d\n",CT_skipLevel(t)));
  597. g_debug(3,("CT_skip() ?= %d\n",CT_skip(t)));
  598. t->level.stack[t->level.ndx--] = CmppLevel_empty;
  599. g_debug(3,("pop to tokenizer level=%u, flags=%04x\n", t->level.ndx,
  600. t->level.stack[t->level.ndx].flags));
  601. g_debug(3,("CT_skipLevel() ?= %d\n",CT_skipLevel(t)));
  602. g_debug(3,("CT_skip() ?= %d\n",CT_skip(t)));
  603. }
  604. CmppLevel * CmppLevel_get(CmppTokenizer * const t){
  605. return &t->level.stack[t->level.ndx];
  606. }
  607. void db_affirm_rc(int rc, const char * zMsg){
  608. if(rc){
  609. fatal("Db error #%d %s: %s", rc, zMsg, sqlite3_errmsg(g.db));
  610. }
  611. }
  612. void db_finalize(sqlite3_stmt *pStmt){
  613. sqlite3_finalize(pStmt);
  614. }
  615. int db_step(sqlite3_stmt *pStmt){
  616. int const rc = sqlite3_step(pStmt);
  617. if(SQLITE_ROW!=rc && SQLITE_DONE!=rc){
  618. db_affirm_rc(rc, "from db_step()");
  619. }
  620. return rc;
  621. }
  622. static sqlite3_str * db_str_new(void){
  623. sqlite3_str * rc = sqlite3_str_new(g.db);
  624. if(!rc) fatal("Alloc failed for sqlite3_str_new()");
  625. return rc;
  626. }
  627. static char * db_str_finish(sqlite3_str *s, int * n){
  628. int const rc = sqlite3_str_errcode(s);
  629. if(rc) fatal("Error #%d from sqlite3_str_errcode()", rc);
  630. if(n) *n = sqlite3_str_length(s);
  631. char * z = sqlite3_str_finish(s);
  632. if(!z) fatal("Alloc failed for sqlite3_str_new()");
  633. return z;
  634. }
  635. void db_prepare(sqlite3_stmt **pStmt, const char * zSql, ...){
  636. int rc;
  637. sqlite3_str * str = db_str_new();
  638. char * z = 0;
  639. int n = 0;
  640. va_list va;
  641. if(!str) fatal("sqlite3_str_new() failed");
  642. va_start(va, zSql);
  643. sqlite3_str_vappendf(str, zSql, va);
  644. va_end(va);
  645. rc = sqlite3_str_errcode(str);
  646. if(rc) fatal("sqlite3_str_errcode() = %d", rc);
  647. z = db_str_finish(str, &n);
  648. rc = sqlite3_prepare_v2(g.db, z, n, pStmt, 0);
  649. if(rc) fatal("Error #%d (%s) preparing: %s",
  650. rc, sqlite3_errmsg(g.db), z);
  651. sqlite3_free(z);
  652. }
  653. void db_bind_int(sqlite3_stmt *pStmt, int col, int val){
  654. int const rc = sqlite3_bind_int(pStmt, col, val);
  655. db_affirm_rc(rc,"from db_bind_int()");
  656. }
  657. #if 0
  658. void db_bind_null(sqlite3_stmt *pStmt, int col){
  659. int const rc = sqlite3_bind_null(pStmt, col);
  660. db_affirm_rc(rc,"from db_bind_null()");
  661. }
  662. #endif
  663. void db_bind_textn(sqlite3_stmt *pStmt, int col,
  664. const char * zStr, int n){
  665. int const rc = zStr
  666. ? sqlite3_bind_text(pStmt, col, zStr, n, SQLITE_TRANSIENT)
  667. : sqlite3_bind_null(pStmt, col);
  668. db_affirm_rc(rc,"from db_bind_textn()");
  669. }
  670. void db_bind_text(sqlite3_stmt *pStmt, int col,
  671. const char * zStr){
  672. db_bind_textn(pStmt, col, zStr, -1);
  673. }
  674. #if 0
  675. void db_bind_textv(sqlite3_stmt *pStmt, int col,
  676. const char * zFmt, ...){
  677. int rc;
  678. sqlite3_str * str = db_str_new();
  679. int n = 0;
  680. char * z;
  681. va_list va;
  682. va_start(va,zFmt);
  683. sqlite3_str_vappendf(str, zFmt, va);
  684. va_end(va);
  685. z = db_str_finish(str, &n);
  686. rc = sqlite3_bind_text(pStmt, col, z, n, sqlite3_free);
  687. db_affirm_rc(rc,"from db_bind_textv()");
  688. }
  689. #endif
  690. void db_free(void *m){
  691. sqlite3_free(m);
  692. }
  693. void db_define_add(const char * zKey){
  694. int rc;
  695. if(!g.stmt.defIns){
  696. db_prepare(&g.stmt.defIns,
  697. "INSERT OR REPLACE INTO def(k) VALUES(?)");
  698. }
  699. db_bind_text(g.stmt.defIns, 1, zKey);
  700. rc = db_step(g.stmt.defIns);
  701. if(SQLITE_DONE != rc){
  702. db_affirm_rc(rc, "Stepping INSERT on def");
  703. }
  704. g_debug(2,("define: %s\n",zKey));
  705. sqlite3_reset(g.stmt.defIns);
  706. }
  707. int db_define_has(const char * zName){
  708. int rc;
  709. if(!g.stmt.defHas){
  710. db_prepare(&g.stmt.defHas, "SELECT 1 FROM def WHERE k=?");
  711. }
  712. db_bind_text(g.stmt.defHas, 1, zName);
  713. rc = db_step(g.stmt.defHas);
  714. if(SQLITE_ROW == rc){
  715. rc = 1;
  716. }else{
  717. assert(SQLITE_DONE==rc);
  718. rc = 0;
  719. }
  720. g_debug(1,("defined [%s] ?= %d\n",zName, rc));
  721. sqlite3_clear_bindings(g.stmt.defHas);
  722. sqlite3_reset(g.stmt.defHas);
  723. return rc;
  724. }
  725. void db_define_rm(const char * zKey){
  726. int rc;
  727. int n = 0;
  728. const char *zPos = zKey;
  729. if(!g.stmt.defDel){
  730. db_prepare(&g.stmt.defDel, "DELETE FROM def WHERE k=?");
  731. }
  732. for( ; *zPos && '='!=*zPos; ++n, ++zPos) {}
  733. db_bind_text(g.stmt.defDel, 1, zKey);
  734. rc = db_step(g.stmt.defDel);
  735. if(SQLITE_DONE != rc){
  736. db_affirm_rc(rc, "Stepping DELETE on def");
  737. }
  738. g_debug(2,("undefine: %.*s\n",n, zKey));
  739. sqlite3_clear_bindings(g.stmt.defDel);
  740. sqlite3_reset(g.stmt.defDel);
  741. }
  742. void db_including_add(const char * zKey, const char * zSrc, int srcLine){
  743. int rc;
  744. if(!g.stmt.inclIns){
  745. db_prepare(&g.stmt.inclIns,
  746. "INSERT OR FAIL INTO incl(file,srcFile,srcLine) VALUES(?,?,?)");
  747. }
  748. db_bind_text(g.stmt.inclIns, 1, zKey);
  749. db_bind_text(g.stmt.inclIns, 2, zSrc);
  750. db_bind_int(g.stmt.inclIns, 3, srcLine);
  751. rc = db_step(g.stmt.inclIns);
  752. if(SQLITE_DONE != rc){
  753. db_affirm_rc(rc, "Stepping INSERT on incl");
  754. }
  755. g_debug(2,("inclpath add [%s] from [%s]:%d\n", zKey, zSrc, srcLine));
  756. sqlite3_clear_bindings(g.stmt.inclIns);
  757. sqlite3_reset(g.stmt.inclIns);
  758. }
  759. void db_include_rm(const char * zKey){
  760. int rc;
  761. if(!g.stmt.inclDel){
  762. db_prepare(&g.stmt.inclDel, "DELETE FROM incl WHERE file=?");
  763. }
  764. db_bind_text(g.stmt.inclDel, 1, zKey);
  765. rc = db_step(g.stmt.inclDel);
  766. if(SQLITE_DONE != rc){
  767. db_affirm_rc(rc, "Stepping DELETE on incl");
  768. }
  769. g_debug(2,("inclpath rm [%s]\n", zKey));
  770. sqlite3_clear_bindings(g.stmt.inclDel);
  771. sqlite3_reset(g.stmt.inclDel);
  772. }
  773. char * db_include_search(const char * zKey){
  774. char * zName = 0;
  775. if(!g.stmt.inclSearch){
  776. db_prepare(&g.stmt.inclSearch,
  777. "SELECT ?1 fn WHERE fileExists(fn) "
  778. "UNION ALL SELECT * FROM ("
  779. "SELECT replace(dir||'/'||?1, '//','/') AS fn "
  780. "FROM inclpath WHERE fileExists(fn) ORDER BY seq"
  781. ")");
  782. }
  783. db_bind_text(g.stmt.inclSearch, 1, zKey);
  784. if(SQLITE_ROW==db_step(g.stmt.inclSearch)){
  785. const unsigned char * z = sqlite3_column_text(g.stmt.inclSearch, 0);
  786. zName = z ? sqlite3_mprintf("%s", z) : 0;
  787. if(!zName) fatal("Alloc failed");
  788. }
  789. sqlite3_clear_bindings(g.stmt.inclSearch);
  790. sqlite3_reset(g.stmt.inclSearch);
  791. return zName;
  792. }
  793. static int db_including_has(const char * zName){
  794. int rc;
  795. if(!g.stmt.inclHas){
  796. db_prepare(&g.stmt.inclHas, "SELECT 1 FROM incl WHERE file=?");
  797. }
  798. db_bind_text(g.stmt.inclHas, 1, zName);
  799. rc = db_step(g.stmt.inclHas);
  800. if(SQLITE_ROW == rc){
  801. rc = 1;
  802. }else{
  803. assert(SQLITE_DONE==rc);
  804. rc = 0;
  805. }
  806. g_debug(2,("inclpath has [%s] = %d\n",zName, rc));
  807. sqlite3_clear_bindings(g.stmt.inclHas);
  808. sqlite3_reset(g.stmt.inclHas);
  809. return rc;
  810. }
  811. #if 0
  812. /*
  813. ** Fails fatally if the `#include` list contains the given key.
  814. */
  815. static void db_including_check(const char * zKey);
  816. void db_including_check(const char * zName){
  817. if(db_including_has(zName)){
  818. fatal("Recursive include detected: %s\n", zName);
  819. }
  820. }
  821. #endif
  822. void db_include_dir_add(const char * zDir){
  823. static int seq = 0;
  824. int rc;
  825. if(!g.stmt.inclPathAdd){
  826. db_prepare(&g.stmt.inclPathAdd,
  827. "INSERT OR FAIL INTO inclpath(seq,dir) VALUES(?,?)");
  828. }
  829. db_bind_int(g.stmt.inclPathAdd, 1, ++seq);
  830. db_bind_text(g.stmt.inclPathAdd, 2, zDir);
  831. rc = db_step(g.stmt.inclPathAdd);
  832. if(SQLITE_DONE != rc){
  833. db_affirm_rc(rc, "Stepping INSERT on inclpath");
  834. }
  835. g_debug(2,("inclpath add #%d: %s\n",seq, zDir));
  836. sqlite3_clear_bindings(g.stmt.inclPathAdd);
  837. sqlite3_reset(g.stmt.inclPathAdd);
  838. }
  839. static void cmpp_atexit(void){
  840. #define FINI(M) if(g.stmt.M) sqlite3_finalize(g.stmt.M)
  841. FINI(defIns); FINI(defDel); FINI(defHas);
  842. FINI(inclIns); FINI(inclDel); FINI(inclHas);
  843. FINI(inclPathAdd); FINI(inclSearch);
  844. #undef FINI
  845. FileWrapper_close(&g.out);
  846. if(g.db) sqlite3_close(g.db);
  847. }
  848. /*
  849. ** sqlite3 UDF which returns true if its argument refers to an
  850. ** accessible file, else false.
  851. */
  852. static void udf_file_exists(
  853. sqlite3_context *context,
  854. int argc,
  855. sqlite3_value **argv
  856. ){
  857. const char *zName;
  858. (void)(argc); /* Unused parameter */
  859. zName = (const char*)sqlite3_value_text(argv[0]);
  860. if( zName==0 ) return;
  861. sqlite3_result_int(context, 0==access(zName, 0));
  862. }
  863. /* Initialize g.db, failing fatally on error. */
  864. static void cmpp_initdb(void){
  865. int rc;
  866. char * zErr = 0;
  867. const char * zSchema =
  868. "CREATE TABLE def("
  869. "k TEXT PRIMARY KEY NOT NULL"
  870. /*"v INTEGER DEFAULT 1"*/
  871. ") WITHOUT ROWID;"
  872. /* ^^^ defines */
  873. "CREATE TABLE incl("
  874. "file TEXT PRIMARY KEY NOT NULL,"
  875. "srcFile TEXT DEFAULT NULL,"
  876. "srcLine INTEGER DEFAULT 0"
  877. ") WITHOUT ROWID;"
  878. /* ^^^ files currently being included */
  879. "CREATE TABLE inclpath("
  880. "seq INTEGER UNIQUE, "
  881. "dir TEXT PRIMARY KEY NOT NULL ON CONFLICT IGNORE"
  882. ")"
  883. /* ^^^ include path */
  884. ;
  885. assert(0==g.db);
  886. if(g.db) return;
  887. rc = sqlite3_open_v2(":memory:", &g.db, SQLITE_OPEN_READWRITE, 0);
  888. if(rc) fatal("Error opening :memory: db.");
  889. rc = sqlite3_exec(g.db, zSchema, 0, 0, &zErr);
  890. if(rc) fatal("Error initializing database: %s", zErr);
  891. rc = sqlite3_create_function(g.db, "fileExists", 1,
  892. SQLITE_UTF8|SQLITE_DIRECTONLY, 0,
  893. udf_file_exists, 0, 0);
  894. db_affirm_rc(rc, "UDF registration failed.");
  895. }
  896. /*
  897. ** For position zPos, which must be in the half-open range
  898. ** [zBegin,zEnd), returns g.nDelim if it is at the start of a line and
  899. ** starts with g.zDelim, else returns 0.
  900. */
  901. static unsigned short cmpp_is_delim(unsigned char const *zBegin,
  902. unsigned char const *zEnd,
  903. unsigned char const *zPos){
  904. assert(zEnd>zBegin);
  905. assert(zPos<zEnd);
  906. assert(zPos>=zBegin);
  907. if(zPos>zBegin &&
  908. ('\n'!=*(zPos - 1)
  909. || ((unsigned)(zEnd - zPos) <= g.nDelim))){
  910. return 0;
  911. }else if(0==memcmp(zPos, g.zDelim, g.nDelim)){
  912. return g.nDelim;
  913. }else{
  914. return 0;
  915. }
  916. }
  917. /*
  918. ** Scans t to the next keyword line, emitting all input before that
  919. ** which is _not_ a keyword line unless it's elided due to being
  920. ** inside a block which elides its content. Returns 0 if no keyword
  921. ** line was found, in which case the end of the input has been
  922. ** reached, else returns a truthy value and sets up t's state for use
  923. ** with cmpp_process_keyword(), which should then be called.
  924. */
  925. static int cmpp_next_keyword_line(CmppTokenizer * const t){
  926. unsigned char const * zStart;
  927. unsigned char const * z;
  928. CmppToken * const tok = &t->token;
  929. unsigned short isDelim = 0;
  930. assert(t->zBegin);
  931. assert(t->zEnd > t->zBegin);
  932. if(!t->zPos) t->zPos = t->zBegin;
  933. t->zAnchor = t->zPos;
  934. zStart = z = t->zPos;
  935. *tok = CmppToken_empty;
  936. while(z<t->zEnd
  937. && 0==(isDelim = cmpp_is_delim(t->zBegin, t->zEnd, z))){
  938. ++z;
  939. }
  940. if(z>zStart){
  941. /* We passed up content */
  942. cmpp_t_out(t, zStart, (unsigned)(z - zStart));
  943. }
  944. assert(isDelim==0 || isDelim==g.nDelim);
  945. tok->lineNo = t->lineNo += count_lines(zStart, z);
  946. if(isDelim){
  947. /* Handle backslash-escaped newlines */
  948. int isEsc = 0, atEol = 0;
  949. tok->zBegin = z+isDelim;
  950. for( ++z ; z<t->zEnd && 0==atEol; ++z ){
  951. switch((int)*z){
  952. case (int)'\\':
  953. isEsc = 0==isEsc; break;
  954. case (int)'\n':
  955. atEol = 0==isEsc;
  956. isEsc = 0;
  957. ++t->lineNo;
  958. break;
  959. default:
  960. break;
  961. }
  962. }
  963. tok->zEnd = atEol ? z-1 : z;
  964. /* Strip leading spaces */
  965. while(tok->zBegin < tok->zEnd && isspace((char)(*tok->zBegin))){
  966. ++tok->zBegin;
  967. }
  968. tok->ttype = TT_Line;
  969. g_debug(2,("Keyword @ line %u: [[[%.*s]]]\n",
  970. tok->lineNo,
  971. (int)(tok->zEnd-tok->zBegin), tok->zBegin));
  972. }
  973. t->zPos = z;
  974. if(isDelim){
  975. /* Split t->token into arguments for the line's keyword */
  976. int i, argc = 0, prevChar = 0;
  977. const unsigned tokLen = (unsigned)(tok->zEnd - tok->zBegin);
  978. unsigned char * zKwd;
  979. unsigned char * zEsc;
  980. unsigned char * zz;
  981. assert(TT_Line==tok->ttype);
  982. if((unsigned)sizeof(t->args.lineBuf) < tokLen + 1){
  983. fatal("Keyword line is unreasonably long: %.*s",
  984. tokLen, tok->zBegin);
  985. }else if(!tokLen){
  986. fatal("Line #%u has no keyword after delimiter", tok->lineNo);
  987. }
  988. g_debug(2,("token @ line %u len=%u [[[%.*s]]]\n",
  989. tok->lineNo, tokLen, tokLen, tok->zBegin));
  990. zKwd = &t->args.lineBuf[0];
  991. memcpy(zKwd, tok->zBegin, tokLen);
  992. memset(zKwd + tokLen, 0, sizeof(t->args.lineBuf) - tokLen);
  993. for( zEsc = 0, zz = zKwd; *zz; ++zz ){
  994. /* Convert backslash-escaped newlines to whitespace */
  995. switch((int)*zz){
  996. case (int)'\\':
  997. if(zEsc) zEsc = 0;
  998. else zEsc = zz;
  999. break;
  1000. case (int)'\n':
  1001. assert(zEsc && "Should not have an unescaped newline?");
  1002. if(zEsc==zz-1){
  1003. *zEsc = (unsigned char)' ';
  1004. /* FIXME?: memmove() lnBuf content one byte to the left here
  1005. ** to collapse backslash and newline into a single
  1006. ** byte. Also consider collapsing all leading space on the
  1007. ** next line. */
  1008. }
  1009. zEsc = 0;
  1010. *zz = (unsigned char)' ';
  1011. break;
  1012. default:
  1013. zEsc = 0;
  1014. break;
  1015. }
  1016. }
  1017. t->args.argv[argc++] = zKwd;
  1018. for( zz = zKwd; *zz; ++zz ){
  1019. if(isspace(*zz)){
  1020. *zz = 0;
  1021. break;
  1022. }
  1023. }
  1024. t->args.pKw = CmppKeyword_search((char const *)zKwd);
  1025. if(!t->args.pKw){
  1026. fatal("Unknown keyword '%s' at line %u\n", (char const *)zKwd,
  1027. tok->lineNo);
  1028. }
  1029. for( ++zz ; *zz && isspace(*zz); ++zz ){}
  1030. if(t->args.pKw->bTokenize){
  1031. for( ; *zz; prevChar = *zz, ++zz ){
  1032. /* Split string into word-shaped tokens.
  1033. ** TODO ?= quoted strings, for the sake of the
  1034. ** #error keyword. */
  1035. if(isspace(*zz)){
  1036. assert(zz!=zKwd && "Leading space was stripped earlier.");
  1037. *zz = 0;
  1038. }else{
  1039. if(argc == (int)CmppArgs_Max){
  1040. fatal("Too many arguments @ line %u: %.*s",
  1041. tok->lineNo, tokLen, tok->zBegin);
  1042. }else if(zz>zKwd && !prevChar){
  1043. t->args.argv[argc++] = zz;
  1044. }
  1045. }
  1046. }
  1047. }else{
  1048. /* Treat rest of line as one token */
  1049. if(*zz) t->args.argv[argc++] = zz;
  1050. }
  1051. tok->ttype = t->args.pKw->ttype;
  1052. if(g.doDebug>1){
  1053. for(i = 0; i < argc; ++i){
  1054. g_debug(0,("line %u arg #%d=%s\n",
  1055. tok->lineNo, i,
  1056. (char const *)t->args.argv[i]));
  1057. }
  1058. }
  1059. t->args.argc = argc;
  1060. }else{
  1061. t->args.pKw = 0;
  1062. t->args.argc = 0;
  1063. }
  1064. return isDelim;
  1065. }
  1066. static void cmpp_kwd__err_prefix(CmppKeyword const * pKw, CmppTokenizer *t,
  1067. char const *zPrefix){
  1068. g_stderr("%s%s%s @ %s line %u: ",
  1069. zPrefix ? zPrefix : "",
  1070. zPrefix ? ": " : "",
  1071. pKw->zName, t->zName, t->token.lineNo);
  1072. }
  1073. /* Internal error reporting helper for cmpp_keyword_f() impls. */
  1074. static CMPP_NORETURN void cmpp_kwd__misuse(CmppKeyword const * pKw,
  1075. CmppTokenizer *t,
  1076. char const *zFmt, ...){
  1077. va_list va;
  1078. cmpp_kwd__err_prefix(pKw, t, "Fatal error");
  1079. va_start(va, zFmt);
  1080. fatalv(zFmt, va);
  1081. va_end(va);
  1082. }
  1083. /* No-op cmpp_keyword_f() impl. */
  1084. static void cmpp_kwd_noop(CmppKeyword const * pKw, CmppTokenizer *t){
  1085. if(t || pKw){/*unused*/}
  1086. }
  1087. /* #error impl. */
  1088. static void cmpp_kwd_error(CmppKeyword const * pKw, CmppTokenizer *t){
  1089. if(CT_skip(t)) return;
  1090. else{
  1091. assert(t->args.argc < 3);
  1092. const char *zBegin = t->args.argc>1
  1093. ? (const char *)t->args.argv[1] : 0;
  1094. cmpp_kwd__err_prefix(pKw, t, NULL);
  1095. fatal("%s", zBegin ? zBegin : "(no additional info)");
  1096. }
  1097. }
  1098. /* Impl. for #define, #undef */
  1099. static void cmpp_kwd_define(CmppKeyword const * pKw, CmppTokenizer *t){
  1100. if(CT_skip(t)) return;
  1101. if(t->args.argc<2){
  1102. cmpp_kwd__misuse(pKw, t, "Expecting one or more arguments");
  1103. }else{
  1104. int i = 1;
  1105. void (*func)(const char *) = TT_Define==pKw->ttype
  1106. ? db_define_add : db_define_rm;
  1107. for( ; i < t->args.argc; ++i){
  1108. func( (char const *)t->args.argv[i] );
  1109. }
  1110. }
  1111. }
  1112. /* Impl. for #if, #ifnot, #elif, #elifnot. */
  1113. static void cmpp_kwd_if(CmppKeyword const * pKw, CmppTokenizer *t){
  1114. int buul;
  1115. CmppParseState tmpState = TS_Start;
  1116. if(t->args.argc!=2){
  1117. cmpp_kwd__misuse(pKw, t, "Expecting exactly 1 argument");
  1118. }
  1119. /*g_debug(0,("%s %s level %u pstate=%d\n", pKw->zName,
  1120. (char const *)t->args.argv[1],
  1121. t->level.ndx, (int)CT_pstate(t)));*/
  1122. switch(pKw->ttype){
  1123. case TT_Elif:
  1124. case TT_ElifNot:
  1125. switch(CT_pstate(t)){
  1126. case TS_If: break;
  1127. case TS_IfPassed: CT_level(t).flags |= CmppLevel_F_ELIDE; return;
  1128. default: goto misuse;
  1129. }
  1130. break;
  1131. case TT_If:
  1132. case TT_IfNot:
  1133. CmppLevel_push(t);
  1134. break;
  1135. default:
  1136. cmpp_kwd__misuse(pKw, t, "Unpexected keyword token type");
  1137. break;
  1138. }
  1139. buul = db_define_has((char const *)t->args.argv[1]);
  1140. if(TT_IfNot==pKw->ttype || TT_ElifNot==pKw->ttype) buul = !buul;
  1141. if(buul){
  1142. CT_pstate(t) = tmpState = TS_IfPassed;
  1143. CT_skipLevel(t) = 0;
  1144. }else{
  1145. CT_pstate(t) = TS_If /* also for TT_IfNot, TT_Elif, TT_ElifNot */;
  1146. CT_skipLevel(t) = 1;
  1147. g_debug(3,("setting CT_skipLevel = 1 @ level %d\n", t->level.ndx));
  1148. }
  1149. if(TT_If==pKw->ttype || TT_IfNot==pKw->ttype){
  1150. unsigned const lvlIf = t->level.ndx;
  1151. CmppToken const lvlToken = CT_level(t).token;
  1152. while(cmpp_next_keyword_line(t)){
  1153. cmpp_process_keyword(t);
  1154. if(lvlIf > t->level.ndx){
  1155. assert(TT_EndIf == t->token.ttype);
  1156. break;
  1157. }
  1158. #if 0
  1159. if(TS_IfPassed==tmpState){
  1160. tmpState = TS_Start;
  1161. t->level.stack[lvlIf].flags |= CmppLevel_F_ELIDE;
  1162. g_debug(1,("Setting ELIDE for TS_IfPassed @ lv %d (lvlIf=%d)\n", t->level.ndx, lvlIf));
  1163. }
  1164. #endif
  1165. }
  1166. if(lvlIf <= t->level.ndx){
  1167. cmpp_kwd__err_prefix(pKw, t, NULL);
  1168. fatal("Input ended inside an unterminated %sif "
  1169. "opened at [%s] line %u",
  1170. g.zDelim, t->zName, lvlToken.lineNo);
  1171. }
  1172. }
  1173. return;
  1174. misuse:
  1175. cmpp_kwd__misuse(pKw, t, "'%s' used out of context",
  1176. pKw->zName);
  1177. }
  1178. /* Impl. for #else. */
  1179. static void cmpp_kwd_else(CmppKeyword const * pKw, CmppTokenizer *t){
  1180. if(t->args.argc>1){
  1181. cmpp_kwd__misuse(pKw, t, "Expecting no arguments");
  1182. }
  1183. switch(CT_pstate(t)){
  1184. case TS_IfPassed: CT_skipLevel(t) = 1; break;
  1185. case TS_If: CT_skipLevel(t) = 0; break;
  1186. default:
  1187. cmpp_kwd__misuse(pKw, t, "'%s' with no matching 'if'",
  1188. pKw->zName);
  1189. }
  1190. /*g_debug(0,("else flags=0x%02x skipLevel=%u\n",
  1191. CT_level(t).flags, CT_level(t).skipLevel));*/
  1192. CT_pstate(t) = TS_Else;
  1193. }
  1194. /* Impl. for #endif. */
  1195. static void cmpp_kwd_endif(CmppKeyword const * pKw, CmppTokenizer *t){
  1196. /* Maintenance reminder: we ignore all arguments after the endif
  1197. ** to allow for constructs like:
  1198. **
  1199. ** #endif // foo
  1200. **
  1201. ** in a manner which does not require a specific comment style */
  1202. switch(CT_pstate(t)){
  1203. case TS_Else:
  1204. case TS_If:
  1205. case TS_IfPassed:
  1206. break;
  1207. default:
  1208. cmpp_kwd__misuse(pKw, t, "'%s' with no matching 'if'",
  1209. pKw->zName);
  1210. }
  1211. CmppLevel_pop(t);
  1212. }
  1213. /* Impl. for #include. */
  1214. static void cmpp_kwd_include(CmppKeyword const * pKw, CmppTokenizer *t){
  1215. char const * zFile;
  1216. char * zResolved;
  1217. if(CT_skip(t)) return;
  1218. else if(t->args.argc!=2){
  1219. cmpp_kwd__misuse(pKw, t, "Expecting exactly 1 filename argument");
  1220. }
  1221. zFile = (const char *)t->args.argv[1];
  1222. if(db_including_has(zFile)){
  1223. /* Note that different spellings of the same filename
  1224. ** will elude this check, but that seems okay, as different
  1225. ** spellings means that we're not re-running the exact same
  1226. ** invocation. We might want some other form of multi-include
  1227. ** protection, rather than this, however. There may well be
  1228. ** sensible uses for recursion. */
  1229. cmpp_kwd__err_prefix(pKw, t, NULL);
  1230. fatal("Recursive include of file: %s", zFile);
  1231. }
  1232. zResolved = db_include_search(zFile);
  1233. if(zResolved){
  1234. db_including_add(zFile, t->zName, t->token.lineNo);
  1235. cmpp_process_file(zResolved);
  1236. db_include_rm(zFile);
  1237. db_free(zResolved);
  1238. }else{
  1239. cmpp_kwd__err_prefix(pKw, t, NULL);
  1240. fatal("file not found: %s", zFile);
  1241. }
  1242. }
  1243. /* Impl. for #pragma. */
  1244. static void cmpp_kwd_pragma(CmppKeyword const * pKw, CmppTokenizer *t){
  1245. const char * zArg;
  1246. if(CT_skip(t)) return;
  1247. else if(t->args.argc!=2){
  1248. cmpp_kwd__misuse(pKw, t, "Expecting one argument");
  1249. }
  1250. zArg = (const char *)t->args.argv[1];
  1251. #define M(X) 0==strcmp(zArg,X)
  1252. if(M("defines")){
  1253. sqlite3_stmt * q = 0;
  1254. db_prepare(&q, "SELECT k FROM def ORDER BY k");
  1255. g_stderr("cmpp defines:\n");
  1256. while(SQLITE_ROW==db_step(q)){
  1257. int const n = sqlite3_column_bytes(q, 0);
  1258. const char * z = (const char *)sqlite3_column_text(q, 0);
  1259. g_stderr("\t%.*s\n", n, z);
  1260. }
  1261. db_finalize(q);
  1262. }else{
  1263. cmpp_kwd__misuse(pKw, t, "Unknown pragma");
  1264. }
  1265. #undef M
  1266. }
  1267. /* #stder impl. */
  1268. static void cmpp_kwd_stderr(CmppKeyword const * pKw, CmppTokenizer *t){
  1269. if(CT_skip(t)) return;
  1270. else{
  1271. const char *zBegin = t->args.argc>1
  1272. ? (const char *)t->args.argv[1] : 0;
  1273. if(zBegin){
  1274. g_stderr("%s:%u: %s\n", t->zName, t->token.lineNo, zBegin);
  1275. }else{
  1276. g_stderr("%s:%u: (no %.*s%s argument)\n",
  1277. t->zName, t->token.lineNo,
  1278. g.nDelim, g.zDelim, pKw->zName);
  1279. }
  1280. }
  1281. }
  1282. #if 0
  1283. /* Impl. for dummy placeholder. */
  1284. static void cmpp_kwd_todo(CmppKeyword const * pKw, CmppTokenizer *t){
  1285. if(t){/*unused*/}
  1286. g_debug(0,("TODO: keyword handler for %s\n", pKw->zName));
  1287. }
  1288. #endif
  1289. CmppKeyword aKeywords[] = {
  1290. /* Keep these sorted by zName */
  1291. {"//", 2, 0, TT_Comment, cmpp_kwd_noop},
  1292. {"define", 6, 1, TT_Define, cmpp_kwd_define},
  1293. {"elif", 4, 1, TT_Elif, cmpp_kwd_if},
  1294. {"elifnot", 7, 1, TT_ElifNot, cmpp_kwd_if},
  1295. {"else", 4, 1, TT_Else, cmpp_kwd_else},
  1296. {"endif", 5, 0, TT_EndIf, cmpp_kwd_endif},
  1297. {"error", 4, 0, TT_Error, cmpp_kwd_error},
  1298. {"if", 2, 1, TT_If, cmpp_kwd_if},
  1299. {"ifnot", 5, 1, TT_IfNot, cmpp_kwd_if},
  1300. {"include", 7, 0, TT_Include, cmpp_kwd_include},
  1301. {"pragma", 6, 1, TT_Pragma, cmpp_kwd_pragma},
  1302. {"stderr", 6, 0, TT_Stderr, cmpp_kwd_stderr},
  1303. {"undef", 5, 1, TT_Undef, cmpp_kwd_define},
  1304. {0,0,TT_Invalid, 0}
  1305. };
  1306. static int cmp_CmppKeyword(const void *p1, const void *p2){
  1307. char const * zName = (const char *)p1;
  1308. CmppKeyword const * kw = (CmppKeyword const *)p2;
  1309. return strcmp(zName, kw->zName);
  1310. }
  1311. CmppKeyword const * CmppKeyword_search(const char *zName){
  1312. return (CmppKeyword const *)bsearch(zName, &aKeywords[0],
  1313. sizeof(aKeywords)/sizeof(aKeywords[0]) - 1,
  1314. sizeof(aKeywords[0]),
  1315. cmp_CmppKeyword);
  1316. }
  1317. void cmpp_process_keyword(CmppTokenizer * const t){
  1318. assert(t->args.pKw);
  1319. assert(t->args.argc);
  1320. t->args.pKw->xCall(t->args.pKw, t);
  1321. t->args.pKw = 0;
  1322. t->args.argc = 0;
  1323. }
  1324. void cmpp_process_file(const char * zName){
  1325. FileWrapper fw = FileWrapper_empty;
  1326. CmppTokenizer ct = CmppTokenizer_empty;
  1327. FileWrapper_open(&fw, zName, "r");
  1328. FileWrapper_slurp(&fw);
  1329. g_debug(1,("Read %u byte(s) from [%s]\n", fw.nContent, fw.zName));
  1330. ct.zName = zName;
  1331. ct.zBegin = fw.zContent;
  1332. ct.zEnd = fw.zContent + fw.nContent;
  1333. while(cmpp_next_keyword_line(&ct)){
  1334. cmpp_process_keyword(&ct);
  1335. }
  1336. FileWrapper_close(&fw);
  1337. if(0!=ct.level.ndx){
  1338. CmppLevel * const lv = CmppLevel_get(&ct);
  1339. fatal("Input ended inside an unterminated nested construct"
  1340. "opened at [%s] line %u", zName, lv->token.lineNo);
  1341. }
  1342. }
  1343. static void usage(int isErr){
  1344. FILE * const fOut = isErr ? stderr : stdout;
  1345. fprintf(fOut,
  1346. "Usage: %s [flags] [infile]\n"
  1347. "Flags:\n",
  1348. g.zArgv0);
  1349. #define arg(F,D) fprintf(fOut," %s\n %s\n",F, D)
  1350. arg("-f|--file FILE","Read input from FILE (default=- (stdin)).\n"
  1351. " Alternately, the first non-flag argument is assumed to "
  1352. "be the input file.");
  1353. arg("-o|--outfile FILE","Send output to FILE (default=- (stdout))");
  1354. arg("-DXYZ","Define XYZ to true");
  1355. arg("-UXYZ","Undefine XYZ (equivalent to false)");
  1356. arg("-IXYZ","Add dir XYZ to include path");
  1357. arg("-d|--delimiter VALUE", "Set keyword delimiter to VALUE "
  1358. "(default=" CMPP_DEFAULT_DELIM ")");
  1359. #undef arg
  1360. fputs("",fOut);
  1361. }
  1362. int main(int argc, char const * const * argv){
  1363. int rc = 0;
  1364. int i;
  1365. int inclCount = 0;
  1366. const char * zInfile = 0;
  1367. #define M(X) (0==strcmp(X,zArg))
  1368. #define ISFLAG(X) else if(M(X))
  1369. #define ISFLAG2(X,Y) else if(M(X) || M(Y))
  1370. #define ARGVAL \
  1371. if(i+1>=argc) fatal("Missing value for flag '%s'", zArg); \
  1372. zArg = argv[++i]
  1373. g.zArgv0 = argv[0];
  1374. atexit(cmpp_atexit);
  1375. cmpp_initdb();
  1376. for(i = 1; i < argc; ++i){
  1377. char const * zArg = argv[i];
  1378. while('-'==*zArg) ++zArg;
  1379. if(M("?") || M("help")) {
  1380. usage(0);
  1381. goto end;
  1382. }else if('D'==*zArg){
  1383. ++zArg;
  1384. if(!*zArg) fatal("Missing key for -D");
  1385. db_define_add(zArg);
  1386. }else if('U'==*zArg){
  1387. ++zArg;
  1388. if(!*zArg) fatal("Missing key for -U");
  1389. db_define_rm(zArg);
  1390. }else if('I'==*zArg){
  1391. ++zArg;
  1392. if(!*zArg) fatal("Missing directory for -I");
  1393. db_include_dir_add(zArg);
  1394. ++inclCount;
  1395. }
  1396. ISFLAG2("o","outfile"){
  1397. ARGVAL;
  1398. if(g.out.zName) fatal("Cannot use -o more than once.");
  1399. g.out.zName = zArg;
  1400. }
  1401. ISFLAG2("f","file"){
  1402. ARGVAL;
  1403. do_infile:
  1404. if(zInfile) fatal("Cannot use -i more than once.");
  1405. zInfile = zArg;
  1406. }
  1407. ISFLAG2("d","delimiter"){
  1408. ARGVAL;
  1409. g.zDelim = zArg;
  1410. g.nDelim = (unsigned short)strlen(zArg);
  1411. if(!g.nDelim) fatal("Keyword delimiter may not be empty.");
  1412. }
  1413. ISFLAG("debug"){
  1414. ++g.doDebug;
  1415. }else if(!zInfile && '-'!=argv[i][0]){
  1416. goto do_infile;
  1417. }else{
  1418. fatal("Unhandled flag: %s", argv[i]);
  1419. }
  1420. }
  1421. if(!zInfile) zInfile = "-";
  1422. if(!g.out.zName) g.out.zName = "-";
  1423. if(!inclCount) db_include_dir_add(".");
  1424. FileWrapper_open(&g.out, g.out.zName, "w");
  1425. cmpp_process_file(zInfile);
  1426. FileWrapper_close(&g.out);
  1427. end:
  1428. return rc ? EXIT_FAILURE : EXIT_SUCCESS;
  1429. }
  1430. #undef CT_level
  1431. #undef CT_pstate
  1432. #undef CT_skipLevel
  1433. #undef CT_skip
  1434. #undef CLvl_skip