[comp.sources.misc] v19i029: dmake - dmake version 3.7, Part08/37

dvadura@watdragon.waterloo.edu (Dennis Vadura) (05/11/91)

Submitted-by: Dennis Vadura <dvadura@watdragon.waterloo.edu>
Posting-number: Volume 19, Issue 29
Archive-name: dmake/part08
Supersedes: dmake-3.6: Volume 15, Issue 52-77

---- Cut Here and feed the following to sh ----
#!/bin/sh
# this is dmake.shar.08 (part 8 of a multipart archive)
# do not concatenate these parts, unpack them in order with /bin/sh
# file dmake/dmake.c continued
#
if test ! -r _shar_seq_.tmp; then
	echo 'Please unpack part 1 first!'
	exit 1
fi
(read Scheck
 if test "$Scheck" != 8; then
	echo Please unpack part "$Scheck" next!
	exit 1
 else
	exit 0
 fi
) < _shar_seq_.tmp || exit 1
if test -f _shar_wnt_.tmp; then
sed 's/^X//' << 'SHAR_EOF' >> 'dmake/dmake.c' &&
X   
X   if( next_file_slot == MAX_INC_DEPTH )
X      Fatal( "Too many open files. Max nesting level is %d.", MAX_INC_DEPTH);
X
X   DB_PRINT( "io", ("Opening file [%s], in slot %d", name, next_file_slot) );
X
X   if( strcmp("-", name) == 0 ) {
X      name = "stdin";
X      fil = stdin;
X   }
X   else
X      fil = fopen( name, mode ? "w":"r" );
X
X   if( Verbose & V_FILE_IO )
X      printf( "%s:  Openning [%s] for %s", Pname, name, mode?"write":"read" );
X
X   if( fil == NIL(FILE) ) {
X      if( Verbose & V_FILE_IO ) printf( " (fail)\n" );
X      if( err )
X         Fatal( mode ? "Cannot open file %s for write" : "File %s not found",
X		name );
X   }
X   else {
X      if( Verbose & V_FILE_IO ) printf( " (success)\n" );
X      ftab[next_file_slot].file   = fil;
X      ftab[next_file_slot].numb   = Line_number;
X      ftab[next_file_slot++].name = _strdup(name);
X      Line_number = 0;
X      _set_inc_depth();
X   }
X
X   DB_RETURN(fil);
}
X
X
PUBLIC FILE *
Closefile()/*
=============
X   This routine is used to close the last file opened.  This forces make
X   to open files in a last open first close fashion.  It returns the
X   file pointer to the next file on the stack, and NULL if the stack is empty.*/
{
X   DB_ENTER("Closefile");
X
X   if( !next_file_slot )
X      DB_RETURN( NIL(FILE) );
X
X   if( ftab[--next_file_slot].file != stdin ) {
X      DB_PRINT( "io", ("Closing file in slot %d", next_file_slot) );
X
X      if( Verbose & V_FILE_IO )
X	 printf( "%s:  Closing [%s]\n", Pname, ftab[next_file_slot].name );
X
X      fclose( ftab[next_file_slot].file );
X      FREE( ftab[next_file_slot].name );
X   }
X
X   _set_inc_depth();
X
X   if( next_file_slot > 0 ) {
X      Line_number = ftab[next_file_slot].numb;
X      DB_RETURN( ftab[next_file_slot-1].file );
X   }
X   else
X      Line_number = 0;
X
X   DB_RETURN( NIL(FILE) );
}
X
X
PUBLIC FILE *
Search_file( macname, rname )
char *macname;
char **rname;
{
X   HASHPTR hp;
X   FILE *fil = NIL(FILE);
X   char *fname;
X   char *ename = NIL(char);
X
X   /* order of precedence is:
X    *
X    *   MACNAME  from command line (precious is marked)
X    *		 ... via MACNAME:=filename definition.
X    *   MACNAME  from environment
X    *   MACNAME  from builtin rules (not precious)
X    */
X
X   if( (hp = GET_MACRO(macname)) != NIL(HASH) )
X      ename = fname = Expand(hp->ht_value);
X
X   if( hp->ht_flag & M_PRECIOUS ) fil = Openfile(fname, FALSE, FALSE);
X
X   if( fil == NIL(FILE) ) {
X      fname=Expand(Read_env_string(macname));
X      if( fil = Openfile(fname, FALSE, FALSE) ) FREE(ename);
X   }
X
X   if( fil == NIL(FILE) && hp != NIL(HASH) )
X      fil = Openfile(fname=ename, FALSE, FALSE);
X
X   if( rname ) *rname = fname;
X
X   return(fil);
}
X
X
PUBLIC char *
Filename()/*
============
X   Return name of file on top of stack */
{
X   return( next_file_slot==0 ? NIL(char) : ftab[next_file_slot-1].name );
}
X
/*
** print error message from variable arg list
*/
X
static int errflg = TRUE;
static int warnflg = FALSE;
X
static void
errargs(fmt, args)
char    *fmt;
va_list  args;
{
X   int warn = _warn && warnflg && !(Glob_attr & A_SILENT);
X
X   if( errflg || warn ) {
X      char *f = Filename();
X
X      fprintf( stderr, "%s:  ", Pname );
X      if( f != NIL(char) ) fprintf(stderr, "%s:  line %d:  ", f, Line_number);
X
X      if( errflg )
X         fprintf(stderr, "Error -- ");
X      else if( warn )
X         fprintf(stderr, "Warning -- ");
X
X      vfprintf( stderr, fmt, args );
X      putc( '\n', stderr );
X      if( errflg && !Continue ) Quit( NIL(CELL) );
X   }
}
X
/*
** Print error message and abort
*/
int
Fatal(fmt, va_alist)
char *fmt;
va_dcl;
{
X   va_list args;
X
X   va_start(args, fmt);
X   Continue = FALSE;
X   errargs(fmt, args);
X   va_end(args);
}
X
/*
** error message and exit (unless -k)
*/
int
Error(fmt, va_alist)
char*   fmt;
va_dcl;
{
X   va_list args;
X
X   va_start(args, fmt);
X   errargs(fmt, args);
X   va_end(args);
}
X
X
/*
** non-fatal message
*/
int
Warning(fmt, va_alist)
char *fmt;
va_dcl;
{
X   va_list args;
X
X   va_start(args, fmt);
X   warnflg = TRUE;
X   errflg = FALSE;
X   errargs(fmt, args);
X   errflg = TRUE;
X   warnflg = FALSE;
X   va_end(args);
}
X
X
PUBLIC void
No_ram()
{
X   Fatal( "No more memory" );
}
X
X
PUBLIC
X
Usage( eflag )
int eflag;
{
X   if( eflag ) {
X      fprintf(stderr, USAGE, Pname);
X   }
X   else {
X   printf(USAGE, Pname);
X   puts("    -P#        - set max number of child processes for parallel make");
X   puts("    -f file    - use file as the makefile");
#ifdef MSDOS
X   puts("    -C [+]file - duplicate console output to file, ('+' => append)");
#endif
X   puts("    -K file    - use file as the .KEEP_STATE file");
X   puts("    -v{dfimt}  - verbose, indicate what we are doing, (-v => -vdimt)");
X   puts("                   d => dump change of directory info only" );
X   puts("                   f => dump file open/close info only" );
X   puts("                   i => dump inference information only" );
X   puts("                   m => dump make of target information only" );
X   puts("                   t => keep temporary files when done\n" );
X
X   puts("Options: (can be catenated, ie -irn == -i -r -n)");
X   puts("    -A   - enable AUGMAKE special target mapping");
X   puts("    -c   - use non standard comment scanning");
X   puts("    -e   - define environment strings as macros");
X   puts("    -E   - same as -e but done after parsing makefile");
X   puts("    -h   - print out usage info");
X   puts("    -i   - ignore errors");
X   puts("    -k   - make independent targets, even if errors");
X   puts("    -n   - trace and print, do not execute commands");
X   puts("    -p   - print out a version of the makefile");
X   puts("    -q   - check if target is up to date.  Does not do");
X   puts("           anything.  Returns 0 if up to date, 1 otherwise");
X   puts("    -r   - don't use internal rules");
X   puts("    -s   - do your work silently");
X   puts("    -S   - disable parallel (force sequential) make, overrides -P");
X   puts("    -t   - touch, update time stamps without executing commands");
X   puts("    -T   - do not apply transitive closure");
X   puts("    -u   - force unconditional update of target");
X   puts("    -V   - print out version number");
X   puts("    -x   - export macro values to environment");
X   }
X
X   Quit(NIL(CELL));
}
X
X
PUBLIC
Version()
{
X   extern char **Rule_tab;
X   char **p;
X   
X   printf("%s - %s, ", Pname, sccid);
X   printf("Version %s, PL %d\n\n", VERSION, PATCHLEVEL);
X
X   puts("Default Configuration:");
X   for (p=Rule_tab;  *p != NIL(char);  p++)
X      printf("\t%s\n", *p);
}
SHAR_EOF
chmod 0640 dmake/dmake.c ||
echo 'restore of dmake/dmake.c failed'
Wc_c="`wc -c < 'dmake/dmake.c'`"
test 20025 -eq "$Wc_c" ||
	echo 'dmake/dmake.c: original size 20025, current size' "$Wc_c"
