diff options
| author | Patrick Simianer <simianer@cl.uni-heidelberg.de> | 2012-05-13 03:35:30 +0200 | 
|---|---|---|
| committer | Patrick Simianer <simianer@cl.uni-heidelberg.de> | 2012-05-13 03:35:30 +0200 | 
| commit | 670a8f984fc6d8342180c59ae9e96b0b76f34d3d (patch) | |
| tree | 9f2ce7eec1a77e56b3bb1ad0ad40f212d7a996b0 /jam-files/engine/variable.c | |
| parent | eb3ee28dc0eb1d3e5ed01ba0df843be329ae450d (diff) | |
| parent | 2f64af3e06a518b93f7ca2c30a9d0aeb2c947031 (diff) | |
Merge remote-tracking branch 'upstream/master'
Diffstat (limited to 'jam-files/engine/variable.c')
| -rw-r--r-- | jam-files/engine/variable.c | 631 | 
1 files changed, 631 insertions, 0 deletions
| diff --git a/jam-files/engine/variable.c b/jam-files/engine/variable.c new file mode 100644 index 00000000..795f3458 --- /dev/null +++ b/jam-files/engine/variable.c @@ -0,0 +1,631 @@ +/* + * Copyright 1993, 2000 Christopher Seiwald. + * + * This file is part of Jam - see jam.c for Copyright information. + */ + +/*  This file is ALSO: + *  Copyright 2001-2004 David Abrahams. + *  Copyright 2005 Reece H. Dunn. + *  Copyright 2005 Rene Rivera. + *  Distributed under the Boost Software License, Version 1.0. + *  (See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt) + */ + +#include "jam.h" +#include "lists.h" +#include "parse.h" +#include "variable.h" +#include "expand.h" +#include "hash.h" +#include "filesys.h" +#include "newstr.h" +#include "strings.h" +#include "pathsys.h" +#include <stdlib.h> +#include <stdio.h> + +/* + * variable.c - handle Jam multi-element variables. + * + * External routines: + * + *  var_defines() - load a bunch of variable=value settings. + *  var_string()  - expand a string with variables in it. + *  var_get()     - get value of a user defined symbol. + *  var_set()     - set a variable in jam's user defined symbol table. + *  var_swap()    - swap a variable's value with the given one. + *  var_done()    - free variable tables. + * + * Internal routines: + * + *  var_enter() - make new var symbol table entry, returning var ptr. + *  var_dump()  - dump a variable to stdout. + * + * 04/13/94 (seiwald) - added shorthand L0 for null list pointer + * 08/23/94 (seiwald) - Support for '+=' (append to variable) + * 01/22/95 (seiwald) - split environment variables at blanks or :'s + * 05/10/95 (seiwald) - split path variables at SPLITPATH (not :) + * 09/11/00 (seiwald) - defunct var_list() removed + */ + +static struct hash *varhash = 0; + +/* + * VARIABLE - a user defined multi-value variable + */ + +typedef struct _variable VARIABLE ; + +struct _variable +{ +    char * symbol; +    LIST * value; +}; + +static VARIABLE * var_enter( char * symbol ); +static void var_dump( char * symbol, LIST * value, char * what ); + + +/* + * var_hash_swap() - swap all variable settings with those passed + * + * Used to implement separate settings spaces for modules + */ + +void var_hash_swap( struct hash * * new_vars ) +{ +    struct hash * old = varhash; +    varhash = *new_vars; +    *new_vars = old; +} + + +/* + * var_defines() - load a bunch of variable=value settings + * + * If preprocess is false, take the value verbatim. + * + * Otherwise, if the variable value is enclosed in quotes, strip the + * quotes. + * + * Otherwise, if variable name ends in PATH, split value at :'s. + * + * Otherwise, split the value at blanks. + */ + +void var_defines( char * const * e, int preprocess ) +{ +    string buf[1]; + +    string_new( buf ); + +    for ( ; *e; ++e ) +    { +        char * val; + +# ifdef OS_MAC +        /* On the mac (MPW), the var=val is actually var\0val */ +        /* Think different. */ + +        if ( ( val = strchr( *e, '=' ) ) || ( val = *e + strlen( *e ) ) ) +# else +        if ( ( val = strchr( *e, '=' ) ) ) +# endif +        { +            LIST * l = L0; +            char * pp; +            char * p; +# ifdef OPT_NO_EXTERNAL_VARIABLE_SPLIT +            char split = '\0'; +# else +    # ifdef OS_MAC +            char split = ','; +    # else +            char split = ' '; +    # endif +# endif +            size_t len = strlen( val + 1 ); + +            int quoted = ( val[1] == '"' ) && ( val[len] == '"' ) && +                ( len > 1 ); + +            if ( quoted && preprocess ) +            { +                string_append_range( buf, val + 2, val + len ); +                l = list_new( l, newstr( buf->value ) ); +                string_truncate( buf, 0 ); +            } +            else +            { +                /* Split *PATH at :'s, not spaces. */ +                if ( val - 4 >= *e ) +                { +                    if ( !strncmp( val - 4, "PATH", 4 ) || +                        !strncmp( val - 4, "Path", 4 ) || +                        !strncmp( val - 4, "path", 4 ) ) +                        split = SPLITPATH; +                } + +                /* Do the split. */ +                for +                ( +                    pp = val + 1; +                    preprocess && ( ( p = strchr( pp, split ) ) != 0 ); +                    pp = p + 1 +                ) +                { +                    string_append_range( buf, pp, p ); +                    l = list_new( l, newstr( buf->value ) ); +                    string_truncate( buf, 0 ); +                } + +                l = list_new( l, newstr( pp ) ); +            } + +            /* Get name. */ +            string_append_range( buf, *e, val ); +            var_set( buf->value, l, VAR_SET ); +            string_truncate( buf, 0 ); +        } +    } +    string_free( buf ); +} + + +/* + * var_string() - expand a string with variables in it + * + * Copies in to out; doesn't modify targets & sources. + */ + +int var_string( char * in, char * out, int outsize, LOL * lol ) +{ +    char * out0 = out; +    char * oute = out + outsize - 1; + +    while ( *in ) +    { +        char * lastword; +        int    dollar = 0; + +        /* Copy white space. */ +        while ( isspace( *in ) ) +        { +            if ( out >= oute ) +                return -1; +            *out++ = *in++; +        } + +        lastword = out; + +        /* Copy non-white space, watching for variables. */ +        while ( *in && !isspace( *in ) ) +        { +            if ( out >= oute ) +                return -1; + +            if ( ( in[ 0 ] == '$' ) && ( in[ 1 ] == '(' ) ) +            { +                ++dollar; +                *out++ = *in++; +            } +            #ifdef OPT_AT_FILES +            else if ( ( in[ 0 ] == '@' ) && ( in[ 1 ] == '(' ) ) +            { +                int depth = 1; +                char * ine = in + 2; +                char * split = 0; + +                /* Scan the content of the response file @() section. */ +                while ( *ine && ( depth > 0 ) ) +                { +                    switch ( *ine ) +                    { +                    case '(': ++depth; break; +                    case ')': --depth; break; +                    case ':': +                        if ( ( depth == 1 ) && ( ine[ 1 ] == 'E' ) && ( ine[ 2 ] == '=' ) ) +                            split = ine; +                        break; +                    } +                    ++ine; +                } + +                if ( !split ) +                { +                    /*  the @() reference doesn't match the @(foo:E=bar) format. +                        hence we leave it alone by copying directly to output. */ +                    int l = 0; +                    if ( out + 2 >= oute ) return -1; +                    *( out++ ) = '@'; +                    *( out++ ) = '('; +                    l = var_string( in + 2, out, oute - out, lol ); +                    if ( l < 0 ) return -1; +                    out += l; +                    if ( out + 1 >= oute ) return -1; +                    *( out++ ) = ')'; +                } +                else if ( depth == 0 ) +                { +                    string file_name_v; +                    int file_name_l = 0; +                    const char * file_name_s = 0; + +                    /* Expand the temporary file name var inline. */ +                    #if 0 +                    string_copy( &file_name_v, "$(" ); +                    string_append_range( &file_name_v, in + 2, split ); +                    string_push_back( &file_name_v, ')' ); +                    #else +                    string_new( &file_name_v ); +                    string_append_range( &file_name_v, in + 2, split ); +                    #endif +                    file_name_l = var_string( file_name_v.value, out, oute - out + 1, lol ); +                    string_free( &file_name_v ); +                    if ( file_name_l < 0 ) return -1; +                    file_name_s = out; + +                    /* For stdout/stderr we will create a temp file and generate +                     * a command that outputs the content as needed. +                     */ +                    if ( ( strcmp( "STDOUT", out ) == 0 ) || +                        ( strcmp( "STDERR", out ) == 0 ) ) +                    { +                        int err_redir = strcmp( "STDERR", out ) == 0; +                        out[ 0 ] = '\0'; +                        file_name_s = path_tmpfile(); +                        file_name_l = strlen(file_name_s); +                        #ifdef OS_NT +                        if ( ( out + 7 + file_name_l + ( err_redir ? 5 : 0 ) ) >= oute ) +                            return -1; +                        sprintf( out,"type \"%s\"%s", file_name_s, +                            err_redir ? " 1>&2" : "" ); +                        #else +                        if ( ( out + 6 + file_name_l + ( err_redir ? 5 : 0 ) ) >= oute ) +                            return -1; +                        sprintf( out,"cat \"%s\"%s", file_name_s, +                            err_redir ? " 1>&2" : "" ); +                        #endif +                        /* We also make sure that the temp files created by this +                         * get nuked eventually. +                         */ +                        file_remove_atexit( file_name_s ); +                    } + +                    /* Expand the file value into the file reference. */ +                    var_string_to_file( split + 3, ine - split - 4, file_name_s, +                        lol ); + +                    /* Continue on with the expansion. */ +                    out += strlen( out ); +                } + +                /* And continue with the parsing just past the @() reference. */ +                in = ine; +            } +            #endif +            else +            { +                *out++ = *in++; +            } +        } + +        /* Add zero to 'out' so that 'lastword' is correctly zero-terminated. */ +        if ( out >= oute ) +            return -1; +        /* Do not increment, intentionally. */ +        *out = '\0'; + +        /* If a variable encountered, expand it and and embed the +         * space-separated members of the list in the output. +         */ +        if ( dollar ) +        { +            LIST * l = var_expand( L0, lastword, out, lol, 0 ); + +            out = lastword; + +            while ( l ) +            { +                int so = strlen( l->string ); + +                if ( out + so >= oute ) +                    return -1; + +                strcpy( out, l->string ); +                out += so; +                l = list_next( l ); +                if ( l ) *out++ = ' '; +            } + +            list_free( l ); +        } +    } + +    if ( out >= oute ) +        return -1; + +    *out++ = '\0'; + +    return out - out0; +} + + +void var_string_to_file( const char * in, int insize, const char * out, LOL * lol ) +{ +    char const * ine = in + insize; +    FILE * out_file = 0; +    int out_debug = DEBUG_EXEC ? 1 : 0; +    if ( globs.noexec ) +    { +        /* out_debug = 1; */ +    } +    else if ( strcmp( out, "STDOUT" ) == 0 ) +    { +        out_file = stdout; +    } +    else if ( strcmp( out, "STDERR" ) == 0 ) +    { +        out_file = stderr; +    } +    else +    { +        /* Handle "path to file" filenames. */ +        string out_name; +        if ( ( out[ 0 ] == '"' ) && ( out[ strlen( out ) - 1 ] == '"' ) ) +        { +            string_copy( &out_name, out + 1 ); +            string_truncate( &out_name, out_name.size - 1 ); +        } +        else +        { +            string_copy( &out_name,out ); +        } +        out_file = fopen( out_name.value, "w" ); +        if ( !out_file ) +        { +            printf( "failed to write output file '%s'!\n", out_name.value ); +            exit( EXITBAD ); +        } +        string_free( &out_name ); +    } + +    if ( out_debug ) printf( "\nfile %s\n", out ); + +    while ( *in && ( in < ine ) ) +    { +        int dollar = 0; +        const char * output_0 = in; +        const char * output_1 = in; + +        /* Copy white space. */ +        while ( ( output_1 < ine ) && isspace( *output_1 ) ) +            ++output_1; + +        if ( output_0 < output_1 ) +        { +            if ( out_file  ) fwrite( output_0, output_1 - output_0, 1, out_file ); +            if ( out_debug ) fwrite( output_0, output_1 - output_0, 1, stdout   ); +        } +        output_0 = output_1; + +        /* Copy non-white space, watching for variables. */ +        while ( ( output_1 < ine ) && *output_1 && !isspace( *output_1 ) ) +        { +            if ( ( output_1[ 0 ] == '$' ) && ( output_1[ 1 ] == '(' ) ) +                ++dollar; +            ++output_1; +        } + +        /* If a variable encountered, expand it and embed the space-separated +         * members of the list in the output. +         */ +        if ( dollar ) +        { +            LIST * l = var_expand( L0, (char *)output_0, (char *)output_1, lol, 0 ); + +            while ( l ) +            { +                if ( out_file ) fputs( l->string, out_file ); +                if ( out_debug ) puts( l->string ); +                l = list_next( l ); +                if ( l ) +                { +                    if ( out_file ) fputc( ' ', out_file ); +                    if ( out_debug ) fputc( ' ', stdout ); +                } +            } + +            list_free( l ); +        } +        else if ( output_0 < output_1 ) +        { +            if ( out_file ) +            { +                const char * output_n = output_0; +                while ( output_n < output_1 ) +                { +                    output_n += fwrite( output_n, 1, output_1-output_n, out_file ); +                } +            } +            if ( out_debug ) +            { +                const char * output_n = output_0; +                while ( output_n < output_1 ) +                { +                    output_n += fwrite( output_n, 1, output_1-output_n, stdout ); +                } +            } +        } + +        in = output_1; +    } + +    if ( out_file && ( out_file != stdout ) && ( out_file != stderr ) ) +    { +        fflush( out_file ); +        fclose( out_file ); +    } + +    if ( out_debug ) fputc( '\n', stdout ); +} + + +/* + * var_get() - get value of a user defined symbol. + * + * Returns NULL if symbol unset. + */ + +LIST * var_get( char * symbol ) +{ +    LIST * result = 0; +#ifdef OPT_AT_FILES +    /* Some "fixed" variables... */ +    if ( strcmp( "TMPDIR", symbol ) == 0 ) +    { +        result = list_new( L0, newstr( (char *)path_tmpdir() ) ); +    } +    else if ( strcmp( "TMPNAME", symbol ) == 0 ) +    { +        result = list_new( L0, newstr( (char *)path_tmpnam() ) ); +    } +    else if ( strcmp( "TMPFILE", symbol ) == 0 ) +    { +        result = list_new( L0, newstr( (char *)path_tmpfile() ) ); +    } +    else if ( strcmp( "STDOUT", symbol ) == 0 ) +    { +        result = list_new( L0, newstr( "STDOUT" ) ); +    } +    else if ( strcmp( "STDERR", symbol ) == 0 ) +    { +        result = list_new( L0, newstr( "STDERR" ) ); +    } +    else +#endif +    { +        VARIABLE var; +        VARIABLE * v = &var; + +        v->symbol = symbol; + +        if ( varhash && hashcheck( varhash, (HASHDATA * *)&v ) ) +        { +            if ( DEBUG_VARGET ) +                var_dump( v->symbol, v->value, "get" ); +            result = v->value; +        } +    } +    return result; +} + + +/* + * var_set() - set a variable in Jam's user defined symbol table. + * + * 'flag' controls the relationship between new and old values of the variable: + * SET replaces the old with the new; APPEND appends the new to the old; DEFAULT + * only uses the new if the variable was previously unset. + * + * Copies symbol. Takes ownership of value. + */ + +void var_set( char * symbol, LIST * value, int flag ) +{ +    VARIABLE * v = var_enter( symbol ); + +    if ( DEBUG_VARSET ) +        var_dump( symbol, value, "set" ); + +    switch ( flag ) +    { +    case VAR_SET: +        /* Replace value */ +        list_free( v->value ); +        v->value = value; +        break; + +    case VAR_APPEND: +        /* Append value */ +        v->value = list_append( v->value, value ); +        break; + +    case VAR_DEFAULT: +        /* Set only if unset */ +        if ( !v->value ) +            v->value = value; +        else +            list_free( value ); +        break; +    } +} + + +/* + * var_swap() - swap a variable's value with the given one. + */ + +LIST * var_swap( char * symbol, LIST * value ) +{ +    VARIABLE * v = var_enter( symbol ); +    LIST     * oldvalue = v->value; +    if ( DEBUG_VARSET ) +        var_dump( symbol, value, "set" ); +    v->value = value; +    return oldvalue; +} + + +/* + * var_enter() - make new var symbol table entry, returning var ptr. + */ + +static VARIABLE * var_enter( char * symbol ) +{ +    VARIABLE var; +    VARIABLE * v = &var; + +    if ( !varhash ) +        varhash = hashinit( sizeof( VARIABLE ), "variables" ); + +    v->symbol = symbol; +    v->value = 0; + +    if ( hashenter( varhash, (HASHDATA * *)&v ) ) +        v->symbol = newstr( symbol );  /* never freed */ + +    return v; +} + + +/* + * var_dump() - dump a variable to stdout. + */ + +static void var_dump( char * symbol, LIST * value, char * what ) +{ +    printf( "%s %s = ", what, symbol ); +    list_print( value ); +    printf( "\n" ); +} + + +/* + * var_done() - free variable tables. + */ + +static void delete_var_( void * xvar, void * data ) +{ +    VARIABLE * v = (VARIABLE *)xvar; +    freestr( v->symbol ); +    list_free( v-> value ); +} + + +void var_done() +{ +    hashenumerate( varhash, delete_var_, (void *)0 ); +    hashdone( varhash ); +} | 
