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

📄 expand.c

📁 C++的一个好库。。。现在很流行
💻 C
📖 第 1 页 / 共 2 页
字号:
                string_free( variable );
                l = list_copy( l, value );
                continue;
            }

            /* Handle start subscript */

            while( sub1 > 0 && value )
                --sub1, value = list_next( value );

            /* Empty w/ :E=default? */

            if( !value && colon && edits.empty.ptr )
                evalue = value = list_new( L0, newstr( edits.empty.ptr ) );

            /* For each variable value */

            string_new( out1 );
            for( ; value; value = list_next( value ) )
            {
                LIST *rem;
                size_t postfix_start;

                /* Handle end subscript (length actually) */

                if( sub2 >= 0 && --sub2 < 0 )
                    break;

                string_truncate( buf, prefix_length );

                /* Apply : mods, if present */

                if( colon && edits.filemods )
                    var_edit_file( value->string, out1, &edits );
                else
                    string_append( out1, value->string );

                if( colon && ( edits.upshift || edits.downshift || edits.to_slashes || edits.to_windows ) )
                    var_edit_shift( out1, &edits );

                /* Handle :J=joinval */
                /* If we have more values for this var, just */
                /* keep appending them (with the join value) */
                /* rather than creating separate LIST elements. */

                if( colon && edits.join.ptr && 
                    ( list_next( value ) || list_next( vars ) ) )
                {
                    string_append( out1, edits.join.ptr );
                    continue;
                }

                string_append( buf, out1->value );
                string_free( out1 );
                string_new( out1 );

                /* If no remainder, append result to output chain. */

                if( in == end )
                {
                    l = list_new( l, newstr( buf->value ) );
                    continue;
                }

                /* For each remainder, append the complete string */
                /* to the output chain. */
                /* Remember the end of the variable expansion so */
                /* we can just tack on each instance of 'remainder' */

                postfix_start = buf->size;

                for( rem = remainder; rem; rem = list_next( rem ) )
                {
                    string_truncate( buf, postfix_start );
                    string_append( buf, rem->string );
                    l = list_new( l, newstr( buf->value ) );
                }
            }
            string_free( out1 );

            /* Toss used empty */

            if( evalue )
                list_free( evalue );

            string_free( variable );
        }

        /* variables & remainder were gifts from var_expand */
        /* and must be freed */

        if( variables )
            list_free( variables );
        if( remainder)
            list_free( remainder );

        if( DEBUG_VAREXP )
        {
            printf( "expanded to " );
            list_print( l );
            printf( "\n" );
        }

        string_free( buf );
        return l;
    }
}

/*
 * var_edit_parse() - parse : modifiers into PATHNAME structure
 *
 * The : modifiers in a $(varname:modifier) currently support replacing
 * or omitting elements of a filename, and so they are parsed into a 
 * PATHNAME structure (which contains pointers into the original string).
 *
 * Modifiers of the form "X=value" replace the component X with
 * the given value.  Modifiers without the "=value" cause everything 
 * but the component X to be omitted.  X is one of:
 *
 *	G <grist>
 *	D directory name
 *	B base name
 *	S .suffix
 *	M (member)
 *	R root directory - prepended to whole path
 *
 * This routine sets:
 *
 *	f->f_xxx.ptr = 0
 *	f->f_xxx.len = 0
 *		-> leave the original component xxx
 *
 *	f->f_xxx.ptr = string
 *	f->f_xxx.len = strlen( string )
 *		-> replace component xxx with string
 *
 *	f->f_xxx.ptr = ""
 *	f->f_xxx.len = 0
 *		-> omit component xxx
 *
 * var_edit_file() below and path_build() obligingly follow this convention.
 */

static void
var_edit_parse(
	char		*mods,
	VAR_EDITS	*edits )
{
	int havezeroed = 0;
	memset( (char *)edits, 0, sizeof( *edits ) );

	while( *mods )
	{
	    char *p;
	    PATHPART *fp;

	    switch( *mods++ )
	    {
	    case 'L': edits->downshift = 1; continue;
	    case 'U': edits->upshift = 1; continue;
	    case 'P': edits->parent = edits->filemods = 1; continue;
	    case 'E': fp = &edits->empty; goto strval;
	    case 'J': fp = &edits->join; goto strval;
	    case 'G': fp = &edits->f.f_grist; goto fileval;
	    case 'R': fp = &edits->f.f_root; goto fileval;
	    case 'D': fp = &edits->f.f_dir; goto fileval;
	    case 'B': fp = &edits->f.f_base; goto fileval;
	    case 'S': fp = &edits->f.f_suffix; goto fileval;
	    case 'M': fp = &edits->f.f_member; goto fileval;
            case 'T': edits->to_slashes = 1; continue;
            case 'W': edits->to_windows = 1; continue;

	    default: return; /* should complain, but so what... */
	    }

	fileval:

	    /* Handle :CHARS, where each char (without a following =) */
	    /* selects a particular file path element.  On the first such */
	    /* char, we deselect all others (by setting ptr = "", len = 0) */
	    /* and for each char we select that element (by setting ptr = 0) */

	    edits->filemods = 1;

	    if( *mods != '=' )
	    {
		int i;

		if( !havezeroed++ )
		    for( i = 0; i < 6; i++ )
		{
		    edits->f.part[ i ].len = 0;
		    edits->f.part[ i ].ptr = "";
		}

		fp->ptr = 0;
		continue;
	    }

	strval:

	    /* Handle :X=value, or :X */

	    if( *mods != '=' )
	    {
		fp->ptr = "";
		fp->len = 0;
	    }
	    else if( p = strchr( mods, MAGIC_COLON ) )
	    {
		*p = 0;
		fp->ptr = ++mods;
		fp->len = p - mods;
		mods = p + 1;
	    }
	    else
	    {
		fp->ptr = ++mods;
		fp->len = strlen( mods );
		mods += fp->len;
	    }
	}
}

