2 * Exported functions of the Wine preprocessor
4 * Copyright 1998 Bertho A. Stultiens
5 * Copyright 2002 Alexandre Julliard
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.
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.
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
35 #include "wpp_private.h"
37 struct pp_status pp_status
;
41 static struct list pp_defines
[HASHKEY
];
44 static pp_if_state_t if_stack
[MAXIFSTACK
];
45 static int if_stack_idx
= 0;
47 int ppy_debug
, pp_flex_debug
;
56 static struct list cmdline_defines
= LIST_INIT( cmdline_defines
);
57 static struct strarray includes
;
59 static char *wpp_lookup(const char *name
, int type
, const char *parent_name
)
67 cpy
= xmalloc(strlen(name
)+1);
70 for(ccptr
= name
; *ccptr
; ccptr
++)
72 /* Convert to forward slash */
74 /* kill double backslash */
85 if(type
&& parent_name
)
87 /* Search directory of parent include and then -I path */
88 path
= strmake( "%s/%s", get_dirname(parent_name
), cpy
);
89 fd
= open( path
, O_RDONLY
);
99 for(i
= 0; i
< includes
.count
; i
++)
101 path
= strmake("%s/%s", includes
.str
[i
], cpy
);
102 fd
= open( path
, O_RDONLY
);
115 /* Don't comment on the hash, it's primitive but functional... */
116 static int pphash(const char *str
)
121 return sum
% HASHKEY
;
124 pp_entry_t
*pplookup(const char *ident
)
132 LIST_FOR_EACH_ENTRY( ppp
, &pp_defines
[idx
], pp_entry_t
, entry
)
134 if(!strcmp(ident
, ppp
->ident
))
140 static void free_pp_entry( pp_entry_t
*ppp
, int idx
)
144 list_remove( &ppp
->iep
->entry
);
145 free(ppp
->iep
->filename
);
148 list_remove( &ppp
->entry
);
152 /* initialize the define state */
153 static void pp_init_define_state(void)
157 for (i
= 0; i
< HASHKEY
; i
++) list_init( &pp_defines
[i
] );
160 /* free the current define state */
161 static void pp_free_define_state(void)
164 pp_entry_t
*ppp
, *ppp2
;
166 for (i
= 0; i
< HASHKEY
; i
++)
168 LIST_FOR_EACH_ENTRY_SAFE( ppp
, ppp2
, &pp_defines
[i
], pp_entry_t
, entry
)
171 free( ppp
->subst
.text
);
172 free( ppp
->filename
);
173 free_pp_entry( ppp
, i
);
178 void pp_del_define(const char *name
)
181 int idx
= pphash(name
);
183 if((ppp
= pplookup(name
)) == NULL
)
186 ppy_warning("%s was not defined", name
);
191 printf("Deleting (%s, %d) <%s>\n", pp_status
.input
, pp_status
.line_number
, name
);
194 free( ppp
->subst
.text
);
195 free( ppp
->filename
);
196 free_pp_entry( ppp
, idx
);
199 pp_entry_t
*pp_add_define(const char *def
, const char *text
)
207 if((ppp
= pplookup(def
)) != NULL
)
210 ppy_warning("Redefinition of %s\n%s:%d: note: previous definition was here",
211 def
, ppp
->filename
, ppp
->linenumber
);
214 ppp
= xmalloc(sizeof(pp_entry_t
));
215 memset( ppp
, 0, sizeof(*ppp
) );
216 ppp
->ident
= xstrdup(def
);
217 ppp
->type
= def_define
;
218 ppp
->subst
.text
= text
? xstrdup(text
) : NULL
;
219 ppp
->filename
= xstrdup(pp_status
.input
? pp_status
.input
: "<internal or cmdline>");
220 ppp
->linenumber
= pp_status
.input
? pp_status
.line_number
: 0;
221 list_add_head( &pp_defines
[idx
], &ppp
->entry
);
224 /* Strip trailing white space from subst text */
225 len
= strlen(ppp
->subst
.text
);
226 while(len
&& strchr(" \t\r\n", ppp
->subst
.text
[len
-1]))
228 ppp
->subst
.text
[--len
] = '\0';
230 /* Strip leading white space from subst text */
231 for(cptr
= ppp
->subst
.text
; *cptr
&& strchr(" \t\r", *cptr
); cptr
++)
233 if(ppp
->subst
.text
!= cptr
)
234 memmove(ppp
->subst
.text
, cptr
, strlen(cptr
)+1);
237 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)");
242 pp_entry_t
*pp_add_macro(char *id
, char *args
[], int nargs
, int variadic
, mtext_t
*exp
)
248 if((ppp
= pplookup(id
)) != NULL
)
251 ppy_warning("Redefinition of %s\n%s:%d: note: previous definition was here",
252 id
, ppp
->filename
, ppp
->linenumber
);
255 ppp
= xmalloc(sizeof(pp_entry_t
));
256 memset( ppp
, 0, sizeof(*ppp
) );
258 ppp
->type
= def_macro
;
261 ppp
->variadic
= variadic
;
262 ppp
->subst
.mtext
= exp
;
263 ppp
->filename
= xstrdup(pp_status
.input
? pp_status
.input
: "<internal or cmdline>");
264 ppp
->linenumber
= pp_status
.input
? pp_status
.line_number
: 0;
265 list_add_head( &pp_defines
[idx
], &ppp
->entry
);
268 fprintf(stderr
, "Added macro (%s, %d) <%s(%d%s)> to <", pp_status
.input
, pp_status
.line_number
, ppp
->ident
, nargs
, variadic
? ",va" : "");
269 for(; exp
; exp
= exp
->next
)
274 fprintf(stderr
, " \"%s\" ", exp
->subst
.text
);
277 fprintf(stderr
, " #(%d) ", exp
->subst
.argidx
);
280 fprintf(stderr
, "##");
283 fprintf(stderr
, " <%d> ", exp
->subst
.argidx
);
287 fprintf(stderr
, ">\n");
294 *-------------------------------------------------------------------------
296 *-------------------------------------------------------------------------
298 void wpp_add_include_path(const char *path
)
300 char *dir
= xstrdup(path
);
303 for(cptr
= dir
; *cptr
; cptr
++)
305 /* Convert to forward slash */
309 /* Kill eventual trailing '/' */
310 if(*(cptr
= dir
+ strlen(dir
)-1) == '/') *cptr
= '\0';
312 strarray_add( &includes
, dir
);
315 char *wpp_find_include(const char *name
, const char *parent_name
)
317 return wpp_lookup(name
, !!parent_name
, parent_name
);
320 void *pp_open_include(const char *name
, int type
, const char *parent_name
, char **newpath
)
325 if (!(path
= wpp_lookup(name
, type
, parent_name
))) return NULL
;
326 fp
= fopen(path
, "rt");
331 printf("Going to include <%s>\n", path
);
332 if (newpath
) *newpath
= path
;
341 *-------------------------------------------------------------------------
342 * #if, #ifdef, #ifndef, #else, #elif and #endif state management
344 * #if state transitions are made on basis of the current TOS and the next
345 * required state. The state transitions are required to housekeep because
346 * #if:s can be nested. The ignore case is activated to prevent output from
347 * within a false clause.
348 * Some special cases come from the fact that the #elif cases are not
349 * binary, but three-state. The problem is that all other elif-cases must
350 * be false when one true one has been found. A second problem is that the
351 * #else clause is a final clause. No extra #else:s may follow.
354 * if_true Process input to output
355 * if_false Process input but no output
356 * if_ignore Process input but no output
357 * if_elif Process input but no output
358 * if_elsefalse Process input but no output
359 * if_elsettrue Process input to output
361 * The possible state-sequences are [state(stack depth)] (rest can be deduced):
362 * TOS #if 1 #else #endif
363 * if_true(n) if_true(n+1) if_elsefalse(n+1)
364 * if_false(n) if_ignore(n+1) if_ignore(n+1)
365 * if_elsetrue(n) if_true(n+1) if_elsefalse(n+1)
366 * if_elsefalse(n) if_ignore(n+1) if_ignore(n+1)
367 * if_elif(n) if_ignore(n+1) if_ignore(n+1)
368 * if_ignore(n) if_ignore(n+1) if_ignore(n+1)
370 * TOS #if 1 #elif 0 #else #endif
371 * if_true(n) if_true(n+1) if_elif(n+1) if_elif(n+1)
372 * if_false(n) if_ignore(n+1) if_ignore(n+1) if_ignore(n+1)
373 * if_elsetrue(n) if_true(n+1) if_elif(n+1) if_elif(n+1)
374 * if_elsefalse(n) if_ignore(n+1) if_ignore(n+1) if_ignore(n+1)
375 * if_elif(n) if_ignore(n+1) if_ignore(n+1) if_ignore(n+1)
376 * if_ignore(n) if_ignore(n+1) if_ignore(n+1) if_ignore(n+1)
378 * TOS #if 0 #elif 1 #else #endif
379 * if_true(n) if_false(n+1) if_true(n+1) if_elsefalse(n+1)
380 * if_false(n) if_ignore(n+1) if_ignore(n+1) if_ignore(n+1)
381 * if_elsetrue(n) if_false(n+1) if_true(n+1) if_elsefalse(n+1)
382 * if_elsefalse(n) if_ignore(n+1) if_ignore(n+1) if_ignore(n+1)
383 * if_elif(n) if_ignore(n+1) if_ignore(n+1) if_ignore(n+1)
384 * if_ignore(n) if_ignore(n+1) if_ignore(n+1) if_ignore(n+1)
386 *-------------------------------------------------------------------------
388 static const char * const pp_if_state_str
[] = {
397 void pp_push_if(pp_if_state_t s
)
399 if(if_stack_idx
>= MAXIFSTACK
)
400 error("#if-stack overflow; #{if,ifdef,ifndef} nested too deeply (> %d)\n", MAXIFSTACK
);
403 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);
405 if_stack
[if_stack_idx
++] = s
;
416 pp_push_ignore_state();
423 pp_if_state_t
pp_pop_if(void)
425 if(if_stack_idx
<= 0)
427 ppy_error("#{endif,else,elif} without #{if,ifdef,ifndef} (#if-stack underflow)");
431 switch(pp_if_state())
440 pp_pop_ignore_state();
447 fprintf(stderr
, "Pop if %s:%d: %s(%d) -> %s(%d)\n",
449 pp_status
.line_number
,
450 pp_if_state_str
[pp_if_state()],
452 pp_if_state_str
[if_stack
[if_stack_idx
<= 1 ? if_true
: if_stack_idx
-2]],
455 return if_stack
[--if_stack_idx
];
458 pp_if_state_t
pp_if_state(void)
463 return if_stack
[if_stack_idx
-1];
467 void pp_next_if_state(int i
)
469 switch(pp_if_state())
473 pp_push_if(i
? if_true
: if_false
);
479 pp_push_if(if_ignore
);
486 int pp_get_if_depth(void)
491 static void generic_msg(const char *s
, const char *t
, const char *n
, va_list ap
)
493 fprintf(stderr
, "%s:%d:%d: %s: ", pp_status
.input
? pp_status
.input
: "stdin",
494 pp_status
.line_number
, pp_status
.char_number
, t
);
495 vfprintf(stderr
, s
, ap
);
496 fprintf(stderr
, "\n");
499 int ppy_error(const char *s
, ...)
503 generic_msg(s
, "error", ppy_text
, ap
);
508 int ppy_warning(const char *s
, ...)
512 generic_msg(s
, "warning", ppy_text
, ap
);
517 static void add_cmdline_defines(void)
521 LIST_FOR_EACH_ENTRY( def
, &cmdline_defines
, struct define
, entry
)
523 if (def
->value
) pp_add_define( def
->name
, def
->value
);
527 static void add_special_defines(void)
529 time_t now
= time(NULL
);
533 strftime(buf
, sizeof(buf
), "\"%b %d %Y\"", localtime(&now
));
534 pp_add_define( "__DATE__", buf
);
536 strftime(buf
, sizeof(buf
), "\"%H:%M:%S\"", localtime(&now
));
537 pp_add_define( "__TIME__", buf
);
539 ppp
= pp_add_define( "__FILE__", "" );
540 ppp
->type
= def_special
;
542 ppp
= pp_add_define( "__LINE__", "" );
543 ppp
->type
= def_special
;
546 /* add a define to the preprocessor list */
547 static void wpp_add_define( const char *name
, const char *value
)
551 if (!value
) value
= "";
553 LIST_FOR_EACH_ENTRY( def
, &cmdline_defines
, struct define
, entry
)
555 if (!strcmp( def
->name
, name
))
558 def
->value
= xstrdup(value
);
563 def
= xmalloc( sizeof(*def
) );
564 def
->name
= xstrdup(name
);
565 def
->value
= xstrdup(value
);
566 list_add_head( &cmdline_defines
, &def
->entry
);
570 /* undefine a previously added definition */
571 void wpp_del_define( const char *name
)
575 LIST_FOR_EACH_ENTRY( def
, &cmdline_defines
, struct define
, entry
)
577 if (!strcmp( def
->name
, name
))
587 /* add a command-line define of the form NAME=VALUE */
588 void wpp_add_cmdline_define( const char *value
)
591 char *str
= xstrdup(value
);
593 p
= strchr( str
, '=' );
595 wpp_add_define( str
, p
);
600 /* set the various debug flags */
601 void wpp_set_debug( int lex_debug
, int parser_debug
, int msg_debug
)
603 pp_flex_debug
= lex_debug
;
604 ppy_debug
= parser_debug
;
605 pp_status
.debug
= msg_debug
;
609 /* the main preprocessor parsing loop */
610 int wpp_parse( const char *input
, FILE *output
)
614 pp_status
.input
= NULL
;
615 pp_status
.line_number
= 1;
616 pp_status
.char_number
= 1;
618 pp_init_define_state();
619 add_cmdline_defines();
620 add_special_defines();
622 if (!input
) pp_status
.file
= stdin
;
623 else if (!(pp_status
.file
= fopen(input
, "rt")))
624 ppy_error("Could not open %s\n", input
);
626 pp_status
.input
= input
? xstrdup(input
) : NULL
;
629 fprintf(ppy_out
, "# 1 \"%s\" 1\n", input
? input
: "");
635 fclose(pp_status
.file
);
636 free(pp_status
.input
);
638 /* Clean if_stack, it could remain dirty on errors */
639 while (pp_get_if_depth()) pp_pop_if();
640 pp_free_define_state();