コード例 #1
0
ファイル: luasupport.c プロジェクト: caryhaynie/jamplus
int LS_jam_setvar(ls_lua_State *L)
{
    int numParams = ls_lua_gettop(L);
    if (numParams < 2  ||  numParams > 3)
        return 0;

    if (!ls_lua_isstring(L, 1))
        return 0;

    if (numParams == 2)
    {
        var_set(ls_lua_tostring(L, 1), luahelper_addtolist(L, L0, 2), VAR_SET);
    }
    else
    {
        TARGET *t;

        if (!ls_lua_isstring(L, 2))
            return 0;

        t = bindtarget(ls_lua_tostring(L, 1));
        t->settings = addsettings(t->settings, VAR_SET, ls_lua_tostring(L, 2), luahelper_addtolist(L, L0, 3));
    }

    return 0;
}
コード例 #2
0
ファイル: make1.c プロジェクト: Albermg7/boost
static SETTINGS *
make1settings( LIST *vars )
{
	SETTINGS *settings = 0;

	for( ; vars; vars = list_next( vars ) )
	{
	    LIST *l = var_get( vars->string );
	    LIST *nl = 0;

	    for( ; l; l = list_next( l ) ) 
	    {
		TARGET *t = bindtarget( l->string );

		/* Make sure the target is bound */

		if( t->binding == T_BIND_UNBOUND )
		    make1bind( t );

		/* Build new list */

		nl = list_new( nl, copystr( t->boundname ) );
	    }

	    /* Add to settings chain */

	    settings = addsettings( settings, 0, vars->string, nl );
	}

	return settings;
}
コード例 #3
0
ファイル: builtins.c プロジェクト: larus/jamplus
LIST *
builtin_usefilecache(
	PARSE	*parse,
	LOL	*args,
	int	*jmp )
{
	LIST *l = lol_get( args, 0 );
	LIST *l2 = lol_get( args, 1 );
	const char* cachevar = l2 ? l2->string : "generic";
	BUFFER buff;
	buffer_init( &buff );
	buffer_addstring( &buff, "FILECACHE.", 10 );
	buffer_addstring( &buff, cachevar, strlen( cachevar ) );
	buffer_addchar( &buff, 0 );

	for( ; l; l = list_next( l ) ) {
	    TARGET *t = bindtarget( l->string );
	    t->settings = addsettings( t->settings, VAR_SET, "FILECACHE", list_new( L0, buffer_ptr( &buff ), 0 ) );
	    t->flags |= parse->num;
	}

	buffer_free( &buff );

	return L0;
}
コード例 #4
0
ファイル: compile.c プロジェクト: 4ukuta/core
LIST * compile_foreach( PARSE * parse, FRAME * frame )
{
    LIST     * nv = parse_evaluate( parse->left, frame );
    LIST     * l;
    SETTINGS * s = 0;

    if ( parse->num )
    {
        s = addsettings( s, VAR_SET, parse->string, L0 );
        pushsettings( s );
    }

    /* Call var_set to reset $(parse->string) for each val. */

    for ( l = nv; l; l = list_next( l ) )
    {
        LIST * val = list_new( L0, copystr( l->string ) );
        var_set( parse->string, val, VAR_SET );
        list_free( parse_evaluate( parse->right, frame ) );
    }

    if ( parse->num )
    {
        popsettings( s );
        freesettings( s );
    }

    list_free( nv );

    return L0;
}
コード例 #5
0
ファイル: make1.c プロジェクト: 0xb1dd1e/jamplus
static SETTINGS *
make1settings( LIST *vars )
{
	SETTINGS *settings = 0;

	for( ; vars; vars = list_next( vars ) )
	{
	    LIST *l = var_get( vars->string );
	    LIST *nl = 0;

	    for( ; l; l = list_next( l ) )
	    {
		TARGET *t = bindtarget( l->string );

		/* Make sure the target is bound, warning if it is not in the */
		/* dependency graph. */

		if( t->binding == T_BIND_UNBOUND )
		    make1bind( t, 1 );

		/* Build new list */

		nl = list_new( nl, t->boundname, 1 );
	    }

	    /* Add to settings chain */

	    settings = addsettings( settings, 0, vars->string, nl );
	}

	return settings;
}
コード例 #6
0
ファイル: make1.c プロジェクト: CarterTsai/clasp
static SETTINGS * make1settings( struct module_t * module, LIST * vars )
{
    SETTINGS * settings = 0;

    LISTITER vars_iter = list_begin( vars );
    LISTITER const vars_end = list_end( vars );
    for ( ; vars_iter != vars_end; vars_iter = list_next( vars_iter ) )
    {
        LIST * const l = var_get( module, list_item( vars_iter ) );
        LIST * nl = L0;
        LISTITER iter = list_begin( l );
        LISTITER const end = list_end( l );

        for ( ; iter != end; iter = list_next( iter ) )
        {
            TARGET * const t = bindtarget( list_item( iter ) );

            /* Make sure the target is bound. */
            if ( t->binding == T_BIND_UNBOUND )
                make1bind( t );

            /* Build a new list. */
            nl = list_push_back( nl, object_copy( t->boundname ) );
        }

        /* Add to settings chain. */
        settings = addsettings( settings, VAR_SET, list_item( vars_iter ), nl );
    }

    return settings;
}
コード例 #7
0
SETTINGS * copysettings( SETTINGS * head )
{
    SETTINGS * copy = 0;
    SETTINGS * v;
    for ( v = head; v; v = v->next )
        copy = addsettings( copy, VAR_SET, v->symbol, list_copy( 0, v->value ) );
    return copy;
}
コード例 #8
0
ファイル: builtins.c プロジェクト: larus/jamplus
LIST *
builtin_usedepcache(
	PARSE	*parse,
	LOL	*args,
	int	*jmp )
{
	LIST *l = lol_get( args, 0 );
	LIST *l2 = lol_get( args, 1 );

	for( ; l; l = list_next( l ) ) {
	    TARGET *t = bindtarget( l->string );
	    if ( l2 )
		t->settings = addsettings( t->settings, VAR_SET, "DEPCACHE", list_copy( L0, l2 ) );
	    else
		t->settings = addsettings( t->settings, VAR_SET, "DEPCACHE", L0 );
	    t->flags |= parse->num;
	}

	return L0;
}
コード例 #9
0
ファイル: builtins.c プロジェクト: larus/jamplus
LIST *
builtin_usemd5callback(
	PARSE	*parse,
	LOL	*args,
	int	*jmp )
{
	LIST *l = lol_get( args, 0 );
	LIST *l2 = lol_get( args, 1 );

	for( ; l; l = list_next( l ) ) {
	    TARGET *t = bindtarget( l->string );
	    t->settings = addsettings( t->settings, VAR_SET, "MD5CALLBACK", list_copy( L0, l2 ) );
	}

	return L0;
}
コード例 #10
0
ファイル: builtins.c プロジェクト: larus/jamplus
LIST *
builtin_usecommandline(
	PARSE	*parse,
	LOL	*args,
	int	*jmp )
{
	LIST *l = lol_get( args, 0 );
	LIST *l2 = lol_get( args, 1 );

	for( ; l; l = list_next( l ) ) {
	    TARGET *t = bindtarget( l->string );
	    t->settings = addsettings( t->settings, VAR_SET, "COMMANDLINE", list_copy( L0, l2 ) );
	    t->flags |= parse->num;
	}

	return L0;
}
コード例 #11
0
ファイル: compile.c プロジェクト: caryhaynie/jamplus
LIST *
compile_settings(
	PARSE	*parse,
	LOL	*args,
	int	*jmp )
{
	LIST	*nt = (*parse->left->func)( parse->left, args, jmp );
	LIST	*ns = (*parse->third->func)( parse->third, args, jmp );
	LIST	*targets = (*parse->right->func)( parse->right, args, jmp );
	LISTITEM	*ts;

	if( DEBUG_COMPILE )
	{
	    debug_compile( 0, "set" );
	    list_print( nt );
	    printf( "on " );
	    list_print( targets );
	    printf( " %s ", set_names[ parse->num ] );
	    list_print( ns );
	    printf( "\n" );
	}

	/* Call addsettings to save variable setting */
	/* addsettings keeps ns, so need to copy it */
	/* Pass append flag to addsettings() */

	for( ts = list_first(targets); ts; ts = list_next( ts ) )
	{
	    TARGET 	*t = bindtarget( list_value(ts) );
	    LISTITEM	*l;

	    for( l = list_first(nt); l; l = list_next( l ) )
		t->settings = addsettings( t->settings, parse->num,
				list_value(l), list_copy( NULL, ns ) );
	}

	list_free( nt );
	list_free( targets );

	return ns;
}
コード例 #12
0
ファイル: compile.c プロジェクト: Albermg7/boost
LIST *
compile_settings(
    PARSE   *parse,
    FRAME *frame )
{
    LIST    *nt = parse_evaluate( parse->left, frame );
    LIST    *ns = parse_evaluate( parse->third, frame );
    LIST    *targets = parse_evaluate( parse->right, frame );
    LIST    *ts;
    int append = parse->num == ASSIGN_APPEND;

    if( DEBUG_COMPILE )
    {
        debug_compile( 0, "set", frame);
        list_print( nt );
        printf( " on " );
        list_print( targets );
        printf( " %s ", append ? "+=" : "=" );
        list_print( ns );
        printf( "\n" );
    }

    /* Call addsettings to save variable setting */
    /* addsettings keeps ns, so need to copy it */
    /* Pass append flag to addsettings() */

    for( ts = targets; ts; ts = list_next( ts ) )
    {
        TARGET  *t = bindtarget( ts->string );
        LIST    *l;

        for( l = nt; l; l = list_next( l ) )
        t->settings = addsettings( t->settings, append, 
                l->string, list_copy( (LIST*)0, ns ) );
    }

    list_free( nt );
    list_free( targets );

    return ns;
}
コード例 #13
0
ファイル: compile.c プロジェクト: caryhaynie/jamplus
LIST *
compile_local(
	PARSE	*parse,
	LOL	*args,
	int	*jmp )
{
	LISTITEM *l;
	SETTINGS *s = 0;
	LIST	*nt = (*parse->left->func)( parse->left, args, jmp );
	LIST	*ns = (*parse->right->func)( parse->right, args, jmp );
	LIST	*result;

	if( DEBUG_COMPILE )
	{
	    debug_compile( 0, "local" );
	    list_print( nt );
	    printf( " = " );
	    list_print( ns );
	    printf( "\n" );
	}

	/* Initial value is ns */

	for( l = list_first(nt); l; l = list_next( l ) )
	    s = addsettings( s, 0, list_value(l), list_copy( NULL, ns ) );

	list_free( ns );
	list_free( nt );

	/* Note that callees of the current context get this "local" */
	/* variable, making it not so much local as layered. */

	pushsettings( s );
	result = (*parse->third->func)( parse->third, args, jmp );
	popsettings( s );
	freesettings( s );

	return result;
}
コード例 #14
0
ファイル: compile.c プロジェクト: Albermg7/boost
LIST *
compile_local(
    PARSE   *parse,
    FRAME *frame )
{
    LIST *l;
    SETTINGS *s = 0;
    LIST    *nt = parse_evaluate( parse->left, frame );
    LIST    *ns = parse_evaluate( parse->right, frame );
    LIST    *result;

    if( DEBUG_COMPILE )
    {
        debug_compile( 0, "local", frame);
        list_print( nt );
        printf( " = " );
        list_print( ns );
        printf( "\n" );
    }

    /* Initial value is ns */

    for( l = nt; l; l = list_next( l ) )
        s = addsettings( s, 0, l->string, list_copy( (LIST*)0, ns ) );

    list_free( ns );
    list_free( nt );

    /* Note that callees of the current context get this "local" */
    /* variable, making it not so much local as layered. */

    pushsettings( s );
    result = parse_evaluate( parse->third, frame );
    popsettings( s );

    freesettings( s );

    return result;
}
コード例 #15
0
ファイル: compile.c プロジェクト: 4ukuta/core
LIST * compile_settings( PARSE * parse, FRAME * frame )
{
    LIST       * nt = parse_evaluate( parse->left, frame );
    LIST       * ns = parse_evaluate( parse->third, frame );
    LIST       * targets = parse_evaluate( parse->right, frame );
    LIST       * ts;
    char const * trace;
    int          setflag = assign_var_mode( parse->num, &trace );

    if ( DEBUG_COMPILE )
    {
        debug_compile( 0, "set", frame );
        list_print( nt );
        printf( " on " );
        list_print( targets );
        printf( " %s ", trace );
        list_print( ns );
        printf( "\n" );
    }

    /* Call addsettings() to save variable setting. addsettings() keeps ns, so
     * need to copy it. Pass append flag to addsettings().
     */
    for ( ts = targets; ts; ts = list_next( ts ) )
    {
        TARGET * t = bindtarget( ts->string );
        LIST   * l;

        for ( l = nt; l; l = list_next( l ) )
        t->settings = addsettings( t->settings, setflag, l->string,
            list_copy( (LIST *)0, ns ) );
    }

    list_free( nt );
    list_free( targets );
    return ns;
}
コード例 #16
0
ファイル: compile.c プロジェクト: 4ukuta/core
/*
 * collect_arguments() - local argument checking and collection
 */
