[comp.sources.misc] v14i026: dmake version 3.5 part 16/21

dvadura@watdragon.waterloo.edu (Dennis Vadura) (07/27/90)

Posting-number: Volume 14, Issue 26
Submitted-by: dvadura@watdragon.waterloo.edu (Dennis Vadura)
Archive-name: dmake/part16

#!/bin/sh
# this is part 16 of a multipart archive
# do not concatenate these parts, unpack them in order with /bin/sh
# file infer.c continued
#
CurArch=16
if test ! -r s2_seq_.tmp
then echo "Please unpack part 1 first!"
     exit 1; fi
( read Scheck
  if test "$Scheck" != $CurArch
  then echo "Please unpack part $Scheck next!"
       exit 1;
  else exit 0; fi
) < s2_seq_.tmp || exit 1
echo "x - Continuing file infer.c"
sed 's/^X//' << 'SHAR_EOF' >> infer.c
X       * these circumstances the CELL is marked as a MULTI cell.
X       */
X      nhow = how->hw_next;
X      for( ihow=meta->CE_EDGES->ed_how; ihow != NIL(HOW); ihow=ihow->hw_next ) {
X	 how->hw_per     = pdfa->dl_per;
X	 how->hw_flag   |= (ihow->hw_flag & (F_SINGLE | F_GROUP)) | F_INFER;
X	 how->hw_attr   |= ihow->hw_attr & (A_SILENT | A_IGNORE);
X	 how->hw_recipe  = ihow->hw_recipe;
X
X	 /* If infcell is not NIL then we have inferred a prerequisite, so
X	  * add it to the first HOW cell as well.
X	  */
X	 if( infcell != NIL(CELL) ) {
X	    (Add_prerequisite( how, infcell, TRUE))->cl_flag |= F_TARGET;
X
X	    if( Verbose )
X	       printf( "%s:  Inferred prerequisite [%s]\n",
X	               Pname, infcell->CE_NAME );
X	 }
X
X	 /* Add global prerequisites to the first HOW cell
X	  */
X	 for( lp=ihow->hw_indprq; lp != NIL(LINK); lp=lp->cl_next ) {
X	    char    *name = lp->cl_prq->CE_NAME;
X	    CELLPTR tcp;
X
X	    name = _build_name( cp->CE_NAME, name, pdfa->dl_per );
X	    tcp  = Def_cell( name, setdirroot );
X	    tcp->ce_flag |= F_REMOVE;
X	    Add_prerequisite( how, tcp, FALSE );
X
X	    if( Verbose )
X	       printf( "%s:  Inferred indirect prerequisite [%s]\n",
X	               Pname, name );
X	    FREE(name);
X	 }
X
X	 /* If the recipe is a :: recipe then Insert a new HOW node after
X	  * the inferred recipe HOW node and prior to any previous
X	  * :: nodes.
X	  */
X	 if( ihow->hw_next != NIL(HOW) ) {
X	    cp->ce_flag |= F_MULTI;
X	    TALLOC( how->hw_next, 1, HOW );
X	    how = how->hw_next;
X	 }
X      }
X      how->hw_next = nhow;
X      pdfa->dl_per = NIL(char);		/* We used it, so don't FREE it */
X
X      /* Make sure to set the FLAGS, and ATTRIBUTES of the CELL so that it
X       * gets made correctly.
X       */
X      cp->ce_flag |= F_RULES | F_TARGET | F_INFER;
X
X      if( !(cp->ce_attr & A_SETDIR) ) {
X         cp->ce_attr |= (meta->ce_attr & A_SETDIR);
X	 cp->ce_dir   = meta->ce_dir;
X      }
X   }
X   else
X      cp = NIL(CELL);
X
X   _free_dfas( dfas );
X
X   DB_PRINT( "mem", ("%s:-< mem %ld", (cp!=NIL(CELL)) ? cp->CE_NAME : "(none)",
X	     (long)coreleft()));
X   DB_PRINT( "inf", ("<<< Exit, cp = %04x", cp) );
X   DB_RETURN( cp );
X}
X
X
Xstatic char *
X_build_name( tg, meta, per )
Xchar *tg;
Xchar *meta;
Xchar *per;
X{
X   char    *name;
X
X   name = Apply_edit( meta, "%", per, FALSE, FALSE );
X   if( strchr(name, '$') ) {
X      HASHPTR m_at;
X      char *tmp;
X
X      m_at = Def_macro( "@", tg, M_MULTI );
X      tmp = Expand( name );
X
X      if( m_at->ht_value != NIL(char) ) {
X	 FREE( m_at->ht_value );
X	 m_at->ht_value = NIL(char);
X      }
X
X      if( name != meta ) FREE( name );
X      name = tmp;
X   }
X   else if( name == meta )
X      name = _strdup( name );
X
X   return(name);
X}
X
X
Xstatic DFALINKPTR
X_dfa_subset( pdfa, stack )/*
X============================
X   This is the valid DFA subset computation.  Whenever a CELL has a Match_dfa
X   subset computed this algorithm is run to see if any of the previously
X   computed sets on the DFA stack are proper subsets of the new set.  If they
X   are, then any elements of the matching subset whose Prep counts exceed
X   the allowed maximum given by Prep are removed from the computed DFA set,
X   and hence from consideration, thereby cutting off the cycle in the
X   inference graph. */
XDFALINKPTR	   pdfa;
Xregister DFASETPTR stack;
X{
X   register DFALINKPTR element;
X   DFALINKPTR          nelement;
X
X   DB_ENTER( "_dfa_subset" );
X
X   for(; pdfa != NIL(DFALINK) && stack != NIL(DFASET); stack = stack->df_next) {
X      int subset = TRUE;
X
X      for( element=stack->df_set; subset && element != NIL(DFALINK);
X           element=element->dl_next ) {
X         register DFALINKPTR subel;
X
X	 for( subel = pdfa;
X	      subel != NIL(DFALINK) && (subel->dl_meta != element->dl_meta);
X	      subel = subel->dl_next );
X
X	 if( subset = (subel != NIL(DFALINK)) ) element->dl_member = subel;
X      }
X
X      if( subset )
X	 for( element=stack->df_set; element != NIL(DFALINK);
X	      element=element->dl_next ) {
X	    DFALINKPTR mem = element->dl_member;
X	    int        npr = element->dl_prep + 1;
X
X	    if( npr > _prep )
X	       mem->dl_delete++;
X	    else
X	       mem->dl_prep = npr;
X	 }
X   }
X
X   for( element = pdfa; element != NIL(DFALINK); element = nelement ) {
X      nelement = element->dl_next;
X
X      if( element->dl_delete ) {
X	 /* A member of the subset has a PREP count equal to PREP, so
X	  * it should not be considered further in the inference, hence
X	  * we remove it from the doubly linked set list */
X	 if( element == pdfa )
X	    pdfa = element->dl_next;
X	 else
X	    element->dl_prev->dl_next = element->dl_next;
X
X	 if( element->dl_next != NIL(DFALINK) )
X	    element->dl_next->dl_prev = element->dl_prev;
X
X	 DB_PRINT("inf", ("deleting dfa [%s]", element->dl_meta->CE_NAME));
X	 FREE( element->dl_per );
X	 FREE( element );
X      }
X   }
X
X   DB_RETURN( pdfa );
X}
X
X
X
Xstatic void
X_free_dfas( chain )/*
X=====================
X   Free the list of DFA's constructed by Match_dfa, and linked together by
X   LINK cells.  FREE the % value as well, as long as it isn't NIL. */
XDFALINKPTR chain;
X{
X   register DFALINKPTR tl;
X
X   DB_ENTER( "_free_dfas" );
X
X   for( tl=chain; tl != NIL(DFALINK); chain = tl ) {
X      tl = tl->dl_next;
X
X      DB_PRINT( "inf", ("Freeing DFA [%s], %% = [%s]", chain->dl_meta->CE_NAME,
X                chain->dl_per) );
X
X      if( chain->dl_per != NIL(char) ) FREE( chain->dl_per );
X      FREE( chain );
X   }
X
X   DB_VOID_RETURN;
X}
X
X
Xstatic int
X_count_dots( name )/*
X=====================*/
Xchar *name;
X{
X   register char *p;
X   register int  i = 0;
X
X   for( p = name; *p; p++ ) if(*p == '.') i++;
X
X   return( i );
X}
SHAR_EOF
echo "File infer.c is complete"
chmod 0440 infer.c || echo "restore of infer.c fails"
echo "x - extracting imacs.c (Text)"
sed 's/^X//' << 'SHAR_EOF' > imacs.c &&
X/* RCS      -- $Header: /u2/dvadura/src/generic/dmake/src/RCS/imacs.c,v 1.1 90/07/19 13:53:17 dvadura Exp $
X-- SYNOPSIS -- define default internal macros.
X-- 
X-- DESCRIPTION
X--	This file adds to the internal macro tables the set of default
X--	internal macros, and for those that are accessible internally via
X--	variables creates these variables, and initializes them to point
X--	at the default values of these macros.
X--
X-- AUTHOR
X--      Dennis Vadura, dvadura@watdragon.uwaterloo.ca
X--      CS DEPT, University of Waterloo, Waterloo, Ont., Canada
X--
X-- COPYRIGHT
X--      Copyright (c) 1990 by Dennis Vadura.  All rights reserved.
X-- 
X--      This program is free software; you can redistribute it and/or
X--      modify it under the terms of the GNU General Public License
X--      (version 1), as published by the Free Software Foundation, and
X--      found in the file 'LICENSE' included with this distribution.
X-- 
X--      This program is distributed in the hope that it will be useful,
X--      but WITHOUT ANY WARRANTY; without even the implied warrant of
X--      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
X--      GNU General Public License for more details.
X-- 
X--      You should have received a copy of the GNU General Public License
X--      along with this program;  if not, write to the Free Software
X--      Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
X--
X-- LOG
X--     $Log:	imacs.c,v $
X * Revision 1.1  90/07/19  13:53:17  dvadura
X * Initial Revision of Version 3.5
X * 
X*/
X
X#include "extern.h"
X
Xstatic	void	_set_int_var ANSI((char *, char *, int, int *));
Xstatic	void	_set_string_var ANSI((char *, char *, int, char **));
Xstatic	void	_set_bit_var ANSI((char *, char *, int));
X
X/*
X** Arrange to parse the strings stored in Rules[]
X*/
Xvoid
XMake_rules()
X{
X   Parse(NIL(FILE));
X}
X
X
X#define M_FLAG   M_DEFAULT | M_EXPANDED
X
X/*
X** Add to the macro table all of the internal macro variables plus
X** create secondary variables which will give access to their values
X** easily, both when needed and when the macro value is modified.
X** The latter is accomplished by providing a flag in the macro and a field
X** which gives a pointer to the value if it is a char or string macro value
X** and a mask representing the bit of the global flag register that is affected
X** by this macro's value.
X*/
Xvoid
XCreate_macro_vars()
X{
X   static   char*   switChar;
X   char   swchar[2];
X
X   swchar[0] = Get_switch_char(), swchar[1] = '\0';
X   _set_string_var("SWITCHAR", swchar, M_PRECIOUS, &switChar);
X   _set_string_var("DIRSEPSTR", "/", M_PRECIOUS, &DirSepStr);
X   _set_string_var("DIRBRKSTR", DirBrkStr, M_PRECIOUS, &DirBrkStr);
X   
X   _set_bit_var(".SILENT",   "", A_SILENT  );
X   _set_bit_var(".IGNORE",   "", A_IGNORE  );
X   _set_bit_var(".PRECIOUS", "", A_PRECIOUS);
X   _set_bit_var(".EPILOG",   "", A_EPILOG  );
X   _set_bit_var(".PROLOG",   "", A_PROLOG  );
X   _set_bit_var(".NOINFER",  "", A_NOINFER );
X   _set_bit_var(".SEQUENTIAL","",A_SEQ     );
X
X   Glob_attr    = A_DEFAULT;        /* set all flags to NULL   */
X   
X   _set_string_var("SHELL",        "",  M_DEFAULT, &Shell       );
X   _set_string_var("SHELLFLAGS",   " ", M_DEFAULT, &Shell_flags );
X   _set_string_var("GROUPSHELL",   "",  M_DEFAULT, &GShell      );
X   _set_string_var("GROUPFLAGS",   " ", M_DEFAULT, &GShell_flags);
X   _set_string_var("SHELLMETAS",   "",  M_DEFAULT, &Shell_metas );
X   _set_string_var("GROUPSUFFIX",  "",  M_DEFAULT, &Grp_suff    );
X   _set_string_var("PREP",         "0", M_DEFAULT, &Prep        );
X   _set_string_var("AUGMAKE",      NIL(char), M_DEFAULT, &Augmake );
X
X   _set_string_var("MAKEDIR", Get_current_dir(), M_PRECIOUS|M_NOEXPORT,
X         &Makedir);
X   _set_string_var("PWD",  Makedir, M_DEFAULT|M_NOEXPORT, &Pwd);
X
X   Def_macro("NULL", "", M_PRECIOUS|M_NOEXPORT|M_FLAG);
X 
X   _set_int_var( "MAXLINELENGTH", "0", M_DEFAULT|M_NOEXPORT, &Buffer_size );
X   (void) Def_macro("MAXLINELENGTH", "0", M_FLAG | M_DEFAULT);
X
X   /* set MAXPROCESSLIMIT high initially so that it allows MAXPROCESS to
X    * change from command line. */
X   _set_int_var( "MAXPROCESSLIMIT", "100", M_DEFAULT|M_NOEXPORT, &Max_proclmt );
X   _set_int_var( "MAXPROCESS", "1", M_DEFAULT|M_NOEXPORT, &Max_proc );
X}
X
X/*
X** Define a string variable value, and set up the macro.
X*/
Xstatic void
X_set_int_var(name, val, flag, var)
Xchar *name;
Xchar *val;
Xint  flag;
Xint  *var;
X{
X   HASHPTR hp;
X
X   hp = Def_macro(name, val, M_FLAG | flag);
X   hp->ht_flag |= M_VAR_INT | M_MULTI;
X   hp->MV_IVAR  = var;
X   *var         = atoi(val);
X}
X
X/*
X** Define a string variables value, and set up the macro.
X*/
Xstatic void
X_set_string_var(name, val, flag, var)
Xchar *name;
Xchar *val;
Xint  flag;
Xchar **var;
X{
X   HASHPTR hp;
X
X   hp = Def_macro(name, val, M_FLAG | flag);
X   hp->ht_flag |= M_VAR_STRING | M_MULTI;
X   hp->MV_SVAR  = var;
X   *var         = hp->ht_value;
X}
X
X/*
X** Define a string variables value, and set up the macro.
X*/
Xstatic void
X_set_bit_var(name, val, mask)
Xchar *name;
Xchar *val;
Xint  mask;
X{
X   HASHPTR hp;
X
X   hp           = Def_macro(name, val, M_FLAG);
X   hp->ht_flag |= M_VAR_BIT | M_MULTI;
X   hp->MV_MASK  = mask;
X   hp->MV_BVAR  = &Glob_attr;
X}
X
SHAR_EOF
chmod 0440 imacs.c || echo "restore of imacs.c fails"
echo "x - extracting hash.c (Text)"
sed 's/^X//' << 'SHAR_EOF' > hash.c &&
X/* RCS      -- $Header: /u2/dvadura/src/generic/dmake/src/RCS/hash.c,v 1.1 90/07/19 13:53:14 dvadura Exp $
X-- SYNOPSIS -- hashing function for hash tables.
X-- 
X-- DESCRIPTION
X--      Hash an identifier.  The hashing function works by computing the sum
X--      of each char and the previous hash value multiplied by 129.  Finally the
X--      length of the identifier is added in.  This way the hash depends on the
X--      chars as well as the length, and appears to be sufficiently unique,
X--      and is FAST to COMPUTE, unlike the previous hash function...
X-- 
X-- AUTHOR
X--      Dennis Vadura, dvadura@watdragon.uwaterloo.ca
X--      CS DEPT, University of Waterloo, Waterloo, Ont., Canada
X--
X-- COPYRIGHT
X--      Copyright (c) 1990 by Dennis Vadura.  All rights reserved.
X-- 
X--      This program is free software; you can redistribute it and/or
X--      modify it under the terms of the GNU General Public License
X--      (version 1), as published by the Free Software Foundation, and
X--      found in the file 'LICENSE' included with this distribution.
X-- 
X--      This program is distributed in the hope that it will be useful,
X--      but WITHOUT ANY WARRANTY; without even the implied warrant of
X--      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
X--      GNU General Public License for more details.
X-- 
X--      You should have received a copy of the GNU General Public License
X--      along with this program;  if not, write to the Free Software
X--      Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
X--
X-- LOG
X--     $Log:	hash.c,v $
X * Revision 1.1  90/07/19  13:53:14  dvadura
X * Initial Revision of Version 3.5
X * 
X*/
X
X#include "extern.h"
X
Xuint16
XHash( id, phv )/*
X=================
X      This function computes the identifier's hash value and returns the hash
X      value modulo the key size as well as the full hash value.  The reason
X      for returning both is so that hash table searches can be sped up.  You
X      compare hash keys instead and compare strings only for those whose 32-bit
X      hash keys match. (not many) */
X
Xchar   *id;
Xuint32 *phv;
X{
X   register char   *p    = id;
X   register uint32 hash  = (uint32) 0;
X
X   while( *p ) hash = (hash << 7) + hash + (uint32) (*p++);
X   *phv = hash = hash + (uint32) (p-id);
X
X   return( (uint16) (hash % HASH_TABLE_SIZE) );
X}
X
SHAR_EOF
chmod 0440 hash.c || echo "restore of hash.c fails"
echo "x - extracting getinp.c (Text)"
sed 's/^X//' << 'SHAR_EOF' > getinp.c &&
X/* RCS      -- $Header: /u2/dvadura/src/generic/dmake/src/RCS/getinp.c,v 1.1 90/07/19 13:53:12 dvadura Exp $
X-- SYNOPSIS -- handle reading of input.
X-- 
X-- DESCRIPTION
X--	The code in this file reads the input from the specified stream
X--	into the provided buffer of size Buffer_size.  In doing so it deletes
X--	comments.  Comments are delimited by the #, and
X--	<nl> character sequences.  An exception is \# which
X--	is replaced by # in the input.  Line continuations are signalled
X--	at the end of a line and are recognized inside comments.
X--	The line continuation is always  <\><nl>.
X--
X--	If the file to read is NIL(FILE) then the Get_line routine returns the
X--	next rule from the builtin rule table if there is one.
X--
X-- AUTHOR
X--      Dennis Vadura, dvadura@watdragon.uwaterloo.ca
X--      CS DEPT, University of Waterloo, Waterloo, Ont., Canada
X--
X-- COPYRIGHT
X--      Copyright (c) 1990 by Dennis Vadura.  All rights reserved.
X-- 
X--      This program is free software; you can redistribute it and/or
X--      modify it under the terms of the GNU General Public License
X--      (version 1), as published by the Free Software Foundation, and
X--      found in the file 'LICENSE' included with this distribution.
X-- 
X--      This program is distributed in the hope that it will be useful,
X--      but WITHOUT ANY WARRANTY; without even the implied warrant of
X--      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
X--      GNU General Public License for more details.
X-- 
X--      You should have received a copy of the GNU General Public License
X--      along with this program;  if not, write to the Free Software
X--      Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
X--
X-- LOG
X--     $Log:	getinp.c,v $
X * Revision 1.1  90/07/19  13:53:12  dvadura
X * Initial Revision of Version 3.5
X * 
X*/
X
X#include "extern.h"
X#include "alloc.h"
X#include "db.h"
X
X#define IS_WHITE(A)  ((A == ' ') || (A == '\t') || (A == '\n'))
X#define SCAN_WHITE(A) \
X    while( IS_WHITE(*A) ) A++;
X
Xstatic	int	_is_conditional ANSI((char*));
Xstatic	int	_handle_conditional ANSI((int, TKSTRPTR));
X
Xstatic int  rule_ind = 0;	/* index of rule when reading Rule_tab	 */
Xstatic int  skip = FALSE;	/* if true the skip input		 */
X
X
Xint
XGet_line( buf, fil )/*
X======================
X		Read a line of input from the file stripping
X		off comments.  The routine returns TRUE if EOF */
Xchar *buf;
XFILE *fil;
X{
X   extern   char **Rule_tab;
X   register char *p;
X   register char *q;
X   register char *c;
X   char	    	 *buf_org;
X   static   int	 ignore = FALSE;
X   int 		 cont   = FALSE;
X   int 		 pos    = 0;
X   int		 res;
X
X   DB_ENTER( "Get_line" );
X
X   if( fil == NIL(FILE) ) {
X      /* Reading the internal rule table.  Set the rule_index to zero.
X       * This way ReadEnvironment works as expected every time. */
X
X      while( (p = Rule_tab[ rule_ind++ ]) != NIL(char) )
X	 /* The last test in this if '*p != '~', handles the environment
X	  * passing conventions used by MKS to pass arguments.  We want to
X	  * skip those environment entries. */
X	 if( !Readenv || (Readenv && (strchr(p,'=') != NIL(char)) && *p!='~')){
X	    strcpy( buf, p );
X
X	    DB_PRINT( "io", ("Returning [%s]", buf) );
X	    DB_RETURN( FALSE );
X	 }
X
X      rule_ind = 0;
X
X      DB_PRINT( "io", ("Done Ruletab") );
X      DB_RETURN( TRUE );
X   }
X
X   buf_org = buf;
X
Xdo_again:
X   do {
X      p = buf+pos;
X      if(feof( fil ) || (fgets( p, Buffer_size-pos, fil ) == NIL(char)))
X	 DB_RETURN( TRUE );
X
X      Line_number++;
X
X      /* ignore input if ignore flag set and line ends in a continuation
X	 character. */
X
X      q = p+strlen(p)-2;
X      if( ignore ) {
X	 if( q[0] != CONTINUATION_CHAR || q[1] != '\n' )  ignore = FALSE;
X	 *p = '\0';
X	 continue;
X      }
X
X      /* Search the input string looking for comment chars.  If it contains
X       * comment chars then NUKE the remainder of the line, if the comment
X       * char is preceeded by \ then shift the remainder of the line left
X       * by one char. */
X
X      c = p;
X
X      while( (c = strchr(c, COMMENT_CHAR)) != NIL(char) ) {
X	 if( c != p && c[-1] == ESCAPE_CHAR ) {
X	    strcpy( c-1, c );             /* copy it left, due to \# */
X	    q--;			  /* shift tail pointer left */
X	 }
X	 else {
X	    *c = '\0';                    /* a true comment so break */
X	    break;
X	 }
X      }
X      
X      /* Does the end of the line end in a continuation sequence? */
X      
X      if( (q[0] == CONTINUATION_CHAR) && (q[1] == '\n')) {
X	 /* If the continuation was at the end of a comment then ignore the
X	    next input line, (or lines until we get one ending in just <nl>)
X	    else it's a continuation, so build the input line from several
X	    text lines on input.  The maximum size of this is governened by
X	    Buffer_size */
X
X	 if( c != NIL(char) )
X	    ignore = TRUE;
X	 else
X	    cont   = TRUE;
X      }
X      else {
X	 cont = FALSE;
X      }
X
X      q    = ( c == NIL(char) ) ? q+2 : c;
X      pos += q-p;
X   }
X   while( (cont || !*buf) && (pos <= Buffer_size) );
X
X   if( buf[ pos-1 ] == '\n' )
X      buf[ --pos ] = '\0';
X   else
X      if( pos == Buffer_size-1 )
X	 Fatal( "Input line too long, increase MAXLINELENGTH" );
X
X
X   /* Now that we have the next line of input to make, we should check to
X    * see if it is a conditional expression.  If it is then process it,
X    * otherwise pass it on to the parser. */
X
X   if( *(p = _strspn(buf, " \t")) == CONDSTART ) {
X      TKSTR token;
X
X      SET_TOKEN( &token, p );
X
X      p = Get_token( &token, "", FALSE );
X
X      if( (res = _is_conditional( p )) )	/* ignore non control special */
X      {						/* targets 		      */
X	 res  = _handle_conditional( res, &token );
X	 skip = TRUE;
X      }
X      else {
X	 CLEAR_TOKEN( &token );
X	 res  = TRUE;
X      }
X   }
X
X   if( skip ) {
X      buf  = buf_org;		/* ignore line just read in */
X      pos  = 0;
X      skip = res;
X      goto do_again;
X   }
X
X   DB_PRINT( "io", ("Returning [%s]", buf) );
X   DB_RETURN( FALSE );
X}
X
X
X
Xchar *
XGet_token( string, brk, anchor )/*
X==================================
X	Return the next token in string.
X	Returns empty string when no more tokens in string.
X	brk is a list of chars that also cause breaks in addition to space and
X	tab, but are themselves returned as tokens.  if brk is NULL then the
X	remainder of the line is returned as a single token.
X	
X	anchor if TRUE, says break on chars in the brk list, but only if
X	the entire token begins with the first char of the brk list, if
X	FALSE then any char of brk will cause a break to occurr. */
X
XTKSTRPTR  string;
Xchar      *brk;
Xint	  anchor;
X{
X   register char *s;
X   register char *curp;
X   register char *t;
X   int           done = FALSE;
X   char          space[10];
X
X   DB_ENTER( "Get_token" );
X
X   s  = string->tk_str;			  /* Get string parameters	*/
X   *s = string->tk_cchar;		  /* ... and strip leading w/s	*/
X
X   SCAN_WHITE( s );
X
X   DB_PRINT( "tok", ("What's left [%s]", s) );
X
X   if( !*s ) {
X      DB_PRINT( "tok", ("Returning NULL token") );
X      DB_RETURN( "" );
X   }
X
X
X   /* Build the space list.  space contains all those chars that may possibly
X    * cause breaks.  This includes the brk list as well as white space. */
X
X   if( brk != NIL(char) ) {
X      strcpy( space, " \t\n" );
X      strcat( space, brk   );
X   }
X   else {
X      space[0] = 0xff;            /* a char we know will not show up      */
X      space[1] = 0;
X   }
X
X
X   /* Handle processing of quoted tokens.  Note that this is disabled if
X    * brk is equal to NIL */
X
X   while( *s == '\"' && ((brk != NIL(char)) || !string->tk_quote) ) {
X      s++;
X      if( string->tk_quote ) {
X	 curp = s-1;
X	 do { curp = strchr( curp+1, '\"' ); }
X	 while( (curp != NIL(char)) && (*(curp+1) == '\"'));
X
X         if( curp == NIL(char) ) Fatal( "Unmatched quote in token" );
X	 string->tk_quote = !string->tk_quote;
X
X	 /* Check for "" case, and if found ignore it */
X	 if( curp == s ) continue;
X	 goto found_token;
X      }
X      else
X	 SCAN_WHITE( s );
X
X      string->tk_quote = !string->tk_quote;
X   }
X   
X
X   /* Check for a token break character at the beginning of the token.
X    * If found return the next set of break chars as a token. */
X
X   if( (brk != NIL(char)) && (strchr( brk, *s ) != NIL(char)) ) {
X      curp = _strspn( s, brk );
X      done = anchor ? (*s == *brk) : TRUE;
X   }
X
X
X   /* Scan for the next token in the list and return it less the break char
X    * that was used to terminate the token.  It will possibly be returned in
X    * the next call to Get_token */
X
X   if( !done ) {
X      SCAN_WHITE( s );
X
X      t = s;
X      do {
X	 done = TRUE;
X	 curp = _strpbrk( t, space);
X	 
X	 if( anchor && *curp && !IS_WHITE( *curp ) )
X	    if( *curp != *brk ) {
X	       t++;
X	       done = FALSE;
X	    }
X      }
X      while( !done );
X
X      if( (curp == s) && (strchr(brk, *curp) != NIL(char)) ) curp++;
X   }
X
Xfound_token:
X   string->tk_str   = curp;
X   string->tk_cchar = *curp;
X   *curp = '\0';
X
X   DB_PRINT( "tok", ("Returning [%s]", s) );
X   DB_RETURN( s );
X}
X
X
X
Xstatic int
X_is_conditional( tg )/*
X=======================
X	Look at tg and return it's value if it is a conditional identifier
X	otherwise return 0. */
Xchar *tg;
X{
X   DB_ENTER( "_is_conditional" );
X   
X   tg++;
X   switch( *tg ) {
X      case 'I': if( !strcmp( tg, "IF" )) DB_RETURN( ST_IF   ); break;
X      
X      case 'E':
X         if( !strcmp( tg, "END" ))	 DB_RETURN( ST_END  );
X         else if( !strcmp( tg, "ELSE" )) DB_RETURN( ST_ELSE );
X	 break;
X   }
X   
X   DB_RETURN( 0 );
X}
X
X
X
Xstatic int
X_handle_conditional( opcode, tg )/*
X===================================
X	Perform the necessary processing for .IF conditinal targets.
X	Someday this should be modified to do bracketted expressions ala
X	CPP... sigh */
Xint      opcode;
XTKSTRPTR tg;
X{
X   static short	action[MAX_COND_DEPTH];
X   char 	*tok, *lhs, *rhs, *op, *expr;
X   int  	result;
X
X   DB_ENTER( "_handle_conditional" );
X
X   switch( opcode ) {
X      case ST_IF:
X	 if( Nest_level+1 == MAX_COND_DEPTH )
X	    Fatal( ".IF .ELSE ... .END nesting too deep" );
X
X	 If_expand = TRUE;
X	 expr = Expand( Get_token( tg, NIL(char), FALSE ));
X	 If_expand = FALSE;
X	 lhs = _strspn( expr, " \t" );
X	 if( !*lhs ) lhs = NIL(char);
X
X	 if( (op = _strstr( lhs, "==" )) == NIL(char) )
X	    op = _strstr( lhs, "!=" );
X
X	 if( op == NIL(char) )
X	    result = (lhs != NIL(char));
X	 else {
X	    op[1] = op[0];
X	    if( lhs != op ) {
X	       for( tok = op-1; (tok != lhs) && ((*tok == ' ')||(*tok == '\t'));
X	            tok-- );
X	       tok[1] = '\0';
X	    }
X	    else
X	       lhs = NIL(char);
X
X	    op++;
X	    rhs = _strspn( op+1, " \t" );
X	    if( !*rhs ) rhs = NIL(char);
X
X	    if( (rhs == NIL(char)) || (lhs == NIL(char)) )
X	       result = (rhs == lhs) ? TRUE : FALSE;
X	    else {
X	       tok = rhs + strlen( rhs );
X	       for( tok=tok-1; (tok != lhs) && ((*tok == ' ')||(*tok == '\t'));
X		    tok--);
X	       tok[1] = '\0';
X
X	       result = (strcmp( lhs, rhs ) == 0) ? TRUE : FALSE;
X	    }
X
X	    if( *op == '!' ) result = !result;
X	 }
X
X	 if( expr != NIL(char) ) FREE( expr );
X	 Nest_level++;
X
X	 if( result )
X	    action[ Nest_level ] = action[ Nest_level-1 ];
X	 else
X	    action[ Nest_level ] = 1;
X	 break;
X
X      case ST_ELSE:
X	 if( Nest_level <= 0 ) Fatal( ".ELSE without .IF" );
X	 if( action[ Nest_level-1 ] != 1 )
X	    action[ Nest_level ] ^=  0x1;	/* flip between 0 and 1	*/
X	 break;
X
X      case ST_END:
X	 Nest_level--;
X	 if( Nest_level < 0 ) Fatal( "Unmatched .END" );
X	 break;
X   }
X
X   DB_RETURN( action[ Nest_level ] );
X}
X
SHAR_EOF
chmod 0440 getinp.c || echo "restore of getinp.c fails"
echo "x - extracting extern.h (Text)"
sed 's/^X//' << 'SHAR_EOF' > extern.h &&
X/* RCS      -- $Header: /u2/dvadura/src/generic/dmake/src/RCS/extern.h,v 1.1 90/07/19 13:55:31 dvadura Exp $
X-- SYNOPSIS -- external declarations for dmake functions.
X-- 
X-- DESCRIPTION
X--	ANSI is a macro that allows the proper handling of ANSI style
X--	function declarations.
X-- 
X-- AUTHOR
X--      Dennis Vadura, dvadura@watdragon.uwaterloo.ca
X--      CS DEPT, University of Waterloo, Waterloo, Ont., Canada
X--
X-- COPYRIGHT
X--      Copyright (c) 1990 by Dennis Vadura.  All rights reserved.
X-- 
X--      This program is free software; you can redistribute it and/or
X--      modify it under the terms of the GNU General Public License
X--      (version 1), as published by the Free Software Foundation, and
X--      found in the file 'LICENSE' included with this distribution.
X-- 
X--      This program is distributed in the hope that it will be useful,
X--      but WITHOUT ANY WARRANTY; without even the implied warrant of
X--      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
X--      GNU General Public License for more details.
X-- 
X--      You should have received a copy of the GNU General Public License
X--      along with this program;  if not, write to the Free Software
X--      Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
X--
X-- LOG
X--     $Log:	extern.h,v $
X * Revision 1.1  90/07/19  13:55:31  dvadura
X * Initial Revision of Version 3.5
X * 
X*/
X
X#ifndef EXTERN_h
X#define EXTERN_h
X
X#include "vextern.h"
X#include "config.h"
X#include <stdlib.h>
X#include <string.h>
X
Xextern	void	Add_dfa ANSI((char *));
Xextern	void	Add_fringe ANSI((CELLPTR));
Xextern	void	Add_recipe_to_list ANSI((char *, int, int));
Xextern	LINKPTR	Add_prerequisite ANSI((HOWPTR, CELLPTR, int));
Xextern	char*	Apply_edit ANSI((char *, char *, char *, int, int));
Xextern	char*	basename ANSI((char*));
Xextern	void	Bind_rules_to_targets ANSI((int));
Xextern	char*	Build_path ANSI((char *, char *));
Xextern	void 	Catch_signals ANSI((void (*)()));
Xextern	void	Check_circle ANSI((LINKPTR));
Xextern	void	Check_circle_dfa ANSI(());
Xextern	void	Clear_prerequisites ANSI((HOWPTR));
Xextern	void	Clear_signals ANSI(());
Xextern  void	Clean_up_processes ANSI(());
Xextern	FILE*	Closefile ANSI(());
Xextern  void    Close_temp ANSI((HOWPTR, FILE *));
Xextern	void	Create_macro_vars ANSI(());
Xextern	DFAPTR	Construct_dfa ANSI((char *));
Xextern	CELLPTR	Def_cell ANSI((char *, CELLPTR));
Xextern	HASHPTR	Def_macro ANSI((char *, char *, int));
Xextern	STRINGPTR	Def_recipe ANSI((char *, STRINGPTR, int, int));
Xextern	int 	Do_cmnd ANSI((char *, int, int, CELLPTR, HOWPTR, int, int));
Xextern	time_t	Do_stat ANSI((char *, char *, char **));
Xextern	time_t	Do_time ANSI(());
Xextern	int	Do_touch ANSI((char *, char *, char **));
Xextern	void	Dump ANSI(());
Xextern	void	Dump_recipe ANSI((STRINGPTR));
Xextern	void 	Epilog ANSI((int));
Xextern	char*	Expand ANSI((char *));
Xextern  CELLPTR Explode_cell ANSI((CELLPTR, CELLPTR));
Xextern  HOWPTR  Explode_how ANSI((HOWPTR, CELLPTR, int));
Xextern  LINKPTR Explode_prq ANSI((LINKPTR, CELLPTR, int));
Xextern  char*   Filename ANSI(());
Xextern	char*	Get_current_dir ANSI(());
Xextern	int	Get_line ANSI((char *, FILE *));
Xextern	HASHPTR	Get_name ANSI((char *, HASHPTR *, int, CELLPTR));
Xextern	char*	Get_suffix ANSI((char *));
Xextern	char	Get_switch_char ANSI(());
Xextern	char*	Get_token ANSI((TKSTRPTR, char *, int));
Xextern	uint16	Hash ANSI((char *,uint32 *));
Xextern  void    Handle_result ANSI((int, int, int, CELLPTR));
Xextern	int	If_root_path ANSI((char *));
Xextern	CELLPTR	Infer_recipe ANSI((CELLPTR, HOWPTR, DFASETPTR, CELLPTR));
Xextern	int	Macro_op ANSI((char *));
Xextern	int	Make ANSI((CELLPTR, HOWPTR, CELLPTR));
Xextern	void	Make_rules ANSI(());
Xextern  void	Map_esc ANSI((char *));
Xextern	DFALINKPTR	Match_dfa ANSI((char *));
Xextern	char*	My_malloc ANSI((unsigned int, char *, int));
Xextern	char*	My_calloc ANSI((unsigned int, unsigned int, char *, int));
Xextern	void	My_free ANSI((char *, char *, int));
Xextern  void	No_ram ANSI(());
Xextern	FILE*	Open_temp ANSI((char **, char *));
Xextern	FILE*	Openfile ANSI((char *, int));
Xextern  void    Pack_argv ANSI((char **, int, int, char *));
Xextern	void	Parse ANSI((FILE *));
Xextern	int	Parse_macro ANSI((char *, int));
Xextern	int	Parse_rule_def ANSI((int *));
Xextern	void	Pop_dir ANSI((int));
Xextern	void	Prolog ANSI((int, char **));
Xextern	int	Push_dir ANSI((CELLPTR, int));
Xextern	void	Quit ANSI(());
Xextern	char*	Read_env_string ANSI((char *));
Xextern	void	ReadEnvironment ANSI(());
Xextern  void	Remove_prq ANSI((CELLPTR));
Xextern	int	Rule_op ANSI((char *));
Xextern	int	runargv ANSI((CELLPTR, HOWPTR, int, int, int, char *));
Xextern	time_t	seek_arch ANSI((char*, char*));
Xextern	int	Set_dir ANSI((char *));
Xextern	int	Set_group_attributes ANSI((char *));
Xextern	void	Stat_target ANSI((CELLPTR, int));
Xextern  FILE*   Start_temp ANSI((char *, CELLPTR, HOWPTR, char **));
Xextern	int	Test_circle ANSI((CELLPTR, int));
Xextern	int	touch_arch ANSI((char*, char*));
Xextern  void    Unlink_temp_files ANSI((HOWPTR));
Xextern  void	Update_time_stamp ANSI((CELLPTR, HOWPTR));
Xextern  void    Void_lib_cache ANSI((char *, char *));
Xextern  int	Wait_for_child ANSI((int, int));
Xextern	int	Write_env_string ANSI((char *, char *));
X
Xextern	char*	_stradd ANSI((char *,char *, int));
Xextern	char*	_strapp ANSI((char *,char *));
Xextern	char*	_strjoin ANSI((char *,char *,int, int));
Xextern	char*	_strdup ANSI((char *));
Xextern	char*	_strpbrk ANSI((char *,char *));
Xextern	char*	_strspn ANSI((char *,char *));
Xextern	char*	_strstr ANSI((char *,char *));
Xextern	char*	_substr ANSI((char *,char *));
X
X#endif
X
SHAR_EOF
chmod 0440 extern.h || echo "restore of extern.h fails"
echo "x - extracting expand.c (Text)"
sed 's/^X//' << 'SHAR_EOF' > expand.c &&
X/* RCS      -- $Header: /u2/dvadura/src/generic/dmake/src/RCS/expand.c,v 1.1 90/07/19 13:53:10 dvadura Exp $
X-- SYNOPSIS -- macro expansion code.
X-- 
X-- DESCRIPTION
X--
X--	This routine handles all the necessary junk that deals with macro
X--	expansion.  It understands the following syntax.  If a macro is
X--	not defined it expands to NULL, and {} are synonyms for ().
X--
X--		$$      - expands to $
X--		{{      - expands to {
X--	        }}      - expands to }
X--		$A      - expands to whatever the macro A is defined as
X--		$(AA)   - expands to whatever the macro AA is defined as
X--		$($(A)) - represents macro indirection
X--	
X--        following macro is recognized
X--        
X--                string1{ token_list }string2
X--                
X--        and expands to string1 prepended to each element of token_list and
X--        string2 appended to each of the resulting tokens from the first
X--        operation.  If string2 is of the form above then the result is
X--        the cross product of the specified (possibly modified) token_lists.
X--        
X--        The folowing macro modifiers are defined and expanded:
X--        
X--               $(macro:modifier_list:modifier_list:...)
X--               
X--        where modifier_list a combination of:
X--        
X--               D or d      - Directory portion of token including separator
X--               F or f      - File portion of token including suffix
X--               B or b      - basename portion of token not including suffix
X--		 T or t      - for tokenization
X--
X--	  or a single
X--               S or s      - pattern substitution (simple)
X--               
X--        NOTE:  Modifiers are applied once the macro value has been found.
X--               Thus the construct $($(test):s/joe/mary/) is defined and
X--               modifies the value of $($(test))
X--
X--	       Also the construct $(m:d:f) is not the same as $(m:df)
X--	       the first applies d to the value of $(m) and then
X--	       applies f to the value of that whereas the second form
X--	       applies df to the value of $(m).
X--
X-- AUTHOR
X--      Dennis Vadura, dvadura@watdragon.uwaterloo.ca
X--      CS DEPT, University of Waterloo, Waterloo, Ont., Canada
X--
X-- COPYRIGHT
X--      Copyright (c) 1990 by Dennis Vadura.  All rights reserved.
X-- 
X--      This program is free software; you can redistribute it and/or
X--      modify it under the terms of the GNU General Public License
X--      (version 1), as published by the Free Software Foundation, and
X--      found in the file 'LICENSE' included with this distribution.
X-- 
X--      This program is distributed in the hope that it will be useful,
X--      but WITHOUT ANY WARRANTY; without even the implied warrant of
X--      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
X--      GNU General Public License for more details.
X-- 
X--      You should have received a copy of the GNU General Public License
X--      along with this program;  if not, write to the Free Software
X--      Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
X--
X-- LOG
X--     $Log:	expand.c,v $
X * Revision 1.1  90/07/19  13:53:10  dvadura
X * Initial Revision of Version 3.5
X * 
X*/
X
X#include <ctype.h>
X#include "extern.h"
X#include "alloc.h"
X#include "db.h"
X
Xstatic	char*	_scan_token ANSI((char*, char**));
Xstatic	char*	_scan_macro ANSI((char*, char**));
Xstatic	char*	_scan_brace ANSI((char*, char**, int*));
Xstatic	char*	_cross_prod ANSI((char*, char*));
Xstatic	char*	_apply_modifiers ANSI((int, char*));
Xstatic	char*	_tokenize ANSI((char*, char*));
X
X#define SUFFIX_FLAG	1		/* defines for macro modifier code */
X#define DIRECTORY_FLAG	2
X#define FILE_FLAG	4
X
X
Xchar *
XExpand( src )/*
X===============
X      This is the driver routine for the expansion, it identifies non-white
X      space tokens and gets the _scan_token routine to figure out if they should
X      be treated in a special way. */
X
Xchar *src;                    /* pointer to source string  */
X{
X   char  *tmp;		      /* pointer to temporary str  */
X   char  *res;                /* pointer to result string  */
X   char  *start;              /* pointer to start of token */
X   
X   DB_ENTER( "Expand" );
X   DB_PRINT( "exp", ("Expanding [%s]", src) );
X
X   res = _strdup( "" );
X   if( src == NIL(char) ) DB_RETURN( res );
X
X   while( *src ) {
X      /* Here we find the next non white space token in the string
X       * and find it's end, with respect to non-significant white space. */
X      
X      start = _strspn( src, " \t\n" );
X      res   = _strjoin( res, src, start-src, TRUE );
X      if( !(*start) ) break;
X      res   = _strjoin( res, tmp = _scan_token( start, &src ), -1, TRUE );
X      FREE( tmp );
X   }
X   
X   DB_PRINT( "exp", ("Returning [%s]", res) );
X   DB_RETURN( res );
X}
X
X
X
Xchar *
XApply_edit( src, pat, subst, fr, anchor )/*
X===========================================
X   Take the src string and apply the pattern substitution.  ie. look for
X   occurrences of pat in src and replace each occurrence with subst.  This is
X   NOT a regular expressions pattern substitution, it's just not worth it.
X   
X   if anchor == TRUE then the src pattern match must be at the end of a token.
X   ie. this is for SYSV compatibility and is only used for substitutions of
X   the caused by $(macro:pat=sub).  So if src = "fre.o.k june.o" then
X   $(src:.o=.a) results in "fre.o.k june.a", and $(src:s/.o/.a) results in
X   "fre.a.k june.a" */
X
Xchar *src;			/* the source string */
Xchar *pat;			/* pattern to find   */
Xchar *subst;			/* substitute string */
Xint   fr;			/* if TRUE free src  */
Xint   anchor;			/* if TRUE anchor    */
X{
X   char *res;
X   char *p;
X   char *s;
X   int   l;
X
X   DB_ENTER( "Apply_edit" );
X   
X   if( !*pat ) DB_RETURN( src );		/* do nothing if pat is NULL */
X
X   DB_PRINT( "mod", ("Source str:  [%s]", src) );
X   DB_PRINT( "mod", ("Replacing [%s], with [%s]", pat, subst) );
X
X   s   = src;
X   l   = strlen( pat );
X   if( (p = _strstr( s, pat )) != NIL(char) ) {
X      res = _strdup( "" );
X      do {
X	 if( anchor )
X	    if( !*(p+l) || (strchr(" \t", *(p+l)) != NIL(char)) )
X	       res = _strjoin( _strjoin( res, s, p-s, TRUE ), subst, -1, TRUE );
X	    else
X	       res = _strjoin( res, s, p+l-s, TRUE );
X	 else
X	    res = _strjoin( _strjoin( res, s, p-s, TRUE ), subst, -1, TRUE );
X
X	 s   = p + l;
X      }
X      while( (p = _strstr( s, pat )) != NIL(char) );
X
X      res = _strjoin( res, s, -1, TRUE );
X      if( fr ) FREE( src );
X   }
X   else
X      res = src;
X
X
X   DB_PRINT( "mod", ("Result [%s]", res) );
X   DB_RETURN( res );
X}
X
X
X
Xvoid
XMap_esc( tok )/*
X================
X   Map an escape sequence and replace it by it's corresponding character
X   value.  It is assumed that tok points at the initial \, the esc
X   sequence in the original string is replaced and the value of tok
X   is not modified. */
Xchar *tok;
X{
X   if( strchr( "\"\\vantbrf01234567", tok[1] ) ) {
X      switch( tok[1] ) {
X	 case 'a' : *tok = 0x07; break;
X	 case 'b' : *tok = '\b'; break;
X	 case 'f' : *tok = '\f'; break;
X	 case 'n' : *tok = '\n'; break;
X	 case 'r' : *tok = '\r'; break;
X	 case 't' : *tok = '\t'; break;
X	 case 'v' : *tok = 0x0b; break;
X	 case '\\': *tok = '\\'; break;
X	 case '\"': *tok = '\"'; break;
X
X	 default: {
X	    register int i = 0;
X	    register int j = 0;
X	    for( ; i<2 && isdigit(tok[2]); i++ ) {
X	       j = (j << 3) + (tok[1] - '0');
X	       strcpy( tok+1, tok+2 );
X	    }
X	    j = (j << 3) + (tok[1] - '0');
X	    *tok = j;
X	 }
X      }
X      strcpy( tok+1, tok+2 );
SHAR_EOF
echo "End of part 16"
echo "File expand.c is continued in part 17"
echo "17" > s2_seq_.tmp
exit 0