v19i051: dmake - dmake version 3.7, Part30/37
Dennis Vadura
dvadura at watdragon.waterloo.edu
Tue May 14 00:52:57 AEST 1991
Submitted-by: Dennis Vadura <dvadura at 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 at 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 at 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 at 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 at 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 at 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 at uunet.uu.net.
More information about the Comp.sources.misc
mailing list