📄 rules.c
字号:
/*
* Copyright 1993, 1995 Christopher Seiwald.
*
* This file is part of Jam - see jam.c for Copyright information.
*/
# include "jam.h"
# include "lists.h"
# include "parse.h"
# include "variable.h"
# include "rules.h"
# include "newstr.h"
# include "hash.h"
# include "modules.h"
# include "search.h"
# include "lists.h"
# include "pathsys.h"
# include "timestamp.h"
/* This file is ALSO:
* Copyright 2001-2004 David Abrahams.
* Distributed under the Boost Software License, Version 1.0.
* (See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt)
*/
/*
* rules.c - access to RULEs, TARGETs, and ACTIONs
*
* External routines:
*
* bindrule() - return pointer to RULE, creating it if necessary
* bindtarget() - return pointer to TARGET, creating it if necessary
* touchtarget() - mark a target to simulate being new
* targetlist() - turn list of target names into a TARGET chain
* targetentry() - add a TARGET to a chain of TARGETS
* actionlist() - append to an ACTION chain
* addsettings() - add a deferred "set" command to a target
#ifndef OPT_FIX_TARGET_VARIABLES_EXT
* usesettings() - set all target specific variables
#endif
* pushsettings() - set all target specific variables
* popsettings() - reset target specific variables to their pre-push values
* freesettings() - delete a settings list
* donerules() - free RULE and TARGET tables
*
* 04/12/94 (seiwald) - actionlist() now just appends a single action.
* 08/23/94 (seiwald) - Support for '+=' (append to variable)
*/
static void set_rule_actions( RULE* rule, rule_actions* actions );
static void set_rule_body( RULE* rule, argument_list* args, PARSE* procedure );
static struct hash *targethash = 0;
typedef struct _located_target LOCATED_TARGET ;
struct _located_target {
char* file_name;
TARGET* target;
};
static struct hash *located_targets = 0;
/*
* enter_rule() - return pointer to RULE, creating it if necessary in
* target_module.
*/
static RULE *
enter_rule( char *rulename, module_t *target_module )
{
RULE rule, *r = &rule;
r->name = rulename;
if ( hashenter( demand_rules( target_module ), (HASHDATA **)&r ) )
{
r->name = newstr( rulename ); /* never freed */
r->procedure = (PARSE *)0;
r->module = 0;
r->actions = 0;
r->arguments = 0;
r->exported = 0;
r->module = target_module;
#ifdef HAVE_PYTHON
r->python_function = 0;
#endif
}
return r;
}
/*
* define_rule() - return pointer to RULE, creating it if necessary in
* target_module. Prepare it to accept a body or action originating in
* src_module.
*/
static RULE *
define_rule( module_t *src_module, char *rulename, module_t *target_module )
{
RULE *r = enter_rule( rulename, target_module );
if ( r->module != src_module ) /* if the rule was imported from elsewhere, clear it now */
{
set_rule_body( r, 0, 0 );
set_rule_actions( r, 0 );
r->module = src_module; /* r will be executed in the source module */
}
return r;
}
void
rule_free( RULE* r )
{
freestr( r->name );
r->name = "";
parse_free( r->procedure );
r->procedure = 0;
if ( r->arguments )
args_free( r->arguments );
r->arguments = 0;
if ( r->actions )
actions_free( r->actions );
r->actions = 0;
}
/*
* bindtarget() - return pointer to TARGET, creating it if necessary
*/
TARGET *
bindtarget( const char *targetname )
{
TARGET target, *t = ⌖
if( !targethash )
targethash = hashinit( sizeof( TARGET ), "targets" );
/* Perforce added const everywhere. No time to merge that change. */
t->name = (char*)targetname;
if( hashenter( targethash, (HASHDATA **)&t ) )
{
memset( (char *)t, '\0', sizeof( *t ) );
t->name = newstr( (char*)targetname ); /* never freed */
t->boundname = t->name; /* default for T_FLAG_NOTFILE */
}
return t;
}
static void bind_explicitly_located_target(void* xtarget, void* data)
{
TARGET* t = (TARGET*)xtarget;
if (! (t->flags & T_FLAG_NOTFILE) )
{
/* Check if there's a setting for LOCATE */
SETTINGS* s = t->settings;
for(; s ; s = s->next)
{
if (strcmp(s->symbol, "LOCATE") == 0)
{
pushsettings(t->settings);
/* We're binding a target with explicit LOCATE. So
third argument is of now use: nothing will be returned
through it. */
t->boundname = search( t->name, &t->time, 0 );
popsettings(t->settings);
break;
}
}
}
}
void bind_explicitly_located_targets()
{
if (targethash)
hashenumerate(targethash, bind_explicitly_located_target, (void*)0);
}
/* TODO: this is probably not a good idea to use functions in other modules like
that. */
void call_bind_rule(char* target, char* boundname);
TARGET* search_for_target ( char * name, LIST* search_path )
{
PATHNAME f[1];
string buf[1];
LOCATED_TARGET lt, *lta = <
time_t time;
int found = 0;
TARGET* result;
string_new( buf );
path_parse( name, f );
f->f_grist.ptr = 0;
f->f_grist.len = 0;
while( search_path )
{
f->f_root.ptr = search_path->string;
f->f_root.len = strlen( search_path->string );
string_truncate( buf, 0 );
path_build( f, buf, 1 );
lt.file_name = buf->value ;
if (! located_targets )
located_targets = hashinit( sizeof(LOCATED_TARGET),
"located targets" );
if ( hashcheck( located_targets, (HASHDATA **)<a ) )
{
return lta->target;
}
timestamp( buf->value, &time );
if (time)
{
found = 1;
break;
}
search_path = list_next( search_path );
}
if ( ! found )
{
f->f_root.ptr = 0;
f->f_root.len = 0;
string_truncate( buf, 0 );
path_build( f, buf, 1 );
timestamp( buf->value, &time );
}
result = bindtarget( name );
result->boundname = newstr( buf->value );
result->time = time;
result->binding = time ? T_BIND_EXISTS : T_BIND_MISSING;
call_bind_rule( result->name, result->boundname );
string_free( buf );
return result;
}
/*
* copytarget() - make a new target with the old target's name
*
* Not entered into hash table -- for internal nodes.
*/
TARGET *
copytarget( const TARGET *ot )
{
TARGET *t;
t = (TARGET *)malloc( sizeof( *t ) );
memset( (char *)t, '\0', sizeof( *t ) );
t->name = copystr( ot->name );
t->boundname = t->name;
t->flags |= T_FLAG_NOTFILE | T_FLAG_INTERNAL;
return t;
}
/*
* touchtarget() - mark a target to simulate being new
*/
void
touchtarget( char *t )
{
bindtarget( t )->flags |= T_FLAG_TOUCHED;
}
/*
* targetlist() - turn list of target names into a TARGET chain
*
* Inputs:
* chain existing TARGETS to append to
* targets list of target names
*/
TARGETS *
targetlist(
TARGETS *chain,
LIST *targets )
{
for( ; targets; targets = list_next( targets ) )
chain = targetentry( chain, bindtarget( targets->string ) );
return chain;
}
/*
* targetentry() - add a TARGET to a chain of TARGETS
*
* Inputs:
* chain exisitng TARGETS to append to
* target new target to append
*/
TARGETS *
targetentry(
TARGETS *chain,
TARGET *target )
{
TARGETS *c;
c = (TARGETS *)malloc( sizeof( TARGETS ) );
c->target = target;
if( !chain ) chain = c;
else chain->tail->next = c;
chain->tail = c;
c->next = 0;
return chain;
}
/*
* targetchain() - append two TARGET chains
*
* Inputs:
* chain exisitng TARGETS to append to
* target new target to append
*/
TARGETS *
targetchain(
TARGETS *chain,
TARGETS *targets )
{
TARGETS *c;
if( !targets )
return chain;
else if( !chain )
return targets;
chain->tail->next = targets;
chain->tail = targets->tail;
return chain;
}
/*
* actionlist() - append to an ACTION chain
*/
ACTIONS *
actionlist(
ACTIONS *chain,
ACTION *action )
{
ACTIONS *actions = (ACTIONS *)malloc( sizeof( ACTIONS ) );
actions->action = action;
if( !chain ) chain = actions;
else chain->tail->next = actions;
chain->tail = actions;
actions->next = 0;
return chain;
}
static SETTINGS* settings_freelist;
/*
* addsettings() - add a deferred "set" command to a target
*
* Adds a variable setting (varname=list) onto a chain of settings
* for a particular target. Replaces the previous previous value,
* if any, unless 'append' says to append the new list onto the old.
* Returns the head of the chain of settings.
*/
SETTINGS *
addsettings(
SETTINGS *head,
int append,
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -