mshtml: Implement MediaQueryList's matches prop.
[wine.git] / tools / wrc / wpp.c
blob57baf44862b093164bf564791a406986f3ca83c9
1 /*
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
22 #include "config.h"
24 #include <assert.h>
25 #include <ctype.h>
26 #include <fcntl.h>
27 #include <stdio.h>
28 #include <stdlib.h>
29 #include <string.h>
30 #include <stdarg.h>
31 #include <time.h>
33 #include "../tools.h"
34 #include "utils.h"
35 #include "wpp_private.h"
37 struct pp_status pp_status;
39 #define HASHKEY 2039
41 static struct list pp_defines[HASHKEY];
43 #define MAXIFSTACK 64
44 static pp_if_state_t if_stack[MAXIFSTACK];
45 static int if_stack_idx = 0;
47 int ppy_debug, pp_flex_debug;
49 struct define
51 struct list entry;
52 char *name;
53 char *value;
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)
61 char *cpy;
62 char *cptr;
63 char *path;
64 const char *ccptr;
65 int i, fd;
67 cpy = xmalloc(strlen(name)+1);
68 cptr = cpy;
70 for(ccptr = name; *ccptr; ccptr++)
72 /* Convert to forward slash */
73 if(*ccptr == '\\') {
74 /* kill double backslash */
75 if(ccptr[1] == '\\')
76 ccptr++;
77 *cptr = '/';
78 }else {
79 *cptr = *ccptr;
81 cptr++;
83 *cptr = '\0';
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 );
90 if (fd != -1)
92 close( fd );
93 free( cpy );
94 return path;
96 free( path );
98 /* Search -I path */
99 for(i = 0; i < includes.count; i++)
101 path = strmake("%s/%s", includes.str[i], cpy);
102 fd = open( path, O_RDONLY );
103 if (fd != -1)
105 close( fd );
106 free( cpy );
107 return path;
109 free( path );
111 free( cpy );
112 return NULL;
115 /* Don't comment on the hash, it's primitive but functional... */
116 static int pphash(const char *str)
118 int sum = 0;
119 while(*str)
120 sum += *str++;
121 return sum % HASHKEY;
124 pp_entry_t *pplookup(const char *ident)
126 int idx;
127 pp_entry_t *ppp;
129 if(!ident)
130 return NULL;
131 idx = pphash(ident);
132 LIST_FOR_EACH_ENTRY( ppp, &pp_defines[idx], pp_entry_t, entry )
134 if(!strcmp(ident, ppp->ident))
135 return ppp;
137 return NULL;
140 static void free_pp_entry( pp_entry_t *ppp, int idx )
142 if(ppp->iep)
144 list_remove( &ppp->iep->entry );
145 free(ppp->iep->filename);
146 free(ppp->iep);
148 list_remove( &ppp->entry );
149 free(ppp);
152 /* initialize the define state */
153 static void pp_init_define_state(void)
155 int i;
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)
163 int i;
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 )
170 free( ppp->ident );
171 free( ppp->subst.text );
172 free( ppp->filename );
173 free_pp_entry( ppp, i );
178 void pp_del_define(const char *name)
180 pp_entry_t *ppp;
181 int idx = pphash(name);
183 if((ppp = pplookup(name)) == NULL)
185 if(pedantic)
186 ppy_warning("%s was not defined", name);
187 return;
190 if(pp_status.debug)
191 printf("Deleting (%s, %d) <%s>\n", pp_status.input, pp_status.line_number, name);
193 free( ppp->ident );
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)
201 int len;
202 char *cptr;
203 int idx;
204 pp_entry_t *ppp;
206 idx = pphash(def);
207 if((ppp = pplookup(def)) != NULL)
209 if(pedantic)
210 ppy_warning("Redefinition of %s\n%s:%d: note: previous definition was here",
211 def, ppp->filename, ppp->linenumber);
212 pp_del_define(def);
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 );
222 if(ppp->subst.text)
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);
236 if(pp_status.debug)
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)");
239 return ppp;
242 pp_entry_t *pp_add_macro(char *id, char *args[], int nargs, int variadic, mtext_t *exp)
244 int idx;
245 pp_entry_t *ppp;
247 idx = pphash(id);
248 if((ppp = pplookup(id)) != NULL)
250 if(pedantic)
251 ppy_warning("Redefinition of %s\n%s:%d: note: previous definition was here",
252 id, ppp->filename, ppp->linenumber);
253 pp_del_define(id);
255 ppp = xmalloc(sizeof(pp_entry_t));
256 memset( ppp, 0, sizeof(*ppp) );
257 ppp->ident = id;
258 ppp->type = def_macro;
259 ppp->margs = args;
260 ppp->nargs = nargs;
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 );
266 if(pp_status.debug)
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)
271 switch(exp->type)
273 case exp_text:
274 fprintf(stderr, " \"%s\" ", exp->subst.text);
275 break;
276 case exp_stringize:
277 fprintf(stderr, " #(%d) ", exp->subst.argidx);
278 break;
279 case exp_concat:
280 fprintf(stderr, "##");
281 break;
282 case exp_subst:
283 fprintf(stderr, " <%d> ", exp->subst.argidx);
284 break;
287 fprintf(stderr, ">\n");
289 return ppp;
294 *-------------------------------------------------------------------------
295 * Include management
296 *-------------------------------------------------------------------------
298 void wpp_add_include_path(const char *path)
300 char *dir = xstrdup(path);
301 char *cptr;
303 for(cptr = dir; *cptr; cptr++)
305 /* Convert to forward slash */
306 if(*cptr == '\\')
307 *cptr = '/';
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)
322 char *path;
323 void *fp;
325 if (!(path = wpp_lookup(name, type, parent_name))) return NULL;
326 fp = fopen(path, "rt");
328 if (fp)
330 if (pp_status.debug)
331 printf("Going to include <%s>\n", path);
332 if (newpath) *newpath = path;
333 else free( path );
334 return fp;
336 free( path );
337 return NULL;
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.
353 * The states mean:
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[] = {
389 "if_false",
390 "if_true",
391 "if_elif",
392 "if_elsefalse",
393 "if_elsetrue",
394 "if_ignore"
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);
402 if(pp_flex_debug)
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;
407 switch(s)
409 case if_true:
410 case if_elsetrue:
411 break;
412 case if_false:
413 case if_elsefalse:
414 case if_elif:
415 case if_ignore:
416 pp_push_ignore_state();
417 break;
418 case if_error:
419 assert(0);
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)");
428 return if_error;
431 switch(pp_if_state())
433 case if_true:
434 case if_elsetrue:
435 break;
436 case if_false:
437 case if_elsefalse:
438 case if_elif:
439 case if_ignore:
440 pp_pop_ignore_state();
441 break;
442 case if_error:
443 assert(0);
446 if(pp_flex_debug)
447 fprintf(stderr, "Pop if %s:%d: %s(%d) -> %s(%d)\n",
448 pp_status.input,
449 pp_status.line_number,
450 pp_if_state_str[pp_if_state()],
451 if_stack_idx,
452 pp_if_state_str[if_stack[if_stack_idx <= 1 ? if_true : if_stack_idx-2]],
453 if_stack_idx-1);
455 return if_stack[--if_stack_idx];
458 pp_if_state_t pp_if_state(void)
460 if(!if_stack_idx)
461 return if_true;
462 else
463 return if_stack[if_stack_idx-1];
467 void pp_next_if_state(int i)
469 switch(pp_if_state())
471 case if_true:
472 case if_elsetrue:
473 pp_push_if(i ? if_true : if_false);
474 break;
475 case if_false:
476 case if_elsefalse:
477 case if_elif:
478 case if_ignore:
479 pp_push_if(if_ignore);
480 break;
481 case if_error:
482 assert(0);
486 int pp_get_if_depth(void)
488 return if_stack_idx;
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, ...)
501 va_list ap;
502 va_start(ap, s);
503 generic_msg(s, "error", ppy_text, ap);
504 va_end(ap);
505 exit(1);
508 int ppy_warning(const char *s, ...)
510 va_list ap;
511 va_start(ap, s);
512 generic_msg(s, "warning", ppy_text, ap);
513 va_end(ap);
514 return 0;
517 static void add_cmdline_defines(void)
519 struct define *def;
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);
530 pp_entry_t *ppp;
531 char buf[32];
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 )
549 struct define *def;
551 if (!value) value = "";
553 LIST_FOR_EACH_ENTRY( def, &cmdline_defines, struct define, entry )
555 if (!strcmp( def->name, name ))
557 free( def->value );
558 def->value = xstrdup(value);
559 return;
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 )
573 struct define *def;
575 LIST_FOR_EACH_ENTRY( def, &cmdline_defines, struct define, entry )
577 if (!strcmp( def->name, name ))
579 free( def->value );
580 def->value = NULL;
581 return;
587 /* add a command-line define of the form NAME=VALUE */
588 void wpp_add_cmdline_define( const char *value )
590 char *p;
591 char *str = xstrdup(value);
593 p = strchr( str, '=' );
594 if (p) *p++ = 0;
595 wpp_add_define( str, p );
596 free( str );
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 )
612 int ret;
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;
628 ppy_out = output;
629 fprintf(ppy_out, "# 1 \"%s\" 1\n", input ? input : "");
631 ret = ppy_parse();
633 if (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();
641 return ret;