예제 #1
0
파일: make.c 프로젝트: GustavoMOG/edelib
int
make( 
	int		n_targets,
	const char	**targets,
	int		anyhow )
{
	int i;
	COUNTS counts[1];
	int status = 0;		/* 1 if anything fails */

#ifdef OPT_HEADER_CACHE_EXT
	hcache_init();
#endif

	memset( (char *)counts, 0, sizeof( *counts ) );

	for( i = 0; i < n_targets; i++ )
	{
	    TARGET *t = bindtarget( targets[i] );

	    make0( t, 0, 0, counts, anyhow );
	}

	if( DEBUG_MAKE )
	{
	    if( counts->targets )
		printf( "...found %d target(s)...\n", counts->targets );
	    if( counts->temp )
		printf( "...using %d temp target(s)...\n", counts->temp );
	    if( counts->updating )
		printf( "...updating %d target(s)...\n", counts->updating );
	    if( counts->cantfind )
		printf( "...can't find %d target(s)...\n", counts->cantfind );
	    if( counts->cantmake )
		printf( "...can't make %d target(s)...\n", counts->cantmake );
	}

#ifdef OPT_HEADER_CACHE_EXT
	hcache_done();
#endif

	status = counts->cantfind || counts->cantmake;

	for( i = 0; i < n_targets; i++ )
	    status |= make1( bindtarget( targets[i] ) );

	return status;
}
예제 #2
0
파일: builtins.c 프로젝트: larus/jamplus
LIST *
builtin_md5file(
	PARSE	*parse,
	LOL	*args,
	int	*jmp )
{
	MD5_CTX context;
	unsigned char digest[16];
	unsigned char digest_string[33];
	unsigned char* p;
	int i;
	LIST *l;
	LIST *result;

	const size_t BUFFER_SIZE = 100 * 1024;
	unsigned char* buffer = (unsigned char*)malloc(BUFFER_SIZE);

	MD5Init(&context);

	/* For each argument */
	for (i = 0; i < args->count; ++i) {
	    l = lol_get(args, i);
	    if (l) {
		do {
			FILE* file;
			TARGET *t = bindtarget(l->string);
			pushsettings( t->settings );
			t->boundname = search( t->name, &t->time );
			popsettings( t->settings );
		    file = fopen(t->boundname, "rb");
		    if (file) {
			size_t readSize;

			do
			{
			    readSize = fread(buffer, 1, BUFFER_SIZE, file);
			    MD5Update(&context, buffer, readSize);
			} while (readSize != 0);

			fclose(file);
		    }

		    l = list_next(l);
		} while (l);
	    }
	}

	free(buffer);

	MD5Final(digest, &context);
	p = digest_string;
	for (i = 0, p = digest_string; i < 16; i++, p += 2) {
	    sprintf((char*)p, "%02x", digest[i]);
	}
	*p = 0;

	result = list_new(L0, (const char*)digest_string, 0);

	return result;
}
예제 #3
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;
}
예제 #4
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;
}
예제 #5
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;
}
예제 #6
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;
}
예제 #7
0
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));
	pushsettings(t->settings);
	var_set(ls_lua_tostring(L, 2), luahelper_addtolist(L, L0, 3), VAR_SET);
	popsettings(t->settings);
    }

    return 0;
}
예제 #8
0
파일: hcache.c 프로젝트: larus/jamplus
/*
 * Get a filename in cache for given md5sum.
 */
