[comp.sources.misc] v14i027: dmake version 3.5 part 17/21

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

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

#!/bin/sh
# this is part 17 of a multipart archive
# do not concatenate these parts, unpack them in order with /bin/sh
# file expand.c continued
#
CurArch=17
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 expand.c"
sed 's/^X//' << 'SHAR_EOF' >> expand.c
X   }
X}
X
X
X
Xstatic char*
X_scan_token( s, ps )/*
X======================
X      This routine scans the token characters one at a time and identifies
X      macros starting with $( and ${ and calls _scan_macro to expand their
X      value.   the string1{ token_list }string2 expansion is also handled.
X      In this case a temporary result is maintained so that we can take it's
X      cross product with any other token_lists that may possibly appear. */
X      
Xchar *s;		/* pointer to start of src string */
Xchar **ps;		/* pointer to start pointer	  */
X{
X   char *res;                 /* pointer to result          */
X   char *start;               /* pointer to start of prefix */
X   int  crossproduct = 0;     /* if 1 then computing X-prod */
X
X   start = s;
X   res   = _strdup( "" );
X   while( 1 )
X      switch( *s ) {
X         /* Termination, We halt at seeing a space or a tab or end of string.
X          * We return the value of the result with any new macro's we scanned
X          * or if we were computing cross_products then we return the new
X          * cross_product.
X          * NOTE:  Once we start computing cross products it is impossible to
X          *        stop.  ie. the semantics are such that once a {} pair is
X          *        seen we compute cross products until termination. */
X
X         case ' ':
X         case '\t':
X	 case '\n':
X         case '\0': 
X	 {
X	    char *tmp;
X
X	    *ps = s;
X	    if( !crossproduct )
X	       tmp = _strjoin( res, start, (s-start), TRUE );
X	    else
X	    {
X	       tmp = _substr( start, s );
X	       tmp = _cross_prod( res, tmp );
X	    }
X	    return( tmp );
X	 }
X         
X         case '$':
X         case '{':
X	 {
X	    /* Handle if it's a macro or if it's a {} construct.
X	     * The results of a macro expansion are handled differently based
X	     * on whether we have seen a {} beforehand. */
X	    
X	    char *tmp;
X	    tmp = _substr( start, s );          /* save the prefix */
X
X	    if( *s == '$' ) {
X	       start = _scan_macro( s+1, &s );
X
X	       if( crossproduct )
X		  res = _cross_prod( res, _strjoin( tmp, start, -1, TRUE ) );
X	       else {
X		  res = _strjoin(res,tmp = _strjoin(tmp,start,-1,TRUE),-1,TRUE);
X		  FREE( tmp );
X	       }
X	       FREE( start );
X	    }
X	    else if( s[1] != '{' ) {
X	       int ok;
X	       start = _scan_brace( s+1, &s, &ok );
X		  
X	       if( ok ) {
X		  res = _cross_prod( res, _cross_prod(tmp, start) );
X		  crossproduct = TRUE;
X	       }
X	       else {
X		  res =_strjoin(res,tmp=_strjoin(tmp,start,-1,TRUE),-1,TRUE);
X		  FREE( start );
X		  FREE( tmp   );
X	       }
X	    }
X	    else {    /* handle the {{ case */
X	       res = _strjoin( res, start, (s-start+1), TRUE );
X	       s  += 2;
X	       FREE( tmp );
X	    }
X
X	    start = s;
X	 }
X	 break;
X
X	 case '}':
X	    if( s[1] != '}' ) {
X	       /* error malformed macro expansion */
X	       s++;
X	    }
X	    else {    /* handle the }} case */
X	       res = _strjoin( res, start, (s-start+1), TRUE );
X	       s += 2;
X	       start = s;
X	    }
X	    break;
X         
X         default: s++;
X      }
X}
X
X
X
Xstatic char*
X_scan_macro( s, ps )/*
X======================
X	This routine scans a macro use and expands it to the value.  It
X	returns the macro's expanded value and modifies the pointer into the
X	src string to point at the first character after the macro use.
X	The types of uses recognized are:
X
X		$$		- expands to $
X		$(name)		- expands to value of name
X		${name}		- same as above
X		$($(name))	- recurses on macro names (any level)
X	and 
X	        $(name:modifier_list:modifier_list:...)
X        
X	see comment for Expand for description of valid modifiers.
X
X	NOTE that once a macro name bounded by ( or { is found only
X	the appropriate terminator (ie. ( or } is searched for. */
X
Xchar *s;		/* pointer to start of src string   */
Xchar **ps;		/* pointer to start pointer	    */
X{
X   char sdelim;         /* start of macro delimiter         */
X   char edelim;         /* corresponding end macro delim    */
X   char *start;         /* start of prefix                  */
X   char *macro_name;    /* temporary macro name             */
X   char *recurse_name;  /* recursive macro name             */
X   char *result;	/* result for macro expansion	    */
X   int  bflag = 0;      /* brace flag, ==0 => $A type macro */
X   int  done  = 0;      /* != 0 => done macro search        */
X   int  lev   = 0;      /* brace level                      */
X   int  mflag = 0;      /* != 0 => modifiers present in mac */
X   HASHPTR hp;		/* hash table pointer for macros    */
X   
X   DB_ENTER( "_scan_macro" );
X
X   /* Check for the simple $ at end of line case */
X   if( !*s ) {
X      *ps = s;
X      DB_RETURN( _strdup("") );
X   }
X
X   if( *s == '$' ) {    /* Take care of the simple $$ case. */
X      *ps = s+1;
X      DB_RETURN( _strdup("$") );
X   }
X
X   sdelim = *s;         /* set and remember start/end delim */
X   if( sdelim == '(' )
X      edelim = ')';
X   else
X      edelim = '}';
X
X   start = s;           /* build up macro name, find its end*/
X   while( !done ) {
X      switch( *s ) {
X         case '(':				/* open macro brace  */
X         case '{':
X	    if( *s == sdelim ) {
X	       lev++;
X	       bflag++;
X	    }
X	    break;
X         
X         case ':':                              /* halt at modifier          */
X            if( lev == 1 ) {
X               done = TRUE;
X               mflag = 1;
X            }
X            break;
X            
X	 case '\0':				/* check for EOLN and spaces */
X	 case ' ':				/* inside a macro name 	     */
X	 case '\t':
X	 case '\n':
X	    *ps = s;
X	    if( lev ) {
X	       done  = TRUE;
X	       bflag = 0;
X	       s     = start;
X	    }
X	    break;
X         
X         case ')':				/* close macro brace */
X         case '}':
X	    if( *s == edelim && lev ) --lev;
X	 /*FALLTHROUGH*/
X
X         default:
X	    done = !lev;
X      }
X      s++;
X   }
X
X   /* Check if this is a $A type macro.  If so then we have to
X    * handle it a little differently. */
X
X   if( bflag )
X      macro_name = _substr( start+1, s-1 );
X   else
X      macro_name = _substr( start, s );
X
X
X   /* Check if the macro is a recursive macro name, if so then
X    * EXPAND the name before expanding the value */
X
X   if( strchr( macro_name, '$' ) != NIL(char) ) {
X      recurse_name = Expand( macro_name );
X      FREE( macro_name );
X      macro_name = recurse_name;
X   }
X
X   /* Code to do value expansion goes here, NOTE:  macros whose assign bit
X      is one have been evaluated and assigned, they contain no further
X      expansions and thus do not need their values expanded again. */
X
X   if( (hp = GET_MACRO( macro_name )) != NIL(HASH) ) {
X      if( hp->ht_flag & M_MARK )
X	 Fatal( "Detected circular macro [%s]", hp->ht_name );
X
X      /* for M_MULTI macro variable assignments */
X      If_multi = hp->ht_flag & M_MULTI;
X
X      if( !(hp->ht_flag & M_EXPANDED) ) {
X	 hp->ht_flag |= M_MARK;
X	 result = Expand( hp->ht_value );
X	 hp->ht_flag ^= M_MARK;
X      }
X      else if( hp->ht_value != NIL(char) )
X	 result = _strdup( hp->ht_value );
X      else
X	 result = _strdup( "" );
X
X      /*
X       * Mark macros as used only if we are not expanding them for
X       * the purpose of a .IF test, so we can warn about redef after use*/
X
X      if( !If_expand ) hp->ht_flag |= M_USED;
X   }
X   else
X      result = _strdup( "" );
X
X   if( mflag ) {
X      char separator;
X      int  modifier_list = 0;
X      int  aug_mod       = FALSE;
X      char *pat1;
X      char *pat2;
X      char *p;
X
X      /* Yet another brain damaged AUGMAKE kludge.  We should accept the 
X       * AUGMAKE bullshit of $(f:pat=sub) form of macro expansion.  In
X       * order to do this we will forgo the normal processing if the
X       * AUGMAKE solution pans out, otherwise we will try to process the
X       * modifiers ala dmake.
X       *
X       * So we look for = in modifier string.
X       * If found we process it and not do the normal stuff */
X
X      for( p=s; *p && *p != '=' && *p != edelim; p++ );
X
X      if( *p == '=' ) {
X	 pat1 = _substr( s, p );
X	 for( s=p=p+1; (*p != edelim); p++ );
X
X	 pat2   = _substr( s, p );
X	 result = Apply_edit( result, pat1, pat2, TRUE, TRUE );
X	 FREE( pat1 );
X	 FREE( pat2 );
X	 s = p;
X	 aug_mod = TRUE;
X      }
X
X      if( !aug_mod )
X	 while( *s && *s != edelim ) {		/* while not at end of macro */
X	    switch( *s++ ) {
X	       case 'b':
X	       case 'B': modifier_list |= FILE_FLAG; 		   break;
X
X	       case 'd':
X	       case 'D': modifier_list |= DIRECTORY_FLAG;  	   break;
X
X	       case 'f':
X	       case 'F': modifier_list |= FILE_FLAG | SUFFIX_FLAG; break;
X
X	       case 'S':
X	       case 's':
X		  if( modifier_list ) {
X		     Warning( "Edit modifier must appear alone, ignored");
X		     modifier_list = 0;
X		  }
X		  else {
X		     separator = *s++;
X		     for( p=s; *p != separator && *p != edelim; p++ );
X
X		     if( *p == edelim )
X		        Warning("Syntax error in edit pattern, ignored");
X		     else {
X			char *t1, *t2;
X			pat1 = _substr( s, p );
X			for(s=p=p+1; (*p != separator) && (*p != edelim); p++ );
X			pat2 = _substr( s, p );
X			t1 = Expand(pat1); FREE(pat1);
X			t2 = Expand(pat2); FREE(pat2);
X			result = Apply_edit( result, t1, t2, TRUE, FALSE );
X			FREE( t1 );
X			FREE( t2 );
X		     }
X		     s = p;
X		  }
X		  /* find the end of the macro spec, or the start of a new
X		   * modifier list for further processing of the result */
X
X		  for( ; (*s != edelim) && (*s != ':'); s++ );
X		  if( *s == ':' ) s++;
X		  break;
X
X	       case 'T':
X	       case 't':
X		  if( modifier_list ) {
X		     Warning( "Tokenize modifier must appear alone, ignored");
X		     modifier_list = 0;
X		  }
X		  else {
X		     char *msg = "Separator string must be quoted";
X
X		     separator = *s++;
X
X		     if( separator != '\"' )
X			Warning( msg );
X		     else {
X			/* we change the semantics to allow $(v:t")") */
X			for (p = s; *p && *p != separator; p++)
X			   if (*p == '\\')
X			      if (p[1] == '\\' || p[1] == '"')
X				 p++;
X			if( *p == 0 )
X			   Fatal( "Unterminated separator string" );
X			else {
X			   pat1 = _substr( s, p );
X			   result = _tokenize( result, pat1 );
X			   FREE( pat1 );
X			}
X			s = p;
X		     }
X
X		     /* find the end of the macro spec, or the start of a new
X		      * modifier list for further processing of the result */
X
X		     for( ; (*s != edelim) && (*s != ':'); s++ );
X		     if( *s == ':' ) s++;
X		  }
X		  break;
X
X	       case ':':
X		  if( modifier_list ) {
X		     result = _apply_modifiers( modifier_list, result );
X		     modifier_list = 0;
X		  }
X		  break;
X
X	       default:
X		  Warning( "Illegal modifier in macro, ignored" );
X		  break;
X	    }
X	 }
X
X      if( modifier_list ) /* apply modifier */
X         result = _apply_modifiers( modifier_list, result );
X      
X      s++;
X   }
X
X   *ps = s;
X   FREE( macro_name );
X   DB_RETURN( result );
X}
X
X
X
Xstatic char*
X_scan_brace( s, ps, flag )/*
X============================
X      This routine scans for { token_list } pairs.  It expands the value of
X      token_list by calling Expand on it.  Token_list may be anything at all.
X      Note that the routine count's ballanced parentheses.  This means you
X      cannot have something like { fred { joe }, if that is what you really
X      need the write it as { fred {{ joe }, flag is set to 1 if all ok
X      and to 0 if the braces were unballanced. */
X      
Xchar *s;
Xchar **ps;
Xint  *flag;
X{
X   char *t;
X   char *start;
X   char *res;
X   int  lev  = 1;
X   int  done = 0;
X   
X   DB_ENTER( "_scan_brace" );
X
X   start = s;
X   while( !done )
X      switch( *s++ ) {
X         case '{': 
X            if( *s == '{' ) break;              /* ignore {{ */
X            lev++;
X            break;
X            
X         case '}': 
X            if( *s == '}' ) break;              /* ignore }} */
X	    if( lev )
X	       if( --lev == 0 ) done = TRUE;
X	    break;
X
X	 case '$':
X	    if( *s == '{' || *s == '}' ) {
X	      if( (t = strchr(s,'}')) != NIL(char) )
X	         s = t;
X	      s++;
X	    }
X	    break;
X         
X         case '\0':
X	    if( lev ) {
X	       done = TRUE;
X	       s--;
X	       /* error malformed macro expansion */
X	    }
X	    break;
X      }
X
X   start = _substr( start, (lev) ? s : s-1 );
X
X   if( lev ) {
X      /* Braces were not ballanced so just return the string.
X       * Do not expand it. */
X       
X      res   = _strjoin( "{", start, -1, FALSE );
X      *flag = 0;
X   }
X   else {
X      *flag = 1;
X      res   = Expand( start );
X
X      if( (t = _strspn( res, " \t" )) != res ) strcpy( res, t );
X   }
X
X   FREE( start );       /* this is ok! start is assigned a _substr above */
X   *ps = s;
X
X   DB_RETURN( res );
X}
X
X
X
Xstatic char*
X_cross_prod( x, y )/*
X=====================
X      Given two strings x and y compute the cross-product of the tokens found
X      in each string.  ie. if x = "a b" and y = "c d" return "ac ad bc bd".
X
X	     NOTE:  buf will continue to grow until it is big enough to handle
X	            all cross product requests.  It is never freed!  (maybe I
X		    will fix this someday) */
X      
Xchar *x;
Xchar *y;
X{
X   static char *buf;
X   static int  buf_siz = 0;
X   char *brkx;
X   char *brky;
X   char *cy;
X   char *cx;
X   char *res;
X   int  i;
X
X   if( *x && *y ) {
X      res = _strdup( "" ); cx = x;
X      while( *cx ) {
X	 cy = y;
X         brkx = _strpbrk( cx, " \t\n" );
X	 if( (brkx-cx == 2) && *cx == '\"' && *(cx+1) == '\"' ) cx = brkx;
X
X	 while( *cy ) {
X	    brky = _strpbrk( cy, " \t\n" );
X	    if( (brky-cy == 2) && *cy == '\"' && *(cy+1) == '\"' ) cy = brky;
X	    i    = brkx-cx + brky-cy + 2;
X
X	    if( i > buf_siz ) {		/* grow buf to the correct size */
X	       if( buf != NIL(char) ) FREE( buf );
X	       if( (buf = MALLOC( i, char )) == NIL(char))  No_ram();
X	       buf_siz = i;
X	    }
X
X	    strncpy( buf, cx, (i = brkx-cx) );
X	    buf[i] = '\0';
X	    if (brky-cy > 0) strncat( buf, cy, brky-cy );
X	    strcat( buf, " " );
X	    res = _strjoin( res, buf, -1, TRUE );
X	    cy = _strspn( brky, " \t\n" );
X	 }
X	 cx = _strspn( brkx, " \t\n" );
X      }
X
X      FREE( x );
X      res[ strlen(res)-1 ] = '\0';
X   }
X   else
X      res = _strjoin( x, y, -1, TRUE );
X
X   FREE( y );
X   return( res );
X}
X
X
X
Xstatic char*
X_apply_modifiers( mod, src )/*
X==============================
X   This routine applies the appropriate modifiers to the string src
X   and returns the proper result string */
X
Xint  mod;
Xchar *src;
X{
X   char	   *s;
X   char    *e;
X   TKSTR   str;
X
X   DB_ENTER( "_apply_modifiers" );
X
X   if( mod == (SUFFIX_FLAG | DIRECTORY_FLAG | FILE_FLAG) )
X      DB_RETURN( src );
X
X   SET_TOKEN( &str, src );
X   DB_PRINT( "mod", ("Source string [%s]", src) );
X
X   while( *(s = Get_token( &str, "", FALSE )) != '\0' ) {
X      /* search for the directory portion of the filename.  If the
X       * DIRECTORY_FLAG is set, then we want to keep the directory portion
X       * othewise throw it away and blank out to the end of the token */
X
X      if( (e = basename(s)) != s)
X	 if( !(mod & DIRECTORY_FLAG) ) {
X	    strcpy(s, e);
X	    e = s+(str.tk_str-e);
X	    for(; e != str.tk_str; e++)
X               *e = ' ';
X	 }
X	 else
X	    s = e;
X
X      /* search for the suffix, if there is none, treat it as a NULL suffix.
X       * if no file name treat it as a NULL file name.  same copy op as
X       * for directory case above */
X
X      e = strrchr( s, '.' );			/* NULL suffix if e=0 */
X      if( e == NIL(char) ) e = s+strlen(s);
X
X      if( !(mod & FILE_FLAG) ) {
X	 strcpy( s, e );
X	 e = s+(str.tk_str-e);
X	 for( ; e != str.tk_str; e++ ) *e = ' ';
X      }
X      else
X	 s = e;
X
X      /* The last and final part.  This is the suffix case, if we don't want
X       * it then just erase to the end of the token. */
X
X      if( s != NIL(char) )
X	 if( !(mod & SUFFIX_FLAG) )
X	    for( ; s != str.tk_str; s++ ) *s = ' ';
X   }
X
X   /* delete the extra white space, it looks ugly */
X   for( s = src, e = NIL(char); *s; s++ )
X      if( *s == ' ' || *s == '\t' || *s == '\n' ) {
X	 if( e == NIL(char) )
X	    e = s;
X      }
X      else {
X	 if( e != NIL(char) ) {
X	    if( e+1 < s ) {
X	       strcpy( e+1, s );
X	       s = e+1;
X	       *e = ' ';
X	    }
X	    e = NIL(char);
X	 }
X      }
X
X   if( e != NIL(char) )
X      if( e < s )
X	 strcpy( e, s );
X
X   DB_PRINT( "mod", ("Result string [%s]", src) );
X   DB_RETURN( src );
X}
X
X
X
Xstatic char*
X_tokenize( src, separator )/*
X=============================
X	Tokenize the input of src and join each token found together with
X	the next token separated by the separator string.
X
X	When doing the tokenization, <sp>, <tab>, <nl>, and \<nl> all
X	constitute white space. */
X
Xchar *src;
Xchar *separator;
X{
X   TKSTR	tokens;
X   char		*tok;
X   char		*res;
X   int		first = TRUE;
X
X   DB_ENTER( "_tokenize" );
X
X   SET_TOKEN( &tokens, src );
X
X
X   /* map the escape codes in the separator string first */
X
X   for(tok=separator; (tok = strchr(tok,CONTINUATION_CHAR)) != NIL(char); tok++)
X      Map_esc( tok );
X
X   DB_PRINT( "exp", ("Separator [%s]", separator) );
X
X   /* Build the token list */
X   res = _strdup( "" );
X   while( *(tok = Get_token( &tokens, "", FALSE )) != '\0' ) {
X      DB_PRINT( "exp", ("Tokenizing [%s]", tok) );
X
X      if( first ) {
X	 FREE( res );
X	 res   = _strdup( tok );
X	 first = FALSE;
X      }
X      else {
X      	 char *x;
X	 res = _strjoin(res, x =_strjoin(separator, tok, -1, FALSE), -1, TRUE);
X	 FREE( x );
X      }
X   }
X
X   FREE( src );
X   DB_RETURN( res );
X}
SHAR_EOF
echo "File expand.c is complete"
chmod 0440 expand.c || echo "restore of expand.c fails"
echo "x - extracting dump.c (Text)"
sed 's/^X//' << 'SHAR_EOF' > dump.c &&
X/* RCS      -- $Header: /u2/dvadura/src/generic/dmake/src/RCS/dump.c,v 1.1 90/07/21 11:06:32 dvadura Exp $
X-- SYNOPSIS -- dump the internal dag to stdout.
X-- 
X-- DESCRIPTION
X--	This file contains the routine that is called to dump a version of
X--	the digested makefile to the standard output.  May be useful perhaps
X--	to the ordinary user, and invaluable for debugging make.
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:	dump.c,v $
X * Revision 1.1  90/07/21  11:06:32  dvadura
X * Initial Revision Version 3.5
X * 
X*/
X
X#include "db.h"
X#include "extern.h"
X
X#define M_TEST	(M_PRECIOUS | M_VAR_MASK)
X
Xstatic	void	dump_normal_target ANSI((CELLPTR, HOWPTR, CELLPTR));
Xstatic	void	dump_graph_node ANSI((CELLPTR));
Xstatic	void	dump_name ANSI((HASHPTR, int));
X
X
Xvoid
XDump()/*
X========  Dump onto standard output the digested makefile.  Note that
X	  the form of the dump is not representative of the contents
X	  of the original makefile contents at all */
X{
X   HASHPTR      hp;
X   int          i;
X
X   DB_ENTER( "Dump" );
X
X   puts( "# Dump of dmake macro variables:" );
X   for( i=0; i<HASH_TABLE_SIZE; i++)
X      for( hp=Macs[i]; hp != NIL(HASH); hp = hp->ht_next ) {
X	 int flag = hp->ht_flag;
X
X	 printf( "%s ", hp->ht_name );
X	 if( flag & M_EXPANDED ) putchar( ':' );
X	 printf( "= " );
X	 if( hp->ht_value != NIL(char) ) printf( hp->ht_value );
X	 if( flag & M_PRECIOUS )
X	    printf( "\t # PRECIOUS " );
X	 putchar( '\n' );
X      }
X
X   puts( "\n#====================================" );
X   puts( "# Dump of targets:\n" );
X
X   for( i=0; i<HASH_TABLE_SIZE; i++ )
X      for( hp = Defs[i]; hp != NIL(HASH); hp = hp->ht_next )
X         if( !(hp->CP_OWNR->ce_flag & F_PERCENT) ) {
X	    if( hp->CP_OWNR == Fringe_hd->cl_prq )
X	       puts( "# ******* FIRST TARGET ********" );
X	    dump_normal_target( hp->CP_OWNR, hp->CP_OWNR->CE_HOW, NIL(CELL) );
X	 }
X
X   puts( "\n#====================================" );
X   puts( "# Dump of inference graph\n" );
X
X   for( i=0; i<HASH_TABLE_SIZE; i++ )
X      for( hp = Defs[i]; hp != NIL(HASH); hp = hp->ht_next )
X         if( (hp->CP_OWNR->ce_flag & F_PERCENT) &&
X	    !(hp->CP_OWNR->ce_flag & F_MAGIC) )
X	    dump_graph_node( hp->CP_OWNR );
X
X   DB_VOID_RETURN;
X}
X
X
X
Xvoid
XDump_recipe( sp )/*
X===================
X   Given a string pointer print the recipe line out */
XSTRINGPTR sp;
X{
X   char *st;
X   char *nl;
X
X   if( sp == NIL(STRING) ) return;
X
X   putchar( '\t' );
X   if( sp->st_attr & A_SILENT ) putchar( '@' );
X   if( sp->st_attr & A_IGNORE ) putchar( '-' );
X
X   st = sp->st_string;
X   for( nl=strchr(st,'\n'); nl != NIL( char); nl=strchr(st,'\n') ) {
X      *nl = '\0';
X      printf( "%s\\\n", st );
X      *nl = '\n';
X      st  = nl+1;
X   }
X   printf( "%s\n", st );
X}
X
X
Xstatic char *_attrs[] = { ".PRECIOUS ", ".SILENT ", ".LIBRARY ",
X   ".EPILOG ", ".PROLOG ", ".IGNORE ", ".SYMBOL ", ".NOINFER ",
X   ".UPDATEALL ", ".SEQUENTIAL " };
X
Xstatic void
Xdump_normal_target( cp, hw, prq )/*
X===================================
X	Dump in makefile like format the dag information */
XCELLPTR cp;
XHOWPTR  hw;
XCELLPTR prq;
X{
X   register LINKPTR   lp;
X   register STRINGPTR sp;
X   unsigned int	      attr, k;
X
X   DB_ENTER( "dump_normal_target" );
X
X   if( hw == NIL(HOW) ) { DB_VOID_RETURN; }
X   if( hw->hw_next != NIL(HOW) ) dump_normal_target( cp, hw->hw_next, prq );
X
X   dump_name( cp->ce_name, FALSE );
X
X   for( k=0, attr=1; attr < MAX_ATTR; attr <<= 1, k++ )
X      if( cp->ce_attr & attr )
X         printf( _attrs[k] );
X         
X   if( cp->ce_attr & A_SETDIR )
X      printf( ".SETDIR=%s ", cp->ce_dir ? cp->ce_dir : "" );
X
X   putchar( ':' );
X
X   if( cp->ce_flag & F_MULTI )  putchar( ':' );
X   if( hw->hw_flag & F_SINGLE ) putchar( '!' );
X   putchar( ' ' );
X
X   if( prq != NIL(CELL) ) dump_name( prq->ce_name, FALSE );
X   for( lp = hw->hw_prq; lp != NIL(LINK); lp = lp->cl_next )
X      dump_name( lp->cl_prq->ce_name, FALSE );
X
X   if( (lp = hw->hw_indprq) != NIL(LINK) ) {
X      for( ; lp != NIL(LINK); lp = lp->cl_next )
X	 dump_name( lp->cl_prq->ce_name, TRUE );
X   }
X
X   putchar( '\n' );
X   if( hw->hw_flag & F_GROUP ) {
X      if( hw->hw_attr & A_IGNORE ) putchar( '-' );
X      if( hw->hw_attr & A_SILENT ) putchar( '@' );
X      puts( "[" );
X   }
X
X   for( sp = hw->hw_recipe; sp != NIL(STRING); sp = sp->st_next )
X      Dump_recipe( sp );
X   if( hw->hw_flag & F_GROUP ) puts( "]" );
X
X   putchar( '\n' );
X   DB_VOID_RETURN;
X}
X
X
Xstatic void
Xdump_name( hp, quote )/*
X========================
X	print out a name */
XHASHPTR hp;
Xint     quote;
X{
X   if( quote ) putchar('\'');
X   printf( "%s", hp->ht_name );
X   if( quote ) putchar('\'');
X   putchar(' ');
X}
X 
X
X
Xstatic void
Xdump_graph_node( cp )/*
X=======================*/
XCELLPTR cp;
X{
X   EDGEPTR	pe;
X
X   pe = cp->CE_EDGES; 
X
X   if( pe != NIL(EDGE) )
X      do {
X	 dump_normal_target( cp, pe->ed_how, pe->ed_prq );
X	 pe = pe->ed_next;
X      }
X      while( pe != cp->CE_EDGES );
X}
SHAR_EOF
chmod 0440 dump.c || echo "restore of dump.c fails"
echo "x - extracting dmake.h (Text)"
sed 's/^X//' << 'SHAR_EOF' > dmake.h &&
X/* RCS      -- $Header: /u2/dvadura/src/generic/dmake/src/RCS/dmake.h,v 1.1 90/07/19 13:55:27 dvadura Exp $
X-- SYNOPSIS -- global defines for dmake.
X-- 
X-- DESCRIPTION
X-- 	All the interesting bits and flags that dmake uses are defined here.
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:	dmake.h,v $
X * Revision 1.1  90/07/19  13:55:27  dvadura
X * Initial Revision of Version 3.5
X * 
X*/
X
X#ifndef _DMAKE_INCLUDED_
X#define _DMAKE_INCLUDED_
X
X#define MAX_INC_DEPTH     10     /* max of ten nested include files      */
X#define MAX_COND_DEPTH	  20	 /* max nesting level of conditionals    */
X#define ERROR_EXIT_VALUE  255	 /* return code of aborted make		 */
X#define CONTINUATION_CHAR '\\'   /* line continuation \<nl>              */
X#define ESCAPE_CHAR       '\\'   /* escape char for used chars           */
X#define COMMENT_CHAR      '#'    /* start of comment chars               */
X#define TGT_DEP_SEP       ':'    /* separator for targets and dependents */
X#define CONDSTART	  '.'	 /* start of conditional token	eg .IF	 */
X#define DEF_MAKE_PNAME    "dmake"/* default name to use as name of make  */
X
X
X/* ............... Hashing function constants ......................... */
X#define HASH_TABLE_SIZE  200            /* See hash.c for description   */
X
X
X/* Bit flags for cells and macro definitions. */
X#define M_DEFAULT        0x0000         /* default flag value           */
X#define M_MARK           0x0001         /* mark for circularity checks  */
X#define M_PRECIOUS       0x0002         /* keep macro, same as A_PRE... */
X#define M_MULTI          0x0004         /* multiple redefinitions ok!   */
X#define M_EXPANDED       0x0008         /* macro has been assigned      */
X#define M_USED		 0x0010		/* macro has been expanded	*/
X#define M_LITERAL	 0x0020		/* don't strip w/s on macro def */
X#define	M_NOEXPORT	 0x0040		/* don't export macro for -x	*/
X#define M_FORCE		 0x0080		/* Force a macro redefinition	*/
X#define M_VAR_BIT        0x1000         /* macro bit variable           */
X#define M_VAR_CHAR       0x2000         /* macro char variable          */
X#define M_VAR_STRING     0x4000         /* macro string variable        */
X#define M_VAR_INT	 0x8000		/* macro integer variable	*/
X
X#define M_VAR_MASK       0xf000         /* macro variable mask          */
X
X
X
X/* Global and target attribute flag definitions.
X * If you change the values of these or re-order them make appropriate changes
X * in dump.c so that the output of dmake -p matches the attribute info for a
X * target. */
X
X#define A_DEFAULT        0x0000         /* default flag value           */
X#define A_PRECIOUS       0x0001         /* object is precious           */
X#define A_SILENT         0x0002         /* don't echo commands          */
X#define A_LIBRARY        0x0004         /* target is an archive		*/
X#define A_EPILOG         0x0008         /* insert shell epilog code     */
X#define A_PROLOG         0x0010         /* insert shell prolog code     */
X#define A_IGNORE         0x0020         /* ignore errors                */
X#define A_SYMBOL	 0x0040		/* lib member is a symbol	*/
X#define A_NOINFER	 0x0080		/* no trans closure from cell	*/
X#define A_UPDATEALL	 0x0100		/* all targets of rule modified */
X#define A_SEQ		 0x0200		/* sequential make attribute	*/
X#define A_SETDIR         0x0400         /* cd to dir when making target */
X#define MAX_ATTR	 A_SETDIR	/* highest valid attribute	*/
X#define A_LIBRARYM       0x0800         /* target is an archive member  */
X#define A_FRINGE	 0x1000		/* cell is on the fringe	*/
X#define A_COMPOSITE	 0x2000		/* member of lib(targ) name	*/
X#define A_FFNAME	 0x4000		/* if set, free ce_fname in stat*/
X#define A_UPDATED	 0x8000		/* Used to mark cell as updated */
X
X
X/* Global and target bit flag definitions */
X
X#define F_DEFAULT        0x0000         /* default flag value           */
X#define F_MARK		 0x0001		/* circularity check mark	*/
X#define F_MULTI		 0x0002		/* multiple rules for target	*/
X#define F_SINGLE	 0x0004		/* exec rules one/prerequisite  */
X#define F_TARGET	 0x0008		/* marks a target		*/
X#define F_RULES          0x0010         /* indicates target has rules   */
X#define F_GROUP          0x0020         /* indicates that rules are to  */
X				        /* fed to the shell as a group  */
X
X#define F_TRANS		 0x0040		/* same as F_STAT not used tgthr*/
X#define F_STAT		 0x0040		/* target already stated	*/
X#define F_VISITED	 0x0080		/* target scheduled for make	*/
X#define F_USED		 0x0080		/* used in releparse.c		*/
X#define F_SPECIAL	 0x0100		/* marks a special target	*/
X#define F_DFA	 	 0x0200		/* bit for marking added DFA    */
X#define F_EXPLICIT	 0x0400		/* explicit target in makefile  */
X#define F_PERCENT	 0x0800		/* marks a target as a % rule	*/
X#define F_REMOVE	 0x1000		/* marks an intermediate target */
X#define F_MAGIC		 0x2000		/* marks a magic target		*/
X#define F_INFER		 0x4000		/* target is result of inference*/
X#define F_MADE		 0x8000		/* target is manufactured	*/
X
X
X/* Definitions for the Parser states */
X#define NORMAL_SCAN    0     /* normal processing state */
X#define RULE_SCAN      1     /* scan of rule text       */
X
X/* definitions for macro operator types */
X#define M_OP_EQ  1           /* macro operation is '='  */
X#define M_OP_CL  2           /* macro operation is ':=' */
X#define M_OP_PL  4           /* macro operation is '+=' */
X#define M_OP_PLCL 8          /* macro operation is '+:='*/
X
X/* definitions for rule operator types */
X#define R_OP_CL   1           /* rule operation is ':'   */
X#define R_OP_DCL  2           /* rule operation is '::'  */
X#define R_OP_BG   4           /* rule operation is ':!'  */
X#define R_OP_UP   8           /* rule operation is ':^'  */
X#define R_OP_MI  16           /* rule operation is ':-'  */
X
X
X/* special target definitions for use inside dmake */
X#define ST_IF		1
X#define ST_ELSE		2
X#define ST_END		3
X#define ST_REST		4	/* remaining special targets */
X#define ST_INCLUDE	5
X#define ST_SOURCE	7
X#define ST_EXPORT	8
X#define ST_IMPORT	9
X
X/* Macro definitions for use inside dmake */
X#define SET_TOKEN(A, B)  (A)->tk_str = (B); (A)->tk_cchar = *(B);\
X			 (A)->tk_quote = 1;
X#define CLEAR_TOKEN(A)   *(A)->tk_str = (A)->tk_cchar
X#define GET_MACRO(A)	 Get_name(A, Macs, FALSE, NIL(CELL))
X#define iswhite(C)     ((C == ' ') || (C == '\t'))
X
X#endif
X
SHAR_EOF
chmod 0440 dmake.h || echo "restore of dmake.h fails"
echo "x - extracting dmake.c (Text)"
sed 's/^X//' << 'SHAR_EOF' > dmake.c &&
X/* RCS      -- $Header: /u2/dvadura/src/generic/dmake/src/RCS/dmake.c,v 1.1 90/07/19 13:53:05 dvadura Exp $
X-- SYNOPSIS -- The main program.
X-- 
X-- DESCRIPTION
X-- 
X-- 	dmake [-#dbug_string] [ options ]
X-- 			[ macro definitions ] [ target ... ]
X-- 
X-- 	This file contains the main command line parser for the
X-- 	make utility.  The valid flags recognized are as follows:
X-- 
X-- 	-f file         - use file as the makefile
X-- 	-#dbug_string   - dump out debugging info, see below
X-- 
X-- 	 options: (can be catenated, ie -irn == -i -r -n)
X-- 
X--	-A		- enable AUGMAKE special target mapping
X-- 	-i              - ignore errors
X-- 	-n              - trace and print, do not execute commands
X-- 	-t              - touch, update dates without executing commands
X-- 	-T              - do not apply transitive closure
X-- 	-r              - don't use internal rules
X-- 	-s              - do your work silently
X--	-S		- force Sequential make, overrides -P
X-- 	-q              - check if target is up to date.  Does not
X-- 			  do anything.  Returns 0 if up to date, -1
X-- 			  otherwise.
X-- 	-p              - print out a version of the makefile
X--	-P#		- set value of MAXPROCESS
X-- 	-e              - define environment strings as macros
X-- 	-E              - as -e but done after parsing makefile
X-- 	-u              - force unconditional update of target
X-- 	-k              - make all independent targets even if errors
X-- 	-V              - print out this make version number
X-- 	-v		- verbose, print what we are doing, as we do it.
X-- 	-M		- Microsoft make compatibility, (* disabled *)
X-- 	-h              - print out usage info
X-- 	-x		- export macro defs to environment
X-- 
X-- 	NOTE:  - #ddbug_string is only availabe for versions of dmake that
X-- 		have been compiled with -DDBUG switch on.  Not the case for
X-- 		distributed versions.  Any such versions must be linked
X-- 		together with a version of Fred Fish's debug code.
X-- 			 
X-- 	NOTE:  - in order to compile the code the include file stddef.h
X-- 		must be shipped with the bundled code.
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:	dmake.c,v $
X * Revision 1.1  90/07/19  13:53:05  dvadura
X * Initial Revision of Version 3.5
X * 
X*/
X
X/* Set this flag to one, and the global variables in vextern.h will not
X * be defined as 'extern', instead they will be defined as global vars
X * when this module is compiled. */
X#define _DEFINE_GLOBALS_ 1
X
X#include <ctype.h>
X#include <stdarg.h>
X#include "extern.h"
X#include "alloc.h"
X#include "db.h"
X#include "patchlvl.h"
X#include "version.h"
X
X#ifdef HELP
X#define USAGE \
X"Usage: %s [-AeEhiknpqrsStTuvVx] [-P#] [-f file] [macro=value ...] [target ...]\n"
X#define COPYRIGHT "Copyright (c) 1990 by Dennis Vadura"
X#endif
X
Xstatic char *sccid = COPYRIGHT;
Xstatic char _warn  = TRUE;		/* warnings on by default */
X
Xstatic	void	_do_VPATH();
Xstatic	void	_do_ReadEnvironment();
X
Xmain(argc, argv)
Xint  argc;
Xchar **argv;
X{
X   char*   fil_name = NIL(char);
X   char*   cmdmacs;
X   FILE*   mkfil;
X   int     ex_val;
X   int     m_export;
X   HASHPTR hp;
X
X   DB_ENTER("main");
X
X   /* Initialize Global variables to their default values       */
X   Prolog(argc, argv);
X   Create_macro_vars();
X   Catch_signals(Quit);
X
X   Def_macro( "MAKECMD", Pname, M_PRECIOUS|M_NOEXPORT );
X   Pname = basename(Pname);
X
X   DB_PROCESS(Pname);
X   (void) setvbuf(stdout, NULL, _IOLBF, BUFSIZ); /* stdout line buffered */
X
X   Continue  = FALSE;
X   Get_env   = FALSE;
X   Force     = FALSE;
X   Target    = FALSE;
X   If_expand = FALSE;
X   Listing   = FALSE;
X   Readenv   = FALSE;
X   Rules     = TRUE;
X   Trace     = FALSE;
X   Touch     = FALSE;
X   Check     = FALSE;
X   Microsoft = FALSE;
X   Verbose   = FALSE;
X   Makemkf   = FALSE;
X   m_export  = FALSE;
X   cmdmacs   = NIL(char);
X
X   Transitive     = TRUE;
X   Nest_level     = 0;
X   Line_number    = 0;
X
X   while( --argc > 0 ) {
X      register char *p;
X      char *q;
X
X      if( *(p = *++argv) == '-' ) {
X         if( p[1] == '\0' ) Fatal("Missing option letter");
X
X         /* copy options to Buffer for $(MFLAGS), strip 'f' */
X         q = strchr(Buffer, 0);
X         while (*p != 0)
X            if( (*q++ = *p++) == 'f' ) q--;
X
X	 if( *(q-1) == '-' )
X	    q--;
X	 else
X            *q++ = ' ';
X
X	 *q = 0;
X
X         for( p = *argv+1; *p; p++) switch (*p) {
X	    case 'f':
X	       if( fil_name == NIL(char) ) {
X		  if( *++argv != NIL(char) ) {
X		     fil_name = *argv;
X		     argc--;
X		  } else
X		     Fatal("No file name for -f");
X	       } else
X		  Fatal("Only one `-f file' allowed");
X	       break;
X
X	    case 'k': Continue   = TRUE;  break;
X	    case 'p': Listing    = TRUE;  break;
X	    case 'r': Rules      = FALSE; break;
X	    case 'n': Trace      = TRUE;  break;
X	    case 't': Touch      = TRUE;  break;
X	    case 'q': Check      = TRUE;  break;
X	    case 'u': Force      = TRUE;  break;
X	    case 'v': Verbose    = TRUE;  break;
X	    case 'x': m_export   = TRUE;  break;
X	    case 'T': Transitive = FALSE; break;
X	    case 'e': Get_env    = 'e';   break;
X	    case 'E': Get_env    = 'E';   break;
X
X	    case 'V': Version();  Quit(NIL(CELL));  break;
X	    case 'A': Def_macro("AUGMAKE", "y", M_EXPANDED); break;
X	    case 'i': Def_macro(".IGNORE", "y", M_EXPANDED); break;
X	    case 's': Def_macro(".SILENT", "y", M_EXPANDED); break;
X	    case 'S': Def_macro(".SEQUENTIAL", "y", M_EXPANDED); break;
X
X	    case 'P':
X	       if( p[1] ) {
X		  Def_macro( "MAXPROCESS", p+1, M_MULTI|M_EXPANDED );
X		  p += strlen(p)-1;
X	       }
X	       else
X		  Fatal( "Missing number for -P flag" );
X	       break;
X
X#if 0   /*** disabled */
X	    case 'M': Microsoft  = TRUE;  break;
X#endif
X#ifdef HELP
X	    case 'h': Usage();  Quit(NIL(CELL));  break;
X#endif
X#ifdef DBUG
X	    case '#':
X	       DB_PUSH(p+1);
X	       p += strlen(p)-1;
X	       break;
X#endif
X
X	    default:
X	       fprintf(stderr, USAGE, Pname);
X	       Quit(NIL(CELL));
X	       break;
X	 }
X      }
X      else if( (q = strchr(p, '=')) != NIL(char) ) {
X	 cmdmacs = _stradd( cmdmacs, _strdup(p), FALSE );
X	 Parse_macro( p, M_PRECIOUS );
X      }
X      else {
X	 register CELLPTR cp;
X	 Add_fringe(cp = Def_cell(p, NIL(CELL)));
X	 cp->ce_flag |= F_TARGET;
X	 Target = TRUE;
X      }
X   }
X
X   Def_macro( "MAKEMACROS", cmdmacs, M_PRECIOUS|M_NOEXPORT );
X   if( cmdmacs != NIL(char) ) FREE(cmdmacs);
X
X   Def_macro( "MFLAGS", Buffer, M_PRECIOUS|M_NOEXPORT );
X   Def_macro( "%", "$@", M_PRECIOUS|M_NOEXPORT );
X
X   if( *Buffer ) Def_macro( "MAKEFLAGS", Buffer+1, M_PRECIOUS|M_NOEXPORT );
X
X   _warn  = FALSE;      /* disable warnings for builtin rules */
SHAR_EOF
echo "End of part 17"
echo "File dmake.c is continued in part 18"
echo "18" > s2_seq_.tmp
exit 0