1 /*
2  * tkcond.c
3  *
4  * Eric Youngdale was the original author of xconfig.
5  * Michael Elizabeth Chastain (mec@shout.net) is the current maintainer.
6  *
7  * This file takes the tokenized statement list and transforms 'if ...'
8  * statements.  For each simple statement, I find all of the 'if' statements
9  * that enclose it, and attach the aggregate conditionals of those 'if'
10  * statements to the cond list of the simple statement.
11  *
12  * 14 January 1999, Michael Elizabeth Chastain, <mec@shout.net>
13  * - Steam-clean this file.  I tested this by generating kconfig.tk for
14  *   every architecture and comparing it character-for-character against
15  *   the output of the old tkparse.
16  *
17  * 07 July 1999, Andrzej M. Krzysztofowicz <ankry@mif.pg.gda.pl>
18  * - kvariables removed; all variables are stored in a single table now
19  * - some elimination of options non-valid for current architecture
20  *   implemented.
21  * - negation (!) eliminated from conditions
22  *
23  * TO DO:
24  * - xconfig is at the end of its life cycle.  Contact <mec@shout.net> if
25  *   you are interested in working on the replacement.
26  */
27 
28 #include <stdio.h>
29 #include <stdlib.h>
30 #include <string.h>
31 
32 #include "tkparse.h"
33 
34 
35 
36 /*
37  * Mark variables which are defined anywhere.
38  */
mark_variables(struct kconfig * scfg)39 static void mark_variables( struct kconfig * scfg )
40 {
41     struct kconfig * cfg;
42     int i;
43 
44     for ( i = 1; i <= max_varnum; i++ )
45 	vartable[i].defined = 0;
46     for ( cfg = scfg; cfg != NULL; cfg = cfg->next )
47     {
48 	if ( cfg->token == token_bool
49 	||   cfg->token == token_choice_item
50 	||   cfg->token == token_define_bool
51 	||   cfg->token == token_define_hex
52 	||   cfg->token == token_define_int
53 	||   cfg->token == token_define_string
54 	||   cfg->token == token_define_tristate
55 	||   cfg->token == token_dep_bool
56 	||   cfg->token == token_dep_mbool
57 	||   cfg->token == token_dep_tristate
58 	||   cfg->token == token_hex
59 	||   cfg->token == token_int
60 	||   cfg->token == token_string
61 	||   cfg->token == token_tristate
62 	||   cfg->token == token_unset )
63 	{
64 	    if ( cfg->nameindex > 0 )	/* paranoid */
65 	    {
66 		vartable[cfg->nameindex].defined = 1;
67 	    }
68 	}
69     }
70 }
71 
72 
73 
free_cond(struct condition * cond)74 static void free_cond( struct condition *cond )
75 {
76     struct condition *tmp, *tmp1;
77     for ( tmp = cond; tmp; tmp = tmp1 )
78     {
79 	tmp1 = tmp->next;
80 	free( (void*)tmp );
81     }
82 }
83 
84 
85 
86 /*
87  * Remove the bang operator from a condition to avoid priority problems.
88  * "!" has different priorities as "test" command argument and in
89  * a tk script.
90  */
remove_bang(struct condition * condition)91 static struct condition * remove_bang( struct condition * condition )
92 {
93     struct condition * conda, * condb, * prev = NULL;
94 
95     for ( conda = condition; conda; conda = conda->next )
96     {
97 	if ( conda->op == op_bang && conda->next &&
98 	   ( condb = conda->next->next ) )
99 	{
100 	    if ( condb->op == op_eq || condb->op == op_neq )
101 	    {
102 		condb->op = (condb->op == op_eq) ? op_neq : op_eq;
103 		conda->op = op_nuked;
104 		if ( prev )
105 		{
106 		    prev->next = conda->next;
107 		}
108 		else
109 		{
110 		    condition = conda->next;
111 		}
112 		conda->next = NULL;
113 		free_cond( conda );
114 		conda = condb;
115 	    }
116 	}
117 	prev = conda;
118     }
119     return condition;
120 }
121 
122 
123 
124 /*
125  * Make a new condition chain by joining the current condition stack with
126  * the "&&" operator for glue.
127  */
join_condition_stack(struct condition * conditions[],int depth)128 static struct condition * join_condition_stack( struct condition * conditions [],
129     int depth )
130 {
131     struct condition * cond_list;
132     struct condition * cond_last;
133     int i, is_first = 1;
134 
135     cond_list = cond_last = NULL;
136 
137     for ( i = 0; i < depth; i++ )
138     {
139 	if ( conditions[i]->op == op_false )
140 	{
141 	    struct condition * cnew;
142 
143 	    /* It is always false condition */
144 	    cnew = malloc( sizeof(*cnew) );
145 	    memset( cnew, 0, sizeof(*cnew) );
146 	    cnew->op = op_false;
147 	    cond_list = cond_last = cnew;
148 	    goto join_done;
149 	}
150     }
151     for ( i = 0; i < depth; i++ )
152     {
153 	struct condition * cond;
154 	struct condition * cnew;
155 	int add_paren;
156 
157 	/* omit always true conditions */
158 	if ( conditions[i]->op == op_true )
159 	    continue;
160 
161 	/* if i have another condition, add an '&&' operator */
162 	if ( !is_first )
163 	{
164 	    cnew = malloc( sizeof(*cnew) );
165 	    memset( cnew, 0, sizeof(*cnew) );
166 	    cnew->op = op_and;
167 	    cond_last->next = cnew;
168 	    cond_last = cnew;
169 	}
170 
171 	if ( conditions[i]->op != op_lparen )
172 	{
173 	    /* add a '(' */
174 	    add_paren = 1;
175 	    cnew = malloc( sizeof(*cnew) );
176 	    memset( cnew, 0, sizeof(*cnew) );
177 	    cnew->op = op_lparen;
178 	    if ( cond_last == NULL )
179 		{ cond_list = cond_last = cnew; }
180 	    else
181 		{ cond_last->next = cnew; cond_last = cnew; }
182 	}
183 	else
184 	{
185 	    add_paren = 0;
186 	}
187 
188 	/* duplicate the chain */
189 	for ( cond = conditions [i]; cond != NULL; cond = cond->next )
190 	{
191 	    cnew            = malloc( sizeof(*cnew) );
192 	    cnew->next      = NULL;
193 	    cnew->op        = cond->op;
194 	    cnew->str       = cond->str ? strdup( cond->str ) : NULL;
195 	    cnew->nameindex = cond->nameindex;
196 	    if ( cond_last == NULL )
197 		{ cond_list = cond_last = cnew; }
198 	    else
199 		{ cond_last->next = cnew; cond_last = cnew; }
200 	}
201 
202 	if ( add_paren )
203 	{
204 	    /* add a ')' */
205 	    cnew = malloc( sizeof(*cnew) );
206 	    memset( cnew, 0, sizeof(*cnew) );
207 	    cnew->op = op_rparen;
208 	    cond_last->next = cnew;
209 	    cond_last = cnew;
210 	}
211 	is_first = 0;
212     }
213 
214     /*
215      * Remove duplicate conditions.
216      */
217     {
218 	struct condition *cond1, *cond1b, *cond1c, *cond1d, *cond1e, *cond1f;
219 
220 	for ( cond1 = cond_list; cond1 != NULL; cond1 = cond1->next )
221 	{
222 	    if ( cond1->op == op_lparen )
223 	    {
224 		cond1b = cond1 ->next; if ( cond1b == NULL ) break;
225 		cond1c = cond1b->next; if ( cond1c == NULL ) break;
226 		cond1d = cond1c->next; if ( cond1d == NULL ) break;
227 		cond1e = cond1d->next; if ( cond1e == NULL ) break;
228 		cond1f = cond1e->next; if ( cond1f == NULL ) break;
229 
230 		if ( cond1b->op == op_variable
231 		&& ( cond1c->op == op_eq || cond1c->op == op_neq )
232 		&&   cond1d->op == op_constant
233 		&&   cond1e->op == op_rparen )
234 		{
235 		    struct condition *cond2, *cond2b, *cond2c, *cond2d, *cond2e, *cond2f;
236 
237 		    for ( cond2 = cond1f->next; cond2 != NULL; cond2 = cond2->next )
238 		    {
239 			if ( cond2->op == op_lparen )
240 			{
241 			    cond2b = cond2 ->next; if ( cond2b == NULL ) break;
242 			    cond2c = cond2b->next; if ( cond2c == NULL ) break;
243 			    cond2d = cond2c->next; if ( cond2d == NULL ) break;
244 			    cond2e = cond2d->next; if ( cond2e == NULL ) break;
245 			    cond2f = cond2e->next;
246 
247 			    /* look for match */
248 			    if ( cond2b->op == op_variable
249 			    &&   cond2b->nameindex == cond1b->nameindex
250 			    &&   cond2c->op == cond1c->op
251 			    &&   cond2d->op == op_constant
252 			    &&   strcmp( cond2d->str, cond1d->str ) == 0
253 			    &&   cond2e->op == op_rparen )
254 			    {
255 				/* one of these must be followed by && */
256 				if ( cond1f->op == op_and
257 				|| ( cond2f != NULL && cond2f->op == op_and ) )
258 				{
259 				    /* nuke the first duplicate */
260 				    cond1 ->op = op_nuked;
261 				    cond1b->op = op_nuked;
262 				    cond1c->op = op_nuked;
263 				    cond1d->op = op_nuked;
264 				    cond1e->op = op_nuked;
265 				    if ( cond1f->op == op_and )
266 					cond1f->op = op_nuked;
267 				    else
268 					cond2f->op = op_nuked;
269 				}
270 			    }
271 			}
272 		    }
273 		}
274 	    }
275 	}
276     }
277 
278 join_done:
279     return cond_list;
280 }
281 
282 
283 
284 static char * current_arch = NULL;
285 
286 /*
287  * Eliminating conditions with ARCH = <not current>.
288  */
eliminate_other_arch(struct condition * list)289 static struct condition *eliminate_other_arch( struct condition *list )
290 {
291     struct condition *cond1a = list, *cond1b = NULL, *cond1c = NULL, *cond1d = NULL;
292     if ( current_arch == NULL )
293 	current_arch = getenv( "ARCH" );
294     if ( current_arch == NULL )
295     {
296 	fprintf( stderr, "error: ARCH undefined\n" );
297 	exit( 1 );
298     }
299     if ( cond1a->op == op_variable
300     && ! strcmp( vartable[cond1a->nameindex].name, "ARCH" ) )
301     {
302 	cond1b = cond1a->next; if ( cond1b == NULL ) goto done;
303 	cond1c = cond1b->next; if ( cond1c == NULL ) goto done;
304 	cond1d = cond1c->next;
305 	if ( cond1c->op == op_constant && cond1d == NULL )
306 	{
307 	    if ( (cond1b->op == op_eq && strcmp( cond1c->str, current_arch ))
308 	    ||   (cond1b->op == op_neq && ! strcmp( cond1c->str, current_arch )) )
309 	    {
310 		/* This is for another architecture */
311 		cond1a->op = op_false;
312 		cond1a->next = NULL;
313 		free_cond( cond1b );
314 		return cond1a;
315 	    }
316 	    else if ( (cond1b->op == op_neq && strcmp( cond1c->str, current_arch ))
317 		 ||   (cond1b->op == op_eq && ! strcmp( cond1c->str, current_arch )) )
318 	    {
319 		/* This is for current architecture */
320 		cond1a->op = op_true;
321 		cond1a->next = NULL;
322 		free_cond( cond1b );
323 		return cond1a;
324 	    }
325 	}
326 	else if ( cond1c->op == op_constant && cond1d->op == op_or )
327 	{
328 	    if ( (cond1b->op == op_eq && strcmp( cond1c->str, current_arch ))
329 	    ||   (cond1b->op == op_neq && ! strcmp( cond1c->str, current_arch )) )
330 	    {
331 		/* This is for another architecture */
332 		cond1b = cond1d->next;
333 		cond1d->next = NULL;
334 		free_cond( cond1a );
335 		return eliminate_other_arch( cond1b );
336 	    }
337 	    else if ( (cond1b->op == op_neq && strcmp( cond1c->str, current_arch ))
338 		 || (cond1b->op == op_eq && ! strcmp( cond1c->str, current_arch )) )
339 	    {
340 		/* This is for current architecture */
341 		cond1a->op = op_true;
342 		cond1a->next = NULL;
343 		free_cond( cond1b );
344 		return cond1a;
345 	    }
346 	}
347 	else if ( cond1c->op == op_constant && cond1d->op == op_and )
348 	{
349 	    if ( (cond1b->op == op_eq && strcmp( cond1c->str, current_arch ))
350 	    ||   (cond1b->op == op_neq && ! strcmp( cond1c->str, current_arch )) )
351 	    {
352 		/* This is for another architecture */
353 		int l_par = 0;
354 
355 		for ( cond1c = cond1d->next; cond1c; cond1c = cond1c->next )
356 		{
357 		    if ( cond1c->op == op_lparen )
358 			l_par++;
359 		    else if ( cond1c->op == op_rparen )
360 			l_par--;
361 		    else if ( cond1c->op == op_or && l_par == 0 )
362 		    /* Expression too complex - don't touch */
363 			return cond1a;
364 		    else if ( l_par < 0 )
365 		    {
366 			fprintf( stderr, "incorrect condition: programming error ?\n" );
367 			exit( 1 );
368 		    }
369 		}
370 		cond1a->op = op_false;
371 		cond1a->next = NULL;
372 		free_cond( cond1b );
373 		return cond1a;
374 	    }
375 	    else if ( (cond1b->op == op_neq && strcmp( cond1c->str, current_arch ))
376 		 || (cond1b->op == op_eq && ! strcmp( cond1c->str, current_arch )) )
377 	    {
378 		/* This is for current architecture */
379 		cond1b = cond1d->next;
380 		cond1d->next = NULL;
381 		free_cond( cond1a );
382 		return eliminate_other_arch( cond1b );
383 	    }
384 	}
385     }
386     if ( cond1a->op == op_variable && ! vartable[cond1a->nameindex].defined )
387     {
388 	cond1b = cond1a->next; if ( cond1b == NULL ) goto done;
389 	cond1c = cond1b->next; if ( cond1c == NULL ) goto done;
390 	cond1d = cond1c->next;
391 
392 	if ( cond1c->op == op_constant
393 	&& ( cond1d == NULL || cond1d->op == op_and ) ) /*???*/
394 	{
395 	    if ( cond1b->op == op_eq && strcmp( cond1c->str, "" ) )
396 	    {
397 		cond1a->op = op_false;
398 		cond1a->next = NULL;
399 		free_cond( cond1b );
400 		return cond1a;
401 	    }
402 	}
403 	else if ( cond1c->op == op_constant && cond1d->op == op_or )
404 	{
405 	    if ( cond1b->op == op_eq && strcmp( cond1c->str, "" ) )
406 	    {
407 		cond1b = cond1d->next;
408 		cond1d->next = NULL;
409 		free_cond( cond1a );
410 		return eliminate_other_arch( cond1b );
411 	    }
412 	}
413     }
414 done:
415     return list;
416 }
417 
418 
419 
420 /*
421  * This is the main transformation function.
422  */
fix_conditionals(struct kconfig * scfg)423 void fix_conditionals( struct kconfig * scfg )
424 {
425     struct kconfig * cfg;
426 
427     /*
428      * Transform op_variable to op_kvariable.
429      */
430     mark_variables( scfg );
431 
432     /*
433      * Walk the statement list, maintaining a stack of current conditions.
434      *   token_if      push its condition onto the stack.
435      *   token_else    invert the condition on the top of the stack.
436      *   token_endif   pop the stack.
437      *
438      * For a simple statement, create a condition chain by joining together
439      * all of the conditions on the stack.
440      */
441     {
442 	struct condition * cond_stack [32];
443 	int depth = 0;
444 	struct kconfig * prev = NULL;
445 
446 	for ( cfg = scfg; cfg != NULL; cfg = cfg->next )
447 	{
448 	    int good = 1;
449 	    switch ( cfg->token )
450 	    {
451 	    default:
452 		break;
453 
454 	    case token_if:
455 		cond_stack [depth++] =
456 		    remove_bang( eliminate_other_arch( cfg->cond ) );
457 		cfg->cond = NULL;
458 		break;
459 
460 	    case token_else:
461 		{
462 		    /*
463 		     * Invert the condition chain.
464 		     *
465 		     * Be careful to transfrom op_or to op_and1, not op_and.
466 		     * I will need this later in the code that removes
467 		     * duplicate conditions.
468 		     */
469 		    struct condition * cond;
470 
471 		    for ( cond  = cond_stack [depth-1];
472 			  cond != NULL;
473 			  cond  = cond->next )
474 		    {
475 			switch( cond->op )
476 			{
477 			default:     break;
478 			case op_and: cond->op = op_or;   break;
479 			case op_or:  cond->op = op_and1; break;
480 			case op_neq: cond->op = op_eq;   break;
481 			case op_eq:  cond->op = op_neq;  break;
482 			case op_true: cond->op = op_false;break;
483 			case op_false:cond->op = op_true; break;
484 			}
485 		    }
486 		}
487 		break;
488 
489 	    case token_fi:
490 		--depth;
491 		break;
492 
493 	    case token_bool:
494 	    case token_choice_item:
495 	    case token_choice_header:
496 	    case token_comment:
497 	    case token_define_bool:
498 	    case token_define_hex:
499 	    case token_define_int:
500 	    case token_define_string:
501 	    case token_define_tristate:
502 	    case token_endmenu:
503 	    case token_hex:
504 	    case token_int:
505 	    case token_mainmenu_option:
506 	    case token_string:
507 	    case token_tristate:
508 	    case token_unset:
509 		cfg->cond = join_condition_stack( cond_stack, depth );
510 		if ( cfg->cond && cfg->cond->op == op_false )
511 		{
512 		    good = 0;
513 		    if ( prev )
514 			prev->next = cfg->next;
515 		    else
516 			scfg = cfg->next;
517 		}
518 		break;
519 
520 	    case token_dep_bool:
521 	    case token_dep_mbool:
522 	    case token_dep_tristate:
523 		/*
524 		 * Same as the other simple statements, plus an additional
525 		 * condition for the dependency.
526 		 */
527 		if ( cfg->cond )
528 		{
529 		    cond_stack [depth] = eliminate_other_arch( cfg->cond );
530 		    cfg->cond = join_condition_stack( cond_stack, depth+1 );
531 		}
532 		else
533 		{
534 		    cfg->cond = join_condition_stack( cond_stack, depth );
535 		}
536 		if ( cfg->cond && cfg->cond->op == op_false )
537 		{
538 		    good = 0;
539 		    if ( prev )
540 			prev->next = cfg->next;
541 		    else
542 			scfg = cfg->next;
543 		}
544 		break;
545 	    }
546 	    if ( good )
547 		prev = cfg;
548 	}
549     }
550 }
551 
552 
553 
554 #if 0
555 void dump_condition( struct condition *list )
556 {
557     struct condition *tmp;
558     for ( tmp = list; tmp; tmp = tmp->next )
559     {
560 	switch (tmp->op)
561 	{
562 	default:
563 	    break;
564 	case op_variable:
565 	    printf( " %s", vartable[tmp->nameindex].name );
566 	    break;
567 	case op_constant:
568 	    printf( " %s", tmp->str );
569 	    break;
570 	case op_eq:
571 	    printf( " =" );
572 	    break;
573 	case op_bang:
574 	    printf( " !" );
575 	    break;
576 	case op_neq:
577 	    printf( " !=" );
578 	    break;
579 	case op_and:
580 	case op_and1:
581 	    printf( " -a" );
582 	    break;
583 	case op_or:
584 	    printf( " -o" );
585 	    break;
586 	case op_true:
587 	    printf( " TRUE" );
588 	    break;
589 	case op_false:
590 	    printf( " FALSE" );
591 	    break;
592 	case op_lparen:
593 	    printf( " (" );
594 	    break;
595 	case op_rparen:
596 	    printf( " )" );
597 	    break;
598 	}
599     }
600     printf( "\n" );
601 }
602 #endif
603