wpp.c 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641
  1. /*
  2. * Exported functions of the Wine preprocessor
  3. *
  4. * Copyright 1998 Bertho A. Stultiens
  5. * Copyright 2002 Alexandre Julliard
  6. *
  7. * This library is free software; you can redistribute it and/or
  8. * modify it under the terms of the GNU Lesser General Public
  9. * License as published by the Free Software Foundation; either
  10. * version 2.1 of the License, or (at your option) any later version.
  11. *
  12. * This library is distributed in the hope that it will be useful,
  13. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  14. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  15. * Lesser General Public License for more details.
  16. *
  17. * You should have received a copy of the GNU Lesser General Public
  18. * License along with this library; if not, write to the Free Software
  19. * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
  20. */
  21. #include "config.h"
  22. #include <assert.h>
  23. #include <ctype.h>
  24. #include <fcntl.h>
  25. #include <stdio.h>
  26. #include <stdlib.h>
  27. #include <string.h>
  28. #include <stdarg.h>
  29. #include <time.h>
  30. #include "../tools.h"
  31. #include "utils.h"
  32. #include "wpp_private.h"
  33. struct pp_status pp_status;
  34. #define HASHKEY 2039
  35. static struct list pp_defines[HASHKEY];
  36. #define MAXIFSTACK 64
  37. static pp_if_state_t if_stack[MAXIFSTACK];
  38. static int if_stack_idx = 0;
  39. int ppy_debug, pp_flex_debug;
  40. struct define
  41. {
  42. struct list entry;
  43. char *name;
  44. char *value;
  45. };
  46. static struct list cmdline_defines = LIST_INIT( cmdline_defines );
  47. static struct strarray includes;
  48. static char *wpp_lookup(const char *name, int type, const char *parent_name)
  49. {
  50. char *cpy;
  51. char *cptr;
  52. char *path;
  53. const char *ccptr;
  54. int i, fd;
  55. cpy = xmalloc(strlen(name)+1);
  56. cptr = cpy;
  57. for(ccptr = name; *ccptr; ccptr++)
  58. {
  59. /* Convert to forward slash */
  60. if(*ccptr == '\\') {
  61. /* kill double backslash */
  62. if(ccptr[1] == '\\')
  63. ccptr++;
  64. *cptr = '/';
  65. }else {
  66. *cptr = *ccptr;
  67. }
  68. cptr++;
  69. }
  70. *cptr = '\0';
  71. if(type && parent_name)
  72. {
  73. /* Search directory of parent include and then -I path */
  74. path = strmake( "%s/%s", get_dirname(parent_name), cpy );
  75. fd = open( path, O_RDONLY );
  76. if (fd != -1)
  77. {
  78. close( fd );
  79. free( cpy );
  80. return path;
  81. }
  82. free( path );
  83. }
  84. /* Search -I path */
  85. for(i = 0; i < includes.count; i++)
  86. {
  87. path = strmake("%s/%s", includes.str[i], cpy);
  88. fd = open( path, O_RDONLY );
  89. if (fd != -1)
  90. {
  91. close( fd );
  92. free( cpy );
  93. return path;
  94. }
  95. free( path );
  96. }
  97. free( cpy );
  98. return NULL;
  99. }
  100. /* Don't comment on the hash, it's primitive but functional... */
  101. static int pphash(const char *str)
  102. {
  103. int sum = 0;
  104. while(*str)
  105. sum += *str++;
  106. return sum % HASHKEY;
  107. }
  108. pp_entry_t *pplookup(const char *ident)
  109. {
  110. int idx;
  111. pp_entry_t *ppp;
  112. if(!ident)
  113. return NULL;
  114. idx = pphash(ident);
  115. LIST_FOR_EACH_ENTRY( ppp, &pp_defines[idx], pp_entry_t, entry )
  116. {
  117. if(!strcmp(ident, ppp->ident))
  118. return ppp;
  119. }
  120. return NULL;
  121. }
  122. static void free_pp_entry( pp_entry_t *ppp, int idx )
  123. {
  124. if(ppp->iep)
  125. {
  126. list_remove( &ppp->iep->entry );
  127. free(ppp->iep->filename);
  128. free(ppp->iep);
  129. }
  130. list_remove( &ppp->entry );
  131. free(ppp);
  132. }
  133. /* initialize the define state */
  134. static void pp_init_define_state(void)
  135. {
  136. int i;
  137. for (i = 0; i < HASHKEY; i++) list_init( &pp_defines[i] );
  138. }
  139. /* free the current define state */
  140. static void pp_free_define_state(void)
  141. {
  142. int i;
  143. pp_entry_t *ppp, *ppp2;
  144. for (i = 0; i < HASHKEY; i++)
  145. {
  146. LIST_FOR_EACH_ENTRY_SAFE( ppp, ppp2, &pp_defines[i], pp_entry_t, entry )
  147. {
  148. free( ppp->ident );
  149. free( ppp->subst.text );
  150. free( ppp->filename );
  151. free_pp_entry( ppp, i );
  152. }
  153. }
  154. }
  155. void pp_del_define(const char *name)
  156. {
  157. pp_entry_t *ppp;
  158. int idx = pphash(name);
  159. if((ppp = pplookup(name)) == NULL)
  160. {
  161. if(pedantic)
  162. ppy_warning("%s was not defined", name);
  163. return;
  164. }
  165. if(pp_status.debug)
  166. printf("Deleting (%s, %d) <%s>\n", pp_status.input, pp_status.line_number, name);
  167. free( ppp->ident );
  168. free( ppp->subst.text );
  169. free( ppp->filename );
  170. free_pp_entry( ppp, idx );
  171. }
  172. pp_entry_t *pp_add_define(const char *def, const char *text)
  173. {
  174. int len;
  175. char *cptr;
  176. int idx;
  177. pp_entry_t *ppp;
  178. idx = pphash(def);
  179. if((ppp = pplookup(def)) != NULL)
  180. {
  181. if(pedantic)
  182. ppy_warning("Redefinition of %s\n%s:%d: note: previous definition was here",
  183. def, ppp->filename, ppp->linenumber);
  184. pp_del_define(def);
  185. }
  186. ppp = xmalloc(sizeof(pp_entry_t));
  187. memset( ppp, 0, sizeof(*ppp) );
  188. ppp->ident = xstrdup(def);
  189. ppp->type = def_define;
  190. ppp->subst.text = text ? xstrdup(text) : NULL;
  191. ppp->filename = xstrdup(pp_status.input ? pp_status.input : "<internal or cmdline>");
  192. ppp->linenumber = pp_status.input ? pp_status.line_number : 0;
  193. list_add_head( &pp_defines[idx], &ppp->entry );
  194. if(ppp->subst.text)
  195. {
  196. /* Strip trailing white space from subst text */
  197. len = strlen(ppp->subst.text);
  198. while(len && strchr(" \t\r\n", ppp->subst.text[len-1]))
  199. {
  200. ppp->subst.text[--len] = '\0';
  201. }
  202. /* Strip leading white space from subst text */
  203. for(cptr = ppp->subst.text; *cptr && strchr(" \t\r", *cptr); cptr++)
  204. ;
  205. if(ppp->subst.text != cptr)
  206. memmove(ppp->subst.text, cptr, strlen(cptr)+1);
  207. }
  208. if(pp_status.debug)
  209. printf("Added define (%s, %d) <%s> to <%s>\n", pp_status.input, pp_status.line_number, ppp->ident, ppp->subst.text ? ppp->subst.text : "(null)");
  210. return ppp;
  211. }
  212. pp_entry_t *pp_add_macro(char *id, char *args[], int nargs, mtext_t *exp)
  213. {
  214. int idx;
  215. pp_entry_t *ppp;
  216. idx = pphash(id);
  217. if((ppp = pplookup(id)) != NULL)
  218. {
  219. if(pedantic)
  220. ppy_warning("Redefinition of %s\n%s:%d: note: previous definition was here",
  221. id, ppp->filename, ppp->linenumber);
  222. pp_del_define(id);
  223. }
  224. ppp = xmalloc(sizeof(pp_entry_t));
  225. memset( ppp, 0, sizeof(*ppp) );
  226. ppp->ident = id;
  227. ppp->type = def_macro;
  228. ppp->margs = args;
  229. ppp->nargs = nargs;
  230. ppp->subst.mtext= exp;
  231. ppp->filename = xstrdup(pp_status.input ? pp_status.input : "<internal or cmdline>");
  232. ppp->linenumber = pp_status.input ? pp_status.line_number : 0;
  233. list_add_head( &pp_defines[idx], &ppp->entry );
  234. if(pp_status.debug)
  235. {
  236. fprintf(stderr, "Added macro (%s, %d) <%s(%d)> to <", pp_status.input, pp_status.line_number, ppp->ident, nargs);
  237. for(; exp; exp = exp->next)
  238. {
  239. switch(exp->type)
  240. {
  241. case exp_text:
  242. fprintf(stderr, " \"%s\" ", exp->subst.text);
  243. break;
  244. case exp_stringize:
  245. fprintf(stderr, " #(%d) ", exp->subst.argidx);
  246. break;
  247. case exp_concat:
  248. fprintf(stderr, "##");
  249. break;
  250. case exp_subst:
  251. fprintf(stderr, " <%d> ", exp->subst.argidx);
  252. break;
  253. }
  254. }
  255. fprintf(stderr, ">\n");
  256. }
  257. return ppp;
  258. }
  259. /*
  260. *-------------------------------------------------------------------------
  261. * Include management
  262. *-------------------------------------------------------------------------
  263. */
  264. void wpp_add_include_path(const char *path)
  265. {
  266. char *dir = xstrdup(path);
  267. char *cptr;
  268. for(cptr = dir; *cptr; cptr++)
  269. {
  270. /* Convert to forward slash */
  271. if(*cptr == '\\')
  272. *cptr = '/';
  273. }
  274. /* Kill eventual trailing '/' */
  275. if(*(cptr = dir + strlen(dir)-1) == '/') *cptr = '\0';
  276. strarray_add( &includes, dir );
  277. }
  278. char *wpp_find_include(const char *name, const char *parent_name)
  279. {
  280. return wpp_lookup(name, !!parent_name, parent_name);
  281. }
  282. void *pp_open_include(const char *name, int type, const char *parent_name, char **newpath)
  283. {
  284. char *path;
  285. void *fp;
  286. if (!(path = wpp_lookup(name, type, parent_name))) return NULL;
  287. fp = fopen(path, "rt");
  288. if (fp)
  289. {
  290. if (pp_status.debug)
  291. printf("Going to include <%s>\n", path);
  292. if (newpath) *newpath = path;
  293. else free( path );
  294. return fp;
  295. }
  296. free( path );
  297. return NULL;
  298. }
  299. /*
  300. *-------------------------------------------------------------------------
  301. * #if, #ifdef, #ifndef, #else, #elif and #endif state management
  302. *
  303. * #if state transitions are made on basis of the current TOS and the next
  304. * required state. The state transitions are required to housekeep because
  305. * #if:s can be nested. The ignore case is activated to prevent output from
  306. * within a false clause.
  307. * Some special cases come from the fact that the #elif cases are not
  308. * binary, but three-state. The problem is that all other elif-cases must
  309. * be false when one true one has been found. A second problem is that the
  310. * #else clause is a final clause. No extra #else:s may follow.
  311. *
  312. * The states mean:
  313. * if_true Process input to output
  314. * if_false Process input but no output
  315. * if_ignore Process input but no output
  316. * if_elif Process input but no output
  317. * if_elsefalse Process input but no output
  318. * if_elsettrue Process input to output
  319. *
  320. * The possible state-sequences are [state(stack depth)] (rest can be deduced):
  321. * TOS #if 1 #else #endif
  322. * if_true(n) if_true(n+1) if_elsefalse(n+1)
  323. * if_false(n) if_ignore(n+1) if_ignore(n+1)
  324. * if_elsetrue(n) if_true(n+1) if_elsefalse(n+1)
  325. * if_elsefalse(n) if_ignore(n+1) if_ignore(n+1)
  326. * if_elif(n) if_ignore(n+1) if_ignore(n+1)
  327. * if_ignore(n) if_ignore(n+1) if_ignore(n+1)
  328. *
  329. * TOS #if 1 #elif 0 #else #endif
  330. * if_true(n) if_true(n+1) if_elif(n+1) if_elif(n+1)
  331. * if_false(n) if_ignore(n+1) if_ignore(n+1) if_ignore(n+1)
  332. * if_elsetrue(n) if_true(n+1) if_elif(n+1) if_elif(n+1)
  333. * if_elsefalse(n) if_ignore(n+1) if_ignore(n+1) if_ignore(n+1)
  334. * if_elif(n) if_ignore(n+1) if_ignore(n+1) if_ignore(n+1)
  335. * if_ignore(n) if_ignore(n+1) if_ignore(n+1) if_ignore(n+1)
  336. *
  337. * TOS #if 0 #elif 1 #else #endif
  338. * if_true(n) if_false(n+1) if_true(n+1) if_elsefalse(n+1)
  339. * if_false(n) if_ignore(n+1) if_ignore(n+1) if_ignore(n+1)
  340. * if_elsetrue(n) if_false(n+1) if_true(n+1) if_elsefalse(n+1)
  341. * if_elsefalse(n) if_ignore(n+1) if_ignore(n+1) if_ignore(n+1)
  342. * if_elif(n) if_ignore(n+1) if_ignore(n+1) if_ignore(n+1)
  343. * if_ignore(n) if_ignore(n+1) if_ignore(n+1) if_ignore(n+1)
  344. *
  345. *-------------------------------------------------------------------------
  346. */
  347. static const char * const pp_if_state_str[] = {
  348. "if_false",
  349. "if_true",
  350. "if_elif",
  351. "if_elsefalse",
  352. "if_elsetrue",
  353. "if_ignore"
  354. };
  355. void pp_push_if(pp_if_state_t s)
  356. {
  357. if(if_stack_idx >= MAXIFSTACK)
  358. error("#if-stack overflow; #{if,ifdef,ifndef} nested too deeply (> %d)\n", MAXIFSTACK);
  359. if(pp_flex_debug)
  360. fprintf(stderr, "Push if %s:%d: %s(%d) -> %s(%d)\n", pp_status.input, pp_status.line_number, pp_if_state_str[pp_if_state()], if_stack_idx, pp_if_state_str[s], if_stack_idx+1);
  361. if_stack[if_stack_idx++] = s;
  362. switch(s)
  363. {
  364. case if_true:
  365. case if_elsetrue:
  366. break;
  367. case if_false:
  368. case if_elsefalse:
  369. case if_elif:
  370. case if_ignore:
  371. pp_push_ignore_state();
  372. break;
  373. case if_error:
  374. assert(0);
  375. }
  376. }
  377. pp_if_state_t pp_pop_if(void)
  378. {
  379. if(if_stack_idx <= 0)
  380. {
  381. ppy_error("#{endif,else,elif} without #{if,ifdef,ifndef} (#if-stack underflow)");
  382. return if_error;
  383. }
  384. switch(pp_if_state())
  385. {
  386. case if_true:
  387. case if_elsetrue:
  388. break;
  389. case if_false:
  390. case if_elsefalse:
  391. case if_elif:
  392. case if_ignore:
  393. pp_pop_ignore_state();
  394. break;
  395. case if_error:
  396. assert(0);
  397. }
  398. if(pp_flex_debug)
  399. fprintf(stderr, "Pop if %s:%d: %s(%d) -> %s(%d)\n",
  400. pp_status.input,
  401. pp_status.line_number,
  402. pp_if_state_str[pp_if_state()],
  403. if_stack_idx,
  404. pp_if_state_str[if_stack[if_stack_idx <= 1 ? if_true : if_stack_idx-2]],
  405. if_stack_idx-1);
  406. return if_stack[--if_stack_idx];
  407. }
  408. pp_if_state_t pp_if_state(void)
  409. {
  410. if(!if_stack_idx)
  411. return if_true;
  412. else
  413. return if_stack[if_stack_idx-1];
  414. }
  415. void pp_next_if_state(int i)
  416. {
  417. switch(pp_if_state())
  418. {
  419. case if_true:
  420. case if_elsetrue:
  421. pp_push_if(i ? if_true : if_false);
  422. break;
  423. case if_false:
  424. case if_elsefalse:
  425. case if_elif:
  426. case if_ignore:
  427. pp_push_if(if_ignore);
  428. break;
  429. case if_error:
  430. assert(0);
  431. }
  432. }
  433. int pp_get_if_depth(void)
  434. {
  435. return if_stack_idx;
  436. }
  437. static void generic_msg(const char *s, const char *t, const char *n, va_list ap)
  438. {
  439. fprintf(stderr, "%s:%d:%d: %s: ", pp_status.input ? pp_status.input : "stdin",
  440. pp_status.line_number, pp_status.char_number, t);
  441. vfprintf(stderr, s, ap);
  442. fprintf(stderr, "\n");
  443. }
  444. int ppy_error(const char *s, ...)
  445. {
  446. va_list ap;
  447. va_start(ap, s);
  448. generic_msg(s, "error", ppy_text, ap);
  449. va_end(ap);
  450. exit(1);
  451. }
  452. int ppy_warning(const char *s, ...)
  453. {
  454. va_list ap;
  455. va_start(ap, s);
  456. generic_msg(s, "warning", ppy_text, ap);
  457. va_end(ap);
  458. return 0;
  459. }
  460. static void add_cmdline_defines(void)
  461. {
  462. struct define *def;
  463. LIST_FOR_EACH_ENTRY( def, &cmdline_defines, struct define, entry )
  464. {
  465. if (def->value) pp_add_define( def->name, def->value );
  466. }
  467. }
  468. static void add_special_defines(void)
  469. {
  470. time_t now = time(NULL);
  471. pp_entry_t *ppp;
  472. char buf[32];
  473. strftime(buf, sizeof(buf), "\"%b %d %Y\"", localtime(&now));
  474. pp_add_define( "__DATE__", buf );
  475. strftime(buf, sizeof(buf), "\"%H:%M:%S\"", localtime(&now));
  476. pp_add_define( "__TIME__", buf );
  477. ppp = pp_add_define( "__FILE__", "" );
  478. ppp->type = def_special;
  479. ppp = pp_add_define( "__LINE__", "" );
  480. ppp->type = def_special;
  481. }
  482. /* add a define to the preprocessor list */
  483. static void wpp_add_define( const char *name, const char *value )
  484. {
  485. struct define *def;
  486. if (!value) value = "";
  487. LIST_FOR_EACH_ENTRY( def, &cmdline_defines, struct define, entry )
  488. {
  489. if (!strcmp( def->name, name ))
  490. {
  491. free( def->value );
  492. def->value = xstrdup(value);
  493. return;
  494. }
  495. }
  496. def = xmalloc( sizeof(*def) );
  497. def->name = xstrdup(name);
  498. def->value = xstrdup(value);
  499. list_add_head( &cmdline_defines, &def->entry );
  500. }
  501. /* undefine a previously added definition */
  502. void wpp_del_define( const char *name )
  503. {
  504. struct define *def;
  505. LIST_FOR_EACH_ENTRY( def, &cmdline_defines, struct define, entry )
  506. {
  507. if (!strcmp( def->name, name ))
  508. {
  509. free( def->value );
  510. def->value = NULL;
  511. return;
  512. }
  513. }
  514. }
  515. /* add a command-line define of the form NAME=VALUE */
  516. void wpp_add_cmdline_define( const char *value )
  517. {
  518. char *p;
  519. char *str = xstrdup(value);
  520. p = strchr( str, '=' );
  521. if (p) *p++ = 0;
  522. wpp_add_define( str, p );
  523. free( str );
  524. }
  525. /* set the various debug flags */
  526. void wpp_set_debug( int lex_debug, int parser_debug, int msg_debug )
  527. {
  528. pp_flex_debug = lex_debug;
  529. ppy_debug = parser_debug;
  530. pp_status.debug = msg_debug;
  531. }
  532. /* the main preprocessor parsing loop */
  533. int wpp_parse( const char *input, FILE *output )
  534. {
  535. int ret;
  536. pp_status.input = NULL;
  537. pp_status.line_number = 1;
  538. pp_status.char_number = 1;
  539. pp_init_define_state();
  540. add_cmdline_defines();
  541. add_special_defines();
  542. if (!input) pp_status.file = stdin;
  543. else if (!(pp_status.file = fopen(input, "rt")))
  544. ppy_error("Could not open %s\n", input);
  545. pp_status.input = input ? xstrdup(input) : NULL;
  546. ppy_out = output;
  547. fprintf(ppy_out, "# 1 \"%s\" 1\n", input ? input : "");
  548. ret = ppy_parse();
  549. if (input)
  550. {
  551. fclose(pp_status.file);
  552. free(pp_status.input);
  553. }
  554. /* Clean if_stack, it could remain dirty on errors */
  555. while (pp_get_if_depth()) pp_pop_if();
  556. pp_free_define_state();
  557. return ret;
  558. }