wpp: Merge preproc.c into wpp.c.
[wine/zf.git] / libs / wpp / wpp.c
blob0e26121330c4a04cae428eabc0028988a35fa845
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"
23 #include "wine/port.h"
25 #include <assert.h>
26 #include <ctype.h>
27 #include <fcntl.h>
28 #include <stdio.h>
29 #include <stdlib.h>
30 #include <string.h>
31 #include <stdarg.h>
32 #include <time.h>
33 #ifdef HAVE_UNISTD_H
34 # include <unistd.h>
35 #endif
37 #include "wpp_private.h"
38 #include "wine/wpp.h"
40 struct pp_status pp_status;
42 #define HASHKEY 2039
44 static struct list pp_defines[HASHKEY];
46 #define MAXIFSTACK 64
47 static pp_if_state_t if_stack[MAXIFSTACK];
48 static int if_stack_idx = 0;
50 int ppy_debug, pp_flex_debug;
52 struct define
54 struct list entry;
55 char *name;
56 char *value;
59 static struct list cmdline_defines = LIST_INIT( cmdline_defines );
61 void *pp_xmalloc(size_t size)
63 void *res;
65 assert(size > 0);
66 res = malloc(size);
67 if(res == NULL)
69 fprintf( stderr, "Virtual memory exhausted\n" );
70 exit(1);
72 return res;
75 void *pp_xrealloc(void *p, size_t size)
77 void *res;
79 assert(size > 0);
80 res = realloc(p, size);
81 if(res == NULL)
83 fprintf( stderr, "Virtual memory exhausted\n" );
84 exit(1);
86 return res;
89 char *pp_xstrdup(const char *str)
91 int len = strlen(str)+1;
92 return memcpy(pp_xmalloc(len), str, len);
95 char *wpp_lookup(const char *name, int type, const char *parent_name,
96 char **include_path, int include_path_count)
98 char *cpy;
99 char *cptr;
100 char *path;
101 const char *ccptr;
102 int i, fd;
104 cpy = pp_xmalloc(strlen(name)+1);
105 cptr = cpy;
107 for(ccptr = name; *ccptr; ccptr++)
109 /* Convert to forward slash */
110 if(*ccptr == '\\') {
111 /* kill double backslash */
112 if(ccptr[1] == '\\')
113 ccptr++;
114 *cptr = '/';
115 }else {
116 *cptr = *ccptr;
118 cptr++;
120 *cptr = '\0';
122 if(type && parent_name)
124 /* Search directory of parent include and then -I path */
125 const char *p;
127 if ((p = strrchr( parent_name, '/' ))) p++;
128 else p = parent_name;
129 path = pp_xmalloc( (p - parent_name) + strlen(cpy) + 1 );
130 memcpy( path, parent_name, p - parent_name );
131 strcpy( path + (p - parent_name), cpy );
132 fd = open( path, O_RDONLY );
133 if (fd != -1)
135 close( fd );
136 free( cpy );
137 return path;
139 free( path );
141 /* Search -I path */
142 for(i = 0; i < include_path_count; i++)
144 path = pp_xmalloc(strlen(include_path[i]) + strlen(cpy) + 2);
145 strcpy(path, include_path[i]);
146 strcat(path, "/");
147 strcat(path, cpy);
148 fd = open( path, O_RDONLY );
149 if (fd != -1)
151 close( fd );
152 free( cpy );
153 return path;
155 free( path );
157 free( cpy );
158 return NULL;
161 /* Don't comment on the hash, it's primitive but functional... */
162 static int pphash(const char *str)
164 int sum = 0;
165 while(*str)
166 sum += *str++;
167 return sum % HASHKEY;
170 pp_entry_t *pplookup(const char *ident)
172 int idx;
173 pp_entry_t *ppp;
175 if(!ident)
176 return NULL;
177 idx = pphash(ident);
178 LIST_FOR_EACH_ENTRY( ppp, &pp_defines[idx], pp_entry_t, entry )
180 if(!strcmp(ident, ppp->ident))
181 return ppp;
183 return NULL;
186 static void free_pp_entry( pp_entry_t *ppp, int idx )
188 if(ppp->iep)
190 list_remove( &ppp->iep->entry );
191 free(ppp->iep->filename);
192 free(ppp->iep);
194 list_remove( &ppp->entry );
195 free(ppp);
198 /* initialize the define state */
199 void pp_init_define_state(void)
201 int i;
203 for (i = 0; i < HASHKEY; i++) list_init( &pp_defines[i] );
206 /* free the current define state */
207 void pp_free_define_state(void)
209 int i;
210 pp_entry_t *ppp, *ppp2;
212 for (i = 0; i < HASHKEY; i++)
214 LIST_FOR_EACH_ENTRY_SAFE( ppp, ppp2, &pp_defines[i], pp_entry_t, entry )
216 free( ppp->ident );
217 free( ppp->subst.text );
218 free( ppp->filename );
219 free_pp_entry( ppp, i );
224 void pp_del_define(const char *name)
226 pp_entry_t *ppp;
227 int idx = pphash(name);
229 if((ppp = pplookup(name)) == NULL)
231 if(pp_status.pedantic)
232 ppy_warning("%s was not defined", name);
233 return;
236 if(pp_status.debug)
237 printf("Deleting (%s, %d) <%s>\n", pp_status.input, pp_status.line_number, name);
239 free( ppp->ident );
240 free( ppp->subst.text );
241 free( ppp->filename );
242 free_pp_entry( ppp, idx );
245 pp_entry_t *pp_add_define(const char *def, const char *text)
247 int len;
248 char *cptr;
249 int idx;
250 pp_entry_t *ppp;
252 idx = pphash(def);
253 if((ppp = pplookup(def)) != NULL)
255 if(pp_status.pedantic)
256 ppy_warning("Redefinition of %s\n\tPrevious definition: %s:%d", def, ppp->filename, ppp->linenumber);
257 pp_del_define(def);
259 ppp = pp_xmalloc(sizeof(pp_entry_t));
260 memset( ppp, 0, sizeof(*ppp) );
261 ppp->ident = pp_xstrdup(def);
262 ppp->type = def_define;
263 ppp->subst.text = text ? pp_xstrdup(text) : NULL;
264 ppp->filename = pp_xstrdup(pp_status.input ? pp_status.input : "<internal or cmdline>");
265 ppp->linenumber = pp_status.input ? pp_status.line_number : 0;
266 list_add_head( &pp_defines[idx], &ppp->entry );
267 if(ppp->subst.text)
269 /* Strip trailing white space from subst text */
270 len = strlen(ppp->subst.text);
271 while(len && strchr(" \t\r\n", ppp->subst.text[len-1]))
273 ppp->subst.text[--len] = '\0';
275 /* Strip leading white space from subst text */
276 for(cptr = ppp->subst.text; *cptr && strchr(" \t\r", *cptr); cptr++)
278 if(ppp->subst.text != cptr)
279 memmove(ppp->subst.text, cptr, strlen(cptr)+1);
281 if(pp_status.debug)
282 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)");
284 return ppp;
287 pp_entry_t *pp_add_macro(char *id, char *args[], int nargs, mtext_t *exp)
289 int idx;
290 pp_entry_t *ppp;
292 idx = pphash(id);
293 if((ppp = pplookup(id)) != NULL)
295 if(pp_status.pedantic)
296 ppy_warning("Redefinition of %s\n\tPrevious definition: %s:%d", id, ppp->filename, ppp->linenumber);
297 pp_del_define(id);
299 ppp = pp_xmalloc(sizeof(pp_entry_t));
300 memset( ppp, 0, sizeof(*ppp) );
301 ppp->ident = id;
302 ppp->type = def_macro;
303 ppp->margs = args;
304 ppp->nargs = nargs;
305 ppp->subst.mtext= exp;
306 ppp->filename = pp_xstrdup(pp_status.input ? pp_status.input : "<internal or cmdline>");
307 ppp->linenumber = pp_status.input ? pp_status.line_number : 0;
308 list_add_head( &pp_defines[idx], &ppp->entry );
309 if(pp_status.debug)
311 fprintf(stderr, "Added macro (%s, %d) <%s(%d)> to <", pp_status.input, pp_status.line_number, ppp->ident, nargs);
312 for(; exp; exp = exp->next)
314 switch(exp->type)
316 case exp_text:
317 fprintf(stderr, " \"%s\" ", exp->subst.text);
318 break;
319 case exp_stringize:
320 fprintf(stderr, " #(%d) ", exp->subst.argidx);
321 break;
322 case exp_concat:
323 fprintf(stderr, "##");
324 break;
325 case exp_subst:
326 fprintf(stderr, " <%d> ", exp->subst.argidx);
327 break;
330 fprintf(stderr, ">\n");
332 return ppp;
337 *-------------------------------------------------------------------------
338 * Include management
339 *-------------------------------------------------------------------------
341 #if defined(_WIN32) || defined(__MSDOS__)
342 #define INCLUDESEPARATOR ";"
343 #else
344 #define INCLUDESEPARATOR ":"
345 #endif
347 static char **includepath;
348 static int nincludepath = 0;
350 void wpp_add_include_path(const char *path)
352 char *tok;
353 char *cpy = pp_xstrdup(path);
355 tok = strtok(cpy, INCLUDESEPARATOR);
356 while(tok)
358 if(*tok) {
359 char *dir;
360 char *cptr;
362 dir = pp_xstrdup(tok);
363 for(cptr = dir; *cptr; cptr++)
365 /* Convert to forward slash */
366 if(*cptr == '\\')
367 *cptr = '/';
369 /* Kill eventual trailing '/' */
370 if(*(cptr = dir + strlen(dir)-1) == '/')
371 *cptr = '\0';
373 /* Add to list */
374 includepath = pp_xrealloc(includepath, (nincludepath+1) * sizeof(*includepath));
375 includepath[nincludepath] = dir;
376 nincludepath++;
378 tok = strtok(NULL, INCLUDESEPARATOR);
380 free(cpy);
383 char *wpp_find_include(const char *name, const char *parent_name)
385 return wpp_lookup(name, !!parent_name, parent_name, includepath, nincludepath);
388 void *pp_open_include(const char *name, int type, const char *parent_name, char **newpath)
390 char *path;
391 void *fp;
393 if (!(path = wpp_lookup(name, type, parent_name, includepath, nincludepath))) return NULL;
394 fp = fopen(path, "rt");
396 if (fp)
398 if (pp_status.debug)
399 printf("Going to include <%s>\n", path);
400 if (newpath) *newpath = path;
401 else free( path );
402 return fp;
404 free( path );
405 return NULL;
409 *-------------------------------------------------------------------------
410 * #if, #ifdef, #ifndef, #else, #elif and #endif state management
412 * #if state transitions are made on basis of the current TOS and the next
413 * required state. The state transitions are required to housekeep because
414 * #if:s can be nested. The ignore case is activated to prevent output from
415 * within a false clause.
416 * Some special cases come from the fact that the #elif cases are not
417 * binary, but three-state. The problem is that all other elif-cases must
418 * be false when one true one has been found. A second problem is that the
419 * #else clause is a final clause. No extra #else:s may follow.
421 * The states mean:
422 * if_true Process input to output
423 * if_false Process input but no output
424 * if_ignore Process input but no output
425 * if_elif Process input but no output
426 * if_elsefalse Process input but no output
427 * if_elsettrue Process input to output
429 * The possible state-sequences are [state(stack depth)] (rest can be deduced):
430 * TOS #if 1 #else #endif
431 * if_true(n) if_true(n+1) if_elsefalse(n+1)
432 * if_false(n) if_ignore(n+1) if_ignore(n+1)
433 * if_elsetrue(n) if_true(n+1) if_elsefalse(n+1)
434 * if_elsefalse(n) if_ignore(n+1) if_ignore(n+1)
435 * if_elif(n) if_ignore(n+1) if_ignore(n+1)
436 * if_ignore(n) if_ignore(n+1) if_ignore(n+1)
438 * TOS #if 1 #elif 0 #else #endif
439 * if_true(n) if_true(n+1) if_elif(n+1) if_elif(n+1)
440 * if_false(n) if_ignore(n+1) if_ignore(n+1) if_ignore(n+1)
441 * if_elsetrue(n) if_true(n+1) if_elif(n+1) if_elif(n+1)
442 * if_elsefalse(n) if_ignore(n+1) if_ignore(n+1) if_ignore(n+1)
443 * if_elif(n) if_ignore(n+1) if_ignore(n+1) if_ignore(n+1)
444 * if_ignore(n) if_ignore(n+1) if_ignore(n+1) if_ignore(n+1)
446 * TOS #if 0 #elif 1 #else #endif
447 * if_true(n) if_false(n+1) if_true(n+1) if_elsefalse(n+1)
448 * if_false(n) if_ignore(n+1) if_ignore(n+1) if_ignore(n+1)
449 * if_elsetrue(n) if_false(n+1) if_true(n+1) if_elsefalse(n+1)
450 * if_elsefalse(n) if_ignore(n+1) if_ignore(n+1) if_ignore(n+1)
451 * if_elif(n) if_ignore(n+1) if_ignore(n+1) if_ignore(n+1)
452 * if_ignore(n) if_ignore(n+1) if_ignore(n+1) if_ignore(n+1)
454 *-------------------------------------------------------------------------
456 static const char * const pp_if_state_str[] = {
457 "if_false",
458 "if_true",
459 "if_elif",
460 "if_elsefalse",
461 "if_elsetrue",
462 "if_ignore"
465 void pp_push_if(pp_if_state_t s)
467 if(if_stack_idx >= MAXIFSTACK)
468 pp_internal_error(__FILE__, __LINE__, "#if-stack overflow; #{if,ifdef,ifndef} nested too deeply (> %d)", MAXIFSTACK);
470 if(pp_flex_debug)
471 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);
473 if_stack[if_stack_idx++] = s;
475 switch(s)
477 case if_true:
478 case if_elsetrue:
479 break;
480 case if_false:
481 case if_elsefalse:
482 case if_elif:
483 case if_ignore:
484 pp_push_ignore_state();
485 break;
486 default:
487 pp_internal_error(__FILE__, __LINE__, "Invalid pp_if_state (%d)", (int)pp_if_state());
491 pp_if_state_t pp_pop_if(void)
493 if(if_stack_idx <= 0)
495 ppy_error("#{endif,else,elif} without #{if,ifdef,ifndef} (#if-stack underflow)");
496 return if_error;
499 switch(pp_if_state())
501 case if_true:
502 case if_elsetrue:
503 break;
504 case if_false:
505 case if_elsefalse:
506 case if_elif:
507 case if_ignore:
508 pp_pop_ignore_state();
509 break;
510 default:
511 pp_internal_error(__FILE__, __LINE__, "Invalid pp_if_state (%d)", (int)pp_if_state());
514 if(pp_flex_debug)
515 fprintf(stderr, "Pop if %s:%d: %s(%d) -> %s(%d)\n",
516 pp_status.input,
517 pp_status.line_number,
518 pp_if_state_str[pp_if_state()],
519 if_stack_idx,
520 pp_if_state_str[if_stack[if_stack_idx <= 1 ? if_true : if_stack_idx-2]],
521 if_stack_idx-1);
523 return if_stack[--if_stack_idx];
526 pp_if_state_t pp_if_state(void)
528 if(!if_stack_idx)
529 return if_true;
530 else
531 return if_stack[if_stack_idx-1];
535 void pp_next_if_state(int i)
537 switch(pp_if_state())
539 case if_true:
540 case if_elsetrue:
541 pp_push_if(i ? if_true : if_false);
542 break;
543 case if_false:
544 case if_elsefalse:
545 case if_elif:
546 case if_ignore:
547 pp_push_if(if_ignore);
548 break;
549 default:
550 pp_internal_error(__FILE__, __LINE__, "Invalid pp_if_state (%d) in #{if,ifdef,ifndef} directive", (int)pp_if_state());
554 int pp_get_if_depth(void)
556 return if_stack_idx;
559 static void generic_msg(const char *s, const char *t, const char *n, va_list ap)
561 fprintf(stderr, "%s:%d:%d: %s: ", pp_status.input ? pp_status.input : "stdin",
562 pp_status.line_number, pp_status.char_number, t);
563 vfprintf(stderr, s, ap);
564 fprintf(stderr, "\n");
567 int ppy_error(const char *s, ...)
569 va_list ap;
570 va_start(ap, s);
571 generic_msg(s, "error", ppy_text, ap);
572 va_end(ap);
573 exit(1);
576 int ppy_warning(const char *s, ...)
578 va_list ap;
579 va_start(ap, s);
580 generic_msg(s, "warning", ppy_text, ap);
581 va_end(ap);
582 return 0;
585 void pp_internal_error(const char *file, int line, const char *s, ...)
587 va_list ap;
588 va_start(ap, s);
589 fprintf(stderr, "Internal error (please report) %s %d: ", file, line);
590 vfprintf(stderr, s, ap);
591 fprintf(stderr, "\n");
592 va_end(ap);
593 exit(3);
596 static void add_cmdline_defines(void)
598 struct define *def;
600 LIST_FOR_EACH_ENTRY( def, &cmdline_defines, struct define, entry )
602 if (def->value) pp_add_define( def->name, def->value );
606 static void add_special_defines(void)
608 time_t now = time(NULL);
609 pp_entry_t *ppp;
610 char buf[32];
612 strftime(buf, sizeof(buf), "\"%b %d %Y\"", localtime(&now));
613 pp_add_define( "__DATE__", buf );
615 strftime(buf, sizeof(buf), "\"%H:%M:%S\"", localtime(&now));
616 pp_add_define( "__TIME__", buf );
618 ppp = pp_add_define( "__FILE__", "" );
619 ppp->type = def_special;
621 ppp = pp_add_define( "__LINE__", "" );
622 ppp->type = def_special;
625 /* add a define to the preprocessor list */
626 static void wpp_add_define( const char *name, const char *value )
628 struct define *def;
630 if (!value) value = "";
632 LIST_FOR_EACH_ENTRY( def, &cmdline_defines, struct define, entry )
634 if (!strcmp( def->name, name ))
636 free( def->value );
637 def->value = pp_xstrdup(value);
638 return;
642 def = pp_xmalloc( sizeof(*def) );
643 def->name = pp_xstrdup(name);
644 def->value = pp_xstrdup(value);
645 list_add_head( &cmdline_defines, &def->entry );
649 /* undefine a previously added definition */
650 void wpp_del_define( const char *name )
652 struct define *def;
654 LIST_FOR_EACH_ENTRY( def, &cmdline_defines, struct define, entry )
656 if (!strcmp( def->name, name ))
658 free( def->value );
659 def->value = NULL;
660 return;
666 /* add a command-line define of the form NAME=VALUE */
667 void wpp_add_cmdline_define( const char *value )
669 char *p;
670 char *str = pp_xstrdup(value);
672 p = strchr( str, '=' );
673 if (p) *p++ = 0;
674 wpp_add_define( str, p );
675 free( str );
679 /* set the various debug flags */
680 void wpp_set_debug( int lex_debug, int parser_debug, int msg_debug )
682 pp_flex_debug = lex_debug;
683 ppy_debug = parser_debug;
684 pp_status.debug = msg_debug;
688 /* set the pedantic mode */
689 void wpp_set_pedantic( int on )
691 pp_status.pedantic = on;
695 /* the main preprocessor parsing loop */
696 int wpp_parse( const char *input, FILE *output )
698 int ret;
700 pp_status.input = NULL;
701 pp_status.line_number = 1;
702 pp_status.char_number = 1;
704 pp_init_define_state();
705 add_cmdline_defines();
706 add_special_defines();
708 if (!input) pp_status.file = stdin;
709 else if (!(pp_status.file = fopen(input, "rt")))
710 ppy_error("Could not open %s\n", input);
712 pp_status.input = input ? pp_xstrdup(input) : NULL;
714 ppy_out = output;
715 pp_writestring("# 1 \"%s\" 1\n", input ? input : "");
717 ret = ppy_parse();
719 if (input)
721 fclose(pp_status.file);
722 free(pp_status.input);
724 /* Clean if_stack, it could remain dirty on errors */
725 while (pp_get_if_depth()) pp_pop_if();
726 pp_free_define_state();
727 return ret;