Line data Source code
1 : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 : /* $XConsortium: parse.c,v 1.30 94/04/17 20:10:38 gildea Exp $ */
3 : /*
4 :
5 : Copyright (c) 1993, 1994 X Consortium
6 :
7 : Permission is hereby granted, free of charge, to any person obtaining a copy
8 : of this software and associated documentation files (the "Software"), to deal
9 : in the Software without restriction, including without limitation the rights
10 : to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11 : copies of the Software, and to permit persons to whom the Software is
12 : furnished to do so, subject to the following conditions:
13 :
14 : The above copyright notice and this permission notice shall be included in
15 : all copies or substantial portions of the Software.
16 :
17 : THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18 : IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 : FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20 : X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
21 : AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
22 : CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23 :
24 : Except as contained in this notice, the name of the X Consortium shall not be
25 : used in advertising or otherwise to promote the sale, use or other dealings
26 : in this Software without prior written authorization from the X Consortium.
27 :
28 : */
29 :
30 : #include "def.h"
31 : char *hash_lookup( char *symbol, struct symhash *symbols );
32 : void hash_undefine( char *symbol, struct symhash *symbols );
33 : int gobble( struct filepointer *filep, struct inclist *file,
34 : struct inclist *file_red, struct symhash *symbols );
35 : int deftype ( char *line, struct filepointer *filep,
36 : struct inclist *file_red, struct inclist *file,
37 : int parse_it, struct symhash *symbols);
38 : int zero_value(char *exp, struct filepointer *filep,
39 : struct inclist *file_red, struct symhash *symbols);
40 :
41 : extern char *directives[];
42 : extern struct symhash *maininclist;
43 :
44 0 : int find_includes(struct filepointer *filep, struct inclist *file, struct inclist *file_red, int recursion, boolean failOK, struct IncludesCollection* incCollection, struct symhash *symbols)
45 : {
46 : char *line;
47 : int type;
48 : boolean recfailOK;
49 :
50 0 : while ((line = get_line(filep))) {
51 0 : switch(type = deftype(line, filep, file_red, file, TRUE, symbols)) {
52 : case IF:
53 : doif:
54 0 : type = find_includes(filep, file,
55 : file_red, recursion+1, failOK, incCollection, symbols);
56 0 : while ((type == ELIF) || (type == ELIFFALSE) ||
57 : (type == ELIFGUESSFALSE))
58 0 : type = gobble(filep, file, file_red, symbols);
59 0 : if (type == ELSE)
60 0 : gobble(filep, file, file_red, symbols);
61 0 : break;
62 : case IFFALSE:
63 : case IFGUESSFALSE:
64 : doiffalse:
65 0 : if (type == IFGUESSFALSE || type == ELIFGUESSFALSE)
66 0 : recfailOK = TRUE;
67 : else
68 0 : recfailOK = failOK;
69 0 : type = gobble(filep, file, file_red, symbols);
70 0 : if (type == ELSE)
71 0 : find_includes(filep, file,
72 : file_red, recursion+1, recfailOK, incCollection, symbols);
73 0 : else if (type == ELIF)
74 0 : goto doif;
75 0 : else if ((type == ELIFFALSE) || (type == ELIFGUESSFALSE))
76 : goto doiffalse;
77 0 : break;
78 : case IFDEF:
79 : case IFNDEF:
80 0 : if ((type == IFDEF && hash_lookup(line, symbols))
81 0 : || (type == IFNDEF && !hash_lookup(line, symbols))) {
82 : debug(1,(type == IFNDEF ?
83 : "line %d: %s !def'd in %s via %s%s\n" : "",
84 : filep->f_line, line,
85 : file->i_file, file_red->i_file, ": doit"));
86 0 : type = find_includes(filep, file,
87 : file_red, recursion+1, failOK, incCollection, symbols);
88 0 : while (type == ELIF || type == ELIFFALSE || type == ELIFGUESSFALSE)
89 0 : type = gobble(filep, file, file_red, symbols);
90 0 : if (type == ELSE)
91 0 : gobble(filep, file, file_red, symbols);
92 : }
93 : else {
94 : debug(1,(type == IFDEF ?
95 : "line %d: %s !def'd in %s via %s%s\n" : "",
96 : filep->f_line, line,
97 : file->i_file, file_red->i_file, ": gobble"));
98 0 : type = gobble(filep, file, file_red, symbols);
99 0 : if (type == ELSE)
100 0 : find_includes(filep, file,
101 : file_red, recursion + 1, failOK, incCollection, symbols);
102 0 : else if (type == ELIF)
103 0 : goto doif;
104 0 : else if (type == ELIFFALSE || type == ELIFGUESSFALSE)
105 : goto doiffalse;
106 : }
107 0 : break;
108 : case ELSE:
109 : case ELIFFALSE:
110 : case ELIFGUESSFALSE:
111 : case ELIF:
112 0 : if (!recursion)
113 0 : gobble(filep, file, file_red, symbols);
114 : /*fall-through*/
115 : case ENDIF:
116 0 : if (recursion)
117 0 : return(type);
118 : /*fall-through*/
119 : case DEFINE:
120 0 : define(line, &symbols);
121 0 : break;
122 : case UNDEF:
123 0 : if (!*line) {
124 0 : warning("%s, line %d: incomplete undef == \"%s\"\n",
125 : file_red->i_file, filep->f_line, line);
126 0 : break;
127 : }
128 0 : hash_undefine(line, symbols);
129 0 : break;
130 : case INCLUDE:
131 0 : add_include(filep, file, file_red, line, FALSE, failOK, incCollection, symbols);
132 0 : break;
133 : case INCLUDEDOT:
134 0 : add_include(filep, file, file_red, line, TRUE, failOK, incCollection, symbols);
135 0 : break;
136 : case ERROR:
137 0 : warning("%s: %d: %s\n", file_red->i_file,
138 : filep->f_line, line);
139 0 : break;
140 :
141 : case PRAGMA:
142 : case IDENT:
143 : case SCCS:
144 : case EJECT:
145 0 : break;
146 : case -1:
147 0 : warning("%s", file_red->i_file);
148 0 : if (file_red != file)
149 0 : warning1(" (reading %s)", file->i_file);
150 0 : warning1(", line %d: unknown directive == \"%s\"\n",
151 : filep->f_line, line);
152 0 : break;
153 : case -2:
154 0 : warning("%s", file_red->i_file);
155 0 : if (file_red != file)
156 0 : warning1(" (reading %s)", file->i_file);
157 0 : warning1(", line %d: incomplete include == \"%s\"\n",
158 : filep->f_line, line);
159 0 : break;
160 : }
161 : }
162 0 : return(-1);
163 : }
164 :
165 0 : int gobble(struct filepointer *filep,
166 : struct inclist *file,
167 : struct inclist *file_red,
168 : struct symhash *symbols)
169 : {
170 : char *line;
171 : int type;
172 :
173 0 : while ((line = get_line(filep))) {
174 0 : switch(type = deftype(line, filep, file_red, file, FALSE, symbols)) {
175 : case IF:
176 : case IFFALSE:
177 : case IFGUESSFALSE:
178 : case IFDEF:
179 : case IFNDEF:
180 0 : type = gobble(filep, file, file_red, symbols);
181 0 : while ((type == ELIF) || (type == ELIFFALSE) ||
182 : (type == ELIFGUESSFALSE))
183 0 : type = gobble(filep, file, file_red, symbols);
184 0 : if (type == ELSE)
185 0 : (void)gobble(filep, file, file_red, symbols);
186 0 : break;
187 : case ELSE:
188 : case ENDIF:
189 : debug(0,("%s, line %d: #%s\n",
190 : file->i_file, filep->f_line,
191 : directives[type]));
192 0 : return(type);
193 : case DEFINE:
194 : case UNDEF:
195 : case INCLUDE:
196 : case INCLUDEDOT:
197 : case PRAGMA:
198 : case ERROR:
199 : case IDENT:
200 : case SCCS:
201 : case EJECT:
202 0 : break;
203 : case ELIF:
204 : case ELIFFALSE:
205 : case ELIFGUESSFALSE:
206 0 : return(type);
207 : case -1:
208 0 : warning("%s, line %d: unknown directive == \"%s\"\n",
209 : file_red->i_file, filep->f_line, line);
210 0 : break;
211 : }
212 : }
213 0 : return(-1);
214 : }
215 :
216 : /*
217 : * Decide what type of # directive this line is.
218 : */
219 0 : int deftype (char *line, struct filepointer *filep, struct inclist *file_red, struct inclist *file, int parse_it, struct symhash *symbols)
220 : {
221 : char *p;
222 : char *directive, savechar;
223 : int ret;
224 :
225 : /*
226 : * Parse the directive...
227 : */
228 0 : directive=line+1;
229 0 : while (*directive == ' ' || *directive == '\t')
230 0 : directive++;
231 :
232 0 : p = directive;
233 0 : while (*p >= 'a' && *p <= 'z')
234 0 : p++;
235 0 : savechar = *p;
236 0 : *p = '\0';
237 0 : ret = match(directive, directives);
238 0 : *p = savechar;
239 :
240 : /* If we don't recognize this compiler directive or we happen to just
241 : * be gobbling up text while waiting for an #endif or #elif or #else
242 : * in the case of an #elif we must check the zero_value and return an
243 : * ELIF or an ELIFFALSE.
244 : */
245 :
246 0 : if (ret == ELIF && !parse_it)
247 : {
248 0 : while (*p == ' ' || *p == '\t')
249 0 : p++;
250 : /*
251 : * parse an expression.
252 : */
253 : debug(0,("%s, line %d: #elif %s ",
254 : file->i_file, filep->f_line, p));
255 0 : ret = zero_value(p, filep, file_red, symbols);
256 0 : if (ret != IF)
257 : {
258 : debug(0,("false...\n"));
259 0 : if (ret == IFFALSE)
260 0 : return(ELIFFALSE);
261 : else
262 0 : return(ELIFGUESSFALSE);
263 : }
264 : else
265 : {
266 : debug(0,("true...\n"));
267 0 : return(ELIF);
268 : }
269 : }
270 :
271 0 : if (ret < 0 || ! parse_it)
272 0 : return(ret);
273 :
274 : /*
275 : * now decide how to parse the directive, and do it.
276 : */
277 0 : while (*p == ' ' || *p == '\t')
278 0 : p++;
279 0 : switch (ret) {
280 : case IF:
281 : /*
282 : * parse an expression.
283 : */
284 0 : ret = zero_value(p, filep, file_red, symbols);
285 : debug(0,("%s, line %d: %s #if %s\n",
286 : file->i_file, filep->f_line, ret?"false":"true", p));
287 0 : break;
288 : case IFDEF:
289 : case IFNDEF:
290 : debug(0,("%s, line %d: #%s %s\n",
291 : file->i_file, filep->f_line, directives[ret], p));
292 : //fall-through
293 : case UNDEF:
294 : /*
295 : * separate the name of a single symbol.
296 : */
297 0 : while (isalnum(*p) || *p == '_')
298 0 : *line++ = *p++;
299 0 : *line = '\0';
300 0 : break;
301 : case INCLUDE:
302 : debug(2,("%s, line %d: #include %s\n",
303 : file->i_file, filep->f_line, p));
304 :
305 : /* Support ANSI macro substitution */
306 : {
307 0 : char *sym = hash_lookup(p, symbols);
308 0 : while (sym)
309 : {
310 0 : p = sym;
311 : debug(3,("%s : #includes SYMBOL %s\n",
312 : file->i_incstring,
313 : sym));
314 : /* mark file as having included a 'soft include' */
315 0 : file->i_included_sym = TRUE;
316 0 : sym = hash_lookup(p, symbols);
317 : }
318 : }
319 :
320 : /*
321 : * Separate the name of the include file.
322 : */
323 0 : while (*p && *p != '"' && *p != '<')
324 0 : p++;
325 0 : if (! *p)
326 0 : return(-2);
327 0 : if (*p++ == '"') {
328 0 : ret = INCLUDEDOT;
329 0 : while (*p && *p != '"')
330 0 : *line++ = *p++;
331 : } else
332 0 : while (*p && *p != '>')
333 0 : *line++ = *p++;
334 0 : *line = '\0';
335 0 : break;
336 : case DEFINE:
337 : /*
338 : * copy the definition back to the beginning of the line.
339 : */
340 0 : memmove (line, p, strlen(p));
341 0 : break;
342 : case ELSE:
343 : case ENDIF:
344 : case ELIF:
345 : case PRAGMA:
346 : case ERROR:
347 : case IDENT:
348 : case SCCS:
349 : case EJECT:
350 : debug(0,("%s, line %d: #%s\n",
351 : file->i_file, filep->f_line, directives[ret]));
352 : /*
353 : * nothing to do.
354 : */
355 0 : break;
356 : }
357 0 : return(ret);
358 : }
359 :
360 : /*
361 : * HACK! - so that we do not have to introduce 'symbols' in each cppsetup.c
362 : * function... It's safe, functions from cppsetup.c don't return here.
363 : */
364 : struct symhash *global_symbols = NULL;
365 :
366 0 : char * isdefined( char *symbol )
367 : {
368 0 : return hash_lookup( symbol, global_symbols );
369 : }
370 :
371 : /*
372 : * Return type based on if the #if expression evaluates to 0
373 : */
374 0 : int zero_value(char *exp, struct filepointer *filep, struct inclist *file_red, struct symhash *symbols)
375 : {
376 0 : global_symbols = symbols; /* HACK! see above */
377 0 : if (cppsetup(exp, filep, file_red))
378 0 : return(IFFALSE);
379 : else
380 0 : return(IF);
381 : }
382 :
383 0 : void define( char *def, struct symhash **symbols )
384 : {
385 : char *val;
386 :
387 : /* Separate symbol name and its value */
388 0 : val = def;
389 0 : while (isalnum(*val) || *val == '_')
390 0 : val++;
391 0 : if (*val)
392 0 : *val++ = '\0';
393 0 : while (*val == ' ' || *val == '\t')
394 0 : val++;
395 :
396 0 : if (!*val)
397 0 : val = "1";
398 0 : hash_define( def, val, symbols );
399 0 : }
400 :
401 0 : static int hash( char *str )
402 : {
403 : /* Hash (Kernighan and Ritchie) */
404 0 : unsigned int hashval = 0;
405 :
406 0 : for ( ; *str; str++ )
407 : {
408 0 : hashval = ( hashval * SYMHASHSEED ) + ( *str );
409 : }
410 :
411 0 : return hashval & ( SYMHASHMEMBERS - 1 );
412 : }
413 :
414 0 : struct symhash *hash_copy( struct symhash *symbols )
415 : {
416 : int i;
417 : struct symhash *newsym;
418 0 : if ( !symbols )
419 0 : return NULL;
420 :
421 0 : newsym = (struct symhash *) malloc( sizeof( struct symhash ) );
422 :
423 0 : for ( i = 0; i < SYMHASHMEMBERS; ++i )
424 : {
425 0 : if ( !symbols->s_pairs[ i ] )
426 0 : newsym->s_pairs[ i ] = NULL;
427 : else
428 : {
429 0 : struct pair *it = symbols->s_pairs[ i ];
430 0 : struct pair *nw = newsym->s_pairs[ i ] = (struct pair*) malloc( sizeof( struct pair ) );
431 0 : nw->p_name = it->p_name;
432 0 : nw->p_value = it->p_value;
433 0 : nw->p_next = NULL;
434 :
435 0 : while ( it->p_next )
436 : {
437 0 : nw->p_next = (struct pair*) malloc( sizeof( struct pair ) );
438 0 : it = it->p_next;
439 0 : nw = nw->p_next;
440 0 : nw->p_name = it->p_name;
441 0 : nw->p_value = it->p_value;
442 0 : nw->p_next = NULL;
443 : }
444 : }
445 : }
446 0 : return newsym;
447 : }
448 :
449 0 : void hash_free( struct symhash *symbols )
450 : {
451 : int i;
452 :
453 0 : if ( !symbols )
454 0 : return;
455 :
456 0 : for ( i = 0; i < SYMHASHMEMBERS; ++i )
457 : {
458 0 : struct pair *it = symbols->s_pairs[ i ];
459 : struct pair *next;
460 0 : while ( it )
461 : {
462 0 : next = it->p_next;
463 0 : free( it );
464 0 : it = next;
465 : }
466 : }
467 0 : free( symbols->s_pairs );
468 : }
469 :
470 0 : void hash_define( char *name, char *val, struct symhash **symbols )
471 : {
472 : int hashval;
473 : struct pair *it;
474 :
475 0 : if ( !symbols )
476 0 : return;
477 :
478 : /* Make space if it's needed */
479 0 : if ( *symbols == NULL )
480 : {
481 : int i;
482 :
483 0 : *symbols = (struct symhash *) malloc( sizeof( struct symhash ) );
484 0 : if ( *symbols == NULL )
485 0 : fatalerr( "malloc()/realloc() failure in insert_defn()\n" );
486 :
487 0 : for ( i = 0; i < SYMHASHMEMBERS; ++i )
488 0 : (*symbols)->s_pairs[i] = NULL;
489 : }
490 :
491 0 : hashval = hash( name );
492 0 : it = (*symbols)->s_pairs[ hashval ];
493 :
494 : /* Replace/insert the symbol */
495 0 : if ( it == NULL )
496 : {
497 0 : it = (*symbols)->s_pairs[ hashval ] = (struct pair*) malloc( sizeof( struct pair ) );
498 0 : it->p_name = copy( name );
499 0 : it->p_value = copy( val );
500 0 : it->p_next = NULL;
501 : }
502 0 : else if ( strcmp( it->p_name, name ) == 0 )
503 : {
504 0 : it->p_value = copy( val );
505 : }
506 : else
507 : {
508 0 : while ( it->p_next && ( strcmp( it->p_next->p_name, name ) != 0 ) )
509 : {
510 0 : it = it->p_next;
511 : }
512 0 : if ( it->p_next )
513 0 : it->p_next->p_name = copy( name );
514 : else
515 : {
516 0 : it->p_next = (struct pair*) malloc( sizeof( struct pair ) );
517 0 : it->p_next->p_name = copy( name );
518 0 : it->p_next->p_value = copy( val );
519 0 : it->p_next->p_next = NULL;
520 : }
521 : }
522 : }
523 :
524 0 : char *hash_lookup( char *symbol, struct symhash *symbols )
525 : {
526 : struct pair *it;
527 :
528 0 : if ( !symbols )
529 0 : return NULL;
530 :
531 0 : it = symbols->s_pairs[ hash( symbol ) ];
532 :
533 0 : while ( it && ( strcmp( it->p_name, symbol ) != 0 ) )
534 : {
535 0 : it = it->p_next;
536 : }
537 0 : if ( it )
538 0 : return it->p_value;
539 :
540 0 : return NULL;
541 : }
542 :
543 0 : void hash_undefine( char *symbol, struct symhash *symbols )
544 : {
545 : int hashval;
546 : struct pair *it;
547 :
548 0 : if ( !symbols )
549 0 : return;
550 :
551 0 : hashval = hash( symbol );
552 0 : it = symbols->s_pairs[ hashval ];
553 :
554 : /* Replace/insert the symbol */
555 0 : if ( it == NULL )
556 0 : return;
557 0 : else if ( strcmp( it->p_name, symbol ) == 0 )
558 : {
559 0 : if ( it->p_next )
560 : {
561 : struct pair *tmp;
562 0 : it->p_name = it->p_next->p_name;
563 0 : it->p_value = it->p_next->p_value;
564 0 : tmp = it->p_next->p_next;
565 0 : free( it->p_next );
566 0 : it->p_next = tmp;
567 : }
568 : else
569 : {
570 0 : free( it );
571 0 : symbols->s_pairs[ hashval ] = NULL;
572 : }
573 : }
574 : else
575 : {
576 0 : while ( it->p_next && ( strcmp( it->p_next->p_name, symbol ) != 0 ) )
577 : {
578 0 : it = it->p_next;
579 : }
580 0 : if ( it->p_next )
581 : {
582 0 : struct pair *tmp = it->p_next;
583 0 : it->p_next = it->p_next->p_next;
584 0 : free( tmp );
585 : }
586 : }
587 : }
588 :
589 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|