home *** CD-ROM | disk | FTP | other *** search
Text File | 1990-07-26 | 38.9 KB | 1,298 lines |
- Newsgroups: comp.sources.misc
- subject: v14i014: dmake version 3.5 part 4/21
- From: dvadura@watdragon.waterloo.edu (Dennis Vadura)
- Sender: allbery@uunet.UU.NET (Brandon S. Allbery - comp.sources.misc)
-
- Posting-number: Volume 14, Issue 14
- Submitted-by: dvadura@watdragon.waterloo.edu (Dennis Vadura)
- Archive-name: dmake/part04
-
- #!/bin/sh
- # this is part 4 of a multipart archive
- # do not concatenate these parts, unpack them in order with /bin/sh
- # file struct.h continued
- #
- CurArch=4
- 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 struct.h"
- sed 's/^X//' << 'SHAR_EOF' >> struct.h
- 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 int 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 int 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 int 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 DFA machines that are 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/* This struct stores a single state for the DFA machine */
- X
- Xtypedef struct {
- X statecnt no_match; /* state to go to if no match */
- X statecnt next; /* state to go to if we do match */
- X char symbol; /* the symbol matched by this state */
- X char action; /* action to perform if we match */
- X} STATE, *STATEPTR;
- X
- X
- X/* This struct stores the DFA machine, it's current state, and pointers
- X * indicating the extent of the % substring match */
- X
- Xtypedef struct {
- X char *pstart; /* start of % string match */
- X char *pend; /* end of % string match */
- X statecnt c_state; /* current DFA state */
- X statecnt n_states; /* number of states in this dfa */
- X CELLPTR node; /* % target represented by this DFA */
- X STATEPTR states; /* table of states for the DFA */
- X} DFA, *DFAPTR;
- X
- X
- X/* This struct represents the linked together DFA's which form one large
- X * NFA machine. When a pattern match takes place all DFA's making up this
- X * NFA are run in parallel. */
- X
- Xtypedef struct nfa_machine {
- X DFAPTR dfa; /* The DFA pointed at by epsilon trans */
- X char status; /* DFA state: -1 ==> fail, 4 ==> ACCEPT */
- X struct nfa_machine *next; /* the next DFA in list */
- 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
- echo "File struct.h is complete"
- 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/07/19 13:53:35 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@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/07/19 13:53:35 dvadura
- X * Initial Revision of Version 3.5
- 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/07/19 13:53:34 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@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/07/19 13:53:34 dvadura
- X * Initial Revision of Version 3.5
- 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
- X/* RCS -- $Header: /u2/dvadura/src/generic/dmake/src/RCS/rulparse.c,v 1.1 90/07/21 11:06:33 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@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/07/21 11:06:33 dvadura
- X * Initial Revision Version 3.5
- 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, int, char*));
- Xstatic void _do_special ANSI((int, int, int, char*, CELLPTR, CELLPTR,int*));
- Xstatic int _do_targets ANSI((int, int, char*, CELLPTR, CELLPTR));
- Xstatic int _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((int, char*, CELLPTR));
- Xstatic void _stick_at_head ANSI((HOWPTR, CELLPTR));
- Xstatic void _set_global_attr ANSI((int, 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 int _sv_attr;
- Xstatic int _sv_attro;
- Xstatic int _sv_flag;
- Xstatic int _sv_op;
- Xstatic char *_sv_setdir;
- Xstatic char _sv_globprq_only = 0;
- 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 int attr; /* sum of attribute flags for current tgts*/
- X int op; /* rule operator */
- X int at; /* temp place to keep an attribute code */
- 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_SILENT | A_IGNORE);
- 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_SILENT | A_IGNORE);
- 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
- X * get marked as having rules and being a target if appropriate. */
- X do {
- X tcp->ce_flag |= tg->ce_flag & (F_RULES|F_TARGET);
- X tcp = tcp->ce_all;
- X }
- X while( tcp != tg );
- X break;
- X }
- X }
- X
- X if( tflag ) Target = TRUE;
- X _sv_rules = NIL(STRING);
- X _sv_crule = NIL(STRING);
- X _sv_targets = NIL(CELL);
- X _sv_glb_prq = NIL(LINK);
- X _sv_edgel = NIL(EDGE);
- X _sp_target = FALSE;
- X _sv_globprq_only = 0;
- X
- X DB_VOID_RETURN;
- X}
- X
- X
- X
- Xint
- XSet_group_attributes( list )/*
- X==============================
- X Scan list looking for the standard @ and - (as in recipe line defs)
- X and set the flags accordingly so that they apply when we bind the
- X rules to the appropriate targets. */
- Xchar *list;
- X{
- X int done = FALSE;
- X int res = FALSE;
- X
- X DB_ENTER( "Set_group_attributes" );
- X
- X while( !done )
- X switch( *list++ ) {
- X case '@' : _sv_attr |= A_SILENT; res = TRUE; break;
- X case '-' : _sv_attr |= A_IGNORE; res = TRUE; break;
- X case '[' : res = TRUE; break;
- X
- X case ' ' :
- X case '\t': break;
- X
- X case '\0': done = TRUE; break;
- X
- X default : done = TRUE; res = FALSE; break;
- X }
- X
- X DB_RETURN( res );
- X}
- X
- X
- X
- Xstatic void
- X_do_special( special, op, attr, set_dir, target, prereq, state )/*
- X==================================================================
- X Process a special target. So far the only special targets we have
- X are those recognized by the _is_special function.
- X
- X target is always only a single special target.
- X
- X NOTE: For the cases of .IMPORT, and .INCLUDE, the cells created by the
- X parser are never freed. This is due to the fact that it is too much
- X trouble to get them out of the hash table once they are defined, and
- X if they are per chance used again it will be ok, anyway, since the
- X cell is not really used by the code below. */
- X
- Xint special;
- Xint op;
- Xint attr;
- Xchar *set_dir;
- XCELLPTR target;
- XCELLPTR prereq;
- Xint *state;
- X{
- X HASHPTR hp; /* pointer to macro def cell */
- X CELLPTR cp; /* temporary pointer into cells list */
- X CELLPTR dp; /* pointer to directory dir cell */
- X LINKPTR lp; /* pointer at prerequisite list */
- X char *dir; /* current dir to prepend */
- X char *path; /* resulting path to try to read */
- X char *name; /* File name for processing a .INCLUDE */
- X char *tmp; /* temporary string pointer */
- X FILE *fil; /* File descriptor returned by Openfile */
- X
- X DB_ENTER( "_do_special" );
- X
- X target->ce_flag = F_SPECIAL; /* mark the target as special */
- X
- X switch( special ) {
- X case ST_EXPORT:
- X for( ; prereq != NIL(CELL); prereq = prereq->ce_link ) {
- X DB_PRINT( "par", ("Exporting [%s]", prereq->CE_NAME) );
- X hp = GET_MACRO( prereq->CE_NAME );
- X
- X if( hp != NIL(HASH) ) {
- X char *tmpstr = hp->ht_value;
- X
- X if( tmpstr == NIL(char) ) tmpstr = "";
- X
- X if( Write_env_string( prereq->CE_NAME, tmpstr ) != 0 )
- X Warning( "Could not export %s", prereq->CE_NAME );
- X }
- X }
- X break;
- X
- X case ST_IMPORT:
- X if( prereq != NIL(CELL) && prereq->ce_link == NIL(CELL) &&
- X strcmp(prereq->CE_NAME, ".EVERYTHING") == 0 )
- X {
- X ReadEnvironment();
- X }
- X else {
- X char *tmpstr;
- X
- X for( ; prereq != NIL(CELL); prereq = prereq->ce_link ) {
- X DB_PRINT( "par", ("Importing [%s]", prereq->CE_NAME) );
- X
- X tmpstr = Read_env_string( prereq->CE_NAME );
- X
- X if( tmpstr != NIL(char) )
- X Def_macro( prereq->CE_NAME, tmpstr, M_EXPANDED | M_LITERAL );
- X else
- X if( !((Glob_attr | attr) & A_IGNORE) )
- X Fatal( "Imported macro `%s' not found", prereq->CE_NAME );
- X }
- X
- X attr &= ~A_IGNORE;
- X }
- X break;
- X
- X case ST_INCLUDE:
- X {
- X int ignore = (Glob_attr | attr) & A_IGNORE;
- X int pushed = FALSE;
- X CELL inc;
- X HASH hcell;
- X
- X if( prereq == NIL(CELL) ) Fatal( "No .INCLUDE file(s) specified" );
- X
- X dp = Def_cell( ".INCLUDEDIRS", NIL(CELL) );
- X
- X if( (attr & A_SETDIR) && *(dir = strchr(set_dir, '=')+1) ) {
- X hcell.ht_name = ".INCLUDE";
- X inc.ce_name = &hcell;
- X inc.ce_dir = dir;
- X pushed = Push_dir( &inc, ignore );
- X }
- X
- SHAR_EOF
- echo "End of part 4"
- echo "File rulparse.c is continued in part 5"
- echo "5" > s2_seq_.tmp
- exit 0
-
-