rm -f _shar_wnt_.tmp
fi
# ============= dmake/dmake.h ==============
if test -f 'dmake/dmake.h' -a X"$1" != X"-c"; then
	echo 'x - skipping dmake/dmake.h (File already exists)'
	rm -f _shar_wnt_.tmp
else
> _shar_wnt_.tmp
sed 's/^X//' << 'SHAR_EOF' > 'dmake/dmake.h' &&
/* RCS      -- $Header: /u2/dvadura/src/generic/dmake/src/RCS/dmake.h,v 1.1 91/05/06 15:23:07 dvadura Exp $
-- SYNOPSIS -- global defines for dmake.
-- 
-- DESCRIPTION
-- 	All the interesting bits and flags that dmake uses are defined here.
--
-- AUTHOR
--      Dennis Vadura, dvadura@watdragon.uwaterloo.ca
--      CS DEPT, University of Waterloo, Waterloo, Ont., Canada
--
-- COPYRIGHT
--      Copyright (c) 1990 by Dennis Vadura.  All rights reserved.
-- 
--      This program is free software; you can redistribute it and/or
--      modify it under the terms of the GNU General Public License
--      (version 1), as published by the Free Software Foundation, and
--      found in the file 'LICENSE' included with this distribution.
-- 
--      This program is distributed in the hope that it will be useful,
--      but WITHOUT ANY WARRANTY; without even the implied warrant of
--      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
--      GNU General Public License for more details.
-- 
--      You should have received a copy of the GNU General Public License
--      along with this program;  if not, write to the Free Software
--      Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
--
-- LOG
--     $Log:	dmake.h,v $
X * Revision 1.1  91/05/06  15:23:07  dvadura
X * dmake Release Version 3.7
X * 
*/
X
#ifndef _DMAKE_INCLUDED_
#define _DMAKE_INCLUDED_
X
#define MAX_INC_DEPTH     10     /* max of ten nested include files      */
#define MAX_COND_DEPTH	  20	 /* max nesting level of conditionals    */
#define ERROR_EXIT_VALUE  255	 /* return code of aborted make		 */
#define CONTINUATION_CHAR '\\'   /* line continuation \<nl>              */
#define ESCAPE_CHAR       '\\'   /* escape char for used chars           */
#define COMMENT_CHAR      '#'    /* start of comment chars               */
#define TGT_DEP_SEP       ':'    /* separator for targets and dependents */
#define CONDSTART	  '.'	 /* start of conditional token	eg .IF	 */
#define DEF_MAKE_PNAME    "dmake"/* default name to use as name of make  */
X
X
/* ............... Hashing function constants ......................... */
#define HASH_TABLE_SIZE  200            /* See hash.c for description   */
X
X
/* Bit flags for cells and macro definitions. */
#define M_DEFAULT        0x0000         /* default flag value           */
#define M_MARK           0x0001         /* mark for circularity checks  */
#define M_PRECIOUS       0x0002         /* keep macro, same as A_PRE... */
#define M_MULTI          0x0004         /* multiple redefinitions ok!   */
#define M_EXPANDED       0x0008         /* macro has been assigned      */
#define M_USED		 0x0010		/* macro has been expanded	*/
#define M_LITERAL	 0x0020		/* don't strip w/s on macro def */
#define	M_NOEXPORT	 0x0040		/* don't export macro for -x	*/
#define M_FORCE		 0x0080		/* Force a macro redefinition	*/
#define M_VAR_BIT        0x1000         /* macro bit variable           */
#define M_VAR_CHAR       0x2000         /* macro char variable          */
#define M_VAR_STRING     0x4000         /* macro string variable        */
#define M_VAR_INT	 0x8000		/* macro integer variable	*/
X
#define M_VAR_MASK       0xf000         /* macro variable mask          */
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
#define A_DEFAULT        0x00000        /* default flag value           */
#define A_PRECIOUS       0x00001        /* object is precious           */
#define A_SILENT         0x00002        /* don't echo commands          */
#define A_LIBRARY        0x00004        /* target is an archive		*/
#define A_EPILOG         0x00008        /* insert shell epilog code     */
#define A_PROLOG         0x00010        /* insert shell prolog code     */
#define A_IGNORE         0x00020        /* ignore errors                */
#define A_SYMBOL	 0x00040	/* lib member is a symbol	*/
#define A_NOINFER	 0x00080	/* no trans closure from cell	*/
#define A_UPDATEALL	 0x00100	/* all targets of rule modified */
#define A_SEQ		 0x00200	/* sequential make attribute	*/
#define A_SETDIR         0x00400        /* cd to dir when making target */
#define A_SHELL		 0x00800	/* run the recipe using a shell */
#define A_SWAP		 0x01000	/* swap on exec.		*/
#define A_MKSARGS	 0x02000	/* use MKS argument swapping	*/
#define A_PHONY		 0x04000	/* .PHONY attribute		*/
#define A_NOSTATE        0x08000	/* don't track state for me     */
#define MAX_ATTR	 A_NOSTATE	/* highest valid attribute	*/
#define A_LIBRARYM       0x10000        /* target is an archive member  */
#define A_FRINGE	 0x20000	/* cell is on the fringe	*/
#define A_COMPOSITE	 0x40000	/* member of lib(targ) name	*/
#define A_FFNAME	 0x80000	/* if set, free ce_fname in stat*/
#define A_UPDATED	0x100000	/* Used to mark cell as updated */
#define A_ROOT          0x200000	/* True if it is a root prereq  */
X
X
/* Global and target bit flag definitions */
X
#define F_DEFAULT        0x0000         /* default flag value           */
#define F_MARK		 0x0001		/* circularity check mark	*/
#define F_MULTI		 0x0002		/* multiple rules for target	*/
#define F_SINGLE	 0x0004		/* exec rules one/prerequisite  */
#define F_TARGET	 0x0008		/* marks a target		*/
#define F_RULES          0x0010         /* indicates target has rules   */
#define F_GROUP          0x0020         /* indicates that rules are to  */
X				        /* fed to the shell as a group  */
X
#define F_TRANS		 0x0040		/* same as F_STAT not used tgthr*/
#define F_STAT		 0x0040		/* target already stated	*/
#define F_VISITED	 0x0080		/* target scheduled for make	*/
#define F_USED		 0x0080		/* used in releparse.c		*/
#define F_SPECIAL	 0x0100		/* marks a special target	*/
#define F_DFA	 	 0x0200		/* bit for marking added DFA    */
#define F_EXPLICIT	 0x0400		/* explicit target in makefile  */
#define F_PERCENT	 0x0800		/* marks a target as a % rule	*/
#define F_REMOVE	 0x1000		/* marks an intermediate target */
#define F_MAGIC		 0x2000		/* marks a magic target		*/
#define F_INFER		 0x4000		/* target is result of inference*/
#define F_MADE		 0x8000		/* target is manufactured	*/
X
X
/* Definitions for the Parser states */
#define NORMAL_SCAN    0     /* normal processing state */
#define RULE_SCAN      1     /* scan of rule text       */
X
/* definitions for macro operator types */
#define M_OP_EQ  1           /* macro operation is '='  */
#define M_OP_CL  2           /* macro operation is ':=' */
#define M_OP_PL  3           /* macro operation is '+=' */
#define M_OP_PLCL 4          /* macro operation is '+:='*/
#define M_OP_DF  5	     /* macro operation is '*=' */
#define M_OP_DFCL 6	     /* macro operation is '*:='*/
X
/* definitions for rule operator types */
#define R_OP_CL   1           /* rule operation is ':'   */
#define R_OP_DCL  2           /* rule operation is '::'  */
#define R_OP_BG   4           /* rule operation is ':!'  */
#define R_OP_UP   8           /* rule operation is ':^'  */
#define R_OP_MI  16           /* rule operation is ':-'  */
X
/* definitions for modifier application in Apply_modifiers in expand.c */
#define SUFFIX_FLAG	1		/* defines for macro modifier code */
#define DIRECTORY_FLAG	2
#define FILE_FLAG	4
X
/* special target definitions for use inside dmake */
#define ST_IF		1
#define ST_ELSE		2
#define ST_END		3
#define ST_REST		4	/* remaining special targets */
#define ST_INCLUDE	5
#define ST_SOURCE	7
#define ST_EXPORT	8
#define ST_IMPORT	9
#define ST_ELIF        10
#define ST_KEEP	       11
X
/* Flags for controling use of -v switch */
#define V_NONE		0x00
#define V_LEAVE_TMP	0x01
#define V_PRINT_DIR	0x02
#define V_INFER	        0x04
#define V_MAKE		0x08
#define V_FILE_IO       0x10
#define V_ALL		(V_LEAVE_TMP | V_PRINT_DIR | V_INFER | V_MAKE |\
X			 V_FILE_IO)
X
/* Macro definitions for use inside dmake */
#define SET_TOKEN(A, B)  (A)->tk_str = (B); (A)->tk_cchar = *(B);\
X			 (A)->tk_quote = 1;
#define CLEAR_TOKEN(A)   *(A)->tk_str = (A)->tk_cchar
#define GET_MACRO(A)	 Get_name(A, Macs, FALSE)
#define iswhite(C)     ((C == ' ') || (C == '\t'))
X
#endif
X
SHAR_EOF
chmod 0640 dmake/dmake.h ||
echo 'restore of dmake/dmake.h failed'
Wc_c="`wc -c < 'dmake/dmake.h'`"
test 8165 -eq "$Wc_c" ||
	echo 'dmake/dmake.h: original size 8165, current size' "$Wc_c"