static SETTINGS *
collect_arguments( RULE* rule, FRAME* frame )
{
    SETTINGS *locals = 0;

    LOL * all_actual = frame->args;
    LOL * all_formal = rule->arguments ? rule->arguments->data : 0;
    if ( all_formal ) /* Nothing to set; nothing to check */
    {
        int max = all_formal->count > all_actual->count
            ? all_formal->count
            : all_actual->count;

        int n;
        for ( n = 0; n < max ; ++n )
        {
            LIST *actual = lol_get( all_actual, n );
            char *type_name = 0;

            LIST *formal;
            for ( formal = lol_get( all_formal, n ); formal; formal = formal->next )
            {
                char* name = formal->string;

                if ( is_type_name(name) )
                {
                    if ( type_name )
                        argument_error( "missing argument name before type name:", rule, frame, formal );

                    if ( !formal->next )
                        argument_error( "missing argument name after type name:", rule, frame, formal );

                    type_name = formal->string;
                }
                else
                {
                    LIST* value = 0;
                    char modifier;
                    LIST* arg_name = formal; /* hold the argument name for type checking */
                    int multiple = 0;

                    /* Stop now if a variable number of arguments are specified */
                    if ( name[0] == '*' && name[1] == 0 )
                        return locals;

                    modifier = arg_modifier( formal );

                    if ( !actual && modifier != '?' && modifier != '*' )
                        argument_error( "missing argument", rule, frame, formal );

                    switch ( modifier )
                    {
                    case '+':
                    case '*':
                        value = list_copy( 0, actual );
                        multiple = 1;
                        actual = 0;
                        /* skip an extra element for the modifier */
                        formal = formal->next;
                        break;
                    case '?':
                        /* skip an extra element for the modifier */
                        formal = formal->next;
                        /* fall through */
                    default:
                        if ( actual ) /* in case actual is missing */
                        {
                            value = list_new( 0, actual->string );
                            actual = actual->next;
                        }
                    }

                    locals = addsettings(locals, VAR_SET, name, value);
                    locals->multiple = multiple;
                    type_check( type_name, value, frame, rule, arg_name );
                    type_name = 0;
                }
            }

            if ( actual )
            {
                argument_error( "extra argument", rule, frame, actual );
            }
        }
    }
    return locals;
}
コード例 #17
0
ファイル: compile.c プロジェクト: caryhaynie/jamplus
LIST *
evaluate_rule(
	const char *rulename,
	LOL	*args, 
	LIST	*result )
{
#ifdef OPT_EXPAND_RULE_NAMES_EXT
	RULE	*rule;
	char	*expanded;
	char	*c;
	int i;
	BUFFER	buff;

	buffer_init( &buff );

	if( (i = var_string( rulename, &buff, 0, args, ' ' )) < 0 )
	{
	    printf( "Failed to expand rule %s -- expansion too long\n", rulename );
	    exit( EXITBAD );
	}
	expanded = buffer_ptr( &buff );
	while ( expanded[0] == ' ' )
	    expanded++;
	while ( (c = strrchr(expanded, ' ')) )
	    *c = '\0';

	if( DEBUG_COMPILE )
	{
	    debug_compile( 1, rulename );
	    if ( strcmp(rulename, expanded) )
		printf( "-> %s  ", expanded );
	    lol_print( args );
	    printf( "\n" );
	}

	rule = bindrule( expanded );
#else	
	RULE	*rule = bindrule( rulename );

	if( DEBUG_COMPILE )
	{
	    debug_compile( 1, rulename );
	    lol_print( args );
	    printf( "\n" );
	}
#endif

#ifdef OPT_LOAD_MISSING_RULE_EXT
	if( !rule->actions && !rule->procedure )
	{
		if( ruleexists( "FindMissingRule" ) )
		{
			LOL lol;
			LIST *args = list_append( L0, expanded, 0 );
			LIST *result;

			lol_init( &lol );
			lol_add( &lol, args );
			result = evaluate_rule( "FindMissingRule", &lol, L0 );
			lol_free( &lol );

			if( list_first( result ) ) {
				rule = bindrule( list_value( list_first( result ) ) );
			}

			list_free( result );
		}
	}
#endif /* OPT_LOAD_MISSING_RULE_EXT */

	/* Check traditional targets $(<) and sources $(>) */

#ifdef OPT_IMPROVED_WARNINGS_EXT
	if( !rule->actions && !rule->procedure && !globs.silence )
	    printf( "warning: unknown rule %s %s\n", rule->name,
		   file_and_line());
#else
	if( !rule->actions && !rule->procedure )
	    printf( "warning: unknown rule %s\n", rule->name );
#endif

	/* If this rule will be executed for updating the targets */
	/* then construct the action for make(). */

	if( rule->actions )
	{
	    TARGETS	*t;
	    ACTION	*action;

	    /* The action is associated with this instance of this rule */

	    action = (ACTION *)malloc( sizeof( ACTION ) );
	    memset( (char *)action, '\0', sizeof( *action ) );

	    action->rule = rule;
#ifdef OPT_BUILTIN_NEEDS_EXT
	    action->targets = targetlist( (TARGETS *)0, lol_get( args, 0 ), 0 );
	    action->sources = targetlist( (TARGETS *)0, lol_get( args, 1 ), 0 );
	    action->autosettings = targetlist( (TARGETS *)0, lol_get( args, 2 ), 0 );
#else
	    action->targets = targetlist( (TARGETS *)0, lol_get( args, 0 ) );
	    action->sources = targetlist( (TARGETS *)0, lol_get( args, 1 ) );
#endif
#ifdef OPT_USE_CHECKSUMS_EXT
	    action->extratargets = targetlist( (TARGETS *)0, lol_get( args, 3 ), 0 );
#endif /* OPT_USE_CHECKSUMS_EXT */

#ifdef OPT_CLEAN_GLOBS_EXT
		{
			TARGETS* targets;
			for ( targets = action->targets; targets; targets = targets->next ) {
				if ( !( targets->target->flags & T_FLAG_NOTFILE ) )
					add_used_target_to_hash( targets->target );
			}
		}
#endif /* OPT_CLEAN_GLOBS_EXT */

	    /* Append this action to the actions of each target */

#ifdef OPT_MULTIPASS_EXT
	    action->pass = actionpass;
	    for( t = action->targets; t; t = t->next ) {
		t->target->progress = T_MAKE_INIT;
		t->target->actions = actionlist( t->target->actions, action );
	    }
#else
	    for( t = action->targets; t; t = t->next )
		t->target->actions = actionlist( t->target->actions, action );
#endif
	}

	/* Now recursively compile any parse tree associated with this rule */

	if( rule->procedure )
	{
	    PARSE *parse = rule->procedure;
	    SETTINGS *s = 0;
	    int jmp = JMP_NONE;
	    LISTITEM *l;
	    int i;

	    /* build parameters as local vars */
	    for( l = list_first(rule->params), i = 0; l; l = list_next(l), i++ )
		s = addsettings( s, 0, list_value(l), 
		    list_copy( L0, lol_get( args, i ) ) );

	    /* Run rule. */
	    /* Bring in local params. */
	    /* refer/free to ensure rule not freed during use. */

	    parse_refer( parse );

	    pushsettings( s );
	    result = list_appendList( result, (*parse->func)( parse, args, &jmp ) );
	    popsettings( s );
	    freesettings( s );

	    parse_free( parse );
	}

	if( DEBUG_COMPILE )
	    debug_compile( -1, 0 );

#ifdef OPT_EXPAND_RULE_NAMES_EXT
	buffer_free( &buff );
#endif

	return result;
}
コード例 #18
0
ファイル: compile.c プロジェクト: GustavoMOG/edelib
LIST *
evaluate_rule(
	const char *rulename,
	LOL	*args, 
	LIST	*result,
	int	*jmp )
{
	RULE	*rule = bindrule( rulename );

	if( DEBUG_COMPILE )
	{
	    debug_compile( 1, rulename );
	    lol_print( args );
	    printf( "\n" );
	}

	/* Check traditional targets $(<) and sources $(>) */

	if( !rule->actions && !rule->procedure )
	    printf( "warning: unknown rule %s\n", rule->name );

	/* If this rule will be executed for updating the targets */
	/* then construct the action for make(). */

	if( rule->actions )
	{
	    TARGETS	*t;
	    ACTION	*action;

	    /* The action is associated with this instance of this rule */

	    action = (ACTION *)malloc( sizeof( ACTION ) );
	    memset( (char *)action, '\0', sizeof( *action ) );

	    action->rule = rule;
	    action->targets = targetlist( (TARGETS *)0, lol_get( args, 0 ) );
	    action->sources = targetlist( (TARGETS *)0, lol_get( args, 1 ) );

	    /* Append this action to the actions of each target */

	    for( t = action->targets; t; t = t->next )
		t->target->actions = actionlist( t->target->actions, action );
	}

	/* Now recursively compile any parse tree associated with this rule */

	if( rule->procedure )
	{
	    PARSE *parse = rule->procedure;
	    SETTINGS *s = 0;
	    LIST *l;
	    int i;

# ifdef OPT_RULE_PROFILING_EXT
		struct timeval startTime, endTime;

		if ( DEBUG_PROFILE_RULES )
			gettimeofday(&startTime, 0);
# endif

	    /* build parameters as local vars */

	    for( l = rule->params, i = 0; l; l = l->next, i++ )
		s = addsettings( s, 0, l->string, 
		    list_copy( L0, lol_get( args, i ) ) );

	    /* Run rule. */
	    /* Bring in local params. */
	    /* refer/free to ensure rule not freed during use. */

	    parse_refer( parse );

	    pushsettings( s );
	    result = list_append( result, (*parse->func)( parse, args, jmp ) );
	    popsettings( s );
	    freesettings( s );

	    parse_free( parse );

# ifdef OPT_RULE_PROFILING_EXT
		if ( DEBUG_PROFILE_RULES )
		{
			gettimeofday(&endTime, 0);

			rule->invocations++;
			rule->invocation_time
				+= (endTime.tv_sec - startTime.tv_sec) * (int64_t)1000000
					+ (endTime.tv_usec - startTime.tv_usec);
		}
# endif

	}

	if( DEBUG_COMPILE )
	    debug_compile( -1, 0 );

	return result;
}
コード例 #19
0
ファイル: make1.c プロジェクト: 0xb1dd1e/jamplus
static CMD *
make1cmds( ACTIONS *a0 )
#endif
{
	CMD *cmds = 0;
	LIST *shell = var_get( "JAMSHELL" );	/* shell is per-target */

	/* Step through actions */
	/* Actions may be shared with other targets or grouped with */
	/* RULE_TOGETHER, so actions already seen are skipped. */

	for( ; a0; a0 = a0->next )
	{
	    RULE    *rule = a0->action->rule;
	    SETTINGS *boundvars;
	    LIST    *nt, *ns;
	    ACTIONS *a1;
	    int	    start, chunk, length, maxline;
		TARGETS *autosettingsreverse = 0;
		TARGETS *autot;

#ifdef OPT_MULTIPASS_EXT
	    if ( a0->action->pass != actionpass )
		continue;
#endif

	    /* Only do rules with commands to execute. */
	    /* If this action has already been executed, use saved status */

#ifdef OPT_DEBUG_MAKE1_LOG_EXT
	    if (DEBUG_MAKE1) {
		printf( "make1cmds\t--\t%s (actions %s, running %s)\n" ,
			rule->name,
			rule->actions ? "yes" : "no",
			a0->action->running ? "yes" : "no" );
	    }
#endif
	    if( !rule->actions || a0->action->running )
		continue;

#ifdef OPT_REMOVE_EMPTY_DIRS_EXT
		if ( rule->flags & RULE_REMOVEEMPTYDIRS ) {
			for( a1 = a0; a1; a1 = a1->next ) {
				TARGETS* sources;
				for ( sources = a1->action->sources; sources; sources = sources->next ) {
					emptydirtargets = list_new( emptydirtargets, sources->target->name, 1 );
				}
			}
		}
#endif

		for ( autot = a0->action->autosettings; autot; autot = autot->next ) {
			if ( autot->target != t )
				pushsettings( autot->target->settings );
			autosettingsreverse = targetentryhead( autosettingsreverse, autot->target, 0 );
		}
		pushsettings( t->settings );
	    a0->action->running = 1;
#ifdef OPT_ACTIONS_WAIT_FIX
	    a0->action->run_tgt = t;
#endif

	    /* Make LISTS of targets and sources */
	    /* If `execute together` has been specified for this rule, tack */
	    /* on sources from each instance of this rule for this target. */
#ifdef OPT_DEBUG_MAKE1_LOG_EXT
	    if (DEBUG_MAKE1) {
		LIST *list = make1list(L0, a0->action->targets, 0);
		printf("make1cmds\t--\ttargets: ");
		list_print(list);
		list_free(list);
		printf("\n");
		list = make1list(L0, a0->action->sources, 0);
		printf("make1cmds\t--\tsources: ");
		list_print(list);
		list_free(list);
		printf("\n");
	    }
#endif

#ifdef OPT_BUILTIN_MD5CACHE_EXT
	    if (t->filecache_generate  ||  t->filecache_use)
	    {
		LIST* targets = make1list_unbound( L0, a0->action->targets, 0 );
		LIST* sources = make1list_unbound( L0, a0->action->sources, rule->flags );

		nt = L0;
		ns = L0;

		if ( strncmp( rule->name, "batched_", 8 ) == 0 )
		{
		    int anycacheable = 0;
		    for( ; targets; targets = targets->next, sources = ( sources == NULL ? sources : sources->next ) )
		    {
			TARGET *t = bindtarget(targets->string);
			TARGET *s = sources!=NULL ? bindtarget(sources->string) : NULL;

			/* if this target could be cacheable */
			if ( (t->flags & T_FLAG_USEFILECACHE) && (t->filecache_generate  ||  t->filecache_use) ) {
			    /* find its final md5sum */
			    MD5_CTX context;
			    MD5SUM buildsumorg;
			    anycacheable = 1;
			    memcpy(&buildsumorg, &t->buildmd5sum, sizeof(t->buildmd5sum));
			    MD5Init( &context );
			    MD5Update( &context, t->buildmd5sum, sizeof( t->buildmd5sum ) );
			    {
				TARGET *outt = bindtarget( t->boundname );
				outt->flags |= T_FLAG_USEFILECACHE;
				MD5Final( outt->buildmd5sum, &context );
				memcpy(&t->buildmd5sum, &outt->buildmd5sum, sizeof(t->buildmd5sum));
			    }
			    if (DEBUG_MD5HASH) {
				printf( "Cacheable: %s buildmd5: %s org: %s\n",
				    t->boundname, md5tostring(t->buildmd5sum), md5tostring(buildsumorg) );
			    }

			    /* if using cache is allowed */
			    if (t->filecache_use) {
				const char *cachedname;

				/* if the target is available in the cache */
				cachedname = filecache_getfilename(t, t->buildmd5sum, ".doesntwork");
				if (cachedname!=NULL) {
				    time_t cachedtime;
				    if ( file_time( cachedname, &cachedtime ) == 0 )
				    {
					/* try to get it from the cache */
					if (copyfile(t->boundname, cachedname, NULL)) {
					    printf( "Using cached %s\n", t->name );
					    continue;
					} else {
					    printf( "Cannot retrieve %s from cache (will build normally)\n", t->name );
					}
				    } else {
					if( DEBUG_MD5HASH) {
					    printf( "Cannot find %s in cache as %s\n", t->name, cachedname );
					}
				    }
				}
			    }
			    /* Build new lists */

			    nt = list_new( nt, t->boundname, 1 );
			    if (s)
				ns = list_new( ns, s->boundname, 1 );
			}
		    }

		    if ( !anycacheable ) {
			nt = make1list( L0, a0->action->targets, 0 );
			ns = make1list( L0, a0->action->sources, rule->flags );
		    }
		}
		else
		{
		    int allcached = 1;
		    popsettings( t->settings );
		    for( ; targets; targets = list_next(targets) )
		    {
			TARGET *t = bindtarget(targets->string);
//			TARGET *s = sources!=NULL ? bindtarget(sources->string) : NULL;
			TARGETS *c;
			TARGET *outt;
			LIST *filecache = 0;

			if ( t->flags & T_FLAG_USEFILECACHE )
			{
			    pushsettings( t->settings );
			    filecache = filecache_fillvalues( t );
			    popsettings( t->settings );
			}

			/* if this target could be cacheable */
			if ( (t->flags & T_FLAG_USEFILECACHE) && (t->filecache_generate  ||  t->filecache_use) ) {
			    /* find its final md5sum */
			    MD5_CTX context;

			    if( DEBUG_MD5HASH ) {
				printf( "------------------------------------------------\n" );
				printf( "------------------------------------------------\n" );
				printf( "------------------------------------------------\n" );
			    }

			    /* sort all dependents by name, so we can make reliable md5sums */
			    t->depends = make0sortbyname( t->depends );

			    MD5Init( &context );

			    /* add the path of the file to the sum - it is significant because one command can create more than one file */
			    MD5Update( &context, (unsigned char*)t->name, (unsigned int)strlen( t->name ) );

			    /* add in the COMMANDLINE */
			    if ( t->flags & T_FLAG_USECOMMANDLINE )
			    {
				SETTINGS *vars;
				for ( vars = t->settings; vars; vars = vars->next )
				{
				    if ( vars->symbol[0] == 'C'  &&  strcmp( vars->symbol, "COMMANDLINE" ) == 0 )
				    {
					LIST *list;
					for ( list = vars->value; list; list = list->next )
					{
					    MD5Update( &context, (unsigned char*)list->string, (unsigned int)strlen( list->string ) );
					    if( DEBUG_MD5HASH )
						printf( "\t\tCOMMANDLINE: %s\n", list->string );
					}

					break;
				    }
				}
			    }

			    /* for each dependencies */
			    for( c = t->depends; c; c = c->next )
			    {
				/* If this is a "Needs" dependency, don't care about its contents. */
				if (c->needs)
				{
				    continue;
				}

				/* add name of the dependency and its contents */
				make0calcmd5sum( c->target, 1 );
				if ( c->target->buildmd5sum_calculated )
				{
				    MD5Update( &context, (unsigned char*)c->target->name, (unsigned int)strlen( c->target->name ) );
				    MD5Update( &context, c->target->buildmd5sum, sizeof( c->target->buildmd5sum ) );
				}
			    }

			    outt = bindtarget( t->boundname );
			    outt->flags |= T_FLAG_USEFILECACHE;
			    outt->filecache_generate = t->filecache_generate;
			    outt->filecache_use = t->filecache_use;
			    outt->settings = addsettings( outt->settings, VAR_SET, "FILECACHE", list_new( L0, filecache->string, 1 ) );
			    MD5Final( outt->buildmd5sum, &context );
			    if (DEBUG_MD5HASH)
			    {
				printf( "Cacheable: %s buildmd5: %s\n", t->boundname, md5tostring(outt->buildmd5sum) );
			    }

			    /* if using cache is allowed */
			    if ( t->filecache_use  &&  allcached )
			    {
				allcached = filecache_retrieve( t, outt->buildmd5sum );
			    }
			    else
			    {
				allcached = 0;
			    }
			}
			else
			{
			    allcached = 0;
			}
		    }
		    pushsettings( t->settings );

		    if ( !allcached ) {
			nt = make1list( L0, a0->action->targets, 0 );
			ns = make1list( L0, a0->action->sources, rule->flags );
		    }
		}
		list_free( targets );
		list_free( sources );

		/* if no targets survived (all were retrieved from the cache)
		or no sources survived (all are up to date) */
		if (nt==NULL) { // || ns==NULL) {
		    /* skip this action */
		    list_free(ns);
			popsettings( t->settings );
			for ( autot = autosettingsreverse; autot; autot = autot->next ) {
				if ( autot->target != t )
					pushsettings( autot->target->settings );
			}
		    continue;
		}
	    }
	    else
	    {
#if 0
		if ( strncmp( rule->name, "batched_", 8 ) == 0 )
		{
			TARGETS* targets = a0->action->targets;
			TARGETS* sources = a0->action->sources;
		    int anycacheable = 0;

			nt = L0;
			ns = L0;

			/* walk sources and targets simultaneously */
			for( ; targets; targets = targets->next, sources = (sources==NULL?sources:sources->next) )
			{
				TARGET *t = targets->target;
				TARGET *s = sources!=NULL ? sources->target : NULL;

				/* Sources to 'actions existing' are never in the dependency */
				/* graph (if they were, they'd get built and 'existing' would */
				/* be superfluous, so throttle warning message about independent */
				/* targets. */

				if( t->binding == T_BIND_UNBOUND )
					make1bind( t, 0 );
				if( s!=NULL) {
					if ( s->binding == T_BIND_UNBOUND )
						make1bind( s, !( rule->flags & RULE_EXISTING ) );
					if ( s->binding == T_BIND_UNBOUND )
						printf("Warning using unbound source %s for batched action.\n", s->name);
				}


				if( ( rule->flags & RULE_EXISTING ) && s!=NULL && s->binding != T_BIND_EXISTS )
					continue;

				if( t->fate < T_FATE_BUILD )
					continue;

				/* Build new lists */

				nt = list_new( nt, t->boundname, 1 );
				if (s!=NULL) {
					ns = list_new( ns, s->boundname, 1 );
				}
			}

			if (sources!=NULL) {
				printf("warning: more sources than targets in a batched action!\n");
			}

		} else {
#endif
			nt = make1list( L0, a0->action->targets, 0 );
			ns = make1list( L0, a0->action->sources, rule->flags );
#if 0
	    }
#endif
		}
#else
	    nt = make1list( L0, a0->action->targets, 0 );
	    ns = make1list( L0, a0->action->sources, rule->flags );
#endif

	    if( rule->flags & RULE_TOGETHER )
		for( a1 = a0->next; a1; a1 = a1->next )
#ifdef OPT_MULTIPASS_EXT
		    if( a1->action->pass == actionpass && a1->action->rule == rule && !a1->action->running )
#else
		    if( a1->action->rule == rule && !a1->action->running )
#endif
	    {
		ns = make1list( ns, a1->action->sources, rule->flags );
		a1->action->running = 1;
#ifdef OPT_ACTIONS_WAIT_FIX
		a1->action->run_tgt = t;
#endif
	    }

	    /* If doing only updated (or existing) sources, but none have */
	    /* been updated (or exist), skip this action. */

	    if( !ns && ( rule->flags & ( RULE_UPDATED | RULE_EXISTING ) ) )
	    {
		list_free( nt );
#ifdef OPT_DEBUG_MAKE1_LOG_EXT
		if (DEBUG_MAKE1) {
		    const char* desc = 0;
		    if ((rule->flags & (RULE_UPDATED | RULE_EXISTING))
			== (RULE_UPDATED | RULE_EXISTING)) {
			desc = "updated/existing";
		    } else if (rule->flags & RULE_UPDATED) {
			desc = "updated";
		    } else if (rule->flags & RULE_EXISTING) {
			desc = "existing";
		    }
		    printf( "make1cmds\t--\t%s (skipping actions by %s)\n" ,
			    rule->name, desc );
		}
#endif /* OPT_DEBUG_MAKE1_LOG_EXT */
			popsettings( t->settings );
			for ( autot = autosettingsreverse; autot; autot = autot->next ) {
				if ( autot->target != t )
					pushsettings( autot->target->settings );
			}
		continue;
	    }

	    /* If we had 'actions xxx bind vars' we bind the vars now */

	    boundvars = make1settings( rule->bindlist );
	    pushsettings( boundvars );

	    /*
	     * Build command, starting with all source args.
	     *
	     * If cmd_new returns 0, it's because the resulting command
	     * length is > MAXLINE.  In this case, we'll slowly reduce
	     * the number of source arguments presented until it does
	     * fit.  This only applies to actions that allow PIECEMEAL
	     * commands.
	     *
	     * While reducing slowly takes a bit of compute time to get
	     * things just right, it's worth it to get as close to MAXLINE
	     * as possible, because launching the commands we're executing
	     * is likely to be much more compute intensive!
	     *
	     * Note we loop through at least once, for sourceless actions.
	     *
	     * Max line length is the action specific maxline or, if not
	     * given or bigger than MAXLINE, MAXLINE.
	     */

	    start = 0;
	    chunk = length = list_length( ns );
/* commented out so jamgram.y can compile #ifdef OPT_ACTION_MAXTARGETS_EXT */
	    maxline = rule->maxline;
/* commented so jamgram.y can compile #else
	    maxline = rule->flags / RULE_MAXLINE;
#endif */
#ifdef OPT_PIECEMEAL_PUNT_EXT
	    maxline = maxline && maxline < CMDBUF ? maxline : CMDBUF;
#else
	    maxline = maxline && maxline < MAXLINE ? maxline : MAXLINE;
#endif

	    do
	    {
		/* Build cmd: cmd_new consumes its lists. */
/* commented out so jamgram.y can compile #ifdef OPT_ACTION_MAXTARGETS_EXT */
		int thischunk = rule->maxtargets != 0 ? (chunk < rule->maxtargets ? chunk : rule->maxtargets) : chunk;

		CMD *cmd = cmd_new( rule,
			list_copy( L0, nt ),
			list_sublist( ns, start, thischunk ),
			list_copy( L0, shell ),
			maxline );
/* commented so jamgram.y can compile #else
		CMD *cmd = cmd_new( rule,
			list_copy( L0, nt ),
			list_sublist( ns, start, chunk ),
			list_copy( L0, shell ),
			maxline );
#endif */

		if( cmd )
		{
		    /* It fit: chain it up. */

		    if( !cmds ) cmds = cmd;
		    else cmds->tail->next = cmd;
		    cmds->tail = cmd;
/* commented out so jamgram.y can compile #ifdef OPT_ACTION_MAXTARGETS_EXT */
		    start += thischunk;
/* commented out so jamgram.y can compile #else
		    start += chunk;
#endif */
		}
		else if( ( rule->flags & RULE_PIECEMEAL ) && chunk > 1 )
		{
		    /* Reduce chunk size slowly. */

		    chunk = chunk * 9 / 10;
		}
		else
		{
		    /* Too long and not splittable. */

#ifdef OPT_PIECEMEAL_PUNT_EXT
		    if (maxline < CMDBUF) {
			maxline = CMDBUF;
			continue;
		    }
#endif
		    printf( "%s actions too long (max %d)!\n",
			rule->name, maxline );
		    exit( EXITBAD );
		}
	    }
	    while( start < length );

	    /* These were always copied when used. */

	    list_free( nt );
	    list_free( ns );

	    /* Free the variables whose values were bound by */
	    /* 'actions xxx bind vars' */

	    popsettings( boundvars );
	    freesettings( boundvars );

		popsettings( t->settings );
		for ( autot = autosettingsreverse; autot; autot = autot->next ) {
			if ( autot->target != t )
				pushsettings( autot->target->settings );
		}
	}

	return cmds;
}