const char *filecache_getpath(TARGET *t)
{
	char buffer[1024];
	LIST *filecache;
	const char *cachedir = NULL;
	LIST *cachevar;

	pushsettings( t->settings );
	filecache = var_get( "FILECACHE" );
	if ( !filecache ) {
		popsettings( t->settings );
		return NULL;
	}

	/* get directory where objcache should reside */
	strcpy( buffer, filecache->string );
	strcat( buffer, ".PATH" );
	cachevar = var_get( buffer );
	if( cachevar ) {
		TARGET *t = bindtarget( cachevar->string );
		t->boundname = search( t->name, &t->time );
		cachedir = copystr( t->boundname );
	}

	popsettings( t->settings );

	return cachedir;
}
예제 #9
0
파일: hcache.c 프로젝트: 0xDEC0DE8/mcsema
static const char * cache_name( void )
{
    static OBJECT * name = 0;
    if ( !name )
    {
        LIST * hcachevar = var_get( root_module(), constant_HCACHEFILE );

        if ( !list_empty( hcachevar ) )
        {
            TARGET * t = bindtarget( list_front( hcachevar ) );

            pushsettings( root_module(), t->settings );
            /* Do not expect the cache file to be generated, so pass 0 as the
             * third argument to search. Expect the location to be specified via
             * LOCATE, so pass 0 as the fourth arugment.
             */
            object_free( t->boundname );
            t->boundname = search( t->name, &t->time, 0, 0 );
            popsettings( root_module(), t->settings );

            name = object_copy( t->boundname );
        }
    }
    return name ? object_str( name ) : 0;
}
예제 #10
0
static const char * cache_name( void )
{
    static OBJECT * name = 0;
    if ( !name )
    {
        OBJECT * hcachename = object_new( "HCACHEFILE" );
        LIST * hcachevar = var_get( hcachename );
        object_free( hcachename );

        if ( hcachevar )
        {
            TARGET * t = bindtarget( hcachevar->value );

            pushsettings( t->settings );
            /* Do not expect the cache file to be generated, so pass 0 as the
             * third argument to search. Expect the location to be specified via
             * LOCATE, so pass 0 as the fourth arugment.
             */
            object_free( t->boundname );
            t->boundname = search( t->name, &t->time, 0, 0 );
            popsettings( t->settings );

            if ( hcachevar )
                name = object_copy( t->boundname );
        }
    }
    return name ? object_str( name ) : 0;
}
예제 #11
0
파일: compile.c 프로젝트: Albermg7/boost
LIST *
compile_on(
	PARSE	*parse,
	FRAME	*frame )
{
	LIST    *nt = parse_evaluate( parse->left, frame );
	LIST	*result = 0;

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

	if( nt )
	{
	    TARGET *t = bindtarget( nt->string );
	    pushsettings( t->settings );

	    result = parse_evaluate( parse->right, frame );

	    popsettings( t->settings );
	}

	list_free( nt );

	return result;
}
예제 #12
0
파일: rules.c 프로젝트: Albermg7/boost
TARGETS *
targetlist( 
	TARGETS	*chain,
	LIST 	*targets )
{
	for( ; targets; targets = list_next( targets ) )
	    chain = targetentry( chain, bindtarget( targets->string ) );

	return chain;
}
예제 #13
0
LIST *
builtin_flags(
	PARSE	*parse,
	FRAME *frame )
{
	LIST *l = lol_get( frame->args, 0 );

	for( ; l; l = list_next( l ) )
	    bindtarget( l->string )->flags |= parse->num;

	return L0;
}
예제 #14
0
파일: builtins.c 프로젝트: larus/jamplus
LIST *
builtin_flags(
	PARSE	*parse,
	LOL	*args,
	int	*jmp )
{
	LIST *l = lol_get( args, 0 );

	for( ; l; l = list_next( l ) )
	    bindtarget( l->string )->flags |= parse->num;

	return L0;
}
예제 #15
0
LIST *
builtin_depends(
	PARSE	*parse,
	FRAME *frame )
{
	LIST *targets = lol_get( frame->args, 0 );
	LIST *sources = lol_get( frame->args, 1 );
	LIST *l;

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

	    /* If doing INCLUDES, switch to the TARGET's include */
	    /* TARGET, creating it if needed.  The internal include */
	    /* TARGET shares the name of its parent. */

	    if( parse->num )
	    {
            if( !t->includes ) {
                t->includes = copytarget( t );
                t->includes->original_target = t;
            }
            t = t->includes;
	    }

	    t->depends = targetlist( t->depends, sources );
	}

    /* Enter reverse links */
	for( l = sources; l; l = list_next( l ) )
	{
	    TARGET *s = bindtarget( l->string );
        s->dependents = targetlist( s->dependents, targets );
    }

	return L0;
}
예제 #16
0
파일: make1.c 프로젝트: AlexMioMio/boost
/* push the next MAKE1C state after a command is run. */
static void push_cmds( CMDLIST * cmds, int status )
{
    CMDLIST * cmd_iter;
    for( cmd_iter = cmds; cmd_iter; cmd_iter = cmd_iter->next )
    {
        if ( cmd_iter->iscmd )
        {
            CMD * next_cmd = cmd_iter->impl.cmd;
            /* Propagate the command status. */
            if ( next_cmd->status < status )
                next_cmd->status = status;
            if ( --next_cmd->asynccnt == 0 )
            {
                /* Select the first target associated with the action.
                 * This is safe because sibling CMDs cannot have targets
                 * in common.
                 */
                TARGET * first_target = bindtarget( list_front( lol_get( &next_cmd->args, 0 ) ) );
                first_target->cmds = (char *)next_cmd;
                push_state( &state_stack, first_target, NULL, T_STATE_MAKE1C );
            }
            else if ( DEBUG_EXECCMD )
            {
                TARGET * first_target = bindtarget( list_front( lol_get( &next_cmd->args, 0 ) ) );
                printf( "Delaying %s %s: %d targets not ready\n", object_str( next_cmd->rule->name ), object_str( first_target->boundname ), next_cmd->asynccnt );
            }
        }
        else
        {
            /* This is a target that we're finished updating */
            TARGET * updated_target = cmd_iter->impl.t;
            if ( updated_target->status < status )
                updated_target->status = status;
            updated_target->cmds = NULL;
            push_state( &state_stack, updated_target, NULL, T_STATE_MAKE1C );
        }
    }
}
예제 #17
0
파일: builtins.c 프로젝트: larus/jamplus
LIST *
builtin_flags_nocare(
	PARSE	*parse,
	LOL	*args,
	int	*jmp )
{
	LIST *l = lol_get( args, 0 );

	for( ; l; l = list_next( l ) ) {
		TARGET* t = bindtarget( l->string );
		if ( ! ( t->flags & T_FLAG_FORCECARE ) )
			t->flags |= T_FLAG_NOCARE;
	}

	return L0;
}
예제 #18
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;
}
예제 #19
0
파일: builtins.c 프로젝트: larus/jamplus
LIST *
builtin_depends(
	PARSE	*parse,
	LOL	*args,
	int	*jmp )
{
    int curindex = 0;
    while ( 1 )
    {
	LIST *targets = lol_get( args, curindex );
	LIST *sources = lol_get( args, curindex + 1 );
	LIST *l;

	if ( !sources )
	    break;

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

	    /* If doing INCLUDES, switch to the TARGET's include */
	    /* TARGET, creating it if needed.  The internal include */
	    /* TARGET shares the name of its parent. */

#ifdef OPT_BUILTIN_NEEDS_EXT
	    if( parse->num==1 )
#else
	    if( parse->num )
#endif
	    {
		if( !t->includes )
		    t->includes = copytarget( t );
		t = t->includes;
	    }

#ifdef OPT_BUILTIN_NEEDS_EXT
	    t->depends = targetlist( t->depends, sources, (char)(parse->num==2) );
#else
	    t->depends = targetlist( t->depends, sources );
#endif
	}

	++curindex;
    }

    return L0;
}
예제 #20
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;
}
예제 #21
0
LIST *
builtin_rebuilds(
	PARSE	*parse,
	FRAME *frame )
{
	LIST *targets = lol_get( frame->args, 0 );
	LIST *rebuilds = lol_get( frame->args, 1 );
	LIST *l;

	for( l = targets; l; l = list_next( l ) )
	{
	    TARGET *t = bindtarget( l->string );
	    t->rebuilds = targetlist( t->rebuilds, rebuilds );
	}

	return L0;
}
예제 #22
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;
}
예제 #23
0
파일: compile.c 프로젝트: Albermg7/boost
LIST *
compile_include(
    PARSE   *parse,
    FRAME *frame )
{
    LIST    *nt = parse_evaluate( parse->left, frame );

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

    if( nt )
    {
        TARGET *t = bindtarget( nt->string );

            /* DWA 2001/10/22 - Perforce Jam clears the arguments here, which
             * prevents an included file from being treated as part of the body
             * of a rule. I didn't see any reason to do that, so I lifted the
             * restriction.
             */
               
        /* Bind the include file under the influence of */
        /* "on-target" variables.  Though they are targets, */
        /* include files are not built with make(). */

        pushsettings( t->settings );
        /* We don't expect that file to be included is generated by some
           action. Therefore, pass 0 as third argument. */
        t->boundname = search( t->name, &t->time, 0 );
        popsettings( t->settings );

        parse_file( t->boundname, frame );
    }

    list_free( nt );

    return L0;
}
예제 #24
0
int LS_jam_getvar(ls_lua_State *L)
{
    LIST *list;
    LISTITEM* item;
    int index;

    int numParams = ls_lua_gettop(L);
    if (numParams < 1  ||  numParams > 2)
        return 0;

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

    if (numParams == 1)
    {
        list = var_get(ls_lua_tostring(L, 1));
    }
    else
    {
        TARGET *t;

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

        t = bindtarget(ls_lua_tostring(L, 1));
        pushsettings(t->settings);
        list = var_get(ls_lua_tostring(L, 2));
        popsettings(t->settings);
    }

    ls_lua_newtable(L);
    index = 1;
    for (item = list_first(list); item; item = list_next(item), ++index)
    {
        ls_lua_pushnumber(L, index);
        ls_lua_pushstring(L, list_value(item));
        ls_lua_settable(L, -3);
    }

    return 1;
}
예제 #25
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;
}
예제 #26
0
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;
}
예제 #27
0
파일: hcache.c 프로젝트: Karlan88/xray
/*
 * Return the name of the header cache file.  May return NULL.
 *
 * The user sets this by setting the HCACHEFILE variable in a Jamfile.
 * We cache the result so the user can't change the cache file during
 * header scanning.
 */
