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