⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 expand.c

📁 C++的一个好库。。。现在很流行
💻 C
📖 第 1 页 / 共 2 页
字号:
/*
 * Copyright 1993-2002 Christopher Seiwald and Perforce Software, Inc.
 *
 * This file is part of Jam - see jam.c for Copyright information.
 */

# include "jam.h"
# include "lists.h"
# include "variable.h"
# include "expand.h"
# include "pathsys.h"
# include "newstr.h"
# include <assert.h>

# ifdef OS_CYGWIN
#  include <sys/cygwin.h>
#  include <windows.h>
# endif

/*
 * expand.c - expand a buffer, given variable values
 *
 * External routines:
 *
 *	var_expand() - variable-expand input string into list of strings
 *
 * Internal routines:
 *
 *	var_edit_parse() - parse : modifiers into PATHNAME structure
 *	var_edit_file() - copy input target name to output, modifying filename
 *	var_edit_shift() - do upshift/downshift mods
 *
 * 01/25/94 (seiwald) - $(X)$(UNDEF) was expanding like plain $(X)
 * 04/13/94 (seiwald) - added shorthand L0 for null list pointer
 * 01/11/01 (seiwald) - added support for :E=emptyvalue, :J=joinval
 */

typedef struct {
	PATHNAME	f;		/* :GDBSMR -- pieces */
	char		parent;		/* :P -- go to parent directory */
	char		filemods;	/* one of the above applied */
	char		downshift;	/* :L -- downshift result */
	char		upshift;	     /* :U -- upshift result */
    char        to_slashes;    /* :T -- convert "\" to "/" */
    char        to_windows;    /* :W -- convert cygwin to native paths */
	PATHPART	empty;		/* :E -- default for empties */
	PATHPART	join;		/* :J -- join list with char */
} VAR_EDITS ;

static void var_edit_parse( char *mods, VAR_EDITS *edits );
static void var_edit_file( char *in, string *out, VAR_EDITS *edits );
static void var_edit_shift( string *out, VAR_EDITS *edits );

# define MAGIC_COLON	'\001'
# define MAGIC_LEFT	'\002'
# define MAGIC_RIGHT	'\003'

/*
 * var_expand() - variable-expand input string into list of strings
 *
 * Would just copy input to output, performing variable expansion, 
 * except that since variables can contain multiple values the result
 * of variable expansion may contain multiple values (a list).  Properly
 * performs "product" operations that occur in "$(var1)xxx$(var2)" or
 * even "$($(var2))".
 *
 * Returns a newly created list.
 */

