linux-old/scripts/tkcond.c
<<
>>
Prefs
   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 */
  39static 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
  74static 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 */
  91static 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 */
 128static 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
 278join_done:
 279    return cond_list;
 280}
 281
 282
 283
 284static char * current_arch = NULL;
 285
 286/*
 287 * Eliminating conditions with ARCH = <not current>.
 288 */
 289static 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    }
 414done:
 415    return list;
 416}
 417
 418
 419
 420/*
 421 * This is the main transformation function.
 422 */
 423void 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
 555void 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
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.