preproc.c 16 KB

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