rm -f _shar_wnt_.tmp
fi
# ============= dmake/dmdump.c ==============
if test -f 'dmake/dmdump.c' -a X"$1" != X"-c"; then
	echo 'x - skipping dmake/dmdump.c (File already exists)'
	rm -f _shar_wnt_.tmp
else
> _shar_wnt_.tmp
sed 's/^X//' << 'SHAR_EOF' > 'dmake/dmdump.c' &&
/* RCS      -- $Header: /u2/dvadura/src/generic/dmake/src/RCS/dmdump.c,v 1.1 91/05/06 15:23:08 dvadura Exp $
-- SYNOPSIS -- dump the internal dag to stdout.
-- 
-- DESCRIPTION
--	This file contains the routine that is called to dump a version of
--	the digested makefile to the standard output.  May be useful perhaps
--	to the ordinary user, and invaluable for debugging make.
-- 
-- AUTHOR
--      Dennis Vadura, dvadura@watdragon.uwaterloo.ca
--      CS DEPT, University of Waterloo, Waterloo, Ont., Canada
--
-- COPYRIGHT
--      Copyright (c) 1990 by Dennis Vadura.  All rights reserved.
-- 
--      This program is free software; you can redistribute it and/or
--      modify it under the terms of the GNU General Public License
--      (version 1), as published by the Free Software Foundation, and
--      found in the file 'LICENSE' included with this distribution.
-- 
--      This program is distributed in the hope that it will be useful,
--      but WITHOUT ANY WARRANTY; without even the implied warrant of
--      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
--      GNU General Public License for more details.
-- 
--      You should have received a copy of the GNU General Public License
--      along with this program;  if not, write to the Free Software
--      Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
--
-- LOG
--     $Log:	dmdump.c,v $
X * Revision 1.1  91/05/06  15:23:08  dvadura
X * dmake Release Version 3.7
X * 
*/
X
#include "extern.h"
X
#define M_TEST	(M_PRECIOUS | M_VAR_MASK)
X
static	void	dump_name ANSI((HASHPTR, int));
static	void	dump_normal_target ANSI((CELLPTR, int));
static  void    dump_prerequisites ANSI((LINKPTR, int, int, int));
X
X
PUBLIC void
Dump()/*
========  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   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( Root->ce_prq && hp->CP_OWNR == Root->ce_prq->cl_prq )
X	       puts( "# ******* FIRST TARGET ********" );
X	    dump_normal_target( hp->CP_OWNR, hp->CP_OWNR->ce_flag );
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_normal_target( hp->CP_OWNR, hp->CP_OWNR->ce_flag );
X
X   DB_VOID_RETURN;
}
X
X
X
PUBLIC void
Dump_recipe( sp )/*
===================
X   Given a string pointer print the recipe line out */
STRINGPTR sp;
{
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   if( sp->st_attr & A_SHELL  ) putchar( '+' );
X   if( sp->st_attr & A_SWAP   ) 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
static char *_attrs[] = { ".PRECIOUS", ".SILENT", ".LIBRARY",
X   ".EPILOG", ".PROLOG", ".IGNORE", ".SYMBOL", ".NOINFER",
X   ".UPDATEALL", ".SEQUENTIAL", ".SETDIR=", ".USESHELL", ".SWAP", ".MKSARGS",
X   ".PHONY", ".NOSTATE" };
X
static void
dump_normal_target( cp, flag )/*
================================
X	Dump in makefile like format the dag information */
CELLPTR cp;
int     flag;
{
X   register LINKPTR   lp;
X   register STRINGPTR sp;
X   t_attr	      attr;
X   unsigned int	      k;
X
X   DB_ENTER( "dump_normal_target" );
X
X   if( !(cp->ce_flag & F_TARGET) && !cp->ce_attr ) { DB_VOID_RETURN; }
X
X   if( cp->ce_flag & F_MULTI ) {
X      int tflag = cp->ce_prq->cl_prq->ce_flag;
X      if( !(cp->ce_flag & F_PERCENT) ) tflag |= F_MULTI;
X      dump_prerequisites(cp->ce_prq, FALSE, TRUE, tflag);
X   }
X   else {
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( "%s%s ", _attrs[k],
X		    (attr != A_SETDIR) ? "" : (cp->ce_dir?cp->ce_dir:"") );
X	 }
X	    
X      putchar( ':' );
X
X      if( flag & F_MULTI )  putchar( ':' );
X      if( flag & F_SINGLE ) putchar( '!' );
X      putchar( ' ' );
X
X      dump_prerequisites( cp->ce_prq, FALSE, FALSE, F_DEFAULT);
X      dump_prerequisites( cp->ce_indprq, TRUE, FALSE, F_DEFAULT);
X
X      putchar( '\n' );
X      if( cp->ce_flag & F_GROUP ) puts( "[" );
X      for( sp = cp->ce_recipe; sp != NIL(STRING); sp = sp->st_next )
X	 Dump_recipe( sp );
X      if( cp->ce_flag & F_GROUP ) puts( "]" );
X
X      putchar( '\n' );
X   }
X
X   DB_VOID_RETURN;
}
X
X
static void
dump_prerequisites( lp, quote, recurse, flag )
LINKPTR lp;
int     quote;
int     recurse;
int     flag;
{
X   for( ; lp; lp=lp->cl_next )
X      if( recurse )
X	 dump_normal_target(lp->cl_prq, flag);
X      else if( lp->cl_prq )
X	 dump_name(lp->cl_prq->ce_name, quote);
}
X
X
static void
dump_name( hp, quote )/*
========================
X	print out a name */
HASHPTR hp;
int     quote;
{
X   if( quote ) putchar('\'');
X   printf( "%s", hp->ht_name );
X   if( quote ) putchar('\'');
X   putchar(' ');
}
SHAR_EOF
chmod 0640 dmake/dmdump.c ||
echo 'restore of dmake/dmdump.c failed'
Wc_c="`wc -c < 'dmake/dmdump.c'`"
test 5857 -eq "$Wc_c" ||
	echo 'dmake/dmdump.c: original size 5857, current size' "$Wc_c"
