Added mappings for a few messages.
[wine] / tools / wrc / preproc.c
1 /*
2  * Copyright 1998 Bertho A. Stultiens (BS)
3  *
4  */
5
6 #include "config.h"
7
8 #include <stdio.h>
9 #include <stdlib.h>
10 #include <string.h>
11 #include <assert.h>
12
13 #include "wrc.h"
14 #include "utils.h"
15 #include "preproc.h"
16
17
18 #define HASHKEY         2039
19 static pp_entry_t *pp_defines[HASHKEY];
20
21 #define MAXIFSTACK      64
22 static if_state_t if_stack[MAXIFSTACK];
23 static int if_stack_idx = 0;
24
25 #if 0
26 void pp_status(void) __attribute__((destructor));
27 void pp_status(void)
28 {
29         int i;
30         int sum;
31         int total = 0;
32         pp_entry_t *ppp;
33
34         fprintf(stderr, "Defines statistics:\n");
35         for(i = 0; i < HASHKEY; i++)
36         {
37                 sum = 0;
38                 for(ppp = pp_defines[i]; ppp; ppp = ppp->next)
39                         sum++;
40                 total += sum;
41                 fprintf(stderr, "%4d, %3d\n", i, sum);
42         }
43         fprintf(stderr, "Total defines: %d\n", total);
44 }
45 #endif
46
47 /* Don't comment on the hash, its primitive but functional... */
48 int pphash(char *str)
49 {
50         int sum = 0;
51         while(*str)
52                 sum += *str++;
53         return sum % HASHKEY;
54 }
55
56 pp_entry_t *pplookup(char *ident)
57 {
58         int idx = pphash(ident);
59         pp_entry_t *ppp;
60
61         for(ppp = pp_defines[idx]; ppp; ppp = ppp->next)
62         {
63                 if(!strcmp(ident, ppp->ident))
64                         return ppp;
65         }
66         return NULL;
67 }
68
69 void del_define(char *name)
70 {
71         int idx;
72         pp_entry_t *ppp;
73
74         if((ppp = pplookup(name)) == NULL)
75         {
76                 if(pedantic)
77                         yywarning("%s was not defined", name);
78                 return;
79         }
80
81         if(ppp->iep)
82         {
83                 if(debuglevel & DEBUGLEVEL_PPMSG)
84                         fprintf(stderr, "del_define: %s:%d: includelogic removed, include_ppp='%s', file=%s\n", input_name, line_number, name, ppp->iep->filename);
85                 if(ppp->iep == includelogiclist)
86                 {
87                         includelogiclist = ppp->iep->next;
88                         if(includelogiclist)
89                                 includelogiclist->prev = NULL;
90                 }
91                 else
92                 {
93                         ppp->iep->prev->next = ppp->iep->next;
94                         if(ppp->iep->next)
95                                 ppp->iep->next->prev = ppp->iep->prev;
96                 }
97                 free(ppp->iep->filename);
98                 free(ppp->iep);
99         }
100
101         idx = pphash(name);
102         if(pp_defines[idx] == ppp)
103         {
104                 pp_defines[idx] = ppp->next;
105                 if(pp_defines[idx])
106                         pp_defines[idx]->prev = NULL;
107         }
108         else
109         {
110                 ppp->prev->next = ppp->next;
111                 if(ppp->next)
112                         ppp->next->prev = ppp->prev;
113         }
114
115         free(ppp);
116
117         if(debuglevel & DEBUGLEVEL_PPMSG)
118                 printf("Deleted (%s, %d) <%s>\n", input_name, line_number, name);
119 }
120
121 pp_entry_t *add_define(char *def, char *text)
122 {
123         int len;
124         char *cptr;
125         int idx = pphash(def);
126         pp_entry_t *ppp;
127
128         if((ppp = pplookup(def)) != NULL)
129         {
130                 if(pedantic)
131                         yywarning("Redefinition of %s\n\tPrevious definition: %s:%d", def, ppp->filename, ppp->linenumber);
132                 del_define(def);
133         }
134         ppp = (pp_entry_t *)xmalloc(sizeof(pp_entry_t));
135         ppp->ident = def;
136         ppp->type = def_define;
137         ppp->subst.text = text;
138         ppp->filename = input_name ? xstrdup(input_name) : "<internal or cmdline>";
139         ppp->linenumber = input_name ? line_number : 0;
140         ppp->next = pp_defines[idx];
141         pp_defines[idx] = ppp;
142         if(ppp->next)
143                 ppp->next->prev = ppp;
144         if(text)
145         {
146                 /* Strip trailing white space from subst text */
147                 len = strlen(text);
148                 while(len && strchr(" \t\r\n", text[len-1]))
149                 {
150                         text[--len] = '\0';
151                 }
152                 /* Strip leading white space from subst text */
153                 for(cptr = text; *cptr && strchr(" \t\r", *cptr); cptr++)
154                 ;
155                 if(text != cptr)
156                         memmove(text, cptr, strlen(cptr)+1);
157         }
158         if(debuglevel & DEBUGLEVEL_PPMSG)
159                 printf("Added define (%s, %d) <%s> to <%s>\n", input_name, line_number, ppp->ident, text ? text : "(null)");
160
161         return ppp;
162 }
163
164 pp_entry_t *add_cmdline_define(char *set)
165 {
166         char *cpy = xstrdup(set);       /* Because gcc passes a R/O string */
167         char *cptr = strchr(cpy, '=');
168         if(cptr)
169                 *cptr = '\0';
170         return add_define(cpy, xstrdup(cptr ? cptr+1 : ""));
171 }
172
173 pp_entry_t *add_special_define(char *id)
174 {
175         pp_entry_t *ppp = add_define(xstrdup(id), xstrdup(""));
176         ppp->type = def_special;
177         return ppp;
178 }
179
180 pp_entry_t *add_macro(char *id, marg_t *args[], int nargs, mtext_t *exp)
181 {
182         int idx = pphash(id);
183         pp_entry_t *ppp;
184
185         if((ppp = pplookup(id)) != NULL)
186         {
187                 if(pedantic)
188                         yywarning("Redefinition of %s\n\tPrevious definition: %s:%d", id, ppp->filename, ppp->linenumber);
189                 del_define(id);
190         }
191         ppp = (pp_entry_t *)xmalloc(sizeof(pp_entry_t));
192         ppp->ident      = id;
193         ppp->type       = def_macro;
194         ppp->margs      = args;
195         ppp->nargs      = nargs;
196         ppp->subst.mtext= exp;
197         ppp->filename = input_name ? xstrdup(input_name) : "<internal or cmdline>";
198         ppp->linenumber = input_name ? line_number : 0;
199         ppp->next       = pp_defines[idx];
200         pp_defines[idx] = ppp;
201         if(ppp->next)
202                 ppp->next->prev = ppp;
203
204         if(debuglevel & DEBUGLEVEL_PPMSG)
205         {
206                 fprintf(stderr, "Added macro (%s, %d) <%s(%d)> to <", input_name, line_number, ppp->ident, nargs);
207                 for(; exp; exp = exp->next)
208                 {
209                         switch(exp->type)
210                         {
211                         case exp_text:
212                                 fprintf(stderr, " \"%s\" ", exp->subst.text);
213                                 break;
214                         case exp_stringize:
215                                 fprintf(stderr, " #(%d) ", exp->subst.argidx);
216                                 break;
217                         case exp_concat:
218                                 fprintf(stderr, "##");
219                                 break;
220                         case exp_subst:
221                                 fprintf(stderr, " <%d> ", exp->subst.argidx);
222                                 break;
223                         }
224                 }
225                 fprintf(stderr, ">\n");
226         }
227         return ppp;
228 }
229
230
231 /*
232  *-------------------------------------------------------------------------
233  * Include management
234  *-------------------------------------------------------------------------
235  */
236 #if defined(_Windows) || defined(__MSDOS__)
237 #define INCLUDESEPARATOR        ";"
238 #else
239 #define INCLUDESEPARATOR        ":"
240 #endif
241
242 static char **includepath;
243 static int nincludepath = 0;
244
245 void add_include_path(char *path)
246 {
247         char *tok;
248         char *cpy = xstrdup(path);
249
250         tok = strtok(cpy, INCLUDESEPARATOR);
251         while(tok)
252         {
253                 char *dir;
254                 char *cptr;
255                 if(strlen(tok) == 0)
256                         continue;
257                 dir = xstrdup(tok);
258                 for(cptr = dir; *cptr; cptr++)
259                 {
260                         /* Convert to forward slash */
261                         if(*cptr == '\\')
262                                 *cptr = '/';
263                 }
264                 /* Kill eventual trailing '/' */
265                 if(*(cptr = dir + strlen(dir)-1) == '/')
266                         *cptr = '\0';
267
268                 /* Add to list */
269                 nincludepath++;
270                 includepath = (char **)xrealloc(includepath, nincludepath * sizeof(*includepath));
271                 includepath[nincludepath-1] = dir;
272                 tok = strtok(NULL, INCLUDESEPARATOR);
273         }
274         free(cpy);
275 }
276
277 FILE *open_include(const char *name, int search, char **newpath)
278 {
279         char *cpy = xstrdup(name);
280         char *cptr;
281         FILE *fp;
282         int i;
283
284         for(cptr = cpy; *cptr; cptr++)
285         {
286                 /* kill double backslash */
287                 if(*cptr == '\\' && *(cptr+1) == '\\')
288                         memmove(cptr, cptr+1, strlen(cptr));
289                 /* Convert to forward slash */
290                 if(*cptr == '\\')
291                         *cptr = '/';
292         }
293
294         if(search)
295         {
296                 /* Search current dir and then -I path */
297                 fp = fopen(cpy, "rt");
298                 if(fp)
299                 {
300                         if(debuglevel & DEBUGLEVEL_PPMSG)
301                                 printf("Going to include <%s>\n", name);
302                         if(newpath)
303                                 *newpath = cpy;
304                         else
305                                 free(cpy);
306                         return fp;
307                 }
308         }
309         /* Search -I path */
310         for(i = 0; i < nincludepath; i++)
311         {
312                 char *path;
313                 path = (char *)xmalloc(strlen(includepath[i]) + strlen(cpy) + 2);
314                 strcpy(path, includepath[i]);
315                 strcat(path, "/");
316                 strcat(path, cpy);
317                 fp = fopen(path, "rt");
318                 if(fp && (debuglevel & DEBUGLEVEL_PPMSG))
319                         printf("Going to include <%s>\n", path);
320                 if(fp)
321                 {
322                         if(newpath)
323                                 *newpath = path;
324                         else
325                                 free(path);
326                         free(cpy);
327                         return fp;
328                 }
329                 free(path);
330         }
331         free(cpy);
332         if(newpath)
333                 *newpath = NULL;
334         return NULL;
335 }
336
337 /*
338  *-------------------------------------------------------------------------
339  * #if, #ifdef, #ifndef, #else, #elif and #endif state management
340  *
341  * #if state transitions are made on basis of the current TOS and the next
342  * required state. The state transitions are required to housekeep because
343  * #if:s can be nested. The ignore case is activated to prevent output from
344  * within a false clause.
345  * Some special cases come from the fact that the #elif cases are not
346  * binary, but three-state. The problem is that all other elif-cases must
347  * be false when one true one has been found. A second problem is that the
348  * #else clause is a final clause. No extra #else:s may follow.
349  *
350  * The states mean:
351  * if_true      Process input to output
352  * if_false     Process input but no output
353  * if_ignore    Process input but no output
354  * if_elif      Process input but no output
355  * if_elsefalse Process input but no output
356  * if_elsettrue Process input to output
357  *
358  * The possible state-sequences are [state(stack depth)] (rest can be deduced):
359  *      TOS             #if 1           #else                   #endif
360  *      if_true(n)      if_true(n+1)    if_elsefalse(n+1)
361  *      if_false(n)     if_ignore(n+1)  if_ignore(n+1)
362  *      if_elsetrue(n)  if_true(n+1)    if_elsefalse(n+1)
363  *      if_elsefalse(n) if_ignore(n+1)  if_ignore(n+1)
364  *      if_elif(n)      if_ignore(n+1)  if_ignore(n+1)
365  *      if_ignore(n)    if_ignore(n+1)  if_ignore(n+1)
366  *
367  *      TOS             #if 1           #elif 0         #else           #endif
368  *      if_true(n)      if_true(n+1)    if_elif(n+1)    if_elif(n+1)
369  *      if_false(n)     if_ignore(n+1)  if_ignore(n+1)  if_ignore(n+1)
370  *      if_elsetrue(n)  if_true(n+1)    if_elif(n+1)    if_elif(n+1)
371  *      if_elsefalse(n) if_ignore(n+1)  if_ignore(n+1)  if_ignore(n+1)
372  *      if_elif(n)      if_ignore(n+1)  if_ignore(n+1)  if_ignore(n+1)
373  *      if_ignore(n)    if_ignore(n+1)  if_ignore(n+1)  if_ignore(n+1)
374  *
375  *      TOS             #if 0           #elif 1         #else           #endif
376  *      if_true(n)      if_false(n+1)   if_true(n+1)    if_elsefalse(n+1)
377  *      if_false(n)     if_ignore(n+1)  if_ignore(n+1)  if_ignore(n+1)
378  *      if_elsetrue(n)  if_false(n+1)   if_true(n+1)    if_elsefalse(n+1)
379  *      if_elsefalse(n) if_ignore(n+1)  if_ignore(n+1)  if_ignore(n+1)
380  *      if_elif(n)      if_ignore(n+1)  if_ignore(n+1)  if_ignore(n+1)
381  *      if_ignore(n)    if_ignore(n+1)  if_ignore(n+1)  if_ignore(n+1)
382  *
383  *-------------------------------------------------------------------------
384  */
385 static char *if_state_str[] = {
386         "if_false",
387         "if_true",
388         "if_elif",
389         "if_elsefalse",
390         "if_elsetrue",
391         "if_ignore"
392 };
393
394 void push_if(if_state_t s)
395 {
396         if(if_stack_idx >= MAXIFSTACK)
397                 internal_error(__FILE__, __LINE__, "#if-stack overflow; #{if,ifdef,ifndef} nested too deeply (> %d)", MAXIFSTACK);
398
399         if(debuglevel & DEBUGLEVEL_PPLEX)
400                 fprintf(stderr, "Push if %s:%d: %s(%d) -> %s(%d)\n", input_name, line_number, if_state_str[if_state()], if_stack_idx, if_state_str[s], if_stack_idx+1);
401
402         if_stack[if_stack_idx++] = s;
403
404         switch(s)
405         {
406         case if_true:
407         case if_elsetrue:
408                 break;
409         case if_false:
410         case if_elsefalse:
411         case if_elif:
412         case if_ignore:
413                 push_ignore_state();
414                 break;
415         }
416 }
417
418 if_state_t pop_if(void)
419 {
420         if(if_stack_idx <= 0)
421                 yyerror("#{endif,else,elif} without #{if,ifdef,ifndef} (#if-stack underflow)");
422
423         switch(if_state())
424         {
425         case if_true:
426         case if_elsetrue:
427                 break;
428         case if_false:
429         case if_elsefalse:
430         case if_elif:
431         case if_ignore:
432                 pop_ignore_state();
433                 break;
434         }
435
436         if(debuglevel & DEBUGLEVEL_PPLEX)
437                 fprintf(stderr, "Pop if %s:%d: %s(%d) -> %s(%d)\n",
438                                 input_name,
439                                 line_number,
440                                 if_state_str[if_state()],
441                                 if_stack_idx,
442                                 if_state_str[if_stack[if_stack_idx <= 1 ? if_true : if_stack_idx-2]],
443                                 if_stack_idx-1);
444
445         return if_stack[--if_stack_idx];
446 }
447
448 if_state_t if_state(void)
449 {
450         if(!if_stack_idx)
451                 return if_true;
452         else
453                 return if_stack[if_stack_idx-1];
454 }
455
456
457 void next_if_state(int i)
458 {
459         switch(if_state())
460         {
461         case if_true:
462         case if_elsetrue:
463                 push_if(i ? if_true : if_false);
464                 break;
465         case if_false:
466         case if_elsefalse:
467         case if_elif:
468         case if_ignore:
469                 push_if(if_ignore);
470                 break;
471         default:
472                 internal_error(__FILE__, __LINE__, "Invalid if_state (%d) in #{if,ifdef,ifndef} directive", (int)if_state());
473         }
474 }
475
476 int get_if_depth(void)
477 {
478         return if_stack_idx;
479 }
480