ole32: Move apartment and activation management to a separate file.
[wine.git] / libs / wpp / preproc.c
blob284704b9f41304b2ba82a6a6f9321a6de47562a5
1 /*
2 * Copyright 1998 Bertho A. Stultiens (BS)
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.
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.
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
19 #include "config.h"
20 #include "wine/port.h"
22 #include <assert.h>
23 #include <ctype.h>
24 #include <fcntl.h>
25 #include <stdio.h>
26 #include <stdlib.h>
27 #include <string.h>
28 #include <stdarg.h>
29 #ifdef HAVE_UNISTD_H
30 # include <unistd.h>
31 #endif
33 #include "wine/wpp.h"
34 #include "wpp_private.h"
36 struct pp_status pp_status;
38 #define HASHKEY 2039
40 typedef struct pp_def_state
42 struct pp_def_state *next;
43 pp_entry_t *defines[HASHKEY];
44 } pp_def_state_t;
46 static pp_def_state_t *pp_def_state;
48 #define MAXIFSTACK 64
49 static pp_if_state_t if_stack[MAXIFSTACK];
50 static int if_stack_idx = 0;
52 #if 0
53 void pp_print_status(void) __attribute__((destructor));
54 void pp_print_status(void)
56 int i;
57 int sum;
58 int total = 0;
59 pp_entry_t *ppp;
61 fprintf(stderr, "Defines statistics:\n");
62 for(i = 0; i < HASHKEY; i++)
64 sum = 0;
65 for(ppp = pp_def_state->defines[i]; ppp; ppp = ppp->next)
66 sum++;
67 total += sum;
68 if (sum) fprintf(stderr, "%4d, %3d\n", i, sum);
70 fprintf(stderr, "Total defines: %d\n", total);
72 #endif
74 void *pp_xmalloc(size_t size)
76 void *res;
78 assert(size > 0);
79 res = malloc(size);
80 if(res == NULL)
82 /* Set the error flag */
83 pp_status.state = 1;
85 return res;
88 void *pp_xrealloc(void *p, size_t size)
90 void *res;
92 assert(size > 0);
93 res = realloc(p, size);
94 if(res == NULL)
96 /* Set the error flag */
97 pp_status.state = 1;
99 return res;
102 char *pp_xstrdup(const char *str)
104 char *s;
105 int len;
107 assert(str != NULL);
108 len = strlen(str)+1;
109 s = pp_xmalloc(len);
110 if(!s)
111 return NULL;
112 return memcpy(s, str, len);
115 char *wpp_lookup(const char *name, int type, const char *parent_name,
116 char **include_path, int include_path_count)
118 char *cpy;
119 char *cptr;
120 char *path;
121 const char *ccptr;
122 int i, fd;
124 cpy = pp_xmalloc(strlen(name)+1);
125 if(!cpy)
126 return NULL;
127 cptr = cpy;
129 for(ccptr = name; *ccptr; ccptr++)
131 /* Convert to forward slash */
132 if(*ccptr == '\\') {
133 /* kill double backslash */
134 if(ccptr[1] == '\\')
135 ccptr++;
136 *cptr = '/';
137 }else {
138 *cptr = *ccptr;
140 cptr++;
142 *cptr = '\0';
144 if(type && parent_name)
146 /* Search directory of parent include and then -I path */
147 const char *p;
149 if ((p = strrchr( parent_name, '/' ))) p++;
150 else p = parent_name;
151 path = pp_xmalloc( (p - parent_name) + strlen(cpy) + 1 );
152 if(!path)
154 free(cpy);
155 return NULL;
157 memcpy( path, parent_name, p - parent_name );
158 strcpy( path + (p - parent_name), cpy );
159 fd = open( path, O_RDONLY );
160 if (fd != -1)
162 close( fd );
163 free( cpy );
164 return path;
166 free( path );
168 /* Search -I path */
169 for(i = 0; i < include_path_count; i++)
171 path = pp_xmalloc(strlen(include_path[i]) + strlen(cpy) + 2);
172 if(!path)
174 free(cpy);
175 return NULL;
177 strcpy(path, include_path[i]);
178 strcat(path, "/");
179 strcat(path, cpy);
180 fd = open( path, O_RDONLY );
181 if (fd != -1)
183 close( fd );
184 free( cpy );
185 return path;
187 free( path );
189 free( cpy );
190 return NULL;
193 /* Don't comment on the hash, it's primitive but functional... */
194 static int pphash(const char *str)
196 int sum = 0;
197 while(*str)
198 sum += *str++;
199 return sum % HASHKEY;
202 pp_entry_t *pplookup(const char *ident)
204 int idx;
205 pp_entry_t *ppp;
207 if(!ident)
208 return NULL;
209 idx = pphash(ident);
210 for(ppp = pp_def_state->defines[idx]; ppp; ppp = ppp->next)
212 if(!strcmp(ident, ppp->ident))
213 return ppp;
215 return NULL;
218 static void free_pp_entry( pp_entry_t *ppp, int idx )
220 if(ppp->iep)
222 if(ppp->iep == pp_includelogiclist)
224 pp_includelogiclist = ppp->iep->next;
225 if(pp_includelogiclist)
226 pp_includelogiclist->prev = NULL;
228 else
230 ppp->iep->prev->next = ppp->iep->next;
231 if(ppp->iep->next)
232 ppp->iep->next->prev = ppp->iep->prev;
234 free(ppp->iep->filename);
235 free(ppp->iep);
238 if(pp_def_state->defines[idx] == ppp)
240 pp_def_state->defines[idx] = ppp->next;
241 if(pp_def_state->defines[idx])
242 pp_def_state->defines[idx]->prev = NULL;
244 else
246 ppp->prev->next = ppp->next;
247 if(ppp->next)
248 ppp->next->prev = ppp->prev;
251 free(ppp);
254 /* push a new (empty) define state */
255 int pp_push_define_state(void)
257 pp_def_state_t *state = pp_xmalloc( sizeof(*state) );
258 if(!state)
259 return 1;
261 memset( state->defines, 0, sizeof(state->defines) );
262 state->next = pp_def_state;
263 pp_def_state = state;
264 return 0;
267 /* pop the current define state */
268 void pp_pop_define_state(void)
270 int i;
271 pp_entry_t *ppp;
272 pp_def_state_t *state;
274 for (i = 0; i < HASHKEY; i++)
276 while ((ppp = pp_def_state->defines[i]) != NULL) pp_del_define( ppp->ident );
278 state = pp_def_state;
279 pp_def_state = state->next;
280 free( state );
283 void pp_del_define(const char *name)
285 pp_entry_t *ppp;
286 int idx = pphash(name);
288 if((ppp = pplookup(name)) == NULL)
290 if(pp_status.pedantic)
291 ppy_warning("%s was not defined", name);
292 return;
295 if(pp_status.debug)
296 printf("Deleting (%s, %d) <%s>\n", pp_status.input, pp_status.line_number, name);
298 free( ppp->ident );
299 free( ppp->subst.text );
300 free( ppp->filename );
301 free_pp_entry( ppp, idx );
304 pp_entry_t *pp_add_define(const char *def, const char *text)
306 int len;
307 char *cptr;
308 int idx;
309 pp_entry_t *ppp;
311 if(!def)
312 return NULL;
313 idx = pphash(def);
314 if((ppp = pplookup(def)) != NULL)
316 if(pp_status.pedantic)
317 ppy_warning("Redefinition of %s\n\tPrevious definition: %s:%d", def, ppp->filename, ppp->linenumber);
318 pp_del_define(def);
320 ppp = pp_xmalloc(sizeof(pp_entry_t));
321 if(!ppp)
322 return NULL;
323 memset( ppp, 0, sizeof(*ppp) );
324 ppp->ident = pp_xstrdup(def);
325 if(!ppp->ident)
326 goto error;
327 ppp->type = def_define;
328 ppp->subst.text = text ? pp_xstrdup(text) : NULL;
329 if(text && !ppp->subst.text)
330 goto error;
331 ppp->filename = pp_xstrdup(pp_status.input ? pp_status.input : "<internal or cmdline>");
332 if(!ppp->filename)
333 goto error;
334 ppp->linenumber = pp_status.input ? pp_status.line_number : 0;
335 ppp->next = pp_def_state->defines[idx];
336 pp_def_state->defines[idx] = ppp;
337 if(ppp->next)
338 ppp->next->prev = ppp;
339 if(ppp->subst.text)
341 /* Strip trailing white space from subst text */
342 len = strlen(ppp->subst.text);
343 while(len && strchr(" \t\r\n", ppp->subst.text[len-1]))
345 ppp->subst.text[--len] = '\0';
347 /* Strip leading white space from subst text */
348 for(cptr = ppp->subst.text; *cptr && strchr(" \t\r", *cptr); cptr++)
350 if(ppp->subst.text != cptr)
351 memmove(ppp->subst.text, cptr, strlen(cptr)+1);
353 if(pp_status.debug)
354 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)");
356 return ppp;
358 error:
359 free(ppp->ident);
360 free(ppp->subst.text);
361 free(ppp);
362 return NULL;
365 pp_entry_t *pp_add_macro(char *id, marg_t *args[], int nargs, mtext_t *exp)
367 int idx;
368 pp_entry_t *ppp;
370 if(!id)
371 return NULL;
372 idx = pphash(id);
373 if((ppp = pplookup(id)) != NULL)
375 if(pp_status.pedantic)
376 ppy_warning("Redefinition of %s\n\tPrevious definition: %s:%d", id, ppp->filename, ppp->linenumber);
377 pp_del_define(id);
379 ppp = pp_xmalloc(sizeof(pp_entry_t));
380 if(!ppp)
381 return NULL;
382 memset( ppp, 0, sizeof(*ppp) );
383 ppp->ident = id;
384 ppp->type = def_macro;
385 ppp->margs = args;
386 ppp->nargs = nargs;
387 ppp->subst.mtext= exp;
388 ppp->filename = pp_xstrdup(pp_status.input ? pp_status.input : "<internal or cmdline>");
389 if(!ppp->filename)
391 free(ppp);
392 return NULL;
394 ppp->linenumber = pp_status.input ? pp_status.line_number : 0;
395 ppp->next = pp_def_state->defines[idx];
396 pp_def_state->defines[idx] = ppp;
397 if(ppp->next)
398 ppp->next->prev = ppp;
400 if(pp_status.debug)
402 fprintf(stderr, "Added macro (%s, %d) <%s(%d)> to <", pp_status.input, pp_status.line_number, ppp->ident, nargs);
403 for(; exp; exp = exp->next)
405 switch(exp->type)
407 case exp_text:
408 fprintf(stderr, " \"%s\" ", exp->subst.text);
409 break;
410 case exp_stringize:
411 fprintf(stderr, " #(%d) ", exp->subst.argidx);
412 break;
413 case exp_concat:
414 fprintf(stderr, "##");
415 break;
416 case exp_subst:
417 fprintf(stderr, " <%d> ", exp->subst.argidx);
418 break;
421 fprintf(stderr, ">\n");
423 return ppp;
428 *-------------------------------------------------------------------------
429 * Include management
430 *-------------------------------------------------------------------------
432 #if defined(_WIN32) || defined(__MSDOS__)
433 #define INCLUDESEPARATOR ";"
434 #else
435 #define INCLUDESEPARATOR ":"
436 #endif
438 static char **includepath;
439 static int nincludepath = 0;
441 int wpp_add_include_path(const char *path)
443 char *tok;
444 char *cpy = pp_xstrdup(path);
445 if(!cpy)
446 return 1;
448 tok = strtok(cpy, INCLUDESEPARATOR);
449 while(tok)
451 if(*tok) {
452 char *dir;
453 char *cptr;
454 char **new_path;
456 dir = pp_xstrdup(tok);
457 if(!dir)
459 free(cpy);
460 return 1;
462 for(cptr = dir; *cptr; cptr++)
464 /* Convert to forward slash */
465 if(*cptr == '\\')
466 *cptr = '/';
468 /* Kill eventual trailing '/' */
469 if(*(cptr = dir + strlen(dir)-1) == '/')
470 *cptr = '\0';
472 /* Add to list */
473 new_path = pp_xrealloc(includepath, (nincludepath+1) * sizeof(*includepath));
474 if(!new_path)
476 free(dir);
477 free(cpy);
478 return 1;
480 includepath = new_path;
481 includepath[nincludepath] = dir;
482 nincludepath++;
484 tok = strtok(NULL, INCLUDESEPARATOR);
486 free(cpy);
487 return 0;
490 char *wpp_find_include(const char *name, const char *parent_name)
492 return wpp_lookup(name, !!parent_name, parent_name, includepath, nincludepath);
495 void *pp_open_include(const char *name, int type, const char *parent_name, char **newpath)
497 char *path;
498 void *fp;
500 if (!(path = wpp_lookup(name, type, parent_name, includepath, nincludepath))) return NULL;
501 fp = fopen(path, "rt");
503 if (fp)
505 if (pp_status.debug)
506 printf("Going to include <%s>\n", path);
507 if (newpath) *newpath = path;
508 else free( path );
509 return fp;
511 free( path );
512 return NULL;
516 *-------------------------------------------------------------------------
517 * #if, #ifdef, #ifndef, #else, #elif and #endif state management
519 * #if state transitions are made on basis of the current TOS and the next
520 * required state. The state transitions are required to housekeep because
521 * #if:s can be nested. The ignore case is activated to prevent output from
522 * within a false clause.
523 * Some special cases come from the fact that the #elif cases are not
524 * binary, but three-state. The problem is that all other elif-cases must
525 * be false when one true one has been found. A second problem is that the
526 * #else clause is a final clause. No extra #else:s may follow.
528 * The states mean:
529 * if_true Process input to output
530 * if_false Process input but no output
531 * if_ignore Process input but no output
532 * if_elif Process input but no output
533 * if_elsefalse Process input but no output
534 * if_elsettrue Process input to output
536 * The possible state-sequences are [state(stack depth)] (rest can be deduced):
537 * TOS #if 1 #else #endif
538 * if_true(n) if_true(n+1) if_elsefalse(n+1)
539 * if_false(n) if_ignore(n+1) if_ignore(n+1)
540 * if_elsetrue(n) if_true(n+1) if_elsefalse(n+1)
541 * if_elsefalse(n) if_ignore(n+1) if_ignore(n+1)
542 * if_elif(n) if_ignore(n+1) if_ignore(n+1)
543 * if_ignore(n) if_ignore(n+1) if_ignore(n+1)
545 * TOS #if 1 #elif 0 #else #endif
546 * if_true(n) if_true(n+1) if_elif(n+1) if_elif(n+1)
547 * if_false(n) if_ignore(n+1) if_ignore(n+1) if_ignore(n+1)
548 * if_elsetrue(n) if_true(n+1) if_elif(n+1) if_elif(n+1)
549 * if_elsefalse(n) if_ignore(n+1) if_ignore(n+1) if_ignore(n+1)
550 * if_elif(n) if_ignore(n+1) if_ignore(n+1) if_ignore(n+1)
551 * if_ignore(n) if_ignore(n+1) if_ignore(n+1) if_ignore(n+1)
553 * TOS #if 0 #elif 1 #else #endif
554 * if_true(n) if_false(n+1) if_true(n+1) if_elsefalse(n+1)
555 * if_false(n) if_ignore(n+1) if_ignore(n+1) if_ignore(n+1)
556 * if_elsetrue(n) if_false(n+1) if_true(n+1) if_elsefalse(n+1)
557 * if_elsefalse(n) if_ignore(n+1) if_ignore(n+1) if_ignore(n+1)
558 * if_elif(n) if_ignore(n+1) if_ignore(n+1) if_ignore(n+1)
559 * if_ignore(n) if_ignore(n+1) if_ignore(n+1) if_ignore(n+1)
561 *-------------------------------------------------------------------------
563 static const char * const pp_if_state_str[] = {
564 "if_false",
565 "if_true",
566 "if_elif",
567 "if_elsefalse",
568 "if_elsetrue",
569 "if_ignore"
572 void pp_push_if(pp_if_state_t s)
574 if(if_stack_idx >= MAXIFSTACK)
575 pp_internal_error(__FILE__, __LINE__, "#if-stack overflow; #{if,ifdef,ifndef} nested too deeply (> %d)", MAXIFSTACK);
577 if(pp_flex_debug)
578 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);
580 if_stack[if_stack_idx++] = s;
582 switch(s)
584 case if_true:
585 case if_elsetrue:
586 break;
587 case if_false:
588 case if_elsefalse:
589 case if_elif:
590 case if_ignore:
591 pp_push_ignore_state();
592 break;
593 default:
594 pp_internal_error(__FILE__, __LINE__, "Invalid pp_if_state (%d)", (int)pp_if_state());
598 pp_if_state_t pp_pop_if(void)
600 if(if_stack_idx <= 0)
602 ppy_error("#{endif,else,elif} without #{if,ifdef,ifndef} (#if-stack underflow)");
603 return if_error;
606 switch(pp_if_state())
608 case if_true:
609 case if_elsetrue:
610 break;
611 case if_false:
612 case if_elsefalse:
613 case if_elif:
614 case if_ignore:
615 pp_pop_ignore_state();
616 break;
617 default:
618 pp_internal_error(__FILE__, __LINE__, "Invalid pp_if_state (%d)", (int)pp_if_state());
621 if(pp_flex_debug)
622 fprintf(stderr, "Pop if %s:%d: %s(%d) -> %s(%d)\n",
623 pp_status.input,
624 pp_status.line_number,
625 pp_if_state_str[pp_if_state()],
626 if_stack_idx,
627 pp_if_state_str[if_stack[if_stack_idx <= 1 ? if_true : if_stack_idx-2]],
628 if_stack_idx-1);
630 return if_stack[--if_stack_idx];
633 pp_if_state_t pp_if_state(void)
635 if(!if_stack_idx)
636 return if_true;
637 else
638 return if_stack[if_stack_idx-1];
642 void pp_next_if_state(int i)
644 switch(pp_if_state())
646 case if_true:
647 case if_elsetrue:
648 pp_push_if(i ? if_true : if_false);
649 break;
650 case if_false:
651 case if_elsefalse:
652 case if_elif:
653 case if_ignore:
654 pp_push_if(if_ignore);
655 break;
656 default:
657 pp_internal_error(__FILE__, __LINE__, "Invalid pp_if_state (%d) in #{if,ifdef,ifndef} directive", (int)pp_if_state());
661 int pp_get_if_depth(void)
663 return if_stack_idx;
666 /* #define WANT_NEAR_INDICATION */
668 static void generic_msg(const char *s, const char *t, const char *n, va_list ap)
670 fprintf(stderr, "%s:%d:%d: %s: ", pp_status.input ? pp_status.input : "stdin",
671 pp_status.line_number, pp_status.char_number, t);
672 vfprintf(stderr, s, ap);
673 #ifdef WANT_NEAR_INDICATION
675 char *cpy, *p;
676 if(n)
678 cpy = pp_xstrdup(n);
679 if(!cpy)
680 goto end;
681 for (p = cpy; *p; p++) if(!isprint(*p)) *p = ' ';
682 fprintf(stderr, " near '%s'", cpy);
683 free(cpy);
686 end:
687 #endif
688 fprintf(stderr, "\n");
691 int ppy_error(const char *s, ...)
693 va_list ap;
694 va_start(ap, s);
695 generic_msg(s, "error", ppy_text, ap);
696 va_end(ap);
697 exit(1);
700 int ppy_warning(const char *s, ...)
702 va_list ap;
703 va_start(ap, s);
704 generic_msg(s, "warning", ppy_text, ap);
705 va_end(ap);
706 return 0;
709 void pp_internal_error(const char *file, int line, const char *s, ...)
711 va_list ap;
712 va_start(ap, s);
713 fprintf(stderr, "Internal error (please report) %s %d: ", file, line);
714 vfprintf(stderr, s, ap);
715 fprintf(stderr, "\n");
716 va_end(ap);
717 exit(3);