[comp.sources.misc] v19i051: dmake - dmake version 3.7, Part30/37

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

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

---- Cut Here and feed the following to sh ----
#!/bin/sh
# this is dmake.shar.30 (part 30 of a multipart archive)
# do not concatenate these parts, unpack them in order with /bin/sh
# file dmake/stat.c continued
#
if test ! -r _shar_seq_.tmp; then
	echo 'Please unpack part 1 first!'
	exit 1
fi
(read Scheck
 if test "$Scheck" != 30; 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/stat.c' &&
X
PUBLIC void
Stat_target( cp, setfname )/*
=============================
X	Stat a target.  When doing so follow the following rules, suppose
X	that cp->CE_NAME points at a target called fred.o:
X
X		0.      If A_SYMBOL attribute set look into the library
X			then do the steps 1 thru 4 on the resulting name.
X		1.	Try path's obtained by prepending any dirs found as
X			prerequisites for .SOURCE.o.
X		2.	If not found, do same as 2 but use .SOURCE
X		3.	If not found and .LIBRARYM attribute for the target is
X			set then look for it in the corresponding library.
X	        4.	If found in step 0 thru 3, then ce_fname points at
X			file name associate with target, else ce_fname points
X			at a file name built by the first .SOURCE* dir that
X			applied. */
X
CELLPTR cp;
int     setfname;
{
X   register HASHPTR hp;
X   static   HASHPTR srchp = NIL(HASH);
X   char		    *name;
X   char		    *tmp;
X   int		    res = 0;
X
X   DB_ENTER( "Stat_target" );
X
X   name = cp->CE_NAME;
X   if( srchp == NIL(HASH) ) srchp = Get_name(".SOURCE",Defs,FALSE);
X
X   /* Look for a symbol of the form lib((symbol)) the name of the symbol
X    * as entered in the hash table is (symbol) so pull out symbol and try
X    * to find it's module.  If successful DO_STAT will return the module
X    * as well as the archive member name (pointed at by tmp).  We then
X    * replace the symbol name with the archive member name so that we
X    * have the proper name for any future refrences. */
X
X   if( cp->ce_attr & A_SYMBOL ) {
X      DB_PRINT( "stat", ("Binding lib symbol [%s]", name) );
X
X      cp->ce_time = DO_STAT( name, cp->ce_lib, &tmp );
X
X      if( cp->ce_time != (time_t) 0L ) {
X	 /* stat the new member name below  note tmp must point at a string
X	  * returned by MALLOC... ie. the Do_stat code should use _strdup */
X
X	 if( Verbose & V_MAKE )
X	    printf( "%s:  Mapped ((%s)) to %s(%s)\n", Pname,
X		     name, cp->ce_lib, tmp );
X
X         FREE( name );		
X	 name = cp->CE_NAME = tmp;		
X	 cp->ce_attr &= ~(A_FFNAME | A_SYMBOL);
X      }
X      else
X         { DB_VOID_RETURN; }
X   }
X
X   _first = NIL(char);
X   tmp = _strjoin( ".SOURCE", Get_suffix( name ), -1, FALSE);
X
X   /* Check .SOURCE.xxx target */
X   if( (hp = Get_name(tmp, Defs, FALSE)) != NIL(HASH) )
X      res = _check_dir_list( cp, hp->CP_OWNR, setfname );
X
X   /* Check just .SOURCE */
X   if( !res && (srchp != NIL(HASH)) )
X      res = _check_dir_list( cp, srchp->CP_OWNR, setfname );
X
X   /* If libmember and we haven't found it check the library */
X   if( !res && (cp->ce_attr & A_LIBRARYM) ) {
X      cp->ce_time = DO_STAT(name, cp->ce_lib, NIL(char *));
X
X      if( !cp->ce_time && Tmd && *Tmd && cp->ce_lib ) {
X	 cp->ce_lib=Build_path(Tmd,cp->ce_lib);
X	 cp->ce_time = DO_STAT(name, cp->ce_lib, NIL(char *));
X      }
X
X      if( Verbose & V_MAKE )
X	 printf( "%s:  Checking library '%s' for member [%s], time %ld\n",
X		 Pname, cp->ce_lib, name, cp->ce_time );
X   }
X
X   FREE( tmp );
X
X   if( setfname == 1 || (setfname == -1 && cp->ce_time != (time_t)0L) ) {
X      if( (cp->ce_attr & A_FFNAME) && (cp->ce_fname != NIL(char)) )
X	 FREE( cp->ce_fname );
X
X      if( _first != NIL(char) ) {
X	 cp->ce_fname = _first;
X	 cp->ce_attr |= A_FFNAME;
X      }
X      else {
X	 cp->ce_fname = cp->CE_NAME;
X	 cp->ce_attr &= ~A_FFNAME;
X      }
X   }
X   else if( _first )
X      FREE( _first );
X
X   /* set it as stated only if successful, this way, we shall try again
X    * later. */
X   if( cp->ce_time != (time_t)0L ) cp->ce_flag |= F_STAT;
X
X   DB_VOID_RETURN;
}
X
X
X
static int
_check_dir_list( cp, sp, setfname )/*
=====================================
X	Check the list of dir's given by the prerequisite list of sp, for a
X	file pointed at by cp.  Returns 0 if path not bound, else returns
X	1 and replaces old name for cell with new cell name. */
X
CELLPTR cp;
CELLPTR sp;
int     setfname;
{
X   register LINKPTR lp;
X   char *dir;
X   char *path;
X   char *name;
X   int  res  = 0;
X   int  fset = 0;
X
X   DB_ENTER( "_check_dir_list" );
X   DB_PRINT( "mem", ("%s:-> mem %ld", cp->CE_NAME, (long) coreleft()) );
X
X   if( sp->ce_prq != NIL(LINK) )	/* check prerequisites if any */
X   {
X      /* Use the real name instead of basename, this prevents silly
X       * loops in inference code, and is consistent with man page */
X      name = cp->CE_NAME;
X
X      /* Here we loop through each directory on the list, and try to stat
X       * the target.  We always save the first pathname we try and stat in
X       * _first.  If we subsequently get a match we then replace the value of
X       * _first by the matched path name.  */
X
X      for( lp=sp->CE_PRQ; lp != NIL(LINK) && !res; lp=lp->cl_next ) {
X	 int  nodup = 0;
X	 dir  = lp->cl_prq->CE_NAME;
X
X	 if( strchr( dir, '$' ) ) dir = Expand(dir);
X	 if( strcmp( dir, ".NULL" ) == 0 ) {
X	    nodup = 1;
X	    path = cp->CE_NAME;
X	 }
X	 else
X	    path = Build_path( dir, name );
X
X	 res = ((cp->ce_time = DO_STAT(path,NIL(char),NIL(char *))) != (time_t)0L);
#if 0
I think this will break a lot of things!
X	 /* It didn't work and TMD macro has a value so try to stat it
X	  * relative to the original MAKEDIR directory. */
X	 if( Tmd && !*Tmd && !res ) {
X	    char *p = _strdup(path);
X	    path = Build_path(Tmd,p); FREE(p);
X	    res = ((cp->ce_time = DO_STAT(path,NIL(char),NIL(char *))) != (time_t)0L);
X	 }
#endif
X
X	 /* Have to use _strdup to set _first since Build_path, builds it's
X	  * path names inside a static buffer. */
X	 if( setfname )
X	    if( (_first == NIL(char) && !fset) || res ) {
X	       if( _first != NIL(char) ) FREE( _first );
X	       _first = nodup ? NIL(char) : _strdup(path);
X	       fset = 1;
X	    }
X
X	 DB_PRINT( "stat", ("_first [%s], path [%s]", _first, path) );
X	 if( dir != lp->cl_prq->CE_NAME )  FREE(dir);
X      }
X   }
X
X   DB_PRINT( "mem", ("%s:-< mem %ld", cp->CE_NAME, (long) coreleft()) );
X   DB_RETURN( res );
}
SHAR_EOF
chmod 0640 dmake/stat.c ||
echo 'restore of dmake/stat.c failed'
Wc_c="`wc -c < 'dmake/stat.c'`"
test 7761 -eq "$Wc_c" ||
	echo 'dmake/stat.c: original size 7761, current size' "$Wc_c"
rm -f _shar_wnt_.tmp
fi
# ============= dmake/state.c ==============
if test -f 'dmake/state.c' -a X"$1" != X"-c"; then
	echo 'x - skipping dmake/state.c (File already exists)'
	rm -f _shar_wnt_.tmp
else
> _shar_wnt_.tmp
sed 's/^X//' << 'SHAR_EOF' > 'dmake/state.c' &&
/* RCS      -- $Header: /u2/dvadura/src/generic/dmake/src/RCS/state.c,v 1.1 91/05/06 15:23:31 dvadura Exp $
-- SYNOPSIS -- .KEEP_STATE state file management
-- 
-- DESCRIPTION
-- 	Three routines to interface to the .KEEP_STATE state file.
--
--		Read_state()	- reads the state file if any.
--		Write_state()	- writes the state file.
--
--		Check_state(cp,how) - checks an entry returns 0 or 1
--				      and updates the entry.
--
-- 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:	state.c,v $
X * Revision 1.1  91/05/06  15:23:31  dvadura
X * dmake Release Version 3.7
X * 
*/
X
#include "extern.h"
X
typedef struct se {
X   char		*st_name;		/* name of cell		*/
X   uint32	st_nkey;		/* name hash key	*/
X   int		st_count;		/* how count for how	*/
X   uint32	st_dkey;		/* directory hash key	*/
X   uint32	st_key;			/* hash key		*/
X   struct se    *st_next;
} KSTATE, *KSTATEPTR;
X
static KSTATEPTR _st_head  = NIL(KSTATE);
static KSTATEPTR _st_tail  = NIL(KSTATE);
static int       _st_upd   = FALSE;
static char     *_st_file  = NIL(char);
X
static int  _my_fgets ANSI((char *, int, FILE *));
X
PUBLIC void
Read_state()
{
X   char *buf;
X   char sizeb[20];
X   int  size;
X   FILE *fp;
X   KSTATEPTR sp;
X
X   if( (fp = Search_file(".KEEP_STATE", &_st_file)) != NIL(FILE) ) {
X      if( _my_fgets( sizeb, 20, fp ) ) {
X	 size = atol(sizeb);
X	 buf = MALLOC(size+2, char);
X
X	 while( _my_fgets(buf, size, fp) != NULL ) {
X	    TALLOC(sp, 1, KSTATE);
X	    sp->st_name = _strdup(buf);
X	    (void) Hash(buf, &sp->st_nkey);
X
X	    if( _my_fgets(buf, size, fp) ) sp->st_count = atoi(buf);
X	    if( _my_fgets(buf, size, fp) ) sp->st_dkey   = (uint32) atol(buf);
X
X	    if( _my_fgets(buf, size, fp) )
X	       sp->st_key = (uint32) atol(buf);
X	    else {
X	       FREE(sp);
X	       break;
X	    }
X
X	    if( _st_head == NIL(KSTATE) )
X	       _st_head = sp;
X	    else
X	       _st_tail->st_next = sp;
X
X	    _st_tail = sp;
X	 }
X
X	 FREE(buf);
X      }
X
X      Closefile(fp);
X   }
}
X
X
PUBLIC void
Write_state()
{
X   static int in_write = 0;
X   register KSTATEPTR sp;
X   FILE *fp;
X
X   if( !_st_upd || !_st_file || (_st_file && !*_st_file) ||
X       Trace || in_write ) return;
X
X   in_write++;
X   if( (fp = Openfile(_st_file, TRUE, TRUE)) != NIL(FILE) ) {
X      int maxlen = 0;
X      int tmplen;
X
X      for( sp = _st_head; sp; sp=sp->st_next )
X	 if( (tmplen = strlen(sp->st_name)) > maxlen )
X	    maxlen = tmplen;
X
X      /* A nice arbitrary minimum size */
X      if( maxlen < 20 ) maxlen = 20;
X      fprintf( fp, "%d\n", maxlen );
X
X      for( sp = _st_head; sp; sp=sp->st_next ) {
X	 uint16 hv;
X	 uint32 hk;
X
X	 if( Search_table(Defs, sp->st_name, &hv, &hk) ) {
X	    fprintf( fp, "%s\n",  sp->st_name   );
X	    fprintf( fp, "%d\n",  sp->st_count );
X	    fprintf( fp, "%lu\n", sp->st_dkey   );
X	    fprintf( fp, "%lu\n", sp->st_key    );
X	 }
X      }
X
X      Closefile();
X   }
X   else
X      Fatal("Cannot open STATE file %s", _st_file);
X
X   in_write = 0;
}
X
X
PUBLIC int
Check_state( cp, recipes, maxrcp )
CELLPTR cp;
STRINGPTR *recipes;
int  maxrcp;
{
X   KSTATEPTR  st;
X   STRINGPTR sp;
X   int    i;
X   uint32 thkey;
X   uint32 hkey;
X   uint32 nkey;
X   uint32 dkey;
X   int    update = FALSE;
X
X   if(    strcmp(cp->CE_NAME,".REMOVE") == 0
X       || (cp->ce_attr & (A_PHONY|A_NOSTATE)) )
X      return(FALSE);
X
X   (void) Hash( cp->CE_NAME, &nkey ); thkey = nkey + (uint32) cp->ce_count;
X   (void) Hash( Pwd,  &dkey ); thkey += dkey;
X
X   Suppress_temp_file = TRUE;
X   for( i=0 ; i<maxrcp; i++ )
X      for(sp=recipes[i]; sp != NIL(STRING); sp=sp->st_next ) {
X	 char *cmnd = Expand(sp->st_string);
X
X	 (void) Hash(cmnd, &hkey); thkey += hkey;
X	 FREE(cmnd);
X      }
X   Suppress_temp_file = FALSE;
X
X   for( st=_st_head; st != NIL(KSTATE); st=st->st_next ) {
X      if(    st->st_nkey   == nkey
X	  && st->st_dkey   == dkey
X	  && st->st_count  == cp->ce_count
X	  && !strcmp(cp->CE_NAME, st->st_name) )
X	 break;
X   }
X
X   if( st == NIL(KSTATE) ) {
X      KSTATEPTR nst;
X
X      TALLOC(nst, 1, KSTATE);
X      nst->st_name = cp->CE_NAME;
X      nst->st_nkey = nkey;
X      nst->st_dkey = dkey;
X      nst->st_key  = thkey;
X      nst->st_count = cp->ce_count;
X
X      if( _st_head == NIL(KSTATE) )
X	 _st_head = nst;
X      else
X	 _st_tail->st_next = nst;
X
X      _st_tail = nst;
X      _st_upd  = TRUE;
X   }
X   else if( st->st_key != thkey ) {
X      st->st_key = thkey;
X      _st_upd = update = TRUE;
X   }
X
X   return(st != NIL(KSTATE) && update);
}
X
X
static int
_my_fgets(buf, size, fp)
char *buf;
int  size;
FILE *fp;
{
X   char *p;
X
X   if( fgets(buf, size, fp) == NULL ) return(0);
X
X   if( (p=strrchr(buf,'\n')) != NIL(char) ) *p='\0';
X   return(1);
}
SHAR_EOF
chmod 0640 dmake/state.c ||
echo 'restore of dmake/state.c failed'
Wc_c="`wc -c < 'dmake/state.c'`"
test 5520 -eq "$Wc_c" ||
	echo 'dmake/state.c: original size 5520, current size' "$Wc_c"
rm -f _shar_wnt_.tmp
fi
# ============= dmake/stdmacs.h ==============
if test -f 'dmake/stdmacs.h' -a X"$1" != X"-c"; then
	echo 'x - skipping dmake/stdmacs.h (File already exists)'
	rm -f _shar_wnt_.tmp
else
> _shar_wnt_.tmp
sed 's/^X//' << 'SHAR_EOF' > 'dmake/stdmacs.h' &&
/* RCS      -- $Header: /u2/dvadura/src/generic/dmake/src/RCS/stdmacs.h,v 1.1 91/05/06 15:23:32 dvadura Exp $
-- SYNOPSIS -- general use macros.
-- 
-- DESCRIPTION
-- 	ANSI macro relies on the fact that it can be replaced by (), or by
--	its value, where the value is one value due to the preprocessors
--	handling of arguments that are surrounded by ()'s as a single
--	argument.
--
-- 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:	stdmacs.h,v $
X * Revision 1.1  91/05/06  15:23:32  dvadura
X * dmake Release Version 3.7
X * 
*/
X
#ifndef	MACROS_h
#define	MACROS_h
X
/* stupid AIX defines __STDC__ as special, but defined(__STDC__) is false, and
X * it's value is nothing */
#if !defined(__STDC__) && !defined(_AIX)
#define __STDC__ 0
#endif
X
#if __STDC__ || defined(__TURBOC__)
#define	ANSI(x)	x
#else
#define	ANSI(x)	()
#endif
X
#define	NIL(p)	((p*)NULL)
X
#if !defined(atarist)
#define	offsetof(type,id) ((size_t)&((type*)NULL)->id)
#endif
X
#define	FALSE	0
#define	TRUE	1
X
#define PUBLIC
X
#endif
X
SHAR_EOF
chmod 0640 dmake/stdmacs.h ||
echo 'restore of dmake/stdmacs.h failed'
Wc_c="`wc -c < 'dmake/stdmacs.h'`"
test 1943 -eq "$Wc_c" ||
	echo 'dmake/stdmacs.h: original size 1943, current size' "$Wc_c"
rm -f _shar_wnt_.tmp
fi
# ============= dmake/struct.h ==============
if test -f 'dmake/struct.h' -a X"$1" != X"-c"; then
	echo 'x - skipping dmake/struct.h (File already exists)'
	rm -f _shar_wnt_.tmp
else
> _shar_wnt_.tmp
sed 's/^X//' << 'SHAR_EOF' > 'dmake/struct.h' &&
/* RCS      -- $Header: /u2/dvadura/src/generic/dmake/src/RCS/struct.h,v 1.1 91/05/06 15:23:33 dvadura Exp $
-- SYNOPSIS -- structure definitions
-- 
-- DESCRIPTION
--	dmake main data structure definitions.  See each of the individual
--	struct declarations for more detailed information on the defined
--	fields and their use.
-- 
-- 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:	struct.h,v $
X * Revision 1.1  91/05/06  15:23:33  dvadura
X * dmake Release Version 3.7
X * 
*/
X
#ifndef _STRUCT_INCLUDED_
#define _STRUCT_INCLUDED_
X
typedef uint32 t_attr;
X
/* The following struct is the cell used in the hash table.
X * NOTE:  It contains the actual hash value.  This allows the hash table
X *        insertion to compare hash values and to do a string compare only
X *        for entries that have matching hash_key values.  This elliminates
X *        99.9999% of all extraneous string compare operations when searching
X *        a hash table chain for matching entries.  */
X
typedef struct hcell {
X	struct hcell	*ht_next;	/* next entry in the hash table */
X	char		*ht_name;	/* name of this cell */
X	char		*ht_value;	/* cell value if and */
X	uint32		ht_hash;	/* actual hash_value of cell */
X	int		ht_flag;	/* flags belonging to hash entry */
X
X	/* NOTE: some macros have corresponding variables defined
X	 * that control program behaviour.  For these macros a
X	 * bit of ht_flag indicates the variable value will be set, and the
X	 * type of the value that will be set.
X	 *
X	 * The struct below contains a mask for bit variables, and a
X	 * pointer to the global STATIC location for that variable.
X	 * String and char variables point to the same place as ht_value
X	 * and must be updated when ht_value changes, bit variables must
X	 * have their value recomputed. See Def_macro code for more
X	 * details.
X	 *
X	 * NOTE:  Macro variables and Targets are always distinct.  Thus
X	 * the value union contains pointers back at cells that own
X	 * a particular name entry.  A conflict in this can never
X	 * arise, ie pointers at cells will never be used as
X	 * values for a macro variable, since the cell and macro
X	 * name spaces are completely distinct. */
X
X	struct {
X		int	mv_mask;	/* bit mask for bit variable      */
X		union {
X	 		char**	mv_svar;/* ptr to string valued glob var  */
X			char*	mv_cvar;/* ptr to char   valued glob var */
X			t_attr*	mv_bvar;/* ptr to bit    valued glob var */
X 			int*    mv_ivar;/* ptr to int    valued glob var  */
X
X			struct {
X			   struct tcell*  ht_owner;/* ptr to CELL owning name */
X			   struct tcell*  ht_root; /* root ptr for explode */
X			} ht;
X		} val;
X	} var;				/* variable's static equivalent */
} HASH, *HASHPTR;
X
#define MV_MASK		var.mv_mask
#define MV_SVAR 	var.val.mv_svar
#define MV_CVAR 	var.val.mv_cvar
#define MV_BVAR 	var.val.mv_bvar
#define MV_IVAR 	var.val.mv_ivar
#define CP_OWNR         var.val.ht.ht_owner
#define CP_ROOT         var.val.ht.ht_root
X
X
X
/* This struct holds the list of temporary files that have been created.
X * It gets unlinked when Quit is called due to an execution error */
typedef struct flst {
X   char		*fl_name;	/* file name 		*/
X   FILE		*fl_file;	/* the open file	*/
X   struct flst  *fl_next;	/* pointer to next file */
} FILELIST, *FILELISTPTR;
X
X
X
/* This is the structure of a target cell in the dag which represents the
X * graph of dependencies.  Each possible target is represented as a cell.
X * 
X * Each cell contains a pointer to the hash table entry for this cell.
X * The hash table entry records the name of the cell. */
X
typedef struct tcell {
X	struct hcell	*ce_name;	/* name of this cell                */
X
X	struct tcell	*ce_all;	/* link for grouping UPDATEALL cells*/
X	struct tcell    *ce_setdir;	/* SETDIR ROOT pointer for this cell*/
X	struct tcell	*ce_link;	/* link for temporary list making   */
X
X	struct lcell    *ce_prq;	/* list of prerequisites for cell   */
X	struct lcell    *ce_indprq;	/* indirect prerequisites for % cell*/
X
X	struct str      *ce_recipe;	/* recipe for making this cell      */
X	FILELISTPTR     ce_files;	/* list of temporary files for cell */
X
X	char 		*ce_per;	/* value of % in %-meta expansion   */
X	char		*ce_fname;	/* file name associated with target */
X	char		*ce_lib;	/* archive name, if A_LIBRARYM      */
X	char		*ce_dir;	/* value for .SETDIR attribute      */
X
X	int		ce_count;	/* value for :: recipe set          */
X	int		ce_index;	/* value of count for next :: child */
X	int   		ce_flag;	/* all kinds of goodies		    */
X	t_attr		ce_attr;	/* attributes for this target	    */
X	time_t		ce_time;	/* time stamp value of target if any*/
} CELL, *CELLPTR;
X
#define CE_NAME		ce_name->ht_name
#define CE_RECIPE       ce_recipe
#define CE_PRQ          ce_prq
X
X
/* This struct represents that used by Get_token to return and control
X * access to a token list inside a particular string.  This gives the
X * ability to access non overlapping tokens simultaneously from
X * multiple strings. */
X	
typedef struct {
X	char *tk_str;              /* the string to search for tokens  */
X	char tk_cchar;             /* current char under *str          */
X	int  tk_quote;	           /* if we are scanning a quoted str  */
}  TKSTR, *TKSTRPTR;
X
X
X
/* Below is the struct used to represent a string.  It points at possibly
X * another string, since the set of rules for making a target is a collection
X * of strings. */
X
X
typedef struct str {
X	char		*st_string;	/* the string value */
X	struct str	*st_next;	/* pointer to the next string */
X	t_attr		st_attr;	/* attr for rule operations */
} STRING, *STRINGPTR;
X
X
/* The next struct is used to link together prerequisite lists */
X
typedef struct lcell {
X	struct tcell	*cl_prq;	/* link to a prerequisite 	*/
X	struct lcell	*cl_next;	/* next cell on dependency list */
X	int		cl_flag;	/* flags for link cell		*/
} LINK, *LINKPTR;
X
X
X
/* These structs are used in processing of the % rules, and in building
X * the NFA machine that is used to match an arbitrary target string to
X * one of the % rules that is represented by each DFA */
X
typedef int16 statecnt;		/* limits the max number of dfa states	*/
X
X
/* Each state of the DFA contains four pieces of information. */
typedef struct st {
X	struct st	*no_match;	/* state to go to if no match */
X	struct st	*match;		/* state to go to if we do match */
X	char		symbol;		/* symbol on which we transit */
X	char		action;		/* action to perform if match */
} STATE, *STATEPTR;
X
X
/* Each DFA machine looks like this.  It must have two pointers that represent
X * the value of % in the matched string, and it contains a pointer into the
X * current state, as well as the array of all states. */
typedef struct {
X	char		*pstart;	/* start of % string match */
X	char		*pend;		/* end of % string match */
X	STATEPTR	c_state;	/* current DFA state */
X	CELLPTR		node;		/* % target represented by this DFA */
X	STATEPTR	states;		/* table of states for the DFA */
} DFA, *DFAPTR;
X
X
/* An NFA is a collection of DFA's.  For each DFA we must know it's current
X * state and where the next NFA is. */
typedef struct nfa_machine {
X	DFAPTR		dfa;		/* The DFA for this eps transition */
X	char		status;		/* DFA state */
X	struct nfa_machine *next; 	/* the next DFA in NFA */
} NFA, *NFAPTR;
X
X
X
/* The next struct is used to link together DFA nodes for inference. */
X
typedef struct dfal {
X	struct tcell	*dl_meta;	/* link to %-meta cell		*/
X	struct dfal	*dl_next;	/* next cell on matched DFA list*/
X	struct dfal	*dl_prev;	/* prev cell on matched DFA list*/
X	struct dfal	*dl_member;	/* used during subset calc	*/
X	char		dl_delete;	/* used during subset calc	*/
X	char   		*dl_per;	/* value of % for matched DFA   */
X	statecnt        dl_state;	/* matched state of the DFA	*/
X	int		dl_prep;	/* repetion count for the cell	*/
} DFALINK, *DFALINKPTR;
X
X
/* This struct is used to store the stack of DFA sets during inference */
typedef struct dfst {
X   DFALINKPTR	df_set;			/* pointer to the set		*/
X   struct dfst *df_next;		/* next element in the stack	*/
} DFASET, *DFASETPTR;
X
X
/* We need sets of items during inference, here is the item, we form sets
X * by linking them together. */
X
typedef struct ic {
X   CELLPTR	ic_meta;		/* Edge we used to make this cell*/
X   DFALINKPTR   ic_dfa;			/* Dfa that we matched against	 */
X   CELLPTR	ic_setdirroot;		/* setdir root pointer for cell	 */
X   DFASET       ic_dfastack;		/* set of dfas we're working with*/
X   int		ic_dmax;		/* max depth of cycles in graph  */
X   char	       *ic_name;		/* name of the cell to insert    */
X   char        *ic_dir;			/* dir to CD to prior to recurse */
X   struct ic   *ic_next;		/* next pointer to link		 */
X   struct ic   *ic_link;		/* link all ICELL'S together     */
X   struct ic   *ic_parent;		/* pointer to post-requisite	 */
X   char		ic_flag;		/* flag, used for NOINFER only	 */
X   char         ic_exists;		/* TRUE if prerequisite exists	 */
} ICELL, *ICELLPTR;
X
#endif
SHAR_EOF
chmod 0640 dmake/struct.h ||
echo 'restore of dmake/struct.h failed'
Wc_c="`wc -c < 'dmake/struct.h'`"
test 9748 -eq "$Wc_c" ||
	echo 'dmake/struct.h: original size 9748, current size' "$Wc_c"
rm -f _shar_wnt_.tmp
fi
# ============= dmake/sysintf.c ==============
if test -f 'dmake/sysintf.c' -a X"$1" != X"-c"; then
	echo 'x - skipping dmake/sysintf.c (File already exists)'
	rm -f _shar_wnt_.tmp
else
> _shar_wnt_.tmp
sed 's/^X//' << 'SHAR_EOF' > 'dmake/sysintf.c' &&
/* RCS      -- $Header: /u2/dvadura/src/generic/dmake/src/RCS/sysintf.c,v 1.1 91/05/06 15:23:35 dvadura Exp $
-- SYNOPSIS -- system independent interface
-- 
-- DESCRIPTION
--	These are the routines constituting the system interface.
--	The system is taken to be essentially POSIX conformant.
--	The original code was extensively revised by T J Thompson at MKS,
--	and the library cacheing was added by Eric Gisin at MKS.  I then
--	revised the code yet again, to improve the lib cacheing, and to
--	make it more portable.
--
--	The following is a list of routines that are required by this file
--	in order to work.  These routines are provided as functions by the
--	standard C lib of the target system or as #defines in system/sysintf.h
--	or via appropriate C code in the system/ directory for the given
--	system.
--
--	The first group must be provided by a file in the system/ directory
--	the second group is ideally provided by the C lib.  However, there
--	are instances where the C lib implementation of the specified routine
--	does not exist, or is incorrect.  In these instances the routine
--	must be provided by the the user in the system/ directory of dmake.
--	(For example, the bsd/ dir contains code for putenv(), and tempnam())
--
--	DMAKE SPECIFIC:
--		seek_arch()
--		touch_arch()
--		void_lcache()
--		runargv()
--		STAT()
--		Remove_prq()
--
--	C-LIB SPECIFIC:  (should be present in your C-lib)
--		utime()
--		time()
--		getenv()
--		putenv()
--		getcwd()
--		signal()
--		chdir()
--		tempnam()
-- 
-- 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:	sysintf.c,v $
X * Revision 1.1  91/05/06  15:23:35  dvadura
X * dmake Release Version 3.7
X * 
*/
X
#include "extern.h"
#include "sysintf.h"
X
/*
** Tries to stat the file name.  Returns 0 if the file
** does not exist.  Note that if lib is not null it tries to stat
** the name found inside lib.
**
** If member is NOT nil then look for the library object which defines the
** symbol given by name.  If found _strdup the name and return make the
** pointer pointed at by sym point at it.  Not handled for now!
*/
PUBLIC time_t
Do_stat(name, lib, member)
char *name;
char *lib;
char **member;
{
X   struct stat buf;
X   time_t seek_arch();
X
X   if( member != NIL(char *) )
X      Fatal("Library symbol names not supported");
X
X   buf.st_mtime = (time_t)0L;
X   if( lib != NIL(char) )
X      return( seek_arch(basename(name), lib) );
X   else
X      return( (STAT(name,&buf)==-1 || (Augmake && (buf.st_mode & S_IFDIR)))
X	      ? (time_t)0L
X	      : (time_t) buf.st_mtime
X	    );
}
X
X
X
/* Touch existing file to force modify time to present.
X */
PUBLIC int
Do_touch(name, lib, member)
char *name;
char *lib;
char **member;
{
X   if( member != NIL(char *) )
X      Fatal("Library symbol names not supported");
X
X   if (lib != NIL(char))
X      return( touch_arch(basename(name), lib) );
X   else
X      return( utime(name, NIL(time_t)) );
}
X
X
X
PUBLIC void
Void_lib_cache( lib_name, member_name )/*
=========================================
X   Void the library cache for lib lib_name, and member member_name. */
char *lib_name;
char *member_name;
{
X   VOID_LCACHE( lib_name, member_name );
}
X
X
X
/*
** return the current time
*/
PUBLIC time_t
Do_time()
{
X   extern time_t time();
X   return (time((time_t*)0));
}
X
X
X
/*
** Execute the string passed in as a command and return
** the return code. The command line arguments are
** assumed to be separated by spaces or tabs.  The first
** such argument is assumed to be the command.
**
** If group is true then this is a group of commands to be fed to the
** the shell as a single unit.  In this case cmd is of the form
** "file" indicating the file that should be read by the shell
** in order to execute the command group.
*/
PUBLIC int
Do_cmnd(cmd, group, do_it, target, ignore, shell, last)
char   *cmd;
int     group;
int	do_it;
CELLPTR target;
int     ignore;
int     shell;
int	last;
{
X   int  i;
X
X   if( !do_it ) {
X      if( last && !Doing_bang ) {
X         Update_time_stamp( target );
X      }
X      return(0);
X   }
X
X   if( Max_proc == 1 ) Wait_for_completion = TRUE;
X
X   if( (i = runargv(target, ignore, group, last, shell, cmd)) == -1 )
X      Quit();
X
X   /* NOTE:  runargv must return either 0 or 1, 0 ==> command executed, and
X    * we waited for it to return, 1 ==> command started and is running
X    * concurrently with make process. */
X   return(i);
}
X
X
#define MINARGV 64
/* Take a command and pack it into an argument vector to be executed. */
PUBLIC char **
Pack_argv( group, shell, cmd )
int    group;
int    shell;
char  *cmd;
{
X   static char **av = NIL(char *);
X   static int   avs = 0;
X   int i = 0;
X
X   if( av == NIL(char *) ) {
X      TALLOC(av, MINARGV, char*);
X      avs = MINARGV;
X   }
X
X   if( (Packed_shell = shell||group||(*_strpbrk(cmd, Shell_metas)!='\0')) ) {
X      char* sh = group ? GShell : Shell;
X
X      if( sh != NIL(char) ) {
X         av[i++] = sh;
X         if( (av[i] = (group?GShell_flags:Shell_flags)) != NIL(char) ) i++;
X
X	 av[i++] = cmd;
X	 av[i]   = NIL(char);
X      }
X      else
X	 Fatal("%sSHELL macro not defined", group?"GROUP":"");
X   }
X   else {
X      do {
X         while( iswhite(*cmd) ) ++cmd;
X         if( *cmd ) av[i++] = cmd;
X
X         while( *cmd != '\0' && !iswhite(*cmd) ) ++cmd;
X         if( *cmd ) *cmd++ = '\0';
X
X	 if( i == avs ) {
X	    avs += MINARGV;
X	    av = (char **) realloc( av, avs*sizeof(char *) );
X	 }
X      } while( *cmd );
X
X      av[i] = NIL(char);
X   }
X
X   return(av);
}
X
X
/*
** Return the value of ename from the environment
** if ename is not defined in the environment then
** NIL(char) should be returned
*/
PUBLIC char *
Read_env_string(ename)
char *ename;
{
#if !defined(_MSC_VER) || _MSC_VER < 600
X   extern char *getenv();
#endif
X   return( getenv(ename) );
}
X
X
X
/*
** Set the value of the environment string ename to value.
**  Returns 0 if success, non-zero if failure
*/
PUBLIC int
Write_env_string(ename, value)
char *ename;
char *value;
{
X   extern int putenv();
X   char*   p;
X   char*   envstr = _stradd(ename, value, FALSE);
X
X   p = envstr+strlen(ename);	/* Don't change this code, _stradd does not */
X   *p++ = '=';			/* add the space if *value is 0, it does    */
X   if( !*value ) *p = '\0';	/* allocate enough memory for one though.   */
X
X   return( putenv(envstr) );
}
X
X
X
PUBLIC void
ReadEnvironment()
{
X   extern char **Rule_tab;
#if !defined(_MSC_VER)
X   extern char **environ;
#endif
X   char **rsave;
X
X   rsave    = Rule_tab;
X   Rule_tab = environ;
X   Readenv  = TRUE;
X
X   Parse( NIL(FILE) );
X
X   Readenv  = FALSE;
X   Rule_tab = rsave;
}
X
X
X
/*
** All we have to catch is SIG_INT
*/
PUBLIC void
Catch_signals(fn)
void (*fn)();
{
X   if( signal(SIGINT, SIG_IGN) != SIG_IGN )
X      signal( SIGINT, fn );
X   if( signal(SIGQUIT, SIG_IGN) != SIG_IGN )
X      signal( SIGQUIT, fn );
}
X
X
X
/*
** Clear any previously set signals
*/
PUBLIC void
Clear_signals()
{
X   if( signal(SIGINT, SIG_IGN) != SIG_IGN )
X      signal( SIGINT, SIG_DFL );
X   if( signal(SIGQUIT, SIG_IGN) != SIG_IGN )
X      signal( SIGQUIT, SIG_DFL );
}
X
X
X
/*
** Set program name
*/
PUBLIC void
Prolog(argc, argv)
int   argc;
char* argv[];
{
X   char buf[50];
X
X   Pname = (argc == 0) ? DEF_MAKE_PNAME : argv[0];
X   sprintf( buf, "dmake-%d-root", GETPID );
X   Root = Def_cell( buf );
X   tzset();
}
X
X
X
/*
** Do any clean up for exit.
*/
PUBLIC void
Epilog(ret_code)
int ret_code;
{
X   Write_state();
X   Unlink_temp_files(Root);
X   Hook_std_writes(NIL(char));		/* For MSDOS tee (-F option) */
X   exit( ret_code );
}
X
X
X
/*
** Use the built-in functions of the operating system to get the current
** working directory.
*/
PUBLIC char *
Get_current_dir()
{
X   static char buf[MAX_PATH_LEN+1];
X
X   return( getcwd(buf, sizeof(buf)) );
}
X
X
X
/*
** change working directory
*/
PUBLIC int
Set_dir(path)
char*   path;
{
X   return( chdir(path) );
}
X
X
X
/*
** return switch char
*/
PUBLIC char
Get_switch_char()
{
X   return( getswitchar() );
}
X
X
X
/*
** Generate a temporary file name and open the file for writing.
** If a name cannot be generated or the file cannot be opened
** return -1, else return the fileno of the open file.
** and update the source file pointer to point at the new file name.
** Note that the new name should be freed when the file is removed.
*/
PUBLIC FILE*
Get_temp(path, suff, op)
char **path;
char *suff;
int  op;
{
X   extern char *tempnam();
X
X   *path = _strjoin( tempnam(NIL(char), "mk"), suff, -1, TRUE );
X   Def_macro( "TMPFILE", *path, M_MULTI|M_EXPANDED );
X
X   return( op?fopen(*path, "w"):NIL(FILE) );
}
X
X
/*
** Open a new temporary file and set it up for writing.
*/
PUBLIC FILE *
Start_temp( suffix, cp, fname )
char     *suffix;
CELLPTR   cp;
char    **fname;
{
X   FILE	       *fp;
X   char        *tmpname;
X   char	       *name;
X
X   name = (cp != NIL(CELL))?cp->CE_NAME:"makefile text";
X
X   if( (fp = Get_temp(&tmpname, suffix, TRUE)) == NIL(FILE) )
X      Open_temp_error( tmpname, name );
X
X   Link_temp( cp, fp, tmpname );
X   *fname = tmpname;
X
X   return( fp );
}
X
X
/*
** Issue an error on failing to open a temporary file
*/
PUBLIC void
Open_temp_error( tmpname, name )
char *tmpname;
char *name;
{
X   Fatal("Cannot open temp file `%s' while processing `%s'", tmpname, name );
}
X
X
/*
** Link a temp file onto the list of files.
*/
PUBLIC void
Link_temp( cp, fp, fname )
CELLPTR cp;
FILE   *fp;
char   *fname;
{
X   FILELISTPTR new;
X
X   if( cp == NIL(CELL) ) cp = Root;
X
X   TALLOC( new, 1, FILELIST );
X
X   new->fl_next = cp->ce_files;
X   new->fl_name = fname;
X   new->fl_file = fp;		/* indicates temp file is open */
X
X   cp->ce_files = new;
}
X
X
/*
** Close a previously used temporary file.
*/
PUBLIC void
Close_temp(cp, file)
CELLPTR cp;
FILE    *file;
{
X   FILELISTPTR fl;
X   if( cp == NIL(CELL) ) cp = Root;
X
X   for( fl=cp->ce_files; fl && fl->fl_file != file; fl=fl->fl_next );
X   if( fl ) {
X      fl->fl_file = NIL(FILE);
X      fclose(file);
X   }
}
X
X
/*
** Clean-up, and close all temporary files associated with a target.
*/
PUBLIC void
Unlink_temp_files( cp )/*
==========================
X   Unlink the tempfiles if any exist.  Make sure you close the files first
X   though.  This ensures that under DOS there is no disk space lost. */
CELLPTR cp;
{
X   FILELISTPTR cur, next;
X
X   if( cp == NIL(CELL) || cp->ce_files == NIL(FILELIST) ) return;
X
X   for( cur=cp->ce_files; cur != NIL(FILELIST); cur=next ) {
X      next = cur->fl_next;
X
X      if( cur->fl_file ) fclose( cur->fl_file );
X
X      if( Verbose & V_LEAVE_TMP )
X         printf( "%s:  Left temp file [%s]\n", Pname, cur->fl_name );
X      else
X         (void) unlink( cur->fl_name );
X
X      FREE(cur->fl_name);
X      FREE(cur);
X   }
X
X   cp->ce_files = NIL(FILELIST);
}
X
X
PUBLIC void
Handle_result(status, ignore, abort_flg, target)
int	status;
int	ignore;
int	abort_flg;
CELLPTR target;
{
X   status = ((status&0xff)==0 ? status>>8
X	    : (status & 0xff)==SIGTERM ? -1
X	    : (status & 0x7f)+128);
X
X   if( status )
X      if( !abort_flg ) {
X	 fprintf( stderr, "%s:  Error code %d, while making '%s'",
X		  Pname, status, target->ce_fname );
X
X	 if( ignore || Continue ) {
X	    fputs( " (Ignored)\n", stderr );
X	 }
X	 else {
X	    fputc( '\n', stderr );
X
X	    if( !(target->ce_attr & A_PRECIOUS) )
X	       if( unlink( target->ce_fname ) == 0 )
X		  fprintf(stderr,"%s:  '%s' removed.\n",Pname,target->ce_fname);
X
X	    Quit();
X	 }
X      }
X      else if( !(target->ce_attr & A_PRECIOUS) )
X	 unlink( target->ce_fname );
}
X
X
PUBLIC void
Update_time_stamp( cp )
CELLPTR cp;
{
X   HASHPTR hp;
X   CELLPTR tcp;
X   int     tmpflg; 
X   int     phony = ((cp->ce_attr&A_PHONY) != 0);
X
X   tcp = cp;
X   do {
X      if( tcp->ce_attr & A_LIBRARY )
X	 Void_lib_cache( tcp->ce_fname, NIL(char) );
X      else if( !Touch && (tcp->ce_attr & A_LIBRARYM) )
X	 Void_lib_cache( tcp->ce_lib, tcp->ce_fname );
X
X      if( !phony )
X	 Stat_target(tcp, -1);
X
X      if( tcp->ce_time == (time_t) 0L )
X	 tcp->ce_time = Do_time();
X
X      if( Trace )
X	 tcp->ce_flag |= F_STAT;		/* pretend we stated ok */
X
X      if( Verbose & V_MAKE )
X	 printf( "%s:  <<<< Set [%s] time stamp to %ld\n",
X		 Pname, tcp->CE_NAME, tcp->ce_time );
X
X      Unlink_temp_files( tcp );
X      tcp->ce_flag |= F_MADE;
X      tcp->ce_attr |= A_UPDATED;
X      tcp = tcp->ce_all;
X   }
X   while( tcp != NIL(CELL) && tcp != cp );
X
X
X   /* Scan the list of prerequisites and if we find one that is
X    * marked as being removable, (ie. an inferred intermediate node
X    * then remove it.  We remove a prerequisite by running the recipe
X    * associated with the special target .REMOVE, with $< set to
X    * the list of prerequisites to remove. */
X
X   /* Make sure we don't try to remove prerequisites for the .REMOVE
X    * target. */
X   if( strcmp(cp->CE_NAME,".REMOVE") != 0 &&
X       (hp = Get_name( ".REMOVE", Defs, FALSE )) != NIL(HASH) ) {
X      register LINKPTR dp;
X      int flag = FALSE;
X      int rem;
X      t_attr attr;
X
X      tcp = hp->CP_OWNR;
X
X      tcp->ce_flag |= F_TARGET;
X      Clear_prerequisites( tcp );
X
X      for( dp = cp->ce_prq; dp != NIL(LINK); dp = dp->cl_next ) {
X	 register CELLPTR prq = dp->cl_prq;
X
X	 attr = Glob_attr | prq->ce_attr;
SHAR_EOF
true || echo 'restore of dmake/sysintf.c failed'
fi
echo 'End of part 30, continue with part 31'
echo 31 > _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.