LIST *
var_expand( 
	LIST	*l,
	char	*in,
	char	*end,
	LOL	*lol,
	int	cancopyin )
{
    char out_buf[ MAXSYM ];
    string buf[1];
    string out1[1]; /* Temporary buffer */
    size_t prefix_length;
    char *out;
    char *inp = in;
    char *ov;		/* for temp copy of variable in outbuf */
    int depth;

    if( DEBUG_VAREXP )
        printf( "expand '%.*s'\n", end - in, in );

    /* This gets alot of cases: $(<) and $(>) */

    if( in[0] == '$' && in[1] == '(' && in[3] == ')' && !in[4] )
    {
        switch( in[2] )
        {
        case '1':
        case '<':
            return list_copy( l, lol_get( lol, 0 ) );

        case '2':
        case '>':
            return list_copy( l, lol_get( lol, 1 ) );
        }
    }

    /* Just try simple copy of in to out. */

    while( in < end )
        if( *in++ == '$' && *in == '(' ) 
            goto expand;

    /* No variables expanded - just add copy of input string to list. */

    /* Cancopyin is an optimization: if the input was already a list */
    /* item, we can use the copystr() to put it on the new list. */
    /* Otherwise, we use the slower newstr(). */

    if( cancopyin ) 
    {
        return list_new( l, copystr( inp ) );
    }
    else
    {
        LIST* r;
        string_new( buf );
        string_append_range( buf, inp, end );

        r = list_new( l, newstr( buf->value) );
        string_free( buf );
        return r;
    }

expand:
    string_new( buf );
    string_append_range( buf, inp, in - 1); /* copy the part before '$'. */
    /*
     * Input so far (ignore blanks):
     *
     *  stuff-in-outbuf $(variable) remainder
     *                   ^                   ^
     *                   in                  end
     * Output so far:
     *
     *  stuff-in-outbuf $
     *  ^                ^
     *  out_buf          out
     *
     *
     * We just copied the $ of $(...), so back up one on the output.
     * We now find the matching close paren, copying the variable and
     * modifiers between the $( and ) temporarily into out_buf, so that
     * we can replace :'s with MAGIC_COLON.  This is necessary to avoid
     * being confused by modifier values that are variables containing
     * :'s.  Ugly.
     */

    depth = 1;
    inp = ++in; /* skip over the '(' */

    while( in < end && depth )
    {
        switch( *in++ )
        {
        case '(': depth++; break;
        case ')': depth--; break;
        }
    }

    /*
     * Input so far (ignore blanks):
     *
     *  stuff-in-outbuf $(variable) remainder
     *                    ^        ^         ^
     *                    inp      in        end
     */
    prefix_length = buf->size;
    string_append_range( buf, inp, in - 1 );

    out = buf->value + prefix_length;
    for ( ov = out; ov < buf->value + buf->size; ++ov )
    {
        switch( *ov )
        {
        case ':': *ov = MAGIC_COLON; break;
        case '[': *ov = MAGIC_LEFT; break;
        case ']': *ov = MAGIC_RIGHT; break;
        }
    }

    /*
     * Input so far (ignore blanks):
     *
     *  stuff-in-outbuf $(variable) remainder
     *                              ^        ^
     *                              in       end
     * Output so far:
     *
     *  stuff-in-outbuf variable
     *  ^               ^       ^
     *  out_buf         out     ov
     *
     * Later we will overwrite 'variable' in out_buf, but we'll be
     * done with it by then.  'variable' may be a multi-element list, 
     * so may each value for '$(variable element)', and so may 'remainder'.
     * Thus we produce a product of three lists.
     */

    {
        LIST *variables = 0;
        LIST *remainder = 0;
        LIST *vars;

        /* Recursively expand variable name & rest of input */

        if( out < ov )
            variables = var_expand( L0, out, ov, lol, 0 );
        if( in < end )
            remainder = var_expand( L0, in, end, lol, 0 );

        /* Now produce the result chain */

        /* For each variable name */

        for( vars = variables; vars; vars = list_next( vars ) )
        {
            LIST *value, *evalue = 0;
            char *colon;
            char *bracket;
            string variable[1];
            char *varname;
            int sub1 = 0, sub2 = -1;
            VAR_EDITS edits;

            /* Look for a : modifier in the variable name */
            /* Must copy into varname so we can modify it */

            string_copy( variable, vars->string );
            varname = variable->value;

            if( colon = strchr( varname, MAGIC_COLON ) )
            {
                string_truncate( variable, colon - varname );
                var_edit_parse( colon + 1, &edits );
            }

            /* Look for [x-y] subscripting */
            /* sub1 and sub2 are x and y. */

            if ( bracket = strchr( varname, MAGIC_LEFT ) )
            {
                /*
                ** Make all syntax errors in [] subscripting
                ** result in the same behavior: silenty return an empty
                ** expansion (by setting sub2 = 0). Brute force parsing;
                ** May get moved into yacc someday.
                */

                char *s = bracket + 1;

                string_truncate( variable, bracket - varname );

                do  /* so we can use "break" */
                {
                    /* Allow negative indexes. */
                    if (! isdigit( *s ) && ! ( *s == '-') )
                    {
                        sub2 = 0;
                        break;
                    }
                    sub1 = atoi(s);

                    /* Skip over the first symbol, which is either a digit or dash. */
                    s++;
                    while ( isdigit( *s ) ) s++;

                    if ( *s == MAGIC_RIGHT )
                    {
                        sub2 = sub1;
                        break;
                    }

                    if ( *s != '-')
                    {
                        sub2 = 0;
                        break;
                    }

                    s++;

                    if ( *s == MAGIC_RIGHT )
                    {
                        sub2 = -1;
                        break;
                    }

                    if (! isdigit( *s ) && ! ( *s == '-') )
                    {
                        sub2 = 0;
                        break;
                    }

                    /* First, compute the index of the last element. */
                    sub2 = atoi(s);               
                    s++;
                    while ( isdigit( *s ) ) s++;

                    if ( *s != MAGIC_RIGHT)
                        sub2 = 0;

                } while (0);

                /*
                ** Anything but the end of the string, or the colon
                ** introducing a modifier is a syntax error.
                */

                s++;                
                if (*s && *s != MAGIC_COLON)
                    sub2 = 0;

                *bracket = '\0';
            }

            /* Get variable value, specially handling $(<), $(>), $(n) */
		
            if( varname[0] == '<' && !varname[1] )
                value = lol_get( lol, 0 );
            else if( varname[0] == '>' && !varname[1] )
                value = lol_get( lol, 1 );
            else if( varname[0] >= '1' && varname[0] <= '9' && !varname[1] )
                value = lol_get( lol, varname[0] - '1' );
            else 
                value = var_get( varname );

            /* Handle negitive indexes: part two. */
            {
                int length = list_length( value );

                if (sub1 < 0)
                    sub1 = length + sub1;
                else
                    sub1 -= 1;

                if (sub2 < 0)
                    sub2 = length + 1 + sub2 - sub1;
                else
                    sub2 -= sub1;
                /*
                ** The "sub2 < 0" test handles the semantic error
                ** of sub2 < sub1.
                */
                if ( sub2 < 0 )
                    sub2 = 0;
            }



            /* The fast path: $(x) - just copy the variable value. */
            /* This is only an optimization */

            if( out == out_buf && !bracket && !colon && in == end )
            {

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -