if( dash == bracket + 2 && *( bracket + 1 ) == '-') --dash;
var_expand( 	LIST	*l,	char	*in,	char	*end,	LOL	*lol,	int	cancopyin ){        string buf[1];        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 ) );	    }	}	/* See if we can use a 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, in );            	    r = list_new( l, newstr( buf->value ) );            string_free( buf );            return r;        }    expand:        string_new( buf );        string_append_range( buf, inp, in - 1 ); /* copy in initial stuff */	/*         * 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;		char *colon;		char *bracket;		int i, sub1, sub2;		string variable;                char *varname;		/* 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 );                }		if( bracket = strchr( varname, MAGIC_LEFT ) )		{		    char *dash = 0;		    if( bracket[1] && ( dash = strchr( bracket + 2, '-' ) ) )		    {			string_truncate( &variable, dash - varname );			sub1 = atoi( bracket + 1 );			sub2 = atoi( dash + 1 );		    }		    else		    {			sub1 = sub2 = atoi( bracket + 1 );		    }                    string_truncate( &variable, bracket - varname );		}		else		{		    sub1 = sub2 = 0;	/* not needed */		}		/* 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 );		}                		/* The fast path: $(x) - just copy the variable value. */		if( out == buf->value && !bracket && !colon && in == end )		{                    string_free( &variable );		    l = list_copy( l, value );		    continue;		}                /* Adjust negative indices */                if ( sub1 < 0 || sub2 < 0 )                {                    int length = list_length( value );                    sub1 = adjust_index( sub1, length );                    sub2 = adjust_index( sub2, length );                }		/* For each variable value */		for( i = 1; value; i++, value = list_next( value ) )		{		    LIST *rem;                    size_t postfix_start;		    /* Skip members not in subscript */		    if( bracket && ( i < sub1 || sub2 && i > sub2 ) )			continue;                    string_truncate( buf, prefix_length );		    /* Apply : mods, if present */		    if( colon )			var_edit( value->string, colon + 1, buf );		    else                        string_append( buf, value->string );		    /* If no remainder, append result to output chain. */		    if( in == end )		    {			l = list_new( l, newstr( buf->value ) );			continue;		    }		    /* Remember the end of the variable expansion so */		    /* we can just tack on each instance of 'remainder' */		    postfix_start = buf->size;		    /* For each remainder, or just once if no remainder, */		    /* append the complete string to the output chain */		    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( &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;	}}