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