From pa.dec.com!decwrl!uunet!sparky!kent Mon May 13 18:19:24 PDT 1991 Article: 2335 of comp.sources.misc Newsgroups: comp.sources.misc Path: pa.dec.com!decwrl!uunet!sparky!kent From: Dennis Vadura Subject: v19i051: dmake - dmake version 3.7, Part30/37 Message-ID: <1991May13.145257.9543@sparky.IMD.Sterling.COM> X-Md4-Signature: 4b5cc2e58ab802d51fec2a27153fe838 Sender: kent@sparky.IMD.Sterling.COM (Kent Landfield) Organization: Sterling Software, IMD Date: Mon, 13 May 1991 14:52:57 GMT Approved: kent@sparky.imd.sterling.com Submitted-by: Dennis Vadura 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 ; ist_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.