Пример #1
0
static LIST *search_using_target_settings_var_get( const char *symbol, void *userData ) {
	SETTINGS* settings = quicksettingslookup( (TARGET*)userData, symbol );
	return settings ? settings->value : NULL;
}
Пример #2
0
LIST *
builtin_groupbyvar(
	PARSE	*parse,
	LOL	*args,
	int	*jmp )
{
	LIST* group1 = L0;
	LIST* rest = L0;
	LIST* f = L0;

	LIST* filelist;
	LIST* varname;
	LIST* maxPerGroupList;
	int numInGroup = 0;
	int maxPerGroup = INT_MAX;

	LIST* all;
	SETTINGS* vars;
	LIST* var1;

	filelist = lol_get( args, 0 );
	if ( !filelist )
		return L0;
    varname = lol_get( args, 1 );
	if ( !varname )
		return L0;
    maxPerGroupList = lol_get( args, 2 );
	if ( maxPerGroupList ) {
		maxPerGroup = atoi( maxPerGroupList->string );
		if ( maxPerGroup == 0 )
			maxPerGroup = INT_MAX;
	}

	/* get the actual filelist */
	all = var_get( filelist->string );

	/* */
	vars = quicksettingslookup( bindtarget( all->string ), varname->string );
	if ( !vars )
		return L0;
	var1 = vars->value;

	for ( f = all; f; f = list_next( f ) ) {
		LIST* it;
		LIST* it1;
		LIST* var;
		vars = quicksettingslookup( bindtarget( f->string ), varname->string );
		if ( !vars )
			continue;
		var = vars->value;

		for ( it = var, it1 = var1; it  &&  it1;  it = list_next( it ), it1 = list_next( it1 ) )
		{
			if ( it->string != it1->string )
				break;
		}

		if ( numInGroup < maxPerGroup  &&  !it  &&  !it1 ) {
			group1 = list_new( group1, f->string, 1 );
			++numInGroup;
		} else
			rest = list_new( rest, f->string, 1 );
	}

	var_set( filelist->string, rest, VAR_SET );

    return group1;
}
Пример #3
0
LIST *
var_expand(
	LIST		*prefix,
	const char 	*in,
	const char 	*end,
	LOL		*lol,
	int		cancopyin )
{
	BUFFER buff;
	const char *inp = in;
	int depth;
	size_t save_buffer_pos, ov_save_buffer_pos;
	int literal = 0;

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

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

	if( end - in == 4 && in[0] == '$' && in[1] == leftParen && in[3] == rightParen )
	{
	    switch( in[2] )
	    {
	    case '1':
	    case '<':
		return list_copy( prefix, lol_get( lol, 0 ) );

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

	buffer_init( &buff );

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

	while( in < end ) {
	    char ch = *in++;
	    buffer_addchar( &buff, ch );
	    if( ch == '$' && *in == leftParen )
		goto expand;
#ifdef OPT_EXPAND_LITERALS_EXT
	    if( ch == '@' && *in == leftParen ) {
		literal = 1;
		goto expand;
	    }
	    if( ch == '@' && in[0] == '$' && in[1] == leftParen ) {
		++in;
		literal = 1;
		goto expand;
	    }
#endif
	}

	/* 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(). */

	buffer_putchar( &buff, 0 );

	if( cancopyin ) {
	    LIST *new_list = list_append( prefix, inp, 1 );
	    buffer_free( &buff );
	    return new_list;
	}
	else {
	    LIST *new_list = list_append( prefix, buffer_ptr( &buff ), 0 );
	    buffer_free( &buff );
	    return new_list;
	}

    expand:
	/*
	 * 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;
	buffer_deltapos( &buff, -1 );
	save_buffer_pos = buffer_pos( &buff );
	in++;

	while( in < end && depth )
	{
	    char ch = *in++;
	    buffer_addchar( &buff, ch );
        if ( ch == leftParen )
        {
            depth++;
        }
        else if ( ch == rightParen )
        {
            depth--;
        }
        else
        {
	    switch( ch )
	    {
	    case ':': buffer_deltapos( &buff, -1 ); buffer_addchar( &buff, MAGIC_COLON ); break;
	    case '[': buffer_deltapos( &buff, -1 ); buffer_addchar( &buff, MAGIC_LEFT ); break;
	    case ']': buffer_deltapos( &buff, -1 ); buffer_addchar( &buff, MAGIC_RIGHT ); break;
	    }
        }
	}

	/* Copied ) - back up. */

	buffer_deltapos( &buff, -1 );
	ov_save_buffer_pos = buffer_pos( &buff );
	buffer_setpos( &buff, save_buffer_pos );

	/*
	 * 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;
	    LISTITEM *vars;

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

	    if( save_buffer_pos < ov_save_buffer_pos )
		variables = var_expand( L0, buffer_posptr( &buff ), buffer_ptr( &buff ) + ov_save_buffer_pos, lol, 0 );
	    if( in < end )
		remainder = var_expand( L0, in, end, lol, 0 );

	    /* Now produce the result chain */

	    /* For each variable name */

	    for( vars = list_first(variables); vars; vars = list_next( vars ) )
	    {
		LIST *value, *evalue = 0;
		LISTITEM* valueSliceStart = NULL;
#ifdef OPT_EXPAND_LITERALS_EXT
		LIST *origvalue = 0;
#endif
		char *colon;
		char *bracket;
		BUFFER varnamebuff;
		int sub1 = 0, sub2 = -1;
		VAR_EDITS edits;
		memset(&edits, 0, sizeof(VAR_EDITS));
		if (leftParen == '{') {
			edits.empty.ptr = "";
			edits.empty.len = 0;
		}

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

		buffer_init( &varnamebuff );
		buffer_addstring( &varnamebuff, list_value(vars), strlen( list_value(vars) ) );
		buffer_addchar( &varnamebuff, 0 );

		if( ( colon = strchr( buffer_ptr( &varnamebuff ), MAGIC_COLON ) ) )
		{
		    *colon = '\0';
		    var_edit_parse( colon + 1, &edits );
		}

		/* Look for [x-y] and [x-] subscripting */
		/* sub1 is x (0 default) */
		/* sub2 is length (-1 means forever) */

		if( ( bracket = strchr( buffer_ptr( &varnamebuff ), MAGIC_LEFT ) ) )
		{
		    char *dash;

		    if( ( dash = strchr( bracket + 1, '-' ) ) )
			*dash = '\0';

		    sub1 = atoi( bracket + 1 ) - 1;

		    if( !dash )
			sub2 = 1;
		    else if( !dash[1] || dash[1] == MAGIC_RIGHT )
			sub2 = -1;
		    else
			sub2 = atoi( dash + 1 ) - sub1;

		    *bracket = '\0';
		}

		/* Get variable value, specially handling $(<), $(>), $(n) */

#ifdef OPT_EXPAND_LITERALS_EXT
		if ( !literal )
#endif
		{
		    const char* varname = buffer_ptr( &varnamebuff );
		    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 if ( edits.targetsetting ) {
				TARGET* t = bindtarget(edits.targetname.ptr);
				SETTINGS* settings = quicksettingslookup(t, varname);
				if (settings)
					value = list_copy(L0, settings->value);
				else
					value = L0;
			} else
			value = var_get( varname );
		}
#ifdef OPT_EXPAND_LITERALS_EXT
		else {
		    origvalue = value = list_append( L0, buffer_ptr( &varnamebuff ), 0 );
		}
#endif

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

		if( buffer_isempty( &buff ) && !bracket && !colon && in == end )
		{
		    prefix = list_copy( prefix, value );
		    buffer_free( &buff );
		    continue;
		}

		/* Handle start subscript */
		valueSliceStart = list_first(value);
		while(sub1 > 0 && valueSliceStart)
		{
			sub1 -= 1;
			valueSliceStart = list_next(valueSliceStart);
		}

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

		if( !valueSliceStart && (colon || leftParen == '{') && edits.empty.ptr ) {
		    evalue = value = list_append( L0, edits.empty.ptr, 0 );
		    valueSliceStart = list_first(value);
		}

#ifdef OPT_EXPAND_LITERALS_EXT
		if ( colon && edits.expandliteral ) {
		    LOL lol;
		    char const* string = list_value(list_first(value));
		    LIST *newvalue = var_expand( L0, string, string + strlen( string ), &lol, 0 );
		    if ( origvalue ) {
			list_free( origvalue );
			origvalue = 0;
		    }
		    value = newvalue;
			valueSliceStart = list_first(value);
		    sub2 = -1;
		}
#endif

#ifdef OPT_EXPAND_FILEGLOB_EXT
		if ( edits.wildcard ) {
		    LIST *newl = L0;
		    for( ; valueSliceStart; valueSliceStart = list_next( valueSliceStart ) ) {
				LIST *foundfiles = L0;
				fileglob* glob;

				/* Handle end subscript (length actually) */
				if( sub2 >= 0 && --sub2 < 0 )
					break;

				glob = fileglob_Create( list_value(valueSliceStart) );
				while ( fileglob_Next( glob ) ) {
					foundfiles = list_append( foundfiles, fileglob_FileName( glob ) + edits.wildcard_remove_prepend.len, 0 );
				}
				fileglob_Destroy( glob );

				/* TODO: Efficiency: Just append to newl above? */
				newl = list_copy( newl, foundfiles );
				list_free( foundfiles );
			}
			if ( origvalue ) {
				list_free( origvalue );
				origvalue = 0;
		    }

		    value = newl;
		    origvalue = value;
			valueSliceStart = list_first(value);
		}
#endif

		/* For each variable value */

		for( ; valueSliceStart; valueSliceStart = list_next( valueSliceStart ) )
		{
		    LISTITEM *rem;
		    size_t save_buffer_pos;
		    size_t end_buffer_pos;
		    const char *valuestring;

		    /* Handle end subscript (length actually) */

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

		    /* Apply : mods, if present */

		    save_buffer_pos = buffer_pos( &buff );

		    valuestring = list_value(valueSliceStart);

#ifdef OPT_EXPAND_BINDING_EXT
		    if( colon && edits.expandbinding ) {
				SETTINGS *expandText;
				TARGET *t = bindtarget( valuestring );
				expandText = quicksettingslookup( t, "EXPAND_TEXT" );
				if ( expandText && list_first(expandText->value) ) {
					valuestring = list_value(list_first(expandText->value));
				} else {
					if( t->binding == T_BIND_UNBOUND ) {
						t->boundname = search_using_target_settings( t, t->name, &t->time );
						t->binding = t->time ? T_BIND_EXISTS : T_BIND_MISSING;
					}
					valuestring = t->boundname;
				}
		    }
#endif

		    if( colon && edits.filemods ) {
			var_edit_file( valuestring, &buff, &edits );
		    } else {
			buffer_addstring( &buff, valuestring, strlen( valuestring ) + 1 );
		    }
		    buffer_setpos( &buff, save_buffer_pos );

		    if( colon && ( edits.upshift || edits.downshift ) )
			var_edit_shift( buffer_posptr( &buff ), &edits );

#ifdef OPT_SLASH_MODIFIERS_EXT
		    if( colon && ( edits.fslash || edits.bslash ) )
			var_edit_slash( buffer_posptr( &buff ), &edits );
#endif

#ifdef OPT_EXPAND_ESCAPE_PATH_EXT
			if ( colon && edits.escapepath )
			{
				const char* ptr = buffer_posptr( &buff );
				const char* endptr = ptr + strlen( ptr );
				BUFFER escapebuff;
				buffer_init( &escapebuff );
			    save_buffer_pos = buffer_pos( &buff );

#ifdef NT
				while ( ptr != endptr  &&  *ptr != ' '  &&  *ptr != '/' )
					++ptr;
				if (*ptr == ' '  ||  *ptr == '/' ) {
					buffer_addchar( &escapebuff, '"' );
					buffer_addstring( &escapebuff, buffer_posptr( &buff ), endptr - buffer_posptr( &buff ) );
					buffer_addchar( &escapebuff, '"' );
					buffer_addchar( &escapebuff, 0 );
					buffer_addstring( &buff, buffer_ptr( &escapebuff ), buffer_pos( &escapebuff ) );
				}

#else
				while ( ptr != endptr ) {
					if ( *ptr == ' '  ||  *ptr == '\\'  ||  *ptr == leftParen  ||  *ptr == rightParen  ||  *ptr == '"' ) {
						buffer_addchar( &escapebuff, '\\' );
					}
					buffer_addchar( &escapebuff, *ptr );
					++ptr;
				}
				buffer_addchar( &escapebuff, 0 );
				buffer_addstring( &buff, buffer_ptr( &escapebuff ), buffer_pos( &escapebuff ) );
#endif

				buffer_setpos( &buff, save_buffer_pos );
				buffer_free( &escapebuff );
			}
#endif

		    /* 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( valueSliceStart ) || list_next( vars ) ) )
		    {
			buffer_setpos( &buff, buffer_pos( &buff ) + strlen( buffer_posptr( &buff ) ) );
			buffer_addstring( &buff, edits.join.ptr, strlen( edits.join.ptr ) + 1 );
			buffer_deltapos( &buff, -1 );
			continue;
		    }

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

		    if( in == end )
		    {
			prefix = list_append( prefix, buffer_ptr( &buff ), 0 );
			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' */

		    save_buffer_pos = buffer_pos( &buff );
		    end_buffer_pos = strlen( buffer_ptr( &buff ) );
		    buffer_setpos( &buff, end_buffer_pos );

		    for( rem = list_first(remainder); rem; rem = list_next( rem ) )
		    {
			buffer_addstring( &buff, list_value(rem), strlen( list_value(rem) ) + 1 );
			buffer_setpos( &buff, end_buffer_pos );
			prefix = list_append( prefix, buffer_ptr( &buff ), 0 );
		    }

		    buffer_setpos( &buff, save_buffer_pos );
		}

		/* Toss used empty */

		if( evalue )
		    list_free( evalue );

#ifdef OPT_EXPAND_LITERALS_EXT
		if ( origvalue )
		    list_free( origvalue );
#endif

#ifdef OPT_EXPAND_INCLUDES_EXCLUDES_EXT
		if ( edits.includes_excludes ) {
		    LIST *newl = L0;
		    LISTITEM* l;

		    LIST *origprefix = prefix;
		    int hasInclude = 0;

		    if ( !regexhash )
			regexhash = hashinit( sizeof(regexdata), "regex" );

		    {
			LISTITEM *inex = list_first(edits.includes_excludes);
			while ( inex ) {
			    char mod = list_value(inex)[0];
			    inex = list_next( inex );

			    if ( mod == 'I' ) {
				hasInclude = 1;
			    }
			}
		    }

		    for (l = list_first(prefix) ; l; l = list_next( l ) )
		    {
			LISTITEM *inex = list_first(edits.includes_excludes);
			int remove = hasInclude;

			while ( inex ) {
			    char mod = list_value(inex)[0];
			    regexp *re;
			    regexdata data, *d = &data;
			    inex = list_next( inex );
			    data.name = list_value(inex);
			    if( !hashcheck( regexhash, (HASHDATA **)&d ) )
			    {
				d->re = jam_regcomp( list_value(inex) );
				(void)hashenter( regexhash, (HASHDATA **)&d );
			    }
			    re = d->re;
			    inex = list_next( inex );

			    if ( mod == 'X' ) {
				if( jam_regexec( re, list_value(l) ) )
				    remove = 1;
			    } else if ( mod == 'I' ) {
				if( jam_regexec( re, list_value(l) ) )
				    remove = 0;
			    }
			}

			if ( !remove )
			    newl = list_append( newl, list_value(l), 1 );
		    }

			/* TODO: Efficiency: Just modify prefix? */
		    list_free( origprefix );
		    prefix = newl;
		}
#endif

//#ifdef OPT_EXPAND_LITERALS_EXT
//		buffer_free( &buff );
//#endif
#ifdef OPT_EXPAND_INCLUDES_EXCLUDES_EXT
		list_free( edits.includes_excludes );
#endif

	    }

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

		list_free( variables );
		list_free( remainder );

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

	    buffer_free( &buff );
	    return prefix;
	}
}
Пример #4
0
/*
 * Get cached md5sum of a file. If none found, or not up to date, if the file is source
 * try to recalculate the sum. If not, then return empty sum (all zeroes).
 */
int getcachedmd5sum( TARGET *t, int forcetimecheck )
{
	CHECKSUMDATA checksumdata, *c = &checksumdata;

	checksums_readfile();

	if ( t->contentchecksum == NULL ) {
		const char *target = t->boundname;
# ifdef DOWNSHIFT_PATHS
		char path[ MAXJPATH ];
		char *p = path;

		do *p++ = (char)tolower( *target ); while( *target++ );

		target = path;
# endif

		c->boundname = target;

		if ( !hashcheck( checksumhash, (HASHDATA **) &c ) ) {
			if ( hashenter( checksumhash, (HASHDATA **)&c ) ) {
				c->boundname = newstr( c->boundname );
				c->next = checksumdatalist;
				checksumdatalist = c;
				c->mtime = 0;
				memset( &c->contentmd5sum, 0, MD5_SUMSIZE );
				c->contentmd5sum_changed = 1;
				c->contentmd5sum_calculated = 0;
				c->age = 0;
			}
		}

		t->contentchecksum = c;
	} else {
		c = t->contentchecksum;
	}

	if ( !c->contentmd5sum_calculated  ||  forcetimecheck  ||  t->time != c->mtime  ||  c->mtime == 0 ) {
		/* This file may have generated or updated in another fashion.  Grab its timestamp. */
		time_t ftime;

		c->contentmd5sum_calculated = 1;

//		if ( file_time( c->boundname, &ftime ) == -1 ) {
		timestamp( c->boundname, &ftime, 0 );
		if ( ftime == 0 ) {
			/* This file is not present anymore. */
			c->age = 0; /* The entry has been used, its young again */
			c->mtime = 0;
			c->contentmd5sum_changed = 1;
			memset( &c->contentmd5sum, 0, MD5_SUMSIZE );
			checksumsdirty = 1;
			return 1;
		}

		/* 'c' points at the cache entry.  Its out of date. */

		if ( ftime != c->mtime )
		{
			MD5SUM origmd5sum;
#ifdef OPT_BUILTIN_LUA_SUPPORT_EXT
			SETTINGS *md5callback;
#endif

			memcpy( &origmd5sum, &c->contentmd5sum, sizeof( MD5SUM ) );
#ifdef OPT_BUILTIN_LUA_SUPPORT_EXT
			md5callback = quicksettingslookup( t, "MD5CALLBACK" );

			if ( md5callback && md5callback->value )
			{
				luahelper_md5callback(t->boundname, c->contentmd5sum, list_value(list_first(md5callback->value)));
			}
			else
			{
#endif
				md5file( t->boundname, c->contentmd5sum );
#ifdef OPT_BUILTIN_LUA_SUPPORT_EXT
			}
#endif
			c->mtime = ftime;
			c->contentmd5sum_changed = memcmp( &origmd5sum, &c->contentmd5sum, sizeof( MD5SUM ) ) != 0;
		}
		//if( DEBUG_MD5HASH )
			//printf( "- content md5: %s (%s)\n", t->boundname, md5tostring(c->contentmd5sum));

		c->age = 0;
		checksumsdirty = 1;
	}

	return c->contentmd5sum_changed;

#if 0
			if( DEBUG_MD5HASH )
				printf( "md5 cache out of date for %s (time %d, md5time %d)\n", t->boundname , (int)t->time, (int)c->mtime );
#endif
}