v15i057: dmake version 3.6 (part 05/25)

Dennis Vadura dvadura at watdragon.waterloo.edu
Mon Oct 15 11:38:03 AEST 1990


Posting-number: Volume 15, Issue 57
Submitted-by: Dennis Vadura <dvadura at watdragon.waterloo.edu>
Archive-name: dmake-3.6/part05

#!/bin/sh
# this is part 5 of a multipart archive
# do not concatenate these parts, unpack them in order with /bin/sh
# file sysintf.c continued
#
CurArch=5
if test ! -r s2_seq_.tmp
then echo "Please unpack part 1 first!"
     exit 1; fi
( read Scheck
  if test "$Scheck" != $CurArch
  then echo "Please unpack part $Scheck next!"
       exit 1;
  else exit 0; fi
) < s2_seq_.tmp || exit 1
echo "x - Continuing file sysintf.c"
sed 's/^X//' << 'SHAR_EOF' >> sysintf.c
X   }
X}
SHAR_EOF
echo "File sysintf.c is complete"
chmod 0440 sysintf.c || echo "restore of sysintf.c fails"
echo "x - extracting struct.h (Text)"
sed 's/^X//' << 'SHAR_EOF' > struct.h &&
X/* RCS      -- $Header: /u2/dvadura/src/generic/dmake/src/RCS/struct.h,v 1.1 90/10/06 12:04:27 dvadura Exp $
X-- SYNOPSIS -- structure definitions
X-- 
X-- DESCRIPTION
X--	dmake main data structure definitions.  See each of the individual
X--	struct declarations for more detailed information on the defined
X--	fields and their use.
X-- 
X-- AUTHOR
X--      Dennis Vadura, dvadura at watdragon.uwaterloo.ca
X--      CS DEPT, University of Waterloo, Waterloo, Ont., Canada
X--
X-- COPYRIGHT
X--      Copyright (c) 1990 by Dennis Vadura.  All rights reserved.
X-- 
X--      This program is free software; you can redistribute it and/or
X--      modify it under the terms of the GNU General Public License
X--      (version 1), as published by the Free Software Foundation, and
X--      found in the file 'LICENSE' included with this distribution.
X-- 
X--      This program is distributed in the hope that it will be useful,
X--      but WITHOUT ANY WARRANTY; without even the implied warrant of
X--      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
X--      GNU General Public License for more details.
X-- 
X--      You should have received a copy of the GNU General Public License
X--      along with this program;  if not, write to the Free Software
X--      Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
X--
X-- LOG
X--     $Log:	struct.h,v $
X * Revision 1.1  90/10/06  12:04:27  dvadura
X * dmake Release, Version 3.6
X * 
X*/
X
X#ifndef _STRUCT_INCLUDED_
X#define _STRUCT_INCLUDED_
X
X#include <sys/types.h>
X#include "itypes.h"
X
Xtypedef int32 t_attr;
X
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
Xtypedef 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; /* rootdir ptr for hash    */
X			} ht;
X		} val;
X	} var;				/* variable's static equivalent */
X} HASH, *HASHPTR;
X
X#define MV_MASK		var.mv_mask
X#define MV_SVAR 	var.val.mv_svar
X#define MV_CVAR 	var.val.mv_cvar
X#define MV_BVAR 	var.val.mv_bvar
X#define MV_IVAR 	var.val.mv_ivar
X#define CP_OWNR         var.val.ht.ht_owner
X#define CP_ROOT		var.val.ht.ht_root
X
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 */
Xtypedef struct flst {
X   char		*fl_name;	/* file name 		*/
X   FILE		*fl_file;	/* the open file	*/
X   struct flst  *fl_next;	/* pointer to next file */
X} FILELIST, *FILELISTPTR;
X
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
Xtypedef struct tcell {
X	struct tcell	*ce_link;	/* link for temporary list making   */
X	struct tcell	*ce_all;	/* link for grouping UPDATEALL cells*/
X	struct hcell	*ce_name;	/* name of this cell                */
X	struct tcell	*ce_setdir;	/* .SETDIR root for this cell       */
X	union {
X		struct hwcell	*ce_how;/* tell all we need to make cell    */
X		struct edge	*ce_edges;/* tell what we can infer */
X	} how;
X	char		*ce_lib;	/* archive name, if A_LIBRARYM      */
X	char		*ce_fname;	/* file name associated with target */
X	char		*ce_dir;	/* dir to set if A_SETDIR set       */
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*/
X} CELL, *CELLPTR;
X
X#define CE_NAME		ce_name->ht_name
X#define CE_RECIPE       how.ce_how->hw_recipe
X#define CE_PRQ		how.ce_how->hw_prq
X#define CE_EDGES	how.ce_edges
X#define CE_HOW		how.ce_how
X
X
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	
Xtypedef 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  */
X}  TKSTR, *TKSTRPTR;
X
X
X
X
X/* This structure defines the necessary fields for handling the :: rules,
X * any flags, and the fact that the target has been made using this
X * set of rules.  All attributes active when making this target are
X * defined in this struct. */
X
Xtypedef struct hwcell {
X	struct hwcell	*hw_next;	/* next set of rules (::)	*/
X	struct lcell	*hw_prq;	/* the list of prerequisites	*/
X	struct lcell	*hw_indprq;	/* the list of glob prereqs	*/
X	struct str	*hw_recipe;	/* list of rules for making tg	*/
X	char		*hw_per;	/* value of % in % meta rules	*/
X	FILELISTPTR	hw_files;	/* temp files associated with tg*/
X	int   		hw_flag;	/* flags for using these rules  */
X	t_attr		hw_attr;	/* attrs for using these rules  */
X} HOW, *HOWPTR;
X
X#define HW_FLAG		CE_HOW->hw_flag
X#define HW_ATTR		CE_HOW->hw_attr
X
X
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
Xtypedef 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 */
X} STRING, *STRINGPTR;
X
X
X/* The next struct is used to link together prerequisite lists */
X
Xtypedef 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		*/
X} LINK, *LINKPTR;
X
X
X
X/* This struct is used to define an edge in the graph of % rules */
X
Xtypedef struct edge {
X	struct tcell	*ed_tg;		/* the % target			*/
X	struct tcell	*ed_prq;	/* the prerequisite for target	*/
X	struct hwcell	*ed_how;	/* chain of how pointers	*/
X	struct edge	*ed_next;	/* next edge of graph		*/
X	struct edge	*ed_link;	/* work list pointer 		*/
X} EDGE, *EDGEPTR;
X
X
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
Xtypedef int16 statecnt;		/* limits the max number of dfa states	*/
X
X
X/* Each state of the DFA contains four pieces of information. */
Xtypedef 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 */
X} STATE, *STATEPTR;
X
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. */
Xtypedef 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 */
X} DFA, *DFAPTR;
X
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. */
Xtypedef 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 */
X} NFA, *NFAPTR;
X
X
X
X/* The next struct is used to link together DFA nodes for inference. */
X
Xtypedef 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	*/
X} DFALINK, *DFALINKPTR;
X
X
X/* This struct is used to store the stack of DFA sets during inference */
Xtypedef struct dfst {
X   DFALINKPTR	df_set;			/* pointer to the set		*/
X   struct dfst *df_next;		/* next element in the stack	*/
X} DFASET, *DFASETPTR;
X
X
X#endif
SHAR_EOF
chmod 0440 struct.h || echo "restore of struct.h fails"
echo "x - extracting string.c (Text)"
sed 's/^X//' << 'SHAR_EOF' > string.c &&
X/* RCS      -- $Header: /u2/dvadura/src/generic/dmake/src/RCS/string.c,v 1.1 90/10/06 12:04:14 dvadura Exp $
X-- SYNOPSIS -- string handling code
X-- 
X-- DESCRIPTION
X--	Routines to handle string manipulation.  This code is not specific
X--	to dmake and has/and will be used in other programs.  The string
X--	"" is considered the NULL string, if NIL(char) is received instead
X--	undefined results may occurr.  (In reality NIL(char) is checked for
X--	but in general it is not safe to assume NIL(char) ==  NULL)
X-- 
X-- AUTHOR
X--      Dennis Vadura, dvadura at watdragon.uwaterloo.ca
X--      CS DEPT, University of Waterloo, Waterloo, Ont., Canada
X--
X-- COPYRIGHT
X--      Copyright (c) 1990 by Dennis Vadura.  All rights reserved.
X-- 
X--      This program is free software; you can redistribute it and/or
X--      modify it under the terms of the GNU General Public License
X--      (version 1), as published by the Free Software Foundation, and
X--      found in the file 'LICENSE' included with this distribution.
X-- 
X--      This program is distributed in the hope that it will be useful,
X--      but WITHOUT ANY WARRANTY; without even the implied warrant of
X--      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
X--      GNU General Public License for more details.
X-- 
X--      You should have received a copy of the GNU General Public License
X--      along with this program;  if not, write to the Free Software
X--      Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
X--
X-- LOG
X--     $Log:	string.c,v $
X * Revision 1.1  90/10/06  12:04:14  dvadura
X * dmake Release, Version 3.6
X * 
X*/
X
X#include "extern.h"
X#include "alloc.h"
X#include "db.h"
X
Xchar *
X_strjoin( src, data, n, fr )/*
X==============================
X   Join data to src according to value of n.
X
X      n = -1   - return strcat( src, data )
X      n >= 0   - return strncat( src, data, n )
X
X   FREE original src if fr == TRUE, else leave it alone */
X
Xchar *src;
Xchar *data;
Xint  n;
Xint  fr;
X{
X   char *t;
X   int  l;
X   int  flag = FALSE;
X
X   DB_ENTER( "_strjoin" );
X   
X   if( src  == NIL( char ) ) { src = ""; flag = TRUE; }
X   if( data == NIL( char ) ) data = "";
X   DB_PRINT( "str", ("Joining [%s] [%s] %d", src, data, n) );
X
X   if( n == -1 )  n = strlen( data );
X
X   l = strlen( src ) + n + 1;
X   if( (t = MALLOC( l, char )) == NIL( char ) ) No_ram();
X
X   strcpy( t, src );
X   if (n) strncat( t, data, n );
X   t[ l-1 ] = '\0';
X
X   if( !flag && fr ) FREE( src );
X
X   DB_PRINT( "str", ("Result  [%s]", t) );
X   DB_RETURN( t );
X}
X
X
X
X
Xchar *
X_stradd( src, data, fr )/*
X==========================
X   append data to src with space in between if src is not NIL( char ) or ""
X   and free both src and data if fr == TRUE, otherwise leave them be */
X
Xchar *src;
Xchar *data;
Xint  fr;
X{
X   char *t;
X   int  l;
X   int  sflag;
X   int  dflag;
X
X   DB_ENTER( "_stradd" );
X
X   sflag = dflag = fr;
X
X   if( src  == NIL( char ) ) { src  = ""; sflag = FALSE; }
X   if( data == NIL( char ) ) { data = ""; dflag = FALSE; }
X   DB_PRINT( "str", ("Adding [%s] [%s] %d", src, data, fr) );
X
X   l = strlen(src) + strlen(data) + 1;
X   if( *src ) l++;
X
X   if( (t = MALLOC( l, char )) == NIL( char ) ) No_ram();
X
X   strcpy( t, src );
X   
X   if( *data )
X   {
X      if( *src ) strcat( t,  " " );
X      strcat( t, data );
X   }
X
X   if( sflag )  FREE( src  );
X   if( dflag )  FREE( data );
X
X   DB_PRINT( "str", ("Result  [%s]", t) );
X   DB_RETURN( t );
X}
X
X
X
Xchar *
X_strapp( src1, src2 )/*
X=======================
X   Append two strings together, and return the result with a space between
X   the two strings.  FREE the first string if it is not NIL and always
X   leave the second string be. */
Xchar *src1;
Xchar *src2;
X{
X   src2 = _stradd( src1, src2, FALSE );
X   if( src1 != NIL( char ) ) FREE( src1 );
X   return( src2 );
X}
X
X
X
Xchar *
X_strdup( str )/*
X================  Duplicate the contents of a string, by using malloc */
Xchar *str;
X{
X   char *t;
X
X   if( str == NIL( char ) ) return( NIL( char ) );
X   
X   if( (t = MALLOC( strlen( str )+1, char )) == NIL( char ) ) No_ram();
X   strcpy( t, str );
X
X   return( t );
X}
X
X
X
X
Xchar *
X_strpbrk( s1, s2 )/*
X====================
X   find first occurence of char in s2 in string s1.
X   Returns a pointer to the first occurrence.  NOTE '\0' is considered part
X   of s2 and a pointer to it is returned if no other chars match. */
X
Xchar *s1;
Xchar *s2;
X{
X   register char *t;
X
X   if( s1 == NIL( char ) ) return( "" );
X
X   for( t=s1; *t && (strchr( s2, *t ) == NIL( char )); t++ );
X   return( t );
X}
X
X
X
X
Xchar *
X_strspn( s1, s2 )/*
X===================
X   return pointer to first char in s1 that does not belong to s2.
X   Returns the pointer if match found, else returns pointer to null char
X   in s1. (ie. "" ) */
X   
Xchar *s1;
Xchar *s2;
X{
X   register char *t;
X
X   if( s1 == NIL( char ) ) return( "" );
X
X   for( t=s1; *t && (strchr( s2, *t ) != NIL( char )); t++ );
X   return( t );
X}
X
X
X
X
Xchar *
X_strstr( s1, s2 )/*
X==================  find first occurrence in s1 of s2 */
Xchar *s1;
Xchar *s2;
X{
X   register char *s;
X   register char *p;
X   register char *r;
X
X   if( s1 != NIL(char) && s2 != NIL(char) )
X      for( s=s1; *s; s++ )
X	 if( *s == *s2 )
X	 {
X	    for( r=s+1, p = s2+1; *p && (*r == *p); r++, p++ );
X	    if( !*p ) return( s );
X	 }
X   
X   return( NIL( char ) );
X}
X
X
X
Xchar *
X_substr( s, e )/*
X=================
X      Return the string between the two pointers s and e, not including the
X      char that e points to.  NOTE:  This routine assumes that s and e point
X      into the same string. */
X
Xchar *s;
Xchar *e;
X{
X   char save;
X
X   save = *e;
X   *e   = '\0';
X   s    = _strdup( s );
X   *e   = save;
X
X   return( s );
X}
SHAR_EOF
chmod 0440 string.c || echo "restore of string.c fails"
echo "x - extracting stat.c (Text)"
sed 's/^X//' << 'SHAR_EOF' > stat.c &&
X/* RCS      -- $Header: /u2/dvadura/src/generic/dmake/src/RCS/stat.c,v 1.1 90/10/06 12:04:12 dvadura Exp $
X-- SYNOPSIS -- bind a target name to a file.
X-- 
X-- DESCRIPTION
X--	This file contains the code to go and stat a target.  The stat rules
X--	follow a predefined order defined in the comment for Stat_target.
X-- 
X-- AUTHOR
X--      Dennis Vadura, dvadura at watdragon.uwaterloo.ca
X--      CS DEPT, University of Waterloo, Waterloo, Ont., Canada
X--
X-- COPYRIGHT
X--      Copyright (c) 1990 by Dennis Vadura.  All rights reserved.
X-- 
X--      This program is free software; you can redistribute it and/or
X--      modify it under the terms of the GNU General Public License
X--      (version 1), as published by the Free Software Foundation, and
X--      found in the file 'LICENSE' included with this distribution.
X-- 
X--      This program is distributed in the hope that it will be useful,
X--      but WITHOUT ANY WARRANTY; without even the implied warrant of
X--      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
X--      GNU General Public License for more details.
X-- 
X--      You should have received a copy of the GNU General Public License
X--      along with this program;  if not, write to the Free Software
X--      Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
X--
X-- LOG
X--     $Log:	stat.c,v $
X * Revision 1.1  90/10/06  12:04:12  dvadura
X * dmake Release, Version 3.6
X * 
X*/
X
X#include "extern.h"
X#include "alloc.h"
X#include "db.h"
X
X
Xstatic	int	_check_dir_list ANSI((CELLPTR, CELLPTR, int));
X
X#ifdef DBUG
X   /* Just a little ditty for debugging this thing */
X   static time_t
X   _do_stat( name, lib, sym )
X   char *name;
X   char *lib;
X   char **sym;
X   {
X      time_t res;
X      DB_ENTER( "_do_stat" );
X
X      res = Do_stat(name, lib, sym);
X      DB_PRINT( "stat", ("Statted [%s,%s,%d,%ld]", name, lib, sym, res) );
X
X      DB_RETURN( res );
X   }   
X#define DO_STAT(A,B,C)  _do_stat(A,B,C)
X#else
X#define DO_STAT(A,B,C)  Do_stat(A,B,C)
X#endif
X
Xstatic char *_first;	/* local storage of first attempted path */
X
Xvoid
XStat_target( cp, setfname )/*
X=============================
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
XCELLPTR cp;
Xint     setfname;
X{
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,NIL(CELL));
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      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 )
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(CELL))) != 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   FREE( tmp );
X
X   if( (cp->ce_attr & A_FFNAME) && (cp->ce_fname != NIL(char)) )
X      FREE( cp->ce_fname );
X
X   if( setfname )
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   /* 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
X
Xstatic int
X_check_dir_list( cp, sp, setfname )/*
X=====================================
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
XCELLPTR cp;
XCELLPTR sp;
Xint     setfname;
X{
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_HOW != NIL(HOW) )		/* 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);
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 );
X}
SHAR_EOF
chmod 0440 stat.c || echo "restore of stat.c fails"
echo "x - extracting rulparse.c (Text)"
sed 's/^X//' << 'SHAR_EOF' > rulparse.c &&
X/* RCS      -- $Header: /u2/dvadura/src/generic/dmake/src/RCS/rulparse.c,v 1.1 90/10/06 12:04:10 dvadura Exp $
X-- SYNOPSIS -- perform semantic analysis on input
X-- 
X-- DESCRIPTION
X--	This code performs semantic analysis on the input, and builds
X--	the complex internal datastructure that is used to represent
X--	the user makefile.
X-- 
X-- AUTHOR
X--      Dennis Vadura, dvadura at watdragon.uwaterloo.ca
X--      CS DEPT, University of Waterloo, Waterloo, Ont., Canada
X--
X-- COPYRIGHT
X--      Copyright (c) 1990 by Dennis Vadura.  All rights reserved.
X-- 
X--      This program is free software; you can redistribute it and/or
X--      modify it under the terms of the GNU General Public License
X--      (version 1), as published by the Free Software Foundation, and
X--      found in the file 'LICENSE' included with this distribution.
X-- 
X--      This program is distributed in the hope that it will be useful,
X--      but WITHOUT ANY WARRANTY; without even the implied warrant of
X--      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
X--      GNU General Public License for more details.
X-- 
X--      You should have received a copy of the GNU General Public License
X--      along with this program;  if not, write to the Free Software
X--      Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
X--
X-- LOG
X--     $Log:	rulparse.c,v $
X * Revision 1.1  90/10/06  12:04:10  dvadura
X * dmake Release, Version 3.6
X * 
X*/
X
X#include <ctype.h>
X#include "extern.h"
X#include "alloc.h"
X#include "db.h"
X
X/* prototypes for local functions */
Xstatic  void    _add_global_prereq ANSI((CELLPTR));
Xstatic	void	_build_graph ANSI((int, CELLPTR, CELLPTR));
Xstatic	char*	_build_meta ANSI((char*));
Xstatic	int	_do_magic ANSI((int, char*, CELLPTR, CELLPTR, t_attr, char*));
Xstatic	void	_do_special ANSI((int, int, t_attr,char*,CELLPTR,CELLPTR,int*));
Xstatic	int	_do_targets ANSI((int, t_attr, char*, CELLPTR, CELLPTR));
Xstatic	t_attr	_is_attribute ANSI((char*));
Xstatic	int	_is_special ANSI((char*));
Xstatic	char*	_is_magic ANSI((char*));
Xstatic	int	_is_percent ANSI((char*));
Xstatic	void	_set_attributes ANSI((t_attr, char*, CELLPTR));
Xstatic	void	_stick_at_head ANSI((HOWPTR, CELLPTR));
Xstatic	void	_set_global_attr ANSI((t_attr, char*));
X
X/* static variables that must persist across invocation of Parse_rule_def */
Xstatic CELLPTR    _sv_targets = NIL(CELL);
Xstatic STRINGPTR  _sv_rules   = NIL(STRING);
Xstatic STRINGPTR  _sv_crule   = NIL(STRING);
Xstatic EDGEPTR    _sv_edgel   = NIL(EDGE);
Xstatic LINKPTR    _sv_glb_prq = NIL(LINK);
Xstatic int	  _sp_target  = FALSE;
Xstatic t_attr     _sv_attr;
Xstatic t_attr     _sv_attro;
Xstatic int        _sv_flag;
Xstatic int	  _sv_op;
Xstatic char      *_sv_setdir;
Xstatic char	  _sv_globprq_only = 0;
X
X/* Define for common attribute mask */
X#define A_HOW    (A_IGNORE | A_SILENT | A_SHELL | A_SWAP)
X#define A_GLOB	 (A_PRECIOUS | A_SILENT | A_IGNORE | A_EPILOG |\
X		  A_PROLOG | A_NOINFER | A_SEQ | A_SHELL | A_SWAP | A_MKSARGS)
X
X
X
Xint
XParse_rule_def( state )/*
X=========================
X   Parse the rule definition contained in Buffer, and modify the state 
X   if appropriate.  The function returns 0, if the definition is found to
X   be an illegal rule definition, and it returns 1 if it is a rule definition.
X   */
Xint *state;
X{
X   TKSTR 	input;		/* input string struct for token search	  */
X   CELLPTR	targets;	/* list of targets if any		  */
X   CELLPTR	prereq;		/* list of prereq if any		  */
X   CELLPTR	prereqtail;	/* tail of prerequisite list		  */
X   CELLPTR	cp;		/* temporary cell pointer for list making */
X   char 	*result;	/* temporary storage for result	  	  */
X   char		*tok;		/* temporary pointer for tokens		  */
X   char         *set_dir;       /* value of setdir attribute              */
X   char		*brk;		/* break char list for Get_token	  */
X   char         *firstrcp;      /* first recipe line, from ; in rule line */
X   t_attr       attr;           /* sum of attribute flags for current tgts*/
X   t_attr	at;		/* temp place to keep an attribute code	  */
X   int		op;		/* rule operator			  */
X   int		special;	/* indicate special targets in rule	  */
X   int		percent;	/* indicate percent rule target		  */
X   int		mixed_glob_prq; /* indicate mixed %-rule prereq possible  */
X
X   DB_ENTER( "Parse_rule_def" );
X
X   op	      = 0;
X   attr       = 0;
X   special    = 0;
X   percent    = 0;
X   set_dir    = NIL( char );
X   targets    = NIL(CELL);
X   prereq     = NIL(CELL);
X   prereqtail = NIL(CELL);
X   mixed_glob_prq = 0;
X
X   /* Check to see if the line is of the form:
X    *    targets : prerequisites; first recipe line
X    * If so remember the first_recipe part of the line. */
X
X   firstrcp = strchr( Buffer, ';' );
X   if( firstrcp != NIL( char ) ) {
X      *firstrcp++ = 0;
X      firstrcp = _strspn( firstrcp, " \t" );
X   }
X
X   result = Expand( Buffer );
X   for( brk=strchr(result,'\\'); brk != NIL(char); brk=strchr(brk,'\\') )
X      if( brk[1] == '\n' )
X	 *brk = ' ';
X      else
X         brk++;
X
X   DB_PRINT( "par", ("Scanning: [%s]", result) );
X
X   SET_TOKEN( &input, result );
X   brk = ":-^!";
X   Def_targets = TRUE;
X   
X   /* Scan the input rule line collecting targets, the operator, and any
X    * prerequisites.  Stop when we run out of targets and prerequisites. */
X
X   while( *(tok = Get_token( &input, brk, TRUE )) != '\0' )
X      if( !op ) {
X	 /* we are scanning targets and attributes
X	  * check to see if token is an operator.  */
X
X	 op = Rule_op( tok );
X
X	 if( !op ) {
X	    /* define a new cell, or get old cell  */
X	    cp = Def_cell(tok, NIL(CELL));
X	    DB_PRINT( "par", ("tg_cell [%s]", tok) );
X	    
X	    if( at = _is_attribute( tok ) ) {
X	       /* Logically OR the attributes specified into one main
X	        * ATTRIBUTE mask. */
X
X	       if( at == A_SETDIR )
X	          if( set_dir != NIL( char ) )
X	             Fatal( "Only one .SETDIR attribute allowed in rule line" );
X	          else
X	             set_dir = _strdup( tok );
X
X	       attr |= at;
X	    }
X	    else {
X	       int tmp;
X	       
X	       tmp = _is_special( tok );
X	       if( _is_percent( tok ) ) percent++;
X
X	       if( percent )
X	          if( targets != NIL(CELL) )
X		     Fatal( "Multiple targets are not allowed in %% rules" );
X		  else
X		     cp->ce_flag |= F_PERCENT;
X
X	       if( special )
X	          Fatal( "Special target must appear alone", tok );
X	       else if( !(cp->ce_flag & F_MARK) ) {
X		  cp->ce_link  = targets;  /* targets are stacked in this list*/
X		  cp->ce_flag |= F_MARK | F_EXPLICIT;
X		  targets      = cp;
X
X		  special = tmp;
X	       }
X	       else if( !(cp->ce_attr & A_LIBRARY) )
X		  Warning("Duplicate entry [%s] in target list",cp->CE_NAME);
X	    }
X	 }
X	 else {
X	    /* found an operator so empty out break list
X	     * and clear mark bits on target list, setting them all to F_USED */
X
X	    brk  = "";
X	    for( cp=targets; cp != NIL(CELL); cp=cp->ce_link ) {
X	       cp->ce_flag ^= F_MARK;
X	       cp->ce_flag |= F_USED;
X	    }
X
X	    Def_targets = FALSE;
X	 }
X      }
X      else {
X         /* Scanning prerequisites so build the prerequisite list.  We use
X          * F_MARK flag to make certain we have only a single copy of the
X          * prerequisite in the list */
X
X	 cp = Def_cell( tok, NIL(CELL) );
X
X	 if( _is_percent( tok ) ) {
X	    if( !percent && !attr )
X	       Fatal( "Syntax error in %% rule, missing %% target");
X	    mixed_glob_prq = 1;
X	 }
X
X	 if( cp->ce_flag & F_USED ) {
X	    if( cp->ce_attr & A_COMPOSITE )
X	       continue;
X	    else
X	       Fatal( "Detected circular dependency in graph at [%s]",
X		      cp->CE_NAME );
X	 }
X         else if( !(cp->ce_flag & F_MARK) ) {
X	    DB_PRINT( "par", ("pq_cell [%s]", tok) );
X	    cp->ce_flag |= F_MARK;
X
X	    if( prereqtail == NIL(CELL) )	/* keep prereq's in order */
X	       prereq = cp;
X	    else
X	       prereqtail->ce_link = cp;
X
X	    prereqtail = cp;
X	 }
X	 else if( !(cp->ce_attr & A_LIBRARY) )
X	    Warning("Duplicate entry [%s] in prerequisite list",cp->CE_NAME);
X      }
X      
X   /* Check to see if we have a percent rule that has only global
X    * prerequisites.  If so then set the flag so that later on, we don't issue
X    * an error if such targets supply an empty set of rules. */
X
X   if( percent && !mixed_glob_prq && (prereq != NIL(CELL)) )
X      _sv_globprq_only = 1;
X
X   /* It's ok to have targets with attributes, and no prerequisites, but it's
X    * not ok to have no targets and no attributes, or no operator */
X
X   if( !op ) {
X      CLEAR_TOKEN( &input );
X      DB_PRINT( "par", ("Not a rule [%s]", Buffer) );
X      DB_RETURN( 0 );
X   }
X
X   if( !attr && targets == NIL(CELL) ) {
X      Fatal( "Missing targets or attributes in rule" );
X      if( set_dir != NIL( char )) FREE( set_dir );
X      DB_RETURN( 0 );
X   }
X
X   /* We have established we have a legal rules line, so we must process it.
X    * In doing so we must handle any special targets.  Special targets must
X    * appear alone possibly accompanied by attributes.
X    * NOTE:  special != 0  ==> targets != NIL(CELL) */
X    
X   if( prereqtail != NIL(CELL) ) prereqtail->ce_link = NIL(CELL);
X
X   /* Clear out MARK bits used in duplicate checking.  I originally wanted
X    * to do this as the lists get processed but that got too error prone
X    * so I bit the bullit and added these two loops. */
X
X   for( cp=prereq;  cp != NIL(CELL); cp=cp->ce_link ) cp->ce_flag &= ~F_MARK;
X   for( cp=targets; cp != NIL(CELL); cp=cp->ce_link ) cp->ce_flag &= ~F_USED;
X
X   /* Check to see if the previous rule line was bound if, not the call
X    * Bind_rules_to_targets to go and bind the line */
X
X   if( _sv_rules != NIL(STRING) ) Bind_rules_to_targets( F_DEFAULT );
X
X   /* Add the first recipe line to the list */
X   if( firstrcp != NIL( char ) )
X      Add_recipe_to_list( firstrcp, TRUE, FALSE );
X
X   if( special )
X      _do_special( special, op, attr, set_dir, targets, prereq, state );
X   else
X      *state = _do_targets( op, attr, set_dir, targets, prereq );
X
X   _sv_op     = op;
X   _sv_setdir = set_dir;
X   DB_RETURN( 1 );
X}
X
X
X
X
Xint
XRule_op( op )/*
X================
X   Check the passed in op string and map it to one of the rule operators */
Xchar *op;
X{
X   int ret = 0;
X
X   DB_ENTER( "rule_op" );
X   
X   if( *op == TGT_DEP_SEP ) {
X      ret = R_OP_CL;
X      op++;
X
X      /* All rule operations begin with a :, but may include any one of the
X       * four modifiers.  In order for the rule to be properly mapped we must
X       * check for each of the modifiers in turn, building up our return bit
X       * string. */
X
X      while( *op && ret )
X         switch( *op ) {
X	    case ':': ret |= R_OP_DCL; op++; break;
X	    case '!': ret |= R_OP_BG;  op++; break;
X	    case '^': ret |= R_OP_UP;  op++; break;
X	    case '-': ret |= R_OP_MI;  op++; break;
X
X	    default : ret  = 0;  /* an invalid modifier, chuck whole string */
X         }
X
X      if( *op != '\0' ) ret = 0;
X   }
X
X   DB_RETURN( ret );
X}
X
X
X
X
Xvoid
XAdd_recipe_to_list( rule, white_too, no_check )/*
X=================================================
X        Take the provided string and add it to the list of recipe lines
X	we are saving to be added to the list of targets we have built
X	previously.  If white_too == TRUE add the rule EVEN IF it contains only
X        whitespace. */
Xchar *rule;
Xint  white_too;
Xint  no_check;
X{
X   DB_ENTER( "Add_recipe_to_list" );
X
X   if( rule != NIL( char ) && (*rule != '\0' || white_too) ) {
X      DB_PRINT( "par", ("Adding recipe [%s]", rule) );
X      _sv_crule = Def_recipe( rule, _sv_crule, white_too, no_check );
X
X      if( _sv_rules == NIL(STRING) )
X         _sv_rules = _sv_crule;
X   }
X
X   DB_VOID_RETURN;
X}
X
X
X
Xvoid
XBind_rules_to_targets( flag )/*
X===============================
X        Take the rules we have defined and bind them with proper attributes
X        to the targets that were previously defined in the parse.  The
X        attributes that get passed here are merged with those that are were
X        previously defined.  (namely F_SINGLE) */
Xint flag;
X{
X   CELLPTR tg;             /* pointer to current target in list */
X   LINKPTR lp;		   /* pointer to link cell		*/
X   HOWPTR  how;		   /* pointer to targets main HOW cell	*/
X   int     magic;          /* TRUE if target is .xxx.yyy form   */
X   int     tflag;          /* TRUE if we assigned targets here  */
X
X   DB_ENTER( "Bind_rules_to_targets" );
X
X   /* This line is needed since Parse may call us twice when the last
X    * GROUP rule appears at the end of file.  In this case the rules
X    * have already been bound and we want to ignore them. */
X
X   if( _sv_targets == NIL(CELL) ) { DB_VOID_RETURN; }
X
X   tflag  = FALSE;
X   flag  |= (_sv_flag & F_SINGLE);
X
X   for( tg = _sv_targets; tg != NIL(CELL); tg = tg->ce_link ) {
X      DB_PRINT( "par", ("Binding to %s, %04x", tg->CE_NAME, tg->ce_flag) );
X      magic = tg->ce_flag & F_PERCENT;
X
X      /* Check to see if we had a rule of the form '%.o : a.h b.h ; xxx'
X       * In which case we must build a NULL prq node to hold the recipe */
X
X      if( _sv_globprq_only && (_sv_rules != NIL(STRING)) )
X	 _build_graph( _sv_op, tg, NIL(CELL) );
X
X      /* NOTE:  For targets that are magic we ignore any previously defined
X       *        rules.  ie. We throw away the old definition and use the new. */
X
X      if( !(tg->ce_flag & F_MULTI) && !magic && (tg->CE_RECIPE != NIL(STRING))
X	  && !_sp_target && (_sv_rules != NIL(STRING)) )
X         Fatal( "Multiply defined recipe for target %s", tg->CE_NAME );
X
X      if( (magic || _sp_target) && (_sv_rules == NIL(STRING)) &&
X	  !(tg->ce_flag & F_SPECIAL) && !_sv_globprq_only )
X         Warning( "Empty recipe for special target %s", tg->CE_NAME );
X
X      if( magic ) {
X	 EDGEPTR el;
X
X	 for( el=_sv_edgel; el != NIL(EDGE); el=el->ed_link ) {
X	    how = el->ed_how;
X	    how->hw_flag |= flag;
X
X	    _set_attributes( _sv_attro, _sv_setdir, el->ed_tg );
X
X	    if( _sv_rules != NIL(STRING) ) {
X	       how->hw_recipe  = _sv_rules;
X	       how->hw_attr   |= _sv_attr & A_HOW;
X	       how->hw_indprq = _sv_glb_prq;
X	    }
X	 }
X      }
X      else {
X	 how = tg->CE_HOW;
X	 how->hw_flag |= flag;
X
X	 if( _sv_rules != NIL(STRING) ) {
X	    how->hw_recipe  = _sv_rules;
X	    how->hw_attr   |= _sv_attr & A_HOW;
X	    tg->ce_flag    |= F_RULES | F_TARGET;
X
X	    /* Bind the current set of prerequisites as belonging to the
X	     * original recipe given for the target */
X
X	    for( lp=how->hw_prq; lp != NIL(LINK); lp = lp->cl_next )
X		  if( !(lp->cl_flag & F_USED) ) lp->cl_flag |= F_TARGET;
X         }
X	 else
X	    for( lp=how->hw_prq; lp != NIL(LINK); lp = lp->cl_next )
X		  lp->cl_flag |= F_USED;
X      }
X
X      if( !Target && !magic && !(tg->ce_flag & F_SPECIAL) ) {
X	 Add_fringe( tg );
X
X	 tg->ce_flag |= F_TARGET;
X	 tflag        = TRUE;
X      }
X
X      /* Break since all prerequisites are attached and all targets in the
X       * .UPDATEALL list point at the same HOW cell. */
X      if( tg->ce_all != NIL(CELL) ) {
X	 CELLPTR tcp = tg;
X
X	 /* Make sure all people participating in a .UPDATEALL prerequisite
SHAR_EOF
echo "End of part 5"
echo "File rulparse.c is continued in part 6"
echo "6" > s2_seq_.tmp
exit 0



More information about the Comp.sources.misc mailing list