static char*
cache_name(void)
{
    static char* name = 0;
    if (!name) {
	LIST *hcachevar = var_get("HCACHEFILE");

	if (hcachevar) {
	    TARGET *t = bindtarget( hcachevar->string );

	    pushsettings( t->settings );
	    t->boundname = search( t->name, &t->time );
	    popsettings( t->settings );

	    if (hcachevar) {
		name = copystr(t->boundname);
	    }
	}
    }
    return name;
}
예제 #28
0
파일: hcache.c 프로젝트: caryhaynie/jamplus
const char *checksums_filename() {
	LIST *var;
	if ( checksumsfilename ) {
		return checksumsfilename;
	}

	var = var_get( "JAM_CHECKSUMS_FILE" );
	if ( list_first( var ) ) {
		const char *value = list_value( list_first( var ) );
		TARGET *t = bindtarget( value );
		checksumsfilename = copystr( search_using_target_settings( t, t->name, &t->time ) );
	}

	if ( !checksumsfilename ) {
		PATHNAME f[1];
		char buf[ MAXJPATH ];

		var = var_get( "ALL_LOCATE_TARGET" );
		if ( !var ) {
			var = var_get( "CWD" );
		}

		path_parse( ".jamchecksums", f );

		f->f_grist.ptr = 0;
		f->f_grist.len = 0;

		if ( var ) {
			f->f_root.ptr = list_value( list_first( var ) );
			f->f_root.len = (int)( strlen( f->f_root.ptr ) );
		}

		path_build( f, buf, 1, 1 );
		checksumsfilename = newstr( buf );
	}

	return checksumsfilename;
}
예제 #29
0
LIST *
compile_include(
	PARSE	*parse,
	LOL	*args,
	int	*jmp )
{
	LIST	*nt = (*parse->left->func)( parse->left, args, jmp );

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

	if( nt && list_first(nt) )
	{
	    TARGET *t = bindtarget( list_value(list_first(nt)) );

	    /* Bind the include file under the influence of */
	    /* "on-target" variables.  Though they are targets, */
	    /* include files are not built with make(). */
	    /* Needn't copysettings(), as search sets no vars. */

	    pushsettings( t->settings );
	    t->boundname = search( t->name, &t->time );
	    popsettings( t->settings );

	    /* Don't parse missing file if NOCARE set */

	    if( t->time || !( t->flags & T_FLAG_NOCARE ) )
		parse_file( t->boundname );
	}

	list_free( nt );

	return L0;
}
예제 #30
0
/*
 * Return the name of the header cache file.  May return NULL.
 *
 * The user sets this by setting the HCACHEFILE variable in a Jamfile.
 * We cache the result so the user can't change the cache file during
 * header scanning.
 */
static char*
cache_name(void)
{
    static char* name = 0;
    if (!name) {
	LIST *hcachevar = var_get("HCACHEFILE");

	if (hcachevar) {
	    TARGET *t = bindtarget( hcachevar->string );

	    pushsettings( t->settings );
        /* Don't expect cache file to be generated, so pass 0
           as third argument to search. */
	    t->boundname = search( t->name, &t->time, 0 );
	    popsettings( t->settings );

	    if (hcachevar) {
		name = copystr(t->boundname);
	    }
	}
    }
    return name;
}