rm -f _shar_wnt_.tmp
fi
# ============= dmake/dmstring.c ==============
if test -f 'dmake/dmstring.c' -a X"$1" != X"-c"; then
	echo 'x - skipping dmake/dmstring.c (File already exists)'
	rm -f _shar_wnt_.tmp
else
> _shar_wnt_.tmp
sed 's/^X//' << 'SHAR_EOF' > 'dmake/dmstring.c' &&
/* RCS      -- $Header: /u2/dvadura/src/generic/dmake/src/RCS/dmstring.c,v 1.1 91/05/06 15:23:09 dvadura Exp $
-- SYNOPSIS -- string handling code
-- 
-- DESCRIPTION
--	Routines to handle string manipulation.  This code is not specific
--	to dmake and has/and will be used in other programs.  The string
--	"" is considered the NULL string, if NIL(char) is received instead
--	undefined results may occurr.  (In reality NIL(char) is checked for
--	but in general it is not safe to assume NIL(char) ==  NULL)
-- 
-- AUTHOR
--      Dennis Vadura, dvadura@watdragon.uwaterloo.ca
--      CS DEPT, University of Waterloo, Waterloo, Ont., Canada
--
-- COPYRIGHT
--      Copyright (c) 1990 by Dennis Vadura.  All rights reserved.
-- 
--      This program is free software; you can redistribute it and/or
--      modify it under the terms of the GNU General Public License
--      (version 1), as published by the Free Software Foundation, and
--      found in the file 'LICENSE' included with this distribution.
-- 
--      This program is distributed in the hope that it will be useful,
--      but WITHOUT ANY WARRANTY; without even the implied warrant of
--      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
--      GNU General Public License for more details.
-- 
--      You should have received a copy of the GNU General Public License
--      along with this program;  if not, write to the Free Software
--      Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
--
-- LOG
--     $Log:	dmstring.c,v $
X * Revision 1.1  91/05/06  15:23:09  dvadura
X * dmake Release Version 3.7
X * 
*/
X
#include "extern.h"
X
PUBLIC char *
_strjoin( src, data, n, fr )/*
==============================
X   Join data to src according to value of n.
X
X      n = -1   - return strcat( src, data )
X      n >= 0   - return strncat( src, data, n )
X
X   FREE original src if fr == TRUE, else leave it alone */
X
char *src;
char *data;
int  n;
int  fr;
{
X   char *t;
X   int  l;
X   int  flag = FALSE;
X
X   DB_ENTER( "_strjoin" );
X   
X   if( src  == NIL(char) ) { src = ""; flag = TRUE; }
X   if( data == NIL(char) ) data = "";
X   DB_PRINT( "str", ("Joining [%s] [%s] %d", src, data, n) );
X
X   if( n == -1 )  n = strlen( data );
X
X   l = strlen( src ) + n + 1;
X   if( (t = MALLOC( l, char )) == NIL(char) ) No_ram();
X
X   strcpy( t, src );
X   if (n) strncat( t, data, n );
X   t[ l-1 ] = '\0';
X
X   if( !flag && fr ) FREE( src );
X
X   DB_PRINT( "str", ("Result  [%s]", t) );
X   DB_RETURN( t );
}
X
X
X
X
PUBLIC char *
_stradd( src, data, fr )/*
==========================
X   append data to src with space in between if src is not NIL(char) or ""
X   and free both src and data if fr == TRUE, otherwise leave them be */
X
char *src;
char *data;
int  fr;
{
X   char *t;
X   int  l;
X   int  sflag;
X   int  dflag;
X
X   DB_ENTER( "_stradd" );
X
X   sflag = dflag = fr;
X
X   if( src  == NIL(char) ) { src  = ""; sflag = FALSE; }
X   if( data == NIL(char) ) { data = ""; dflag = FALSE; }
X   DB_PRINT( "str", ("Adding [%s] [%s] %d", src, data, fr) );
X
X   l = strlen(src) + strlen(data) + 1;
X   if( *src ) l++;
X
X   if( (t = MALLOC( l, char )) == NIL(char) ) No_ram();
X
X   strcpy( t, src );
X   
X   if( *data )
X   {
X      if( *src ) strcat( t,  " " );
X      strcat( t, data );
X   }
X
X   if( sflag )  FREE( src  );
X   if( dflag )  FREE( data );
X
X   DB_PRINT( "str", ("Result  [%s]", t) );
X   DB_RETURN( t );
}
X
X
X
PUBLIC char *
_strapp( src1, src2 )/*
=======================
X   Append two strings together, and return the result with a space between
X   the two strings.  FREE the first string if it is not NIL and always
X   leave the second string be. */
char *src1;
char *src2;
{
X   src2 = _stradd( src1, src2, FALSE );
X   if( src1 != NIL(char) ) FREE( src1 );
X   return( src2 );
}
X
X
X
#ifdef DBUG
#ifdef _strdup
#undef _strdup
#endif
#endif
PUBLIC char *
_strdup( str )/*
================  Duplicate the contents of a string, by using malloc */
char *str;
{
X   char *t;
X
X   if( str == NIL(char) ) return( NIL(char) );
X   
X   if( (t = MALLOC( strlen( str )+1, char )) == NIL(char) ) No_ram();
X   strcpy( t, str );
X
X   return( t );
}
X
X
X
X
PUBLIC char *
_strpbrk( s1, s2 )/*
====================
X   find first occurence of char in s2 in string s1.
X   Returns a pointer to the first occurrence.  NOTE '\0' is considered part
X   of s2 and a pointer to it is returned if no other chars match. */
X
char *s1;
char *s2;
{
X   register char *t;
X
X   if( s1 == NIL(char) || s2 == NIL(char) ) return( "" );
X
X   for( t=s1; *t && (strchr( s2, *t ) == NIL(char)); t++ );
X   return( t );
}
X
X
X
X
PUBLIC char *
_strspn( s1, s2 )/*
===================
X   return pointer to first char in s1 that does not belong to s2.
X   Returns the pointer if match found, else returns pointer to null char
X   in s1. (ie. "" ) */
X   
char *s1;
char *s2;
{
X   register char *t;
X
X   if( s1 == NIL(char) || s2 == NIL(char) ) return( "" );
X
X   for( t=s1; *t && (strchr( s2, *t ) != NIL(char)); t++ );
X   return( t );
}
X
X
X
X
PUBLIC char *
_strstr( s1, s2 )/*
==================  find first occurrence in s1 of s2 */
char *s1;
char *s2;
{
X   register char *s;
X   register char *p;
X   register char *r;
X
X   if( s1 != NIL(char) && s2 != NIL(char) )
X      for( s=s1; *s; s++ )
X	 if( *s == *s2 )
X	 {
X	    for( r=s+1, p = s2+1; *p && (*r == *p); r++, p++ );
X	    if( !*p ) return( s );
X	 }
X   
X   return( NIL(char) );
}
X
X
X
PUBLIC char *
_substr( s, e )/*
=================
X      Return the string between the two pointers s and e, not including the
X      char that e points to.  NOTE:  This routine assumes that s and e point
X      into the same string. */
X
char *s;
char *e;
{
X   char save;
X   int  len = e-s;
X
X   if( len < 0 || len > strlen(s) )
X      Fatal( "Internal Error:  _substr fails consistency test" );
X
X   save = *e;
X   *e   = '\0';
X   s    = _strdup( s );
X   *e   = save;
X
X   return( s );
}
SHAR_EOF
chmod 0640 dmake/dmstring.c ||
echo 'restore of dmake/dmstring.c failed'
Wc_c="`wc -c < 'dmake/dmstring.c'`"
test 5809 -eq "$Wc_c" ||
	echo 'dmake/dmstring.c: original size 5809, current size' "$Wc_c"
