Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
wine-mirror
GitHub Repository: wine-mirror/wine
Path: blob/master/tools/wrc/wpp.c
4388 views
1
/*
2
* Exported functions of the Wine preprocessor
3
*
4
* Copyright 1998 Bertho A. Stultiens
5
* Copyright 2002 Alexandre Julliard
6
*
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.
11
*
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.
16
*
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
20
*/
21
22
#include "config.h"
23
24
#include <assert.h>
25
#include <ctype.h>
26
#include <fcntl.h>
27
#include <stdio.h>
28
#include <stdlib.h>
29
#include <string.h>
30
#include <stdarg.h>
31
#include <time.h>
32
33
#include "../tools.h"
34
#include "utils.h"
35
#include "wpp_private.h"
36
37
struct pp_status pp_status;
38
39
#define HASHKEY 2039
40
41
static struct list pp_defines[HASHKEY];
42
43
#define MAXIFSTACK 64
44
static pp_if_state_t if_stack[MAXIFSTACK];
45
static int if_stack_idx = 0;
46
47
int ppy_debug, pp_flex_debug;
48
49
struct define
50
{
51
struct list entry;
52
char *name;
53
char *value;
54
};
55
56
static struct list cmdline_defines = LIST_INIT( cmdline_defines );
57
static struct strarray includes;
58
59
static char *wpp_lookup(const char *name, int type, const char *parent_name)
60
{
61
char *cpy;
62
char *cptr;
63
char *path;
64
const char *ccptr;
65
int i, fd;
66
67
cpy = xmalloc(strlen(name)+1);
68
cptr = cpy;
69
70
for(ccptr = name; *ccptr; ccptr++)
71
{
72
/* Convert to forward slash */
73
if(*ccptr == '\\') {
74
/* kill double backslash */
75
if(ccptr[1] == '\\')
76
ccptr++;
77
*cptr = '/';
78
}else {
79
*cptr = *ccptr;
80
}
81
cptr++;
82
}
83
*cptr = '\0';
84
85
if(type && parent_name)
86
{
87
/* Search directory of parent include and then -I path */
88
path = strmake( "%s/%s", get_dirname(parent_name), cpy );
89
fd = open( path, O_RDONLY );
90
if (fd != -1)
91
{
92
close( fd );
93
free( cpy );
94
return path;
95
}
96
free( path );
97
}
98
/* Search -I path */
99
for(i = 0; i < includes.count; i++)
100
{
101
path = strmake("%s/%s", includes.str[i], cpy);
102
fd = open( path, O_RDONLY );
103
if (fd != -1)
104
{
105
close( fd );
106
free( cpy );
107
return path;
108
}
109
free( path );
110
}
111
free( cpy );
112
return NULL;
113
}
114
115
/* Don't comment on the hash, it's 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;
127
pp_entry_t *ppp;
128
129
if(!ident)
130
return NULL;
131
idx = pphash(ident);
132
LIST_FOR_EACH_ENTRY( ppp, &pp_defines[idx], pp_entry_t, entry )
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
list_remove( &ppp->iep->entry );
145
free(ppp->iep->filename);
146
free(ppp->iep);
147
}
148
list_remove( &ppp->entry );
149
free(ppp);
150
}
151
152
/* initialize the define state */
153
static void pp_init_define_state(void)
154
{
155
int i;
156
157
for (i = 0; i < HASHKEY; i++) list_init( &pp_defines[i] );
158
}
159
160
/* free the current define state */
161
static void pp_free_define_state(void)
162
{
163
int i;
164
pp_entry_t *ppp, *ppp2;
165
166
for (i = 0; i < HASHKEY; i++)
167
{
168
LIST_FOR_EACH_ENTRY_SAFE( ppp, ppp2, &pp_defines[i], pp_entry_t, entry )
169
{
170
free( ppp->ident );
171
free( ppp->subst.text );
172
free( ppp->filename );
173
free_pp_entry( ppp, i );
174
}
175
}
176
}
177
178
void pp_del_define(const char *name)
179
{
180
pp_entry_t *ppp;
181
int idx = pphash(name);
182
183
if((ppp = pplookup(name)) == NULL)
184
{
185
if(pedantic)
186
ppy_warning("%s was not defined", name);
187
return;
188
}
189
190
if(pp_status.debug)
191
printf("Deleting (%s, %d) <%s>\n", pp_status.input, pp_status.line_number, name);
192
193
free( ppp->ident );
194
free( ppp->subst.text );
195
free( ppp->filename );
196
free_pp_entry( ppp, idx );
197
}
198
199
pp_entry_t *pp_add_define(const char *def, const char *text)
200
{
201
int len;
202
char *cptr;
203
int idx;
204
pp_entry_t *ppp;
205
206
idx = pphash(def);
207
if((ppp = pplookup(def)) != NULL)
208
{
209
if(pedantic)
210
ppy_warning("Redefinition of %s\n%s:%d: note: previous definition was here",
211
def, ppp->filename, ppp->linenumber);
212
pp_del_define(def);
213
}
214
ppp = xmalloc(sizeof(pp_entry_t));
215
memset( ppp, 0, sizeof(*ppp) );
216
ppp->ident = xstrdup(def);
217
ppp->type = def_define;
218
ppp->subst.text = text ? xstrdup(text) : NULL;
219
ppp->filename = xstrdup(pp_status.input ? pp_status.input : "<internal or cmdline>");
220
ppp->linenumber = pp_status.input ? pp_status.line_number : 0;
221
list_add_head( &pp_defines[idx], &ppp->entry );
222
if(ppp->subst.text)
223
{
224
/* Strip trailing white space from subst text */
225
len = strlen(ppp->subst.text);
226
while(len && strchr(" \t\r\n", ppp->subst.text[len-1]))
227
{
228
ppp->subst.text[--len] = '\0';
229
}
230
/* Strip leading white space from subst text */
231
for(cptr = ppp->subst.text; *cptr && strchr(" \t\r", *cptr); cptr++)
232
;
233
if(ppp->subst.text != cptr)
234
memmove(ppp->subst.text, cptr, strlen(cptr)+1);
235
}
236
if(pp_status.debug)
237
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)");
238
239
return ppp;
240
}
241
242
pp_entry_t *pp_add_macro(char *id, char *args[], int nargs, int variadic, mtext_t *exp)
243
{
244
int idx;
245
pp_entry_t *ppp;
246
247
idx = pphash(id);
248
if((ppp = pplookup(id)) != NULL)
249
{
250
if(pedantic)
251
ppy_warning("Redefinition of %s\n%s:%d: note: previous definition was here",
252
id, ppp->filename, ppp->linenumber);
253
pp_del_define(id);
254
}
255
ppp = xmalloc(sizeof(pp_entry_t));
256
memset( ppp, 0, sizeof(*ppp) );
257
ppp->ident = id;
258
ppp->type = def_macro;
259
ppp->margs = args;
260
ppp->nargs = nargs;
261
ppp->variadic = variadic;
262
ppp->subst.mtext= exp;
263
ppp->filename = xstrdup(pp_status.input ? pp_status.input : "<internal or cmdline>");
264
ppp->linenumber = pp_status.input ? pp_status.line_number : 0;
265
list_add_head( &pp_defines[idx], &ppp->entry );
266
if(pp_status.debug)
267
{
268
fprintf(stderr, "Added macro (%s, %d) <%s(%d%s)> to <", pp_status.input, pp_status.line_number, ppp->ident, nargs, variadic ? ",va" : "");
269
for(; exp; exp = exp->next)
270
{
271
switch(exp->type)
272
{
273
case exp_text:
274
fprintf(stderr, " \"%s\" ", exp->subst.text);
275
break;
276
case exp_stringize:
277
fprintf(stderr, " #(%d) ", exp->subst.argidx);
278
break;
279
case exp_concat:
280
fprintf(stderr, "##");
281
break;
282
case exp_subst:
283
fprintf(stderr, " <%d> ", exp->subst.argidx);
284
break;
285
}
286
}
287
fprintf(stderr, ">\n");
288
}
289
return ppp;
290
}
291
292
293
/*
294
*-------------------------------------------------------------------------
295
* Include management
296
*-------------------------------------------------------------------------
297
*/
298
void wpp_add_include_path(const char *path)
299
{
300
char *dir = xstrdup(path);
301
char *cptr;
302
303
for(cptr = dir; *cptr; cptr++)
304
{
305
/* Convert to forward slash */
306
if(*cptr == '\\')
307
*cptr = '/';
308
}
309
/* Kill eventual trailing '/' */
310
if(*(cptr = dir + strlen(dir)-1) == '/') *cptr = '\0';
311
312
strarray_add( &includes, dir );
313
}
314
315
char *wpp_find_include(const char *name, const char *parent_name)
316
{
317
return wpp_lookup(name, !!parent_name, parent_name);
318
}
319
320
void *pp_open_include(const char *name, int type, const char *parent_name, char **newpath)
321
{
322
char *path;
323
void *fp;
324
325
if (!(path = wpp_lookup(name, type, parent_name))) return NULL;
326
fp = fopen(path, "rt");
327
328
if (fp)
329
{
330
if (pp_status.debug)
331
printf("Going to include <%s>\n", path);
332
if (newpath) *newpath = path;
333
else free( path );
334
return fp;
335
}
336
free( path );
337
return NULL;
338
}
339
340
/*
341
*-------------------------------------------------------------------------
342
* #if, #ifdef, #ifndef, #else, #elif and #endif state management
343
*
344
* #if state transitions are made on basis of the current TOS and the next
345
* required state. The state transitions are required to housekeep because
346
* #if:s can be nested. The ignore case is activated to prevent output from
347
* within a false clause.
348
* Some special cases come from the fact that the #elif cases are not
349
* binary, but three-state. The problem is that all other elif-cases must
350
* be false when one true one has been found. A second problem is that the
351
* #else clause is a final clause. No extra #else:s may follow.
352
*
353
* The states mean:
354
* if_true Process input to output
355
* if_false Process input but no output
356
* if_ignore Process input but no output
357
* if_elif Process input but no output
358
* if_elsefalse Process input but no output
359
* if_elsettrue Process input to output
360
*
361
* The possible state-sequences are [state(stack depth)] (rest can be deduced):
362
* TOS #if 1 #else #endif
363
* if_true(n) if_true(n+1) if_elsefalse(n+1)
364
* if_false(n) if_ignore(n+1) if_ignore(n+1)
365
* if_elsetrue(n) if_true(n+1) if_elsefalse(n+1)
366
* if_elsefalse(n) if_ignore(n+1) if_ignore(n+1)
367
* if_elif(n) if_ignore(n+1) if_ignore(n+1)
368
* if_ignore(n) if_ignore(n+1) if_ignore(n+1)
369
*
370
* TOS #if 1 #elif 0 #else #endif
371
* if_true(n) if_true(n+1) if_elif(n+1) if_elif(n+1)
372
* if_false(n) if_ignore(n+1) if_ignore(n+1) if_ignore(n+1)
373
* if_elsetrue(n) if_true(n+1) if_elif(n+1) if_elif(n+1)
374
* if_elsefalse(n) if_ignore(n+1) if_ignore(n+1) if_ignore(n+1)
375
* if_elif(n) if_ignore(n+1) if_ignore(n+1) if_ignore(n+1)
376
* if_ignore(n) if_ignore(n+1) if_ignore(n+1) if_ignore(n+1)
377
*
378
* TOS #if 0 #elif 1 #else #endif
379
* if_true(n) if_false(n+1) if_true(n+1) if_elsefalse(n+1)
380
* if_false(n) if_ignore(n+1) if_ignore(n+1) if_ignore(n+1)
381
* if_elsetrue(n) if_false(n+1) if_true(n+1) if_elsefalse(n+1)
382
* if_elsefalse(n) if_ignore(n+1) if_ignore(n+1) if_ignore(n+1)
383
* if_elif(n) if_ignore(n+1) if_ignore(n+1) if_ignore(n+1)
384
* if_ignore(n) if_ignore(n+1) if_ignore(n+1) if_ignore(n+1)
385
*
386
*-------------------------------------------------------------------------
387
*/
388
static const char * const pp_if_state_str[] = {
389
"if_false",
390
"if_true",
391
"if_elif",
392
"if_elsefalse",
393
"if_elsetrue",
394
"if_ignore"
395
};
396
397
void pp_push_if(pp_if_state_t s)
398
{
399
if(if_stack_idx >= MAXIFSTACK)
400
error("#if-stack overflow; #{if,ifdef,ifndef} nested too deeply (> %d)\n", MAXIFSTACK);
401
402
if(pp_flex_debug)
403
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);
404
405
if_stack[if_stack_idx++] = s;
406
407
switch(s)
408
{
409
case if_true:
410
case if_elsetrue:
411
break;
412
case if_false:
413
case if_elsefalse:
414
case if_elif:
415
case if_ignore:
416
pp_push_ignore_state();
417
break;
418
case if_error:
419
assert(0);
420
}
421
}
422
423
pp_if_state_t pp_pop_if(void)
424
{
425
if(if_stack_idx <= 0)
426
{
427
ppy_error("#{endif,else,elif} without #{if,ifdef,ifndef} (#if-stack underflow)");
428
return if_error;
429
}
430
431
switch(pp_if_state())
432
{
433
case if_true:
434
case if_elsetrue:
435
break;
436
case if_false:
437
case if_elsefalse:
438
case if_elif:
439
case if_ignore:
440
pp_pop_ignore_state();
441
break;
442
case if_error:
443
assert(0);
444
}
445
446
if(pp_flex_debug)
447
fprintf(stderr, "Pop if %s:%d: %s(%d) -> %s(%d)\n",
448
pp_status.input,
449
pp_status.line_number,
450
pp_if_state_str[pp_if_state()],
451
if_stack_idx,
452
pp_if_state_str[if_stack[if_stack_idx <= 1 ? if_true : if_stack_idx-2]],
453
if_stack_idx-1);
454
455
return if_stack[--if_stack_idx];
456
}
457
458
pp_if_state_t pp_if_state(void)
459
{
460
if(!if_stack_idx)
461
return if_true;
462
else
463
return if_stack[if_stack_idx-1];
464
}
465
466
467
void pp_next_if_state(int i)
468
{
469
switch(pp_if_state())
470
{
471
case if_true:
472
case if_elsetrue:
473
pp_push_if(i ? if_true : if_false);
474
break;
475
case if_false:
476
case if_elsefalse:
477
case if_elif:
478
case if_ignore:
479
pp_push_if(if_ignore);
480
break;
481
case if_error:
482
assert(0);
483
}
484
}
485
486
int pp_get_if_depth(void)
487
{
488
return if_stack_idx;
489
}
490
491
static void generic_msg(const char *s, const char *t, const char *n, va_list ap)
492
{
493
fprintf(stderr, "%s:%d:%d: %s: ", pp_status.input ? pp_status.input : "stdin",
494
pp_status.line_number, pp_status.char_number, t);
495
vfprintf(stderr, s, ap);
496
fprintf(stderr, "\n");
497
}
498
499
int ppy_error(const char *s, ...)
500
{
501
va_list ap;
502
va_start(ap, s);
503
generic_msg(s, "error", ppy_text, ap);
504
va_end(ap);
505
exit(1);
506
}
507
508
int ppy_warning(const char *s, ...)
509
{
510
va_list ap;
511
va_start(ap, s);
512
generic_msg(s, "warning", ppy_text, ap);
513
va_end(ap);
514
return 0;
515
}
516
517
static void add_cmdline_defines(void)
518
{
519
struct define *def;
520
521
LIST_FOR_EACH_ENTRY( def, &cmdline_defines, struct define, entry )
522
{
523
if (def->value) pp_add_define( def->name, def->value );
524
}
525
}
526
527
static void add_special_defines(void)
528
{
529
time_t now = time(NULL);
530
pp_entry_t *ppp;
531
char buf[32];
532
533
strftime(buf, sizeof(buf), "\"%b %d %Y\"", localtime(&now));
534
pp_add_define( "__DATE__", buf );
535
536
strftime(buf, sizeof(buf), "\"%H:%M:%S\"", localtime(&now));
537
pp_add_define( "__TIME__", buf );
538
539
ppp = pp_add_define( "__FILE__", "" );
540
ppp->type = def_special;
541
542
ppp = pp_add_define( "__LINE__", "" );
543
ppp->type = def_special;
544
}
545
546
/* add a define to the preprocessor list */
547
static void wpp_add_define( const char *name, const char *value )
548
{
549
struct define *def;
550
551
if (!value) value = "";
552
553
LIST_FOR_EACH_ENTRY( def, &cmdline_defines, struct define, entry )
554
{
555
if (!strcmp( def->name, name ))
556
{
557
free( def->value );
558
def->value = xstrdup(value);
559
return;
560
}
561
}
562
563
def = xmalloc( sizeof(*def) );
564
def->name = xstrdup(name);
565
def->value = xstrdup(value);
566
list_add_head( &cmdline_defines, &def->entry );
567
}
568
569
570
/* undefine a previously added definition */
571
void wpp_del_define( const char *name )
572
{
573
struct define *def;
574
575
LIST_FOR_EACH_ENTRY( def, &cmdline_defines, struct define, entry )
576
{
577
if (!strcmp( def->name, name ))
578
{
579
free( def->value );
580
def->value = NULL;
581
return;
582
}
583
}
584
}
585
586
587
/* add a command-line define of the form NAME=VALUE */
588
void wpp_add_cmdline_define( const char *value )
589
{
590
char *p;
591
char *str = xstrdup(value);
592
593
p = strchr( str, '=' );
594
if (p) *p++ = 0;
595
wpp_add_define( str, p );
596
free( str );
597
}
598
599
600
/* set the various debug flags */
601
void wpp_set_debug( int lex_debug, int parser_debug, int msg_debug )
602
{
603
pp_flex_debug = lex_debug;
604
ppy_debug = parser_debug;
605
pp_status.debug = msg_debug;
606
}
607
608
609
/* the main preprocessor parsing loop */
610
int wpp_parse( const char *input, FILE *output )
611
{
612
int ret;
613
614
pp_status.input = NULL;
615
pp_status.line_number = 1;
616
pp_status.char_number = 1;
617
618
pp_init_define_state();
619
add_cmdline_defines();
620
add_special_defines();
621
622
if (!input) pp_status.file = stdin;
623
else if (!(pp_status.file = fopen(input, "rt")))
624
ppy_error("Could not open %s\n", input);
625
626
pp_status.input = input ? xstrdup(input) : NULL;
627
628
ppy_out = output;
629
fprintf(ppy_out, "# 1 \"%s\" 1\n", input ? input : "");
630
631
ret = ppy_parse();
632
633
if (input)
634
{
635
fclose(pp_status.file);
636
free(pp_status.input);
637
}
638
/* Clean if_stack, it could remain dirty on errors */
639
while (pp_get_if_depth()) pp_pop_if();
640
pp_free_define_state();
641
return ret;
642
}
643
644