v15i073: dmake version 3.6 (part 21/25)
Dennis Vadura
dvadura at watdragon.waterloo.edu
Mon Oct 15 11:44:42 AEST 1990
Posting-number: Volume 15, Issue 73
Submitted-by: Dennis Vadura <dvadura at watdragon.waterloo.edu>
Archive-name: dmake-3.6/part21
#!/bin/sh
# this is part 21 of a multipart archive
# do not concatenate these parts, unpack them in order with /bin/sh
# file expand.c continued
#
CurArch=21
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 expand.c"
sed 's/^X//' << 'SHAR_EOF' >> expand.c
X-- $($(A)) - represents macro indirection
X-- <+...+> - get mapped to $(mktmp ...)
X--
X-- following macro is recognized
X--
X-- string1{ token_list }string2
X--
X-- and expands to string1 prepended to each element of token_list and
X-- string2 appended to each of the resulting tokens from the first
X-- operation. If string2 is of the form above then the result is
X-- the cross product of the specified (possibly modified) token_lists.
X--
X-- The folowing macro modifiers are defined and expanded:
X--
X-- $(macro:modifier_list:modifier_list:...)
X--
X-- where modifier_list a combination of:
X--
X-- D or d - Directory portion of token including separator
X-- F or f - File portion of token including suffix
X-- B or b - basename portion of token not including suffix
X-- T or t - for tokenization
X--
X-- or a single
X-- S or s - pattern substitution (simple)
X--
X-- NOTE: Modifiers are applied once the macro value has been found.
X-- Thus the construct $($(test):s/joe/mary/) is defined and
X-- modifies the value of $($(test))
X--
X-- Also the construct $(m:d:f) is not the same as $(m:df)
X-- the first applies d to the value of $(m) and then
X-- applies f to the value of that whereas the second form
X-- applies df to the value of $(m).
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: expand.c,v $
X * Revision 1.1 90/10/06 12:03:40 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
Xstatic char* _scan_token ANSI((char*, char**));
Xstatic char* _scan_macro ANSI((char*, char**));
Xstatic char* _scan_brace ANSI((char*, char**, int*));
Xstatic char* _cross_prod ANSI((char*, char*));
Xstatic char* _apply_modifiers ANSI((int, char*));
Xstatic char* _tokenize ANSI((char*, char*));
X
X#define SUFFIX_FLAG 1 /* defines for macro modifier code */
X#define DIRECTORY_FLAG 2
X#define FILE_FLAG 4
X
X
Xchar *
XExpand( src )/*
X===============
X This is the driver routine for the expansion, it identifies non-white
X space tokens and gets the _scan_token routine to figure out if they should
X be treated in a special way. */
X
Xchar *src; /* pointer to source string */
X{
X char *tmp; /* pointer to temporary str */
X char *res; /* pointer to result string */
X char *start; /* pointer to start of token */
X
X DB_ENTER( "Expand" );
X DB_PRINT( "exp", ("Expanding [%s]", src) );
X
X res = _strdup( "" );
X if( src == NIL(char) ) DB_RETURN( res );
X
X while( *src ) {
X char *ks, *ke;
X
X /* Here we find the next non white space token in the string
X * and find it's end, with respect to non-significant white space. */
X
X start = _strspn( src, " \t\n" );
X res = _strjoin( res, src, start-src, TRUE );
X if( !(*start) ) break;
X
X /* START <+...+> KLUDGE */
X if( (ks=_strstr(start,"<+")) && (ke=_strstr(ks,"+>")) ){
X char *t1, *t2;
X
X res = _strjoin( res, t2=Expand(t1=_substr(start,ks)), -1, TRUE);
X FREE(t1); FREE(t2);
X
X t1 = _substr(ks+2, ke+1); t1[ke-ks-2] = ')';
X t2 = _strjoin( "$(mktmp ", t1, -1,FALSE);
X FREE(t1);
X res = _strjoin( res, t2=Expand(t2), -1, TRUE);
X FREE(t2);
X src = ke+2;
X }
X /* END <+...+> KLUDGE */
X else {
X res = _strjoin( res, tmp = _scan_token( start, &src ), -1, TRUE );
X FREE( tmp );
X }
X }
X
X DB_PRINT( "exp", ("Returning [%s]", res) );
X DB_RETURN( res );
X}
X
X
X
Xchar *
XApply_edit( src, pat, subst, fr, anchor )/*
X===========================================
X Take the src string and apply the pattern substitution. ie. look for
X occurrences of pat in src and replace each occurrence with subst. This is
X NOT a regular expressions pattern substitution, it's just not worth it.
X
X if anchor == TRUE then the src pattern match must be at the end of a token.
X ie. this is for SYSV compatibility and is only used for substitutions of
X the caused by $(macro:pat=sub). So if src = "fre.o.k june.o" then
X $(src:.o=.a) results in "fre.o.k june.a", and $(src:s/.o/.a) results in
X "fre.a.k june.a" */
X
Xchar *src; /* the source string */
Xchar *pat; /* pattern to find */
Xchar *subst; /* substitute string */
Xint fr; /* if TRUE free src */
Xint anchor; /* if TRUE anchor */
X{
X char *res;
X char *p;
X char *s;
X int l;
X
X DB_ENTER( "Apply_edit" );
X
X if( !*pat ) DB_RETURN( src ); /* do nothing if pat is NULL */
X
X DB_PRINT( "mod", ("Source str: [%s]", src) );
X DB_PRINT( "mod", ("Replacing [%s], with [%s]", pat, subst) );
X
X s = src;
X l = strlen( pat );
X if( (p = _strstr( s, pat )) != NIL(char) ) {
X res = _strdup( "" );
X do {
X if( anchor )
X if( !*(p+l) || (strchr(" \t", *(p+l)) != NIL(char)) )
X res = _strjoin( _strjoin( res, s, p-s, TRUE ), subst, -1, TRUE );
X else
X res = _strjoin( res, s, p+l-s, TRUE );
X else
X res = _strjoin( _strjoin( res, s, p-s, TRUE ), subst, -1, TRUE );
X
X s = p + l;
X }
X while( (p = _strstr( s, pat )) != NIL(char) );
X
X res = _strjoin( res, s, -1, TRUE );
X if( fr ) FREE( src );
X }
X else
X res = src;
X
X
X DB_PRINT( "mod", ("Result [%s]", res) );
X DB_RETURN( res );
X}
X
X
X
Xvoid
XMap_esc( tok )/*
X================
X Map an escape sequence and replace it by it's corresponding character
X value. It is assumed that tok points at the initial \, the esc
X sequence in the original string is replaced and the value of tok
X is not modified. */
Xchar *tok;
X{
X if( strchr( "\"\\vantbrf01234567", tok[1] ) ) {
X switch( tok[1] ) {
X case 'a' : *tok = 0x07; break;
X case 'b' : *tok = '\b'; break;
X case 'f' : *tok = '\f'; break;
X case 'n' : *tok = '\n'; break;
X case 'r' : *tok = '\r'; break;
X case 't' : *tok = '\t'; break;
X case 'v' : *tok = 0x0b; break;
X case '\\': *tok = '\\'; break;
X case '\"': *tok = '\"'; break;
X
X default: {
X register int i = 0;
X register int j = 0;
X for( ; i<2 && isdigit(tok[2]); i++ ) {
X j = (j << 3) + (tok[1] - '0');
X strcpy( tok+1, tok+2 );
X }
X j = (j << 3) + (tok[1] - '0');
X *tok = j;
X }
X }
X strcpy( tok+1, tok+2 );
X }
X}
X
X
X
Xstatic char*
X_scan_token( s, ps )/*
X======================
X This routine scans the token characters one at a time and identifies
X macros starting with $( and ${ and calls _scan_macro to expand their
X value. the string1{ token_list }string2 expansion is also handled.
X In this case a temporary result is maintained so that we can take it's
X cross product with any other token_lists that may possibly appear. */
X
Xchar *s; /* pointer to start of src string */
Xchar **ps; /* pointer to start pointer */
X{
X char *res; /* pointer to result */
X char *start; /* pointer to start of prefix */
X int crossproduct = 0; /* if 1 then computing X-prod */
X
X start = s;
X res = _strdup( "" );
X while( 1 )
X switch( *s ) {
X /* Termination, We halt at seeing a space or a tab or end of string.
X * We return the value of the result with any new macro's we scanned
X * or if we were computing cross_products then we return the new
X * cross_product.
X * NOTE: Once we start computing cross products it is impossible to
X * stop. ie. the semantics are such that once a {} pair is
X * seen we compute cross products until termination. */
X
X case ' ':
X case '\t':
X case '\n':
X case '\0':
X {
X char *tmp;
X
X *ps = s;
X if( !crossproduct )
X tmp = _strjoin( res, start, (s-start), TRUE );
X else
X {
X tmp = _substr( start, s );
X tmp = _cross_prod( res, tmp );
X }
X return( tmp );
X }
X
X case '$':
X case '{':
X {
X /* Handle if it's a macro or if it's a {} construct.
X * The results of a macro expansion are handled differently based
X * on whether we have seen a {} beforehand. */
X
X char *tmp;
X tmp = _substr( start, s ); /* save the prefix */
X
X if( *s == '$' ) {
X start = _scan_macro( s+1, &s );
X
X if( crossproduct )
X res = _cross_prod( res, _strjoin( tmp, start, -1, TRUE ) );
X else {
X res = _strjoin(res,tmp = _strjoin(tmp,start,-1,TRUE),-1,TRUE);
X FREE( tmp );
X }
X FREE( start );
X }
X else if( s[1] != '{' ) {
X int ok;
X start = _scan_brace( s+1, &s, &ok );
X
X if( ok ) {
X res = _cross_prod( res, _cross_prod(tmp, start) );
X crossproduct = TRUE;
X }
X else {
X res =_strjoin(res,tmp=_strjoin(tmp,start,-1,TRUE),-1,TRUE);
X FREE( start );
X FREE( tmp );
X }
X }
X else { /* handle the {{ case */
X res = _strjoin( res, start, (s-start+1), TRUE );
X s += 2;
X FREE( tmp );
X }
X
X start = s;
X }
X break;
X
X case '}':
X if( s[1] != '}' ) {
X /* error malformed macro expansion */
X s++;
X }
X else { /* handle the }} case */
X res = _strjoin( res, start, (s-start+1), TRUE );
X s += 2;
X start = s;
X }
X break;
X
X default: s++;
X }
X}
X
X
X
Xstatic char*
X_scan_macro( s, ps )/*
X======================
X This routine scans a macro use and expands it to the value. It
X returns the macro's expanded value and modifies the pointer into the
X src string to point at the first character after the macro use.
X The types of uses recognized are:
X
X $$ - expands to $
X $(name) - expands to value of name
X ${name} - same as above
X $($(name)) - recurses on macro names (any level)
X and
X $(func[,args ...] [data])
X and
X $(name:modifier_list:modifier_list:...)
X
X see comment for Expand for description of valid modifiers.
X
X NOTE that once a macro name bounded by ( or { is found only
X the appropriate terminator (ie. ( or } is searched for. */
X
Xchar *s; /* pointer to start of src string */
Xchar **ps; /* pointer to start pointer */
X{
X char sdelim; /* start of macro delimiter */
X char edelim; /* corresponding end macro delim */
X char *start; /* start of prefix */
X char *macro_name; /* temporary macro name */
X char *recurse_name; /* recursive macro name */
X char *result; /* result for macro expansion */
X int bflag = 0; /* brace flag, ==0 => $A type macro */
X int done = 0; /* != 0 => done macro search */
X int lev = 0; /* brace level */
X int mflag = 0; /* != 0 => modifiers present in mac */
X int fflag = 0; /* != 0 => GNU style function */
X HASHPTR hp; /* hash table pointer for macros */
X
X DB_ENTER( "_scan_macro" );
X
X /* Check for the simple $ at end of line case */
X if( !*s ) {
X *ps = s;
X DB_RETURN( _strdup("") );
X }
X
X if( *s == '$' ) { /* Take care of the simple $$ case. */
X *ps = s+1;
X DB_RETURN( _strdup("$") );
X }
X
X sdelim = *s; /* set and remember start/end delim */
X if( sdelim == '(' )
X edelim = ')';
X else
X edelim = '}';
X
X start = s; /* build up macro name, find its end*/
X while( !done ) {
X switch( *s ) {
X case '(': /* open macro brace */
X case '{':
X if( *s == sdelim ) {
X lev++;
X bflag++;
X }
X break;
X
X case ':': /* halt at modifier */
X if( lev == 1 ) {
X done = TRUE;
X mflag = 1;
X }
X break;
X
X case ' ':
X case '\t':
X case '\n':
X fflag = 1;
X break;
X
X case '\0': /* check for null */
X *ps = s;
X if( lev ) {
X done = TRUE;
X bflag = 0;
X s = start;
X }
X break;
X
X case ')': /* close macro brace */
X case '}':
X if( *s == edelim && lev ) --lev;
X /*FALLTHROUGH*/
X
X default:
X done = !lev;
X }
X s++;
X }
X
X /* Check if this is a $A type macro. If so then we have to
X * handle it a little differently. */
X if( bflag )
X macro_name = _substr( start+1, s-1 );
X else
X macro_name = _substr( start, s );
X
X /* Check to see if the macro name contains spaces, if so then treat it
X * as a GNU style function invocation and call the function mapper to
X * deal with it. */
X if( fflag )
X result = Exec_function(macro_name);
X else {
X /* Check if the macro is a recursive macro name, if so then
X * EXPAND the name before expanding the value */
X if( strchr( macro_name, '$' ) != NIL(char) ) {
X recurse_name = Expand( macro_name );
X FREE( macro_name );
X macro_name = recurse_name;
X }
X
X /* Code to do value expansion goes here, NOTE: macros whose assign bit
X is one have been evaluated and assigned, they contain no further
X expansions and thus do not need their values expanded again. */
X
X if( (hp = GET_MACRO( macro_name )) != NIL(HASH) ) {
X if( hp->ht_flag & M_MARK )
X Fatal( "Detected circular macro [%s]", hp->ht_name );
X
X /* for M_MULTI macro variable assignments */
X If_multi = hp->ht_flag & M_MULTI;
X
X if( !(hp->ht_flag & M_EXPANDED) ) {
X hp->ht_flag |= M_MARK;
X result = Expand( hp->ht_value );
X hp->ht_flag ^= M_MARK;
X }
X else if( hp->ht_value != NIL(char) )
X result = _strdup( hp->ht_value );
X else
X result = _strdup( "" );
X
X /*
X * Mark macros as used only if we are not expanding them for
X * the purpose of a .IF test, so we can warn about redef after use*/
X
X if( !If_expand ) hp->ht_flag |= M_USED;
X }
X else
X result = _strdup( "" );
X }
X
X if( mflag ) {
X char separator;
X int modifier_list = 0;
X int aug_mod = FALSE;
X char *pat1;
X char *pat2;
X char *p;
X
X /* Yet another brain damaged AUGMAKE kludge. We should accept the
X * AUGMAKE bullshit of $(f:pat=sub) form of macro expansion. In
X * order to do this we will forgo the normal processing if the
X * AUGMAKE solution pans out, otherwise we will try to process the
X * modifiers ala dmake.
X *
X * So we look for = in modifier string.
X * If found we process it and not do the normal stuff */
X
X for( p=s; *p && *p != '=' && *p != edelim; p++ );
X
X if( *p == '=' ) {
X pat1 = _substr( s, p );
X for( s=p=p+1; (*p != edelim); p++ );
X
X pat2 = _substr( s, p );
X result = Apply_edit( result, pat1, pat2, TRUE, TRUE );
X FREE( pat1 );
X FREE( pat2 );
X s = p;
X aug_mod = TRUE;
X }
X
X if( !aug_mod )
X while( *s && *s != edelim ) { /* while not at end of macro */
X switch( *s++ ) {
X case 'b':
X case 'B': modifier_list |= FILE_FLAG; break;
X
X case 'd':
X case 'D': modifier_list |= DIRECTORY_FLAG; break;
X
X case 'f':
X case 'F': modifier_list |= FILE_FLAG | SUFFIX_FLAG; break;
X
X case 'S':
X case 's':
X if( modifier_list ) {
X Warning( "Edit modifier must appear alone, ignored");
X modifier_list = 0;
X }
X else {
X separator = *s++;
X for( p=s; *p != separator && *p != edelim; p++ );
X
X if( *p == edelim )
X Warning("Syntax error in edit pattern, ignored");
X else {
X char *t1, *t2;
X pat1 = _substr( s, p );
X for(s=p=p+1; (*p != separator) && (*p != edelim); p++ );
X pat2 = _substr( s, p );
X t1 = Expand(pat1); FREE(pat1);
X t2 = Expand(pat2); FREE(pat2);
X result = Apply_edit( result, t1, t2, TRUE, FALSE );
X FREE( t1 );
X FREE( t2 );
X }
X s = p;
X }
X /* find the end of the macro spec, or the start of a new
X * modifier list for further processing of the result */
X
X for( ; (*s != edelim) && (*s != ':'); s++ );
X if( *s == ':' ) s++;
X break;
X
X case 'T':
X case 't':
X if( modifier_list ) {
X Warning( "Tokenize modifier must appear alone, ignored");
X modifier_list = 0;
X }
X else {
X char *msg = "Separator string must be quoted";
X
X separator = *s++;
X
X if( separator != '\"' )
X Warning( msg );
X else {
X /* we change the semantics to allow $(v:t")") */
X for (p = s; *p && *p != separator; p++)
X if (*p == '\\')
X if (p[1] == '\\' || p[1] == '"')
X p++;
X if( *p == 0 )
X Fatal( "Unterminated separator string" );
X else {
X pat1 = _substr( s, p );
X result = _tokenize( result, pat1 );
X FREE( pat1 );
X }
X s = p;
X }
X
X /* find the end of the macro spec, or the start of a new
X * modifier list for further processing of the result */
X
X for( ; (*s != edelim) && (*s != ':'); s++ );
X if( *s == ':' ) s++;
X }
X break;
X
X case ':':
X if( modifier_list ) {
X result = _apply_modifiers( modifier_list, result );
X modifier_list = 0;
X }
X break;
X
X default:
X Warning( "Illegal modifier in macro, ignored" );
X break;
X }
X }
X
X if( modifier_list ) /* apply modifier */
X result = _apply_modifiers( modifier_list, result );
X
X s++;
X }
X
X *ps = s;
X FREE( macro_name );
X DB_RETURN( result );
X}
X
X
X
Xstatic char*
X_scan_brace( s, ps, flag )/*
X============================
X This routine scans for { token_list } pairs. It expands the value of
X token_list by calling Expand on it. Token_list may be anything at all.
X Note that the routine count's ballanced parentheses. This means you
X cannot have something like { fred { joe }, if that is what you really
X need the write it as { fred {{ joe }, flag is set to 1 if all ok
X and to 0 if the braces were unballanced. */
X
Xchar *s;
Xchar **ps;
Xint *flag;
X{
X char *t;
X char *start;
X char *res;
X int lev = 1;
X int done = 0;
X
X DB_ENTER( "_scan_brace" );
X
X start = s;
X while( !done )
X switch( *s++ ) {
X case '{':
X if( *s == '{' ) break; /* ignore {{ */
X lev++;
X break;
X
X case '}':
X if( *s == '}' ) break; /* ignore }} */
X if( lev )
X if( --lev == 0 ) done = TRUE;
X break;
X
X case '$':
X if( *s == '{' || *s == '}' ) {
X if( (t = strchr(s,'}')) != NIL(char) )
X s = t;
X s++;
X }
X break;
X
X case '\0':
X if( lev ) {
X done = TRUE;
X s--;
X /* error malformed macro expansion */
X }
X break;
X }
X
X start = _substr( start, (lev) ? s : s-1 );
X
X if( lev ) {
X /* Braces were not ballanced so just return the string.
X * Do not expand it. */
X
X res = _strjoin( "{", start, -1, FALSE );
X *flag = 0;
X }
X else {
X *flag = 1;
X res = Expand( start );
X
X if( (t = _strspn( res, " \t" )) != res ) strcpy( res, t );
X }
X
X FREE( start ); /* this is ok! start is assigned a _substr above */
X *ps = s;
X
X DB_RETURN( res );
X}
X
X
X
Xstatic char*
X_cross_prod( x, y )/*
X=====================
X Given two strings x and y compute the cross-product of the tokens found
X in each string. ie. if x = "a b" and y = "c d" return "ac ad bc bd".
X
X NOTE: buf will continue to grow until it is big enough to handle
X all cross product requests. It is never freed! (maybe I
X will fix this someday) */
X
Xchar *x;
Xchar *y;
X{
X static char *buf;
X static int buf_siz = 0;
X char *brkx;
X char *brky;
X char *cy;
X char *cx;
X char *res;
X int i;
X
X if( *x && *y ) {
X res = _strdup( "" ); cx = x;
X while( *cx ) {
X cy = y;
X brkx = _strpbrk( cx, " \t\n" );
X if( (brkx-cx == 2) && *cx == '\"' && *(cx+1) == '\"' ) cx = brkx;
X
X while( *cy ) {
X brky = _strpbrk( cy, " \t\n" );
X if( (brky-cy == 2) && *cy == '\"' && *(cy+1) == '\"' ) cy = brky;
X i = brkx-cx + brky-cy + 2;
X
X if( i > buf_siz ) { /* grow buf to the correct size */
X if( buf != NIL(char) ) FREE( buf );
X if( (buf = MALLOC( i, char )) == NIL(char)) No_ram();
X buf_siz = i;
X }
X
X strncpy( buf, cx, (i = brkx-cx) );
X buf[i] = '\0';
X if (brky-cy > 0) strncat( buf, cy, brky-cy );
X strcat( buf, " " );
X res = _strjoin( res, buf, -1, TRUE );
X cy = _strspn( brky, " \t\n" );
X }
X cx = _strspn( brkx, " \t\n" );
X }
X
X FREE( x );
X res[ strlen(res)-1 ] = '\0';
X }
X else
X res = _strjoin( x, y, -1, TRUE );
X
X FREE( y );
X return( res );
X}
X
X
X
Xstatic char*
X_apply_modifiers( mod, src )/*
X==============================
X This routine applies the appropriate modifiers to the string src
X and returns the proper result string */
X
Xint mod;
Xchar *src;
X{
X char *s;
X char *e;
X TKSTR str;
X
X DB_ENTER( "_apply_modifiers" );
X
X if( mod == (SUFFIX_FLAG | DIRECTORY_FLAG | FILE_FLAG) )
X DB_RETURN( src );
X
X SET_TOKEN( &str, src );
X DB_PRINT( "mod", ("Source string [%s]", src) );
X
X while( *(s = Get_token( &str, "", FALSE )) != '\0' ) {
X /* search for the directory portion of the filename. If the
X * DIRECTORY_FLAG is set, then we want to keep the directory portion
X * othewise throw it away and blank out to the end of the token */
X
X if( (e = basename(s)) != s)
X if( !(mod & DIRECTORY_FLAG) ) {
X strcpy(s, e);
X e = s+(str.tk_str-e);
X for(; e != str.tk_str; e++)
X *e = ' ';
X }
X else
X s = e;
X
X /* search for the suffix, if there is none, treat it as a NULL suffix.
X * if no file name treat it as a NULL file name. same copy op as
X * for directory case above */
X
X e = strrchr( s, '.' ); /* NULL suffix if e=0 */
X if( e == NIL(char) ) e = s+strlen(s);
X
X if( !(mod & FILE_FLAG) ) {
X strcpy( s, e );
X e = s+(str.tk_str-e);
X for( ; e != str.tk_str; e++ ) *e = ' ';
X }
X else
X s = e;
X
X /* The last and final part. This is the suffix case, if we don't want
X * it then just erase to the end of the token. */
X
X if( s != NIL(char) )
X if( !(mod & SUFFIX_FLAG) )
X for( ; s != str.tk_str; s++ ) *s = ' ';
X }
X
X /* delete the extra white space, it looks ugly */
X for( s = src, e = NIL(char); *s; s++ )
X if( *s == ' ' || *s == '\t' || *s == '\n' ) {
X if( e == NIL(char) )
X e = s;
X }
X else {
X if( e != NIL(char) ) {
X if( e+1 < s ) {
X strcpy( e+1, s );
X s = e+1;
X *e = ' ';
X }
X e = NIL(char);
X }
X }
X
X if( e != NIL(char) )
X if( e < s )
X strcpy( e, s );
X
X DB_PRINT( "mod", ("Result string [%s]", src) );
X DB_RETURN( src );
X}
X
X
X
Xstatic char*
X_tokenize( src, separator )/*
X=============================
X Tokenize the input of src and join each token found together with
X the next token separated by the separator string.
X
X When doing the tokenization, <sp>, <tab>, <nl>, and \<nl> all
X constitute white space. */
X
Xchar *src;
Xchar *separator;
X{
X TKSTR tokens;
X char *tok;
X char *res;
X int first = TRUE;
X
X DB_ENTER( "_tokenize" );
X
X SET_TOKEN( &tokens, src );
X
X
X /* map the escape codes in the separator string first */
X
X for(tok=separator; (tok = strchr(tok,CONTINUATION_CHAR)) != NIL(char); tok++)
X Map_esc( tok );
X
X DB_PRINT( "exp", ("Separator [%s]", separator) );
X
X /* Build the token list */
X res = _strdup( "" );
X while( *(tok = Get_token( &tokens, "", FALSE )) != '\0' ) {
X DB_PRINT( "exp", ("Tokenizing [%s]", tok) );
X
X if( first ) {
X FREE( res );
X res = _strdup( tok );
X first = FALSE;
X }
X else {
X char *x;
X res = _strjoin(res, x =_strjoin(separator, tok, -1, FALSE), -1, TRUE);
X FREE( x );
X }
X }
X
X FREE( src );
X DB_RETURN( res );
X}
SHAR_EOF
echo "File expand.c is complete"
chmod 0440 expand.c || echo "restore of expand.c fails"
echo "x - extracting dump.c (Text)"
sed 's/^X//' << 'SHAR_EOF' > dump.c &&
X/* RCS -- $Header: /u2/dvadura/src/generic/dmake/src/RCS/dump.c,v 1.1 90/10/06 12:03:37 dvadura Exp $
X-- SYNOPSIS -- dump the internal dag to stdout.
X--
X-- DESCRIPTION
X-- This file contains the routine that is called to dump a version of
X-- the digested makefile to the standard output. May be useful perhaps
X-- to the ordinary user, and invaluable for debugging make.
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: dump.c,v $
X * Revision 1.1 90/10/06 12:03:37 dvadura
X * dmake Release, Version 3.6
X *
X*/
X
X#include "db.h"
X#include "extern.h"
X
X#define M_TEST (M_PRECIOUS | M_VAR_MASK)
X
Xstatic void dump_normal_target ANSI((CELLPTR, HOWPTR, CELLPTR));
Xstatic void dump_graph_node ANSI((CELLPTR));
Xstatic void dump_name ANSI((HASHPTR, int));
X
X
Xvoid
XDump()/*
X======== Dump onto standard output the digested makefile. Note that
X the form of the dump is not representative of the contents
X of the original makefile contents at all */
X{
X HASHPTR hp;
X int i;
X
X DB_ENTER( "Dump" );
X
X puts( "# Dump of dmake macro variables:" );
X for( i=0; i<HASH_TABLE_SIZE; i++)
X for( hp=Macs[i]; hp != NIL(HASH); hp = hp->ht_next ) {
X int flag = hp->ht_flag;
X
X printf( "%s ", hp->ht_name );
X if( flag & M_EXPANDED ) putchar( ':' );
X printf( "= " );
X if( hp->ht_value != NIL(char) ) printf( hp->ht_value );
X if( flag & M_PRECIOUS )
X printf( "\t # PRECIOUS " );
X putchar( '\n' );
X }
X
X puts( "\n#====================================" );
X puts( "# Dump of targets:\n" );
X
X for( i=0; i<HASH_TABLE_SIZE; i++ )
X for( hp = Defs[i]; hp != NIL(HASH); hp = hp->ht_next )
X if( !(hp->CP_OWNR->ce_flag & F_PERCENT) ) {
X if( hp->CP_OWNR == Fringe_hd->cl_prq )
X puts( "# ******* FIRST TARGET ********" );
X dump_normal_target( hp->CP_OWNR, hp->CP_OWNR->CE_HOW, NIL(CELL) );
X }
X
X puts( "\n#====================================" );
X puts( "# Dump of inference graph\n" );
X
X for( i=0; i<HASH_TABLE_SIZE; i++ )
X for( hp = Defs[i]; hp != NIL(HASH); hp = hp->ht_next )
X if( (hp->CP_OWNR->ce_flag & F_PERCENT) &&
X !(hp->CP_OWNR->ce_flag & F_MAGIC) )
X dump_graph_node( hp->CP_OWNR );
X
X DB_VOID_RETURN;
X}
X
X
X
Xvoid
XDump_recipe( sp )/*
X===================
X Given a string pointer print the recipe line out */
XSTRINGPTR sp;
X{
X char *st;
X char *nl;
X
X if( sp == NIL(STRING) ) return;
X
X putchar( '\t' );
X if( sp->st_attr & A_SILENT ) putchar( '@' );
X if( sp->st_attr & A_IGNORE ) putchar( '-' );
X if( sp->st_attr & A_SHELL ) putchar( '+' );
X
X st = sp->st_string;
X for( nl=strchr(st,'\n'); nl != NIL( char); nl=strchr(st,'\n') ) {
X *nl = '\0';
X printf( "%s\\\n", st );
X *nl = '\n';
X st = nl+1;
X }
X printf( "%s\n", st );
X}
X
X
Xstatic char *_attrs[] = { ".PRECIOUS", ".SILENT", ".LIBRARY",
X ".EPILOG", ".PROLOG", ".IGNORE", ".SYMBOL", ".NOINFER",
X ".UPDATEALL", ".SEQUENTIAL", ".SETDIR=", ".USESHELL", ".SWAP", ".MKSARGS" };
X
Xstatic void
Xdump_normal_target( cp, hw, prq )/*
X===================================
X Dump in makefile like format the dag information */
XCELLPTR cp;
XHOWPTR hw;
XCELLPTR prq;
X{
X register LINKPTR lp;
X register STRINGPTR sp;
X t_attr attr;
X unsigned int k;
X
X DB_ENTER( "dump_normal_target" );
X
X if( hw == NIL(HOW) ) { DB_VOID_RETURN; }
X if( hw->hw_next != NIL(HOW) ) dump_normal_target( cp, hw->hw_next, prq );
X
X dump_name( cp->ce_name, FALSE );
X
X for( k=0, attr=1; attr <= MAX_ATTR; attr <<= 1, k++ )
X if( (cp->ce_attr & attr) || ((hw->hw_attr & A_SHELL)&attr) ) {
X printf( "%s%s ", _attrs[k],
X (attr != A_SETDIR) ? "" : (cp->ce_dir?cp->ce_dir:"") );
X }
X
X putchar( ':' );
X
X if( cp->ce_flag & F_MULTI ) putchar( ':' );
X if( hw->hw_flag & F_SINGLE ) putchar( '!' );
X putchar( ' ' );
X
X if( prq != NIL(CELL) ) dump_name( prq->ce_name, FALSE );
X for( lp = hw->hw_prq; lp != NIL(LINK); lp = lp->cl_next )
X dump_name( lp->cl_prq->ce_name, FALSE );
X
X if( (lp = hw->hw_indprq) != NIL(LINK) ) {
X for( ; lp != NIL(LINK); lp = lp->cl_next )
X dump_name( lp->cl_prq->ce_name, TRUE );
X }
X
X putchar( '\n' );
X if( hw->hw_flag & F_GROUP ) {
X if( hw->hw_attr & A_IGNORE ) putchar( '-' );
X if( hw->hw_attr & A_SILENT ) putchar( '@' );
X puts( "[" );
X }
X
X for( sp = hw->hw_recipe; sp != NIL(STRING); sp = sp->st_next )
X Dump_recipe( sp );
X if( hw->hw_flag & F_GROUP ) puts( "]" );
X
X putchar( '\n' );
X DB_VOID_RETURN;
X}
X
X
Xstatic void
Xdump_name( hp, quote )/*
X========================
X print out a name */
XHASHPTR hp;
Xint quote;
X{
X if( quote ) putchar('\'');
X printf( "%s", hp->ht_name );
X if( quote ) putchar('\'');
X putchar(' ');
X}
X
X
X
Xstatic void
Xdump_graph_node( cp )/*
X=======================*/
XCELLPTR cp;
X{
X EDGEPTR pe;
X
X pe = cp->CE_EDGES;
X
X if( pe != NIL(EDGE) )
X do {
X dump_normal_target( cp, pe->ed_how, pe->ed_prq );
X pe = pe->ed_next;
X }
X while( pe != cp->CE_EDGES );
X}
SHAR_EOF
chmod 0440 dump.c || echo "restore of dump.c fails"
echo "x - extracting dmake.h (Text)"
sed 's/^X//' << 'SHAR_EOF' > dmake.h &&
X/* RCS -- $Header: /u2/dvadura/src/generic/dmake/src/RCS/dmake.h,v 1.1 90/10/06 12:04:20 dvadura Exp $
X-- SYNOPSIS -- global defines for dmake.
X--
X-- DESCRIPTION
X-- All the interesting bits and flags that dmake uses are defined here.
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: dmake.h,v $
X * Revision 1.1 90/10/06 12:04:20 dvadura
X * dmake Release, Version 3.6
X *
X*/
X
X#ifndef _DMAKE_INCLUDED_
X#define _DMAKE_INCLUDED_
X
X#define MAX_INC_DEPTH 10 /* max of ten nested include files */
X#define MAX_COND_DEPTH 20 /* max nesting level of conditionals */
X#define ERROR_EXIT_VALUE 255 /* return code of aborted make */
X#define CONTINUATION_CHAR '\\' /* line continuation \<nl> */
X#define ESCAPE_CHAR '\\' /* escape char for used chars */
X#define COMMENT_CHAR '#' /* start of comment chars */
X#define TGT_DEP_SEP ':' /* separator for targets and dependents */
X#define CONDSTART '.' /* start of conditional token eg .IF */
X#define DEF_MAKE_PNAME "dmake"/* default name to use as name of make */
X
X
X/* ............... Hashing function constants ......................... */
X#define HASH_TABLE_SIZE 200 /* See hash.c for description */
X
X
X/* Bit flags for cells and macro definitions. */
X#define M_DEFAULT 0x0000 /* default flag value */
X#define M_MARK 0x0001 /* mark for circularity checks */
X#define M_PRECIOUS 0x0002 /* keep macro, same as A_PRE... */
X#define M_MULTI 0x0004 /* multiple redefinitions ok! */
X#define M_EXPANDED 0x0008 /* macro has been assigned */
X#define M_USED 0x0010 /* macro has been expanded */
X#define M_LITERAL 0x0020 /* don't strip w/s on macro def */
X#define M_NOEXPORT 0x0040 /* don't export macro for -x */
X#define M_FORCE 0x0080 /* Force a macro redefinition */
X#define M_VAR_BIT 0x1000 /* macro bit variable */
X#define M_VAR_CHAR 0x2000 /* macro char variable */
X#define M_VAR_STRING 0x4000 /* macro string variable */
X#define M_VAR_INT 0x8000 /* macro integer variable */
X
X#define M_VAR_MASK 0xf000 /* macro variable mask */
X
X
X
X/* Global and target attribute flag definitions.
X * If you change the values of these or re-order them make appropriate changes
X * in dump.c so that the output of dmake -p matches the attribute info for a
X * target. */
X
X#define A_DEFAULT 0x00000 /* default flag value */
X#define A_PRECIOUS 0x00001 /* object is precious */
X#define A_SILENT 0x00002 /* don't echo commands */
X#define A_LIBRARY 0x00004 /* target is an archive */
X#define A_EPILOG 0x00008 /* insert shell epilog code */
X#define A_PROLOG 0x00010 /* insert shell prolog code */
X#define A_IGNORE 0x00020 /* ignore errors */
X#define A_SYMBOL 0x00040 /* lib member is a symbol */
X#define A_NOINFER 0x00080 /* no trans closure from cell */
X#define A_UPDATEALL 0x00100 /* all targets of rule modified */
X#define A_SEQ 0x00200 /* sequential make attribute */
X#define A_SETDIR 0x00400 /* cd to dir when making target */
X#define A_SHELL 0x00800 /* appears only on HOW nodes */
X#define A_SWAP 0x01000 /* swap on exec. */
X#define A_MKSARGS 0x02000 /* use MKS argument swapping */
X#define MAX_ATTR A_MKSARGS /* highest valid attribute */
X#define A_LIBRARYM 0x04000 /* target is an archive member */
X#define A_FRINGE 0x08000 /* cell is on the fringe */
X#define A_COMPOSITE 0x10000 /* member of lib(targ) name */
X#define A_FFNAME 0x20000 /* if set, free ce_fname in stat*/
X#define A_UPDATED 0x40000 /* Used to mark cell as updated */
X
X
X/* Global and target bit flag definitions */
X
X#define F_DEFAULT 0x0000 /* default flag value */
X#define F_MARK 0x0001 /* circularity check mark */
X#define F_MULTI 0x0002 /* multiple rules for target */
X#define F_SINGLE 0x0004 /* exec rules one/prerequisite */
X#define F_TARGET 0x0008 /* marks a target */
X#define F_RULES 0x0010 /* indicates target has rules */
X#define F_GROUP 0x0020 /* indicates that rules are to */
X /* fed to the shell as a group */
X
X#define F_TRANS 0x0040 /* same as F_STAT not used tgthr*/
X#define F_STAT 0x0040 /* target already stated */
X#define F_VISITED 0x0080 /* target scheduled for make */
X#define F_USED 0x0080 /* used in releparse.c */
X#define F_SPECIAL 0x0100 /* marks a special target */
X#define F_DFA 0x0200 /* bit for marking added DFA */
X#define F_EXPLICIT 0x0400 /* explicit target in makefile */
X#define F_PERCENT 0x0800 /* marks a target as a % rule */
X#define F_REMOVE 0x1000 /* marks an intermediate target */
X#define F_MAGIC 0x2000 /* marks a magic target */
X#define F_INFER 0x4000 /* target is result of inference*/
X#define F_MADE 0x8000 /* target is manufactured */
X
X
X/* Definitions for the Parser states */
X#define NORMAL_SCAN 0 /* normal processing state */
X#define RULE_SCAN 1 /* scan of rule text */
X
X/* definitions for macro operator types */
X#define M_OP_EQ 1 /* macro operation is '=' */
X#define M_OP_CL 2 /* macro operation is ':=' */
X#define M_OP_PL 3 /* macro operation is '+=' */
X#define M_OP_PLCL 4 /* macro operation is '+:='*/
X#define M_OP_DF 5 /* macro operation is '*=' */
X#define M_OP_DFCL 6 /* macro operation is '*:='*/
X
X/* definitions for rule operator types */
X#define R_OP_CL 1 /* rule operation is ':' */
X#define R_OP_DCL 2 /* rule operation is '::' */
X#define R_OP_BG 4 /* rule operation is ':!' */
X#define R_OP_UP 8 /* rule operation is ':^' */
X#define R_OP_MI 16 /* rule operation is ':-' */
X
X
X/* special target definitions for use inside dmake */
X#define ST_IF 1
X#define ST_ELSE 2
X#define ST_END 3
X#define ST_REST 4 /* remaining special targets */
X#define ST_INCLUDE 5
X#define ST_SOURCE 7
X#define ST_EXPORT 8
SHAR_EOF
echo "End of part 21"
echo "File dmake.h is continued in part 22"
echo "22" > s2_seq_.tmp
exit 0
More information about the Comp.sources.misc
mailing list