/*
 * var_edit_file() - copy input target name to output, modifying filename
 */
	
static void
var_edit_file( 
	char	*in,
	string	*out,
	VAR_EDITS *edits )
{
	PATHNAME pathname;

	/* Parse apart original filename, putting parts into "pathname" */

	path_parse( in, &pathname );

	/* Replace any pathname with edits->f */

	if( edits->f.f_grist.ptr )
	    pathname.f_grist = edits->f.f_grist;

	if( edits->f.f_root.ptr )
	    pathname.f_root = edits->f.f_root;

	if( edits->f.f_dir.ptr )
	    pathname.f_dir = edits->f.f_dir;

	if( edits->f.f_base.ptr )
	    pathname.f_base = edits->f.f_base;

	if( edits->f.f_suffix.ptr )
	    pathname.f_suffix = edits->f.f_suffix;

	if( edits->f.f_member.ptr )
	    pathname.f_member = edits->f.f_member;

	/* If requested, modify pathname to point to parent */

	if( edits->parent )
	    path_parent( &pathname );

	/* Put filename back together */

    path_build( &pathname, out, 0 );
}

/*
 * var_edit_shift() - do upshift/downshift mods
 */

static void
var_edit_shift( 
	string	*out,
	VAR_EDITS *edits )
{
	/* Handle upshifting, downshifting and slash translation now */

    char *p;
    for ( p = out->value; *p; ++p)
    {
        if (edits->upshift)
        {
            *p = toupper( *p );
        }
        else if ( edits->downshift )
        {
            *p = tolower( *p );
        } 
        if ( edits->to_slashes )
        {
            if ( *p == '\\')
                *p = '/';
        }
# ifdef OS_CYGWIN
        if ( edits->to_windows )
        {
            char result[MAX_PATH + 1];
            cygwin_conv_to_win32_path(out->value, result);
            assert(strlen(result) <= MAX_PATH);
            string_free( out );
            string_copy( out, result );
        }
# endif
    }
    out->size = p - out->value;
}

#ifndef NDEBUG
void var_expand_unit_test()
{
    LOL lol[1];
    LIST* l, *l2;
    LIST *expected = list_new( list_new( L0, newstr( "axb" ) ), newstr( "ayb" ) );
    LIST *e2;
    char axyb[] = "a$(xy)b";
    char azb[] = "a$($(z))b";
    char path[] = "$(p:W)";
        
    lol_init(lol);
    var_set("xy", list_new( list_new( L0, newstr( "x" ) ), newstr( "y" ) ), VAR_SET );
    var_set("z", list_new( L0, newstr( "xy" ) ), VAR_SET );
    var_set("p", list_new( L0, newstr( "/cygdrive/c/foo/bar" ) ), VAR_SET );

    l = var_expand( 0, axyb, axyb + sizeof(axyb) - 1, lol, 0 );
    for ( l2 = l, e2 = expected; l2 && e2; l2 = list_next(l2), e2 = list_next(e2) )
        assert( !strcmp( e2->string, l2->string ) );
    assert(l2 == 0 && e2 == 0);
    list_free(l);
    
    l = var_expand( 0, azb, azb + sizeof(azb) - 1, lol, 0 );
    for ( l2 = l, e2 = expected; l2 && e2; l2 = list_next(l2), e2 = list_next(e2) )
        assert( !strcmp( e2->string, l2->string ) );
    assert(l2 == 0 && e2 == 0);
    list_free(l);

    l = var_expand( 0, path, path + sizeof(path) - 1, lol, 0 );
    assert(l != 0);
    assert(list_next(l) == 0);
# ifdef OS_CYGWIN
    assert( !strcmp( l->string, "c:\\foo\\bar" ) );
# else 
    assert( !strcmp( l->string, "/cygdrive/c/foo/bar" ) );
# endif   
    list_free(l);

    list_free(expected);
    
    lol_free(lol);
}
#endif

/*
     Local Variables:
     tab-width: 8
     End:
 */

⌨️ 快捷键说明

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