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