Logo Search packages:      
Sourcecode: jam version File versions  Download package

rules.c

/*
 * Copyright 1993, 1995 Christopher Seiwald.
 *
 * This file is part of Jam - see jam.c for Copyright information.
 */

/*
 * 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
 *    copytarget() - make a new target with the old target's name
 *    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
 *    targetchain() - append two TARGET chains
 *    actionlist() - append to an ACTION chain
 *    addsettings() - add a deferred "set" command to a target
 *    copysettings() - copy a settings list for temp use
 *    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)
 * 06/21/02 (seiwald) - support for named parameters
 * 11/04/02 (seiwald) - const-ing for string literals
 * 12/03/02 (seiwald) - fix odd includes support by grafting them onto depends
 * 12/17/02 (seiwald) - new copysettings() to protect target-specific vars
 * 01/14/03 (seiwald) - fix includes fix with new internal includes TARGET
 */

# include "jam.h"
# include "lists.h"
# include "parse.h"
# include "variable.h"
# include "rules.h"
# include "newstr.h"
# include "hash.h"

static struct hash *rulehash = 0;
static struct hash *targethash = 0;


/*
 * bindrule() - return pointer to RULE, creating it if necessary
 */

RULE *
bindrule( const char *rulename )
{
      RULE rule, *r = &rule;

      if( !rulehash )
          rulehash = hashinit( sizeof( RULE ), "rules" );

      r->name = rulename;

      if( hashenter( rulehash, (HASHDATA **)&r ) )
      {
          r->name = newstr( rulename );   /* never freed */
          r->procedure = (PARSE *)0;
          r->actions = (char *)0;
          r->bindlist = L0;
          r->params = L0;
          r->flags = 0;
      }

      return r;
}

/*
 * bindtarget() - return pointer to TARGET, creating it if necessary
 */

TARGET *
bindtarget( const char *targetname )
{
      TARGET target, *t = ⌖

      if( !targethash )
          targethash = hashinit( sizeof( TARGET ), "targets" );

      t->name = targetname;

      if( hashenter( targethash, (HASHDATA **)&t ) )
      {
          memset( (char *)t, '\0', sizeof( *t ) );
          t->name = newstr( targetname ); /* never freed */
          t->boundname = t->name;         /* default for T_FLAG_NOTFILE */
      }

      return t;
}

/*
 * 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( const 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;
}

/*
 * 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   setflag,
      const char *symbol,
      LIST  *value )
{
      SETTINGS *v;
      
      /* Look for previous setting */

      for( v = head; v; v = v->next )
          if( !strcmp( v->symbol, symbol ) )
            break;

      /* If not previously set, alloc a new. */
      /* If appending, do so. */
      /* Else free old and set new. */

      if( !v )
      {
          v = (SETTINGS *)malloc( sizeof( *v ) );
          v->symbol = newstr( symbol );
          v->value = value;
          v->next = head;
          head = v;
      }
      else switch( setflag )
      {
      case VAR_SET:
          /* Toss old, set new */
          list_free( v->value );
          v->value = value;
          break;

      case VAR_APPEND:
          /* Append new to old */
          v->value = list_append( v->value, value );
          break;

      case VAR_DEFAULT:
          /* Toss new, old already set */
          list_free( value );
          break;
      }

      /* Return (new) head of list. */

      return head;
}

/*
 * copysettings() - copy a settings list for temp use
 *
 * When target-specific variables are pushed into place with pushsettings(),
 * any global variables with the same name are swapped onto the target's
 * SETTINGS chain.  If that chain gets modified (by using the "on target"
 * syntax), popsettings() would wrongly swap those modified values back 
 * as the new global values.  
 *
 * copysettings() protects the target's SETTINGS chain by providing a
 * copy of the chain to pass to pushsettings() and popsettings(), so that
 * the target's original SETTINGS chain can be modified using the usual
 * "on target" syntax.
 */

SETTINGS *
copysettings( SETTINGS *from )
{
      SETTINGS *head = 0, *v;

      for( ; from; from = from->next )
      {
          SETTINGS *v = (SETTINGS *)malloc( sizeof( *v ) );
          v->symbol = copystr( from->symbol );
          v->value = list_copy( 0, from->value );
          v->next = head;
          head = v;
      }

      return head;
}

/*
 * pushsettings() - set all target specific variables
 */

void
pushsettings( SETTINGS *v )
{
      for( ; v; v = v->next )
          v->value = var_swap( v->symbol, v->value );
}

/*
 * popsettings() - reset target specific variables to their pre-push values
 */

void
popsettings( SETTINGS *v )
{
      pushsettings( v );      /* just swap again */
}

/*
 *    freesettings() - delete a settings list
 */

void
freesettings( SETTINGS *v )
{
      while( v )
      {
          SETTINGS *n = v->next;

          freestr( v->symbol );
          list_free( v->value );
          free( (char *)v );

          v = n;
      }
}

/*
 * donerules() - free RULE and TARGET tables
 */

void
donerules()
{
      hashdone( rulehash );
      hashdone( targethash );
}

Generated by  Doxygen 1.6.0   Back to index