wpp.c 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729
  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 "wine/port.h"
  23. #include <assert.h>
  24. #include <ctype.h>
  25. #include <fcntl.h>
  26. #include <stdio.h>
  27. #include <stdlib.h>
  28. #include <string.h>
  29. #include <stdarg.h>
  30. #include <time.h>
  31. #ifdef HAVE_UNISTD_H
  32. # include <unistd.h>
  33. #endif
  34. #include "wpp_private.h"
  35. #include "wine/wpp.h"
  36. struct pp_status pp_status;
  37. #define HASHKEY 2039
  38. static struct list pp_defines[HASHKEY];
  39. #define MAXIFSTACK 64
  40. static pp_if_state_t if_stack[MAXIFSTACK];
  41. static int if_stack_idx = 0;
  42. int ppy_debug, pp_flex_debug;
  43. struct define
  44. {
  45. struct list entry;
  46. char *name;
  47. char *value;
  48. };
  49. static struct list cmdline_defines = LIST_INIT( cmdline_defines );
  50. void *pp_xmalloc(size_t size)
  51. {
  52. void *res;
  53. assert(size > 0);
  54. res = malloc(size);
  55. if(res == NULL)
  56. {
  57. fprintf( stderr, "Virtual memory exhausted\n" );
  58. exit(1);
  59. }
  60. return res;
  61. }
  62. void *pp_xrealloc(void *p, size_t size)
  63. {
  64. void *res;
  65. assert(size > 0);
  66. res = realloc(p, size);
  67. if(res == NULL)
  68. {
  69. fprintf( stderr, "Virtual memory exhausted\n" );
  70. exit(1);
  71. }
  72. return res;
  73. }
  74. char *pp_xstrdup(const char *str)
  75. {
  76. int len = strlen(str)+1;
  77. return memcpy(pp_xmalloc(len), str, len);
  78. }
  79. char *wpp_lookup(const char *name, int type, const char *parent_name,
  80. char **include_path, int include_path_count)
  81. {
  82. char *cpy;
  83. char *cptr;
  84. char *path;
  85. const char *ccptr;
  86. int i, fd;
  87. cpy = pp_xmalloc(strlen(name)+1);
  88. cptr = cpy;
  89. for(ccptr = name; *ccptr; ccptr++)
  90. {
  91. /* Convert to forward slash */
  92. if(*ccptr == '\\') {
  93. /* kill double backslash */
  94. if(ccptr[1] == '\\')
  95. ccptr++;
  96. *cptr = '/';
  97. }else {
  98. *cptr = *ccptr;
  99. }
  100. cptr++;
  101. }
  102. *cptr = '\0';
  103. if(type && parent_name)
  104. {
  105. /* Search directory of parent include and then -I path */
  106. const char *p;
  107. if ((p = strrchr( parent_name, '/' ))) p++;
  108. else p = parent_name;
  109. path = pp_xmalloc( (p - parent_name) + strlen(cpy) + 1 );
  110. memcpy( path, parent_name, p - parent_name );
  111. strcpy( path + (p - parent_name), cpy );
  112. fd = open( path, O_RDONLY );
  113. if (fd != -1)
  114. {
  115. close( fd );
  116. free( cpy );
  117. return path;
  118. }
  119. free( path );
  120. }
  121. /* Search -I path */
  122. for(i = 0; i < include_path_count; i++)
  123. {
  124. path = pp_xmalloc(strlen(include_path[i]) + strlen(cpy) + 2);
  125. strcpy(path, include_path[i]);
  126. strcat(path, "/");
  127. strcat(path, cpy);
  128. fd = open( path, O_RDONLY );
  129. if (fd != -1)
  130. {
  131. close( fd );
  132. free( cpy );
  133. return path;
  134. }
  135. free( path );
  136. }
  137. free( cpy );
  138. return NULL;
  139. }
  140. /* Don't comment on the hash, it's primitive but functional... */
  141. static int pphash(const char *str)
  142. {
  143. int sum = 0;
  144. while(*str)
  145. sum += *str++;
  146. return sum % HASHKEY;
  147. }
  148. pp_entry_t *pplookup(const char *ident)
  149. {
  150. int idx;
  151. pp_entry_t *ppp;
  152. if(!ident)
  153. return NULL;
  154. idx = pphash(ident);
  155. LIST_FOR_EACH_ENTRY( ppp, &pp_defines[idx], pp_entry_t, entry )
  156. {
  157. if(!strcmp(ident, ppp->ident))
  158. return ppp;
  159. }
  160. return NULL;
  161. }
  162. static void free_pp_entry( pp_entry_t *ppp, int idx )
  163. {
  164. if(ppp->iep)
  165. {
  166. list_remove( &ppp->iep->entry );
  167. free(ppp->iep->filename);
  168. free(ppp->iep);
  169. }
  170. list_remove( &ppp->entry );
  171. free(ppp);
  172. }
  173. /* initialize the define state */
  174. void pp_init_define_state(void)
  175. {
  176. int i;
  177. for (i = 0; i < HASHKEY; i++) list_init( &pp_defines[i] );
  178. }
  179. /* free the current define state */
  180. void pp_free_define_state(void)
  181. {
  182. int i;
  183. pp_entry_t *ppp, *ppp2;
  184. for (i = 0; i < HASHKEY; i++)
  185. {
  186. LIST_FOR_EACH_ENTRY_SAFE( ppp, ppp2, &pp_defines[i], pp_entry_t, entry )
  187. {
  188. free( ppp->ident );
  189. free( ppp->subst.text );
  190. free( ppp->filename );
  191. free_pp_entry( ppp, i );
  192. }
  193. }
  194. }
  195. void pp_del_define(const char *name)
  196. {
  197. pp_entry_t *ppp;
  198. int idx = pphash(name);
  199. if((ppp = pplookup(name)) == NULL)
  200. {
  201. if(pp_status.pedantic)
  202. ppy_warning("%s was not defined", name);
  203. return;
  204. }
  205. if(pp_status.debug)
  206. printf("Deleting (%s, %d) <%s>\n", pp_status.input, pp_status.line_number, name);
  207. free( ppp->ident );
  208. free( ppp->subst.text );
  209. free( ppp->filename );
  210. free_pp_entry( ppp, idx );
  211. }
  212. pp_entry_t *pp_add_define(const char *def, const char *text)
  213. {
  214. int len;
  215. char *cptr;
  216. int idx;
  217. pp_entry_t *ppp;
  218. idx = pphash(def);
  219. if((ppp = pplookup(def)) != NULL)
  220. {
  221. if(pp_status.pedantic)
  222. ppy_warning("Redefinition of %s\n\tPrevious definition: %s:%d", def, ppp->filename, ppp->linenumber);
  223. pp_del_define(def);
  224. }
  225. ppp = pp_xmalloc(sizeof(pp_entry_t));
  226. memset( ppp, 0, sizeof(*ppp) );
  227. ppp->ident = pp_xstrdup(def);
  228. ppp->type = def_define;
  229. ppp->subst.text = text ? pp_xstrdup(text) : NULL;
  230. ppp->filename = pp_xstrdup(pp_status.input ? pp_status.input : "<internal or cmdline>");
  231. ppp->linenumber = pp_status.input ? pp_status.line_number : 0;
  232. list_add_head( &pp_defines[idx], &ppp->entry );
  233. if(ppp->subst.text)
  234. {
  235. /* Strip trailing white space from subst text */
  236. len = strlen(ppp->subst.text);
  237. while(len && strchr(" \t\r\n", ppp->subst.text[len-1]))
  238. {
  239. ppp->subst.text[--len] = '\0';
  240. }
  241. /* Strip leading white space from subst text */
  242. for(cptr = ppp->subst.text; *cptr && strchr(" \t\r", *cptr); cptr++)
  243. ;
  244. if(ppp->subst.text != cptr)
  245. memmove(ppp->subst.text, cptr, strlen(cptr)+1);
  246. }
  247. if(pp_status.debug)
  248. 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)");
  249. return ppp;
  250. }
  251. pp_entry_t *pp_add_macro(char *id, char *args[], int nargs, mtext_t *exp)
  252. {
  253. int idx;
  254. pp_entry_t *ppp;
  255. idx = pphash(id);
  256. if((ppp = pplookup(id)) != NULL)
  257. {
  258. if(pp_status.pedantic)
  259. ppy_warning("Redefinition of %s\n\tPrevious definition: %s:%d", id, ppp->filename, ppp->linenumber);
  260. pp_del_define(id);
  261. }
  262. ppp = pp_xmalloc(sizeof(pp_entry_t));
  263. memset( ppp, 0, sizeof(*ppp) );
  264. ppp->ident = id;
  265. ppp->type = def_macro;
  266. ppp->margs = args;
  267. ppp->nargs = nargs;
  268. ppp->subst.mtext= exp;
  269. ppp->filename = pp_xstrdup(pp_status.input ? pp_status.input : "<internal or cmdline>");
  270. ppp->linenumber = pp_status.input ? pp_status.line_number : 0;
  271. list_add_head( &pp_defines[idx], &ppp->entry );
  272. if(pp_status.debug)
  273. {
  274. fprintf(stderr, "Added macro (%s, %d) <%s(%d)> to <", pp_status.input, pp_status.line_number, ppp->ident, nargs);
  275. for(; exp; exp = exp->next)
  276. {
  277. switch(exp->type)
  278. {
  279. case exp_text:
  280. fprintf(stderr, " \"%s\" ", exp->subst.text);
  281. break;
  282. case exp_stringize:
  283. fprintf(stderr, " #(%d) ", exp->subst.argidx);
  284. break;
  285. case exp_concat:
  286. fprintf(stderr, "##");
  287. break;
  288. case exp_subst:
  289. fprintf(stderr, " <%d> ", exp->subst.argidx);
  290. break;
  291. }
  292. }
  293. fprintf(stderr, ">\n");
  294. }
  295. return ppp;
  296. }
  297. /*
  298. *-------------------------------------------------------------------------
  299. * Include management
  300. *-------------------------------------------------------------------------
  301. */
  302. #if defined(_WIN32) || defined(__MSDOS__)
  303. #define INCLUDESEPARATOR ";"
  304. #else
  305. #define INCLUDESEPARATOR ":"
  306. #endif
  307. static char **includepath;
  308. static int nincludepath = 0;
  309. void wpp_add_include_path(const char *path)
  310. {
  311. char *tok;
  312. char *cpy = pp_xstrdup(path);
  313. tok = strtok(cpy, INCLUDESEPARATOR);
  314. while(tok)
  315. {
  316. if(*tok) {
  317. char *dir;
  318. char *cptr;
  319. dir = pp_xstrdup(tok);
  320. for(cptr = dir; *cptr; cptr++)
  321. {
  322. /* Convert to forward slash */
  323. if(*cptr == '\\')
  324. *cptr = '/';
  325. }
  326. /* Kill eventual trailing '/' */
  327. if(*(cptr = dir + strlen(dir)-1) == '/')
  328. *cptr = '\0';
  329. /* Add to list */
  330. includepath = pp_xrealloc(includepath, (nincludepath+1) * sizeof(*includepath));
  331. includepath[nincludepath] = dir;
  332. nincludepath++;
  333. }
  334. tok = strtok(NULL, INCLUDESEPARATOR);
  335. }
  336. free(cpy);
  337. }
  338. char *wpp_find_include(const char *name, const char *parent_name)
  339. {
  340. return wpp_lookup(name, !!parent_name, parent_name, includepath, nincludepath);
  341. }
  342. void *pp_open_include(const char *name, int type, const char *parent_name, char **newpath)
  343. {
  344. char *path;
  345. void *fp;
  346. if (!(path = wpp_lookup(name, type, parent_name, includepath, nincludepath))) return NULL;
  347. fp = fopen(path, "rt");
  348. if (fp)
  349. {
  350. if (pp_status.debug)
  351. printf("Going to include <%s>\n", path);
  352. if (newpath) *newpath = path;
  353. else free( path );
  354. return fp;
  355. }
  356. free( path );
  357. return NULL;
  358. }
  359. /*
  360. *-------------------------------------------------------------------------
  361. * #if, #ifdef, #ifndef, #else, #elif and #endif state management
  362. *
  363. * #if state transitions are made on basis of the current TOS and the next
  364. * required state. The state transitions are required to housekeep because
  365. * #if:s can be nested. The ignore case is activated to prevent output from
  366. * within a false clause.
  367. * Some special cases come from the fact that the #elif cases are not
  368. * binary, but three-state. The problem is that all other elif-cases must
  369. * be false when one true one has been found. A second problem is that the
  370. * #else clause is a final clause. No extra #else:s may follow.
  371. *
  372. * The states mean:
  373. * if_true Process input to output
  374. * if_false Process input but no output
  375. * if_ignore Process input but no output
  376. * if_elif Process input but no output
  377. * if_elsefalse Process input but no output
  378. * if_elsettrue Process input to output
  379. *
  380. * The possible state-sequences are [state(stack depth)] (rest can be deduced):
  381. * TOS #if 1 #else #endif
  382. * if_true(n) if_true(n+1) if_elsefalse(n+1)
  383. * if_false(n) if_ignore(n+1) if_ignore(n+1)
  384. * if_elsetrue(n) if_true(n+1) if_elsefalse(n+1)
  385. * if_elsefalse(n) if_ignore(n+1) if_ignore(n+1)
  386. * if_elif(n) if_ignore(n+1) if_ignore(n+1)
  387. * if_ignore(n) if_ignore(n+1) if_ignore(n+1)
  388. *
  389. * TOS #if 1 #elif 0 #else #endif
  390. * if_true(n) if_true(n+1) if_elif(n+1) if_elif(n+1)
  391. * if_false(n) if_ignore(n+1) if_ignore(n+1) if_ignore(n+1)
  392. * if_elsetrue(n) if_true(n+1) if_elif(n+1) if_elif(n+1)
  393. * if_elsefalse(n) if_ignore(n+1) if_ignore(n+1) if_ignore(n+1)
  394. * if_elif(n) if_ignore(n+1) if_ignore(n+1) if_ignore(n+1)
  395. * if_ignore(n) if_ignore(n+1) if_ignore(n+1) if_ignore(n+1)
  396. *
  397. * TOS #if 0 #elif 1 #else #endif
  398. * if_true(n) if_false(n+1) if_true(n+1) if_elsefalse(n+1)
  399. * if_false(n) if_ignore(n+1) if_ignore(n+1) if_ignore(n+1)
  400. * if_elsetrue(n) if_false(n+1) if_true(n+1) if_elsefalse(n+1)
  401. * if_elsefalse(n) if_ignore(n+1) if_ignore(n+1) if_ignore(n+1)
  402. * if_elif(n) if_ignore(n+1) if_ignore(n+1) if_ignore(n+1)
  403. * if_ignore(n) if_ignore(n+1) if_ignore(n+1) if_ignore(n+1)
  404. *
  405. *-------------------------------------------------------------------------
  406. */
  407. static const char * const pp_if_state_str[] = {
  408. "if_false",
  409. "if_true",
  410. "if_elif",
  411. "if_elsefalse",
  412. "if_elsetrue",
  413. "if_ignore"
  414. };
  415. void pp_push_if(pp_if_state_t s)
  416. {
  417. if(if_stack_idx >= MAXIFSTACK)
  418. pp_internal_error(__FILE__, __LINE__, "#if-stack overflow; #{if,ifdef,ifndef} nested too deeply (> %d)", MAXIFSTACK);
  419. if(pp_flex_debug)
  420. 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);
  421. if_stack[if_stack_idx++] = s;
  422. switch(s)
  423. {
  424. case if_true:
  425. case if_elsetrue:
  426. break;
  427. case if_false:
  428. case if_elsefalse:
  429. case if_elif:
  430. case if_ignore:
  431. pp_push_ignore_state();
  432. break;
  433. default:
  434. pp_internal_error(__FILE__, __LINE__, "Invalid pp_if_state (%d)", (int)pp_if_state());
  435. }
  436. }
  437. pp_if_state_t pp_pop_if(void)
  438. {
  439. if(if_stack_idx <= 0)
  440. {
  441. ppy_error("#{endif,else,elif} without #{if,ifdef,ifndef} (#if-stack underflow)");
  442. return if_error;
  443. }
  444. switch(pp_if_state())
  445. {
  446. case if_true:
  447. case if_elsetrue:
  448. break;
  449. case if_false:
  450. case if_elsefalse:
  451. case if_elif:
  452. case if_ignore:
  453. pp_pop_ignore_state();
  454. break;
  455. default:
  456. pp_internal_error(__FILE__, __LINE__, "Invalid pp_if_state (%d)", (int)pp_if_state());
  457. }
  458. if(pp_flex_debug)
  459. fprintf(stderr, "Pop if %s:%d: %s(%d) -> %s(%d)\n",
  460. pp_status.input,
  461. pp_status.line_number,
  462. pp_if_state_str[pp_if_state()],
  463. if_stack_idx,
  464. pp_if_state_str[if_stack[if_stack_idx <= 1 ? if_true : if_stack_idx-2]],
  465. if_stack_idx-1);
  466. return if_stack[--if_stack_idx];
  467. }
  468. pp_if_state_t pp_if_state(void)
  469. {
  470. if(!if_stack_idx)
  471. return if_true;
  472. else
  473. return if_stack[if_stack_idx-1];
  474. }
  475. void pp_next_if_state(int i)
  476. {
  477. switch(pp_if_state())
  478. {
  479. case if_true:
  480. case if_elsetrue:
  481. pp_push_if(i ? if_true : if_false);
  482. break;
  483. case if_false:
  484. case if_elsefalse:
  485. case if_elif:
  486. case if_ignore:
  487. pp_push_if(if_ignore);
  488. break;
  489. default:
  490. pp_internal_error(__FILE__, __LINE__, "Invalid pp_if_state (%d) in #{if,ifdef,ifndef} directive", (int)pp_if_state());
  491. }
  492. }
  493. int pp_get_if_depth(void)
  494. {
  495. return if_stack_idx;
  496. }
  497. static void generic_msg(const char *s, const char *t, const char *n, va_list ap)
  498. {
  499. fprintf(stderr, "%s:%d:%d: %s: ", pp_status.input ? pp_status.input : "stdin",
  500. pp_status.line_number, pp_status.char_number, t);
  501. vfprintf(stderr, s, ap);
  502. fprintf(stderr, "\n");
  503. }
  504. int ppy_error(const char *s, ...)
  505. {
  506. va_list ap;
  507. va_start(ap, s);
  508. generic_msg(s, "error", ppy_text, ap);
  509. va_end(ap);
  510. exit(1);
  511. }
  512. int ppy_warning(const char *s, ...)
  513. {
  514. va_list ap;
  515. va_start(ap, s);
  516. generic_msg(s, "warning", ppy_text, ap);
  517. va_end(ap);
  518. return 0;
  519. }
  520. void pp_internal_error(const char *file, int line, const char *s, ...)
  521. {
  522. va_list ap;
  523. va_start(ap, s);
  524. fprintf(stderr, "Internal error (please report) %s %d: ", file, line);
  525. vfprintf(stderr, s, ap);
  526. fprintf(stderr, "\n");
  527. va_end(ap);
  528. exit(3);
  529. }
  530. static void add_cmdline_defines(void)
  531. {
  532. struct define *def;
  533. LIST_FOR_EACH_ENTRY( def, &cmdline_defines, struct define, entry )
  534. {
  535. if (def->value) pp_add_define( def->name, def->value );
  536. }
  537. }
  538. static void add_special_defines(void)
  539. {
  540. time_t now = time(NULL);
  541. pp_entry_t *ppp;
  542. char buf[32];
  543. strftime(buf, sizeof(buf), "\"%b %d %Y\"", localtime(&now));
  544. pp_add_define( "__DATE__", buf );
  545. strftime(buf, sizeof(buf), "\"%H:%M:%S\"", localtime(&now));
  546. pp_add_define( "__TIME__", buf );
  547. ppp = pp_add_define( "__FILE__", "" );
  548. ppp->type = def_special;
  549. ppp = pp_add_define( "__LINE__", "" );
  550. ppp->type = def_special;
  551. }
  552. /* add a define to the preprocessor list */
  553. static void wpp_add_define( const char *name, const char *value )
  554. {
  555. struct define *def;
  556. if (!value) value = "";
  557. LIST_FOR_EACH_ENTRY( def, &cmdline_defines, struct define, entry )
  558. {
  559. if (!strcmp( def->name, name ))
  560. {
  561. free( def->value );
  562. def->value = pp_xstrdup(value);
  563. return;
  564. }
  565. }
  566. def = pp_xmalloc( sizeof(*def) );
  567. def->name = pp_xstrdup(name);
  568. def->value = pp_xstrdup(value);
  569. list_add_head( &cmdline_defines, &def->entry );
  570. }
  571. /* undefine a previously added definition */
  572. void wpp_del_define( const char *name )
  573. {
  574. struct define *def;
  575. LIST_FOR_EACH_ENTRY( def, &cmdline_defines, struct define, entry )
  576. {
  577. if (!strcmp( def->name, name ))
  578. {
  579. free( def->value );
  580. def->value = NULL;
  581. return;
  582. }
  583. }
  584. }
  585. /* add a command-line define of the form NAME=VALUE */
  586. void wpp_add_cmdline_define( const char *value )
  587. {
  588. char *p;
  589. char *str = pp_xstrdup(value);
  590. p = strchr( str, '=' );
  591. if (p) *p++ = 0;
  592. wpp_add_define( str, p );
  593. free( str );
  594. }
  595. /* set the various debug flags */
  596. void wpp_set_debug( int lex_debug, int parser_debug, int msg_debug )
  597. {
  598. pp_flex_debug = lex_debug;
  599. ppy_debug = parser_debug;
  600. pp_status.debug = msg_debug;
  601. }
  602. /* set the pedantic mode */
  603. void wpp_set_pedantic( int on )
  604. {
  605. pp_status.pedantic = on;
  606. }
  607. /* the main preprocessor parsing loop */
  608. int wpp_parse( const char *input, FILE *output )
  609. {
  610. int ret;
  611. pp_status.input = NULL;
  612. pp_status.line_number = 1;
  613. pp_status.char_number = 1;
  614. pp_init_define_state();
  615. add_cmdline_defines();
  616. add_special_defines();
  617. if (!input) pp_status.file = stdin;
  618. else if (!(pp_status.file = fopen(input, "rt")))
  619. ppy_error("Could not open %s\n", input);
  620. pp_status.input = input ? pp_xstrdup(input) : NULL;
  621. ppy_out = output;
  622. pp_writestring("# 1 \"%s\" 1\n", input ? input : "");
  623. ret = ppy_parse();
  624. if (input)
  625. {
  626. fclose(pp_status.file);
  627. free(pp_status.input);
  628. }
  629. /* Clean if_stack, it could remain dirty on errors */
  630. while (pp_get_if_depth()) pp_pop_if();
  631. pp_free_define_state();
  632. return ret;
  633. }