rm -f _shar_wnt_.tmp
fi
# ============= dmake/expand.c ==============
if test -f 'dmake/expand.c' -a X"$1" != X"-c"; then
	echo 'x - skipping dmake/expand.c (File already exists)'
	rm -f _shar_wnt_.tmp
else
> _shar_wnt_.tmp
sed 's/^X//' << 'SHAR_EOF' > 'dmake/expand.c' &&
/* RCS      -- $Header: /u2/dvadura/src/generic/dmake/src/RCS/expand.c,v 1.1 91/05/06 15:23:10 dvadura Exp $
-- SYNOPSIS -- macro expansion code.
-- 
-- DESCRIPTION
--
--	This routine handles all the necessary junk that deals with macro
--	expansion.  It understands the following syntax.  If a macro is
--	not defined it expands to NULL, and {} are synonyms for ().
--
--		$$      - expands to $
--		{{      - expands to {
--	        }}      - expands to }
--		$A      - expands to whatever the macro A is defined as
--		$(AA)   - expands to whatever the macro AA is defined as
--		$($(A)) - represents macro indirection
--		<+...+> - get mapped to $(mktmp ...)
--	
--        following macro is recognized
--        
--                string1{ token_list }string2
--                
--        and expands to string1 prepended to each element of token_list and
--        string2 appended to each of the resulting tokens from the first
--        operation.  If string2 is of the form above then the result is
--        the cross product of the specified (possibly modified) token_lists.
--        
--        The folowing macro modifiers are defined and expanded:
--        
--               $(macro:modifier_list:modifier_list:...)
--               
--        where modifier_list a combination of:
--        
--               D or d      - Directory portion of token including separator
--               F or f      - File portion of token including suffix
--               B or b      - basename portion of token not including suffix
--		 T or t      - for tokenization
--
--	  or a single
--               S or s      - pattern substitution (simple)
--               
--        NOTE:  Modifiers are applied once the macro value has been found.
--               Thus the construct $($(test):s/joe/mary/) is defined and
--               modifies the value of $($(test))
--
--	       Also the construct $(m:d:f) is not the same as $(m:df)
--	       the first applies d to the value of $(m) and then
--	       applies f to the value of that whereas the second form
--	       applies df to the value of $(m).
--
-- AUTHOR
--      Dennis Vadura, dvadura@watdragon.uwaterloo.ca
--      CS DEPT, University of Waterloo, Waterloo, Ont., Canada
--
-- COPYRIGHT
--      Copyright (c) 1990 by Dennis Vadura.  All rights reserved.
-- 
--      This program is free software; you can redistribute it and/or
--      modify it under the terms of the GNU General Public License
--      (version 1), as published by the Free Software Foundation, and
--      found in the file 'LICENSE' included with this distribution.
-- 
--      This program is distributed in the hope that it will be useful,
--      but WITHOUT ANY WARRANTY; without even the implied warrant of
--      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
--      GNU General Public License for more details.
-- 
--      You should have received a copy of the GNU General Public License
--      along with this program;  if not, write to the Free Software
--      Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
--
-- LOG
--     $Log:	expand.c,v $
X * Revision 1.1  91/05/06  15:23:10  dvadura
X * dmake Release Version 3.7
X * 
*/
X
#include "extern.h"
X
/* Microsoft BRAINDAMAGE ALERT!!!!
X * This #ifdef is here only to satisfy stupid bugs in MSC5.0 and MSC5.1
X * it isn't needed for anything else.  It turns loop optimization off. */
#if defined(_MSC_VER)
#include "optoff.h"
#endif
X
static	char*	_scan_token ANSI((char*, char**));
static	char*	_scan_macro ANSI((char*, char**));
static	char*	_scan_brace ANSI((char*, char**, int*));
static	char*	_cross_prod ANSI((char*, char*));
X
X
PUBLIC char *
Expand( src )/*
===============
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
char *src;                    /* pointer to source string  */
{
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      char *ks, *ke;
X
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
X      /* START <+...+> KLUDGE */
X      if( (ks=_strstr(start,"<+")) && (ke=_strstr(ks,"+>")) ){
X	 char *t1, *t2;
X
X	 res = _strjoin( res, t2=Expand(t1=_substr(start,ks)), -1, TRUE);
X	 FREE(t1); FREE(t2);
X
X	 t1 = _substr(ks+2, ke+1); t1[ke-ks-2] = ')';
X	 t2 = _strjoin( "$(mktmp ", t1, -1,FALSE);
X	 FREE(t1);
X	 res = _strjoin( res, t2=Expand(t2), -1, TRUE);
X	 FREE(t2);
X	 src = ke+2;
X      }
X      /* END <+...+> KLUDGE */
X      else {
X	 res   = _strjoin( res, tmp = _scan_token( start, &src ), -1, TRUE );
X	 FREE( tmp );
X      }
X   }
X   
X   DB_PRINT( "exp", ("Returning [%s]", res) );
X   DB_RETURN( res );
}
X
X
PUBLIC char *
Apply_edit( src, pat, subst, fr, anchor )/*
===========================================
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
char *src;			/* the source string */
char *pat;			/* pattern to find   */
char *subst;			/* substitute string */
int   fr;			/* if TRUE free src  */
int   anchor;			/* if TRUE anchor    */
{
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
PUBLIC void
Map_esc( tok )/*
================
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. */
char *tok;
{
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 );
X   }
}
X
X
PUBLIC char*
Apply_modifiers( mod, src )/*
=============================
X   This routine applies the appropriate modifiers to the string src
X   and returns the proper result string */
X
int  mod;
char *src;
{
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
PUBLIC char*
Tokenize( src, separator )/*
============================
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
char *src;
char *separator;
{
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( "" );
SHAR_EOF
true || echo 'restore of dmake/expand.c failed'
fi
echo 'End of part 8, continue with part 9'
echo 9 > _shar_seq_.tmp
exit 0

exit 0 # Just in case...
-- 
Kent Landfield                   INTERNET: kent@sparky.IMD.Sterling.COM
Sterling Software, IMD           UUCP:     uunet!sparky!kent
Phone:    (402) 291-8300         FAX:      (402) 291-4362
Please send comp.sources.misc-related mail to kent@uunet.uu.net.