dvadura@watdragon.waterloo.edu (Dennis Vadura) (05/11/91)
Submitted-by: Dennis Vadura <dvadura@watdragon.waterloo.edu> Posting-number: Volume 19, Issue 29 Archive-name: dmake/part08 Supersedes: dmake-3.6: Volume 15, Issue 52-77 ---- Cut Here and feed the following to sh ---- #!/bin/sh # this is dmake.shar.08 (part 8 of a multipart archive) # do not concatenate these parts, unpack them in order with /bin/sh # file dmake/dmake.c continued # if test ! -r _shar_seq_.tmp; then echo 'Please unpack part 1 first!' exit 1 fi (read Scheck if test "$Scheck" != 8; then echo Please unpack part "$Scheck" next! exit 1 else exit 0 fi ) < _shar_seq_.tmp || exit 1 if test -f _shar_wnt_.tmp; then sed 's/^X//' << 'SHAR_EOF' >> 'dmake/dmake.c' && X X if( next_file_slot == MAX_INC_DEPTH ) X Fatal( "Too many open files. Max nesting level is %d.", MAX_INC_DEPTH); X X DB_PRINT( "io", ("Opening file [%s], in slot %d", name, next_file_slot) ); X X if( strcmp("-", name) == 0 ) { X name = "stdin"; X fil = stdin; X } X else X fil = fopen( name, mode ? "w":"r" ); X X if( Verbose & V_FILE_IO ) X printf( "%s: Openning [%s] for %s", Pname, name, mode?"write":"read" ); X X if( fil == NIL(FILE) ) { X if( Verbose & V_FILE_IO ) printf( " (fail)\n" ); X if( err ) X Fatal( mode ? "Cannot open file %s for write" : "File %s not found", X name ); X } X else { X if( Verbose & V_FILE_IO ) printf( " (success)\n" ); X ftab[next_file_slot].file = fil; X ftab[next_file_slot].numb = Line_number; X ftab[next_file_slot++].name = _strdup(name); X Line_number = 0; X _set_inc_depth(); X } X X DB_RETURN(fil); } X X PUBLIC FILE * Closefile()/* ============= X This routine is used to close the last file opened. This forces make X to open files in a last open first close fashion. It returns the X file pointer to the next file on the stack, and NULL if the stack is empty.*/ { X DB_ENTER("Closefile"); X X if( !next_file_slot ) X DB_RETURN( NIL(FILE) ); X X if( ftab[--next_file_slot].file != stdin ) { X DB_PRINT( "io", ("Closing file in slot %d", next_file_slot) ); X X if( Verbose & V_FILE_IO ) X printf( "%s: Closing [%s]\n", Pname, ftab[next_file_slot].name ); X X fclose( ftab[next_file_slot].file ); X FREE( ftab[next_file_slot].name ); X } X X _set_inc_depth(); X X if( next_file_slot > 0 ) { X Line_number = ftab[next_file_slot].numb; X DB_RETURN( ftab[next_file_slot-1].file ); X } X else X Line_number = 0; X X DB_RETURN( NIL(FILE) ); } X X PUBLIC FILE * Search_file( macname, rname ) char *macname; char **rname; { X HASHPTR hp; X FILE *fil = NIL(FILE); X char *fname; X char *ename = NIL(char); X X /* order of precedence is: X * X * MACNAME from command line (precious is marked) X * ... via MACNAME:=filename definition. X * MACNAME from environment X * MACNAME from builtin rules (not precious) X */ X X if( (hp = GET_MACRO(macname)) != NIL(HASH) ) X ename = fname = Expand(hp->ht_value); X X if( hp->ht_flag & M_PRECIOUS ) fil = Openfile(fname, FALSE, FALSE); X X if( fil == NIL(FILE) ) { X fname=Expand(Read_env_string(macname)); X if( fil = Openfile(fname, FALSE, FALSE) ) FREE(ename); X } X X if( fil == NIL(FILE) && hp != NIL(HASH) ) X fil = Openfile(fname=ename, FALSE, FALSE); X X if( rname ) *rname = fname; X X return(fil); } X X PUBLIC char * Filename()/* ============ X Return name of file on top of stack */ { X return( next_file_slot==0 ? NIL(char) : ftab[next_file_slot-1].name ); } X /* ** print error message from variable arg list */ X static int errflg = TRUE; static int warnflg = FALSE; X static void errargs(fmt, args) char *fmt; va_list args; { X int warn = _warn && warnflg && !(Glob_attr & A_SILENT); X X if( errflg || warn ) { X char *f = Filename(); X X fprintf( stderr, "%s: ", Pname ); X if( f != NIL(char) ) fprintf(stderr, "%s: line %d: ", f, Line_number); X X if( errflg ) X fprintf(stderr, "Error -- "); X else if( warn ) X fprintf(stderr, "Warning -- "); X X vfprintf( stderr, fmt, args ); X putc( '\n', stderr ); X if( errflg && !Continue ) Quit( NIL(CELL) ); X } } X /* ** Print error message and abort */ int Fatal(fmt, va_alist) char *fmt; va_dcl; { X va_list args; X X va_start(args, fmt); X Continue = FALSE; X errargs(fmt, args); X va_end(args); } X /* ** error message and exit (unless -k) */ int Error(fmt, va_alist) char* fmt; va_dcl; { X va_list args; X X va_start(args, fmt); X errargs(fmt, args); X va_end(args); } X X /* ** non-fatal message */ int Warning(fmt, va_alist) char *fmt; va_dcl; { X va_list args; X X va_start(args, fmt); X warnflg = TRUE; X errflg = FALSE; X errargs(fmt, args); X errflg = TRUE; X warnflg = FALSE; X va_end(args); } X X PUBLIC void No_ram() { X Fatal( "No more memory" ); } X X PUBLIC X Usage( eflag ) int eflag; { X if( eflag ) { X fprintf(stderr, USAGE, Pname); X } X else { X printf(USAGE, Pname); X puts(" -P# - set max number of child processes for parallel make"); X puts(" -f file - use file as the makefile"); #ifdef MSDOS X puts(" -C [+]file - duplicate console output to file, ('+' => append)"); #endif X puts(" -K file - use file as the .KEEP_STATE file"); X puts(" -v{dfimt} - verbose, indicate what we are doing, (-v => -vdimt)"); X puts(" d => dump change of directory info only" ); X puts(" f => dump file open/close info only" ); X puts(" i => dump inference information only" ); X puts(" m => dump make of target information only" ); X puts(" t => keep temporary files when done\n" ); X X puts("Options: (can be catenated, ie -irn == -i -r -n)"); X puts(" -A - enable AUGMAKE special target mapping"); X puts(" -c - use non standard comment scanning"); X puts(" -e - define environment strings as macros"); X puts(" -E - same as -e but done after parsing makefile"); X puts(" -h - print out usage info"); X puts(" -i - ignore errors"); X puts(" -k - make independent targets, even if errors"); X puts(" -n - trace and print, do not execute commands"); X puts(" -p - print out a version of the makefile"); X puts(" -q - check if target is up to date. Does not do"); X puts(" anything. Returns 0 if up to date, 1 otherwise"); X puts(" -r - don't use internal rules"); X puts(" -s - do your work silently"); X puts(" -S - disable parallel (force sequential) make, overrides -P"); X puts(" -t - touch, update time stamps without executing commands"); X puts(" -T - do not apply transitive closure"); X puts(" -u - force unconditional update of target"); X puts(" -V - print out version number"); X puts(" -x - export macro values to environment"); X } X X Quit(NIL(CELL)); } X X PUBLIC Version() { X extern char **Rule_tab; X char **p; X X printf("%s - %s, ", Pname, sccid); X printf("Version %s, PL %d\n\n", VERSION, PATCHLEVEL); X X puts("Default Configuration:"); X for (p=Rule_tab; *p != NIL(char); p++) X printf("\t%s\n", *p); } SHAR_EOF chmod 0640 dmake/dmake.c || echo 'restore of dmake/dmake.c failed' Wc_c="`wc -c < 'dmake/dmake.c'`" test 20025 -eq "$Wc_c" || echo 'dmake/dmake.c: original size 20025, current size' "$Wc_c" rm -f _shar_wnt_.tmp fi # ============= dmake/dmake.h ============== if test -f 'dmake/dmake.h' -a X"$1" != X"-c"; then echo 'x - skipping dmake/dmake.h (File already exists)' rm -f _shar_wnt_.tmp else > _shar_wnt_.tmp sed 's/^X//' << 'SHAR_EOF' > 'dmake/dmake.h' && /* RCS -- $Header: /u2/dvadura/src/generic/dmake/src/RCS/dmake.h,v 1.1 91/05/06 15:23:07 dvadura Exp $ -- SYNOPSIS -- global defines for dmake. -- -- DESCRIPTION -- All the interesting bits and flags that dmake uses are defined here. -- -- AUTHOR -- Dennis Vadura, dvadura@watdragon.uwaterloo.ca -- CS DEPT, University of Waterloo, Waterloo, Ont., Canada -- -- COPYRIGHT -- Copyright (c) 1990 by Dennis Vadura. All rights reserved. -- -- This program is free software; you can redistribute it and/or -- modify it under the terms of the GNU General Public License -- (version 1), as published by the Free Software Foundation, and -- found in the file 'LICENSE' included with this distribution. -- -- This program is distributed in the hope that it will be useful, -- but WITHOUT ANY WARRANTY; without even the implied warrant of -- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -- GNU General Public License for more details. -- -- You should have received a copy of the GNU General Public License -- along with this program; if not, write to the Free Software -- Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -- -- LOG -- $Log: dmake.h,v $ X * Revision 1.1 91/05/06 15:23:07 dvadura X * dmake Release Version 3.7 X * */ X #ifndef _DMAKE_INCLUDED_ #define _DMAKE_INCLUDED_ X #define MAX_INC_DEPTH 10 /* max of ten nested include files */ #define MAX_COND_DEPTH 20 /* max nesting level of conditionals */ #define ERROR_EXIT_VALUE 255 /* return code of aborted make */ #define CONTINUATION_CHAR '\\' /* line continuation \<nl> */ #define ESCAPE_CHAR '\\' /* escape char for used chars */ #define COMMENT_CHAR '#' /* start of comment chars */ #define TGT_DEP_SEP ':' /* separator for targets and dependents */ #define CONDSTART '.' /* start of conditional token eg .IF */ #define DEF_MAKE_PNAME "dmake"/* default name to use as name of make */ X X /* ............... Hashing function constants ......................... */ #define HASH_TABLE_SIZE 200 /* See hash.c for description */ X X /* Bit flags for cells and macro definitions. */ #define M_DEFAULT 0x0000 /* default flag value */ #define M_MARK 0x0001 /* mark for circularity checks */ #define M_PRECIOUS 0x0002 /* keep macro, same as A_PRE... */ #define M_MULTI 0x0004 /* multiple redefinitions ok! */ #define M_EXPANDED 0x0008 /* macro has been assigned */ #define M_USED 0x0010 /* macro has been expanded */ #define M_LITERAL 0x0020 /* don't strip w/s on macro def */ #define M_NOEXPORT 0x0040 /* don't export macro for -x */ #define M_FORCE 0x0080 /* Force a macro redefinition */ #define M_VAR_BIT 0x1000 /* macro bit variable */ #define M_VAR_CHAR 0x2000 /* macro char variable */ #define M_VAR_STRING 0x4000 /* macro string variable */ #define M_VAR_INT 0x8000 /* macro integer variable */ X #define M_VAR_MASK 0xf000 /* macro variable mask */ 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 #define A_DEFAULT 0x00000 /* default flag value */ #define A_PRECIOUS 0x00001 /* object is precious */ #define A_SILENT 0x00002 /* don't echo commands */ #define A_LIBRARY 0x00004 /* target is an archive */ #define A_EPILOG 0x00008 /* insert shell epilog code */ #define A_PROLOG 0x00010 /* insert shell prolog code */ #define A_IGNORE 0x00020 /* ignore errors */ #define A_SYMBOL 0x00040 /* lib member is a symbol */ #define A_NOINFER 0x00080 /* no trans closure from cell */ #define A_UPDATEALL 0x00100 /* all targets of rule modified */ #define A_SEQ 0x00200 /* sequential make attribute */ #define A_SETDIR 0x00400 /* cd to dir when making target */ #define A_SHELL 0x00800 /* run the recipe using a shell */ #define A_SWAP 0x01000 /* swap on exec. */ #define A_MKSARGS 0x02000 /* use MKS argument swapping */ #define A_PHONY 0x04000 /* .PHONY attribute */ #define A_NOSTATE 0x08000 /* don't track state for me */ #define MAX_ATTR A_NOSTATE /* highest valid attribute */ #define A_LIBRARYM 0x10000 /* target is an archive member */ #define A_FRINGE 0x20000 /* cell is on the fringe */ #define A_COMPOSITE 0x40000 /* member of lib(targ) name */ #define A_FFNAME 0x80000 /* if set, free ce_fname in stat*/ #define A_UPDATED 0x100000 /* Used to mark cell as updated */ #define A_ROOT 0x200000 /* True if it is a root prereq */ X X /* Global and target bit flag definitions */ X #define F_DEFAULT 0x0000 /* default flag value */ #define F_MARK 0x0001 /* circularity check mark */ #define F_MULTI 0x0002 /* multiple rules for target */ #define F_SINGLE 0x0004 /* exec rules one/prerequisite */ #define F_TARGET 0x0008 /* marks a target */ #define F_RULES 0x0010 /* indicates target has rules */ #define F_GROUP 0x0020 /* indicates that rules are to */ X /* fed to the shell as a group */ X #define F_TRANS 0x0040 /* same as F_STAT not used tgthr*/ #define F_STAT 0x0040 /* target already stated */ #define F_VISITED 0x0080 /* target scheduled for make */ #define F_USED 0x0080 /* used in releparse.c */ #define F_SPECIAL 0x0100 /* marks a special target */ #define F_DFA 0x0200 /* bit for marking added DFA */ #define F_EXPLICIT 0x0400 /* explicit target in makefile */ #define F_PERCENT 0x0800 /* marks a target as a % rule */ #define F_REMOVE 0x1000 /* marks an intermediate target */ #define F_MAGIC 0x2000 /* marks a magic target */ #define F_INFER 0x4000 /* target is result of inference*/ #define F_MADE 0x8000 /* target is manufactured */ X X /* Definitions for the Parser states */ #define NORMAL_SCAN 0 /* normal processing state */ #define RULE_SCAN 1 /* scan of rule text */ X /* definitions for macro operator types */ #define M_OP_EQ 1 /* macro operation is '=' */ #define M_OP_CL 2 /* macro operation is ':=' */ #define M_OP_PL 3 /* macro operation is '+=' */ #define M_OP_PLCL 4 /* macro operation is '+:='*/ #define M_OP_DF 5 /* macro operation is '*=' */ #define M_OP_DFCL 6 /* macro operation is '*:='*/ X /* definitions for rule operator types */ #define R_OP_CL 1 /* rule operation is ':' */ #define R_OP_DCL 2 /* rule operation is '::' */ #define R_OP_BG 4 /* rule operation is ':!' */ #define R_OP_UP 8 /* rule operation is ':^' */ #define R_OP_MI 16 /* rule operation is ':-' */ X /* definitions for modifier application in Apply_modifiers in expand.c */ #define SUFFIX_FLAG 1 /* defines for macro modifier code */ #define DIRECTORY_FLAG 2 #define FILE_FLAG 4 X /* special target definitions for use inside dmake */ #define ST_IF 1 #define ST_ELSE 2 #define ST_END 3 #define ST_REST 4 /* remaining special targets */ #define ST_INCLUDE 5 #define ST_SOURCE 7 #define ST_EXPORT 8 #define ST_IMPORT 9 #define ST_ELIF 10 #define ST_KEEP 11 X /* Flags for controling use of -v switch */ #define V_NONE 0x00 #define V_LEAVE_TMP 0x01 #define V_PRINT_DIR 0x02 #define V_INFER 0x04 #define V_MAKE 0x08 #define V_FILE_IO 0x10 #define V_ALL (V_LEAVE_TMP | V_PRINT_DIR | V_INFER | V_MAKE |\ X V_FILE_IO) X /* Macro definitions for use inside dmake */ #define SET_TOKEN(A, B) (A)->tk_str = (B); (A)->tk_cchar = *(B);\ X (A)->tk_quote = 1; #define CLEAR_TOKEN(A) *(A)->tk_str = (A)->tk_cchar #define GET_MACRO(A) Get_name(A, Macs, FALSE) #define iswhite(C) ((C == ' ') || (C == '\t')) X #endif X SHAR_EOF chmod 0640 dmake/dmake.h || echo 'restore of dmake/dmake.h failed' Wc_c="`wc -c < 'dmake/dmake.h'`" test 8165 -eq "$Wc_c" || echo 'dmake/dmake.h: original size 8165, current size' "$Wc_c" rm -f _shar_wnt_.tmp fi # ============= dmake/dmdump.c ============== if test -f 'dmake/dmdump.c' -a X"$1" != X"-c"; then echo 'x - skipping dmake/dmdump.c (File already exists)' rm -f _shar_wnt_.tmp else > _shar_wnt_.tmp sed 's/^X//' << 'SHAR_EOF' > 'dmake/dmdump.c' && /* RCS -- $Header: /u2/dvadura/src/generic/dmake/src/RCS/dmdump.c,v 1.1 91/05/06 15:23:08 dvadura Exp $ -- SYNOPSIS -- dump the internal dag to stdout. -- -- DESCRIPTION -- This file contains the routine that is called to dump a version of -- the digested makefile to the standard output. May be useful perhaps -- to the ordinary user, and invaluable for debugging make. -- -- AUTHOR -- Dennis Vadura, dvadura@watdragon.uwaterloo.ca -- CS DEPT, University of Waterloo, Waterloo, Ont., Canada -- -- COPYRIGHT -- Copyright (c) 1990 by Dennis Vadura. All rights reserved. -- -- This program is free software; you can redistribute it and/or -- modify it under the terms of the GNU General Public License -- (version 1), as published by the Free Software Foundation, and -- found in the file 'LICENSE' included with this distribution. -- -- This program is distributed in the hope that it will be useful, -- but WITHOUT ANY WARRANTY; without even the implied warrant of -- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -- GNU General Public License for more details. -- -- You should have received a copy of the GNU General Public License -- along with this program; if not, write to the Free Software -- Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -- -- LOG -- $Log: dmdump.c,v $ X * Revision 1.1 91/05/06 15:23:08 dvadura X * dmake Release Version 3.7 X * */ X #include "extern.h" X #define M_TEST (M_PRECIOUS | M_VAR_MASK) X static void dump_name ANSI((HASHPTR, int)); static void dump_normal_target ANSI((CELLPTR, int)); static void dump_prerequisites ANSI((LINKPTR, int, int, int)); X X PUBLIC void Dump()/* ======== 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 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( Root->ce_prq && hp->CP_OWNR == Root->ce_prq->cl_prq ) X puts( "# ******* FIRST TARGET ********" ); X dump_normal_target( hp->CP_OWNR, hp->CP_OWNR->ce_flag ); 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_normal_target( hp->CP_OWNR, hp->CP_OWNR->ce_flag ); X X DB_VOID_RETURN; } X X X PUBLIC void Dump_recipe( sp )/* =================== X Given a string pointer print the recipe line out */ STRINGPTR sp; { 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 if( sp->st_attr & A_SWAP ) 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 static char *_attrs[] = { ".PRECIOUS", ".SILENT", ".LIBRARY", X ".EPILOG", ".PROLOG", ".IGNORE", ".SYMBOL", ".NOINFER", X ".UPDATEALL", ".SEQUENTIAL", ".SETDIR=", ".USESHELL", ".SWAP", ".MKSARGS", X ".PHONY", ".NOSTATE" }; X static void dump_normal_target( cp, flag )/* ================================ X Dump in makefile like format the dag information */ CELLPTR cp; int flag; { 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( !(cp->ce_flag & F_TARGET) && !cp->ce_attr ) { DB_VOID_RETURN; } X X if( cp->ce_flag & F_MULTI ) { X int tflag = cp->ce_prq->cl_prq->ce_flag; X if( !(cp->ce_flag & F_PERCENT) ) tflag |= F_MULTI; X dump_prerequisites(cp->ce_prq, FALSE, TRUE, tflag); X } X else { 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 ) { X printf( "%s%s ", _attrs[k], X (attr != A_SETDIR) ? "" : (cp->ce_dir?cp->ce_dir:"") ); X } X X putchar( ':' ); X X if( flag & F_MULTI ) putchar( ':' ); X if( flag & F_SINGLE ) putchar( '!' ); X putchar( ' ' ); X X dump_prerequisites( cp->ce_prq, FALSE, FALSE, F_DEFAULT); X dump_prerequisites( cp->ce_indprq, TRUE, FALSE, F_DEFAULT); X X putchar( '\n' ); X if( cp->ce_flag & F_GROUP ) puts( "[" ); X for( sp = cp->ce_recipe; sp != NIL(STRING); sp = sp->st_next ) X Dump_recipe( sp ); X if( cp->ce_flag & F_GROUP ) puts( "]" ); X X putchar( '\n' ); X } X X DB_VOID_RETURN; } X X static void dump_prerequisites( lp, quote, recurse, flag ) LINKPTR lp; int quote; int recurse; int flag; { X for( ; lp; lp=lp->cl_next ) X if( recurse ) X dump_normal_target(lp->cl_prq, flag); X else if( lp->cl_prq ) X dump_name(lp->cl_prq->ce_name, quote); } X X static void dump_name( hp, quote )/* ======================== X print out a name */ HASHPTR hp; int quote; { X if( quote ) putchar('\''); X printf( "%s", hp->ht_name ); X if( quote ) putchar('\''); X putchar(' '); } SHAR_EOF chmod 0640 dmake/dmdump.c || echo 'restore of dmake/dmdump.c failed' Wc_c="`wc -c < 'dmake/dmdump.c'`" test 5857 -eq "$Wc_c" || echo 'dmake/dmdump.c: original size 5857, current size' "$Wc_c" rm -f _shar_wnt_.tmp fi # ============= dmake/dmstring.c ============== if test -f 'dmake/dmstring.c' -a X"$1" != X"-c"; then echo 'x - skipping dmake/dmstring.c (File already exists)' rm -f _shar_wnt_.tmp else > _shar_wnt_.tmp sed 's/^X//' << 'SHAR_EOF' > 'dmake/dmstring.c' && /* RCS -- $Header: /u2/dvadura/src/generic/dmake/src/RCS/dmstring.c,v 1.1 91/05/06 15:23:09 dvadura Exp $ -- SYNOPSIS -- string handling code -- -- DESCRIPTION -- Routines to handle string manipulation. This code is not specific -- to dmake and has/and will be used in other programs. The string -- "" is considered the NULL string, if NIL(char) is received instead -- undefined results may occurr. (In reality NIL(char) is checked for -- but in general it is not safe to assume NIL(char) == NULL) -- -- AUTHOR -- Dennis Vadura, dvadura@watdragon.uwaterloo.ca -- CS DEPT, University of Waterloo, Waterloo, Ont., Canada -- -- COPYRIGHT -- Copyright (c) 1990 by Dennis Vadura. All rights reserved. -- -- This program is free software; you can redistribute it and/or -- modify it under the terms of the GNU General Public License -- (version 1), as published by the Free Software Foundation, and -- found in the file 'LICENSE' included with this distribution. -- -- This program is distributed in the hope that it will be useful, -- but WITHOUT ANY WARRANTY; without even the implied warrant of -- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -- GNU General Public License for more details. -- -- You should have received a copy of the GNU General Public License -- along with this program; if not, write to the Free Software -- Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -- -- LOG -- $Log: dmstring.c,v $ X * Revision 1.1 91/05/06 15:23:09 dvadura X * dmake Release Version 3.7 X * */ X #include "extern.h" X PUBLIC char * _strjoin( src, data, n, fr )/* ============================== 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 char *src; char *data; int n; int fr; { 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 PUBLIC char * _stradd( src, data, fr )/* ========================== 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 char *src; char *data; int fr; { 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 PUBLIC char * _strapp( src1, src2 )/* ======================= 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. */ char *src1; char *src2; { X src2 = _stradd( src1, src2, FALSE ); X if( src1 != NIL(char) ) FREE( src1 ); X return( src2 ); } X X X #ifdef DBUG #ifdef _strdup #undef _strdup #endif #endif PUBLIC char * _strdup( str )/* ================ Duplicate the contents of a string, by using malloc */ char *str; { 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 PUBLIC char * _strpbrk( s1, s2 )/* ==================== 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 char *s1; char *s2; { X register char *t; X X if( s1 == NIL(char) || s2 == NIL(char) ) return( "" ); X X for( t=s1; *t && (strchr( s2, *t ) == NIL(char)); t++ ); X return( t ); } X X X X PUBLIC char * _strspn( s1, s2 )/* =================== 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 char *s1; char *s2; { X register char *t; X X if( s1 == NIL(char) || s2 == NIL(char) ) return( "" ); X X for( t=s1; *t && (strchr( s2, *t ) != NIL(char)); t++ ); X return( t ); } X X X X PUBLIC char * _strstr( s1, s2 )/* ================== find first occurrence in s1 of s2 */ char *s1; char *s2; { 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 PUBLIC char * _substr( s, e )/* ================= 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 char *s; char *e; { X char save; X int len = e-s; X X if( len < 0 || len > strlen(s) ) X Fatal( "Internal Error: _substr fails consistency test" ); X X save = *e; X *e = '\0'; X s = _strdup( s ); X *e = save; X X return( s ); } SHAR_EOF chmod 0640 dmake/dmstring.c || echo 'restore of dmake/dmstring.c failed' Wc_c="`wc -c < 'dmake/dmstring.c'`" test 5809 -eq "$Wc_c" || echo 'dmake/dmstring.c: original size 5809, current size' "$Wc_c" rm -f _shar_wnt_.tmp fi # ============= dmake/expand.c ============== if test -f 'dmake/expand.c' -a X"$1" != X"-c"; then echo 'x - skipping dmake/expand.c (File already exists)' rm -f _shar_wnt_.tmp else > _shar_wnt_.tmp sed 's/^X//' << 'SHAR_EOF' > 'dmake/expand.c' && /* RCS -- $Header: /u2/dvadura/src/generic/dmake/src/RCS/expand.c,v 1.1 91/05/06 15:23:10 dvadura Exp $ -- SYNOPSIS -- macro expansion code. -- -- DESCRIPTION -- -- This routine handles all the necessary junk that deals with macro -- expansion. It understands the following syntax. If a macro is -- not defined it expands to NULL, and {} are synonyms for (). -- -- $$ - expands to $ -- {{ - expands to { -- }} - expands to } -- $A - expands to whatever the macro A is defined as -- $(AA) - expands to whatever the macro AA is defined as -- $($(A)) - represents macro indirection -- <+...+> - get mapped to $(mktmp ...) -- -- following macro is recognized -- -- string1{ token_list }string2 -- -- and expands to string1 prepended to each element of token_list and -- string2 appended to each of the resulting tokens from the first -- operation. If string2 is of the form above then the result is -- the cross product of the specified (possibly modified) token_lists. -- -- The folowing macro modifiers are defined and expanded: -- -- $(macro:modifier_list:modifier_list:...) -- -- where modifier_list a combination of: -- -- D or d - Directory portion of token including separator -- F or f - File portion of token including suffix -- B or b - basename portion of token not including suffix -- T or t - for tokenization -- -- or a single -- S or s - pattern substitution (simple) -- -- NOTE: Modifiers are applied once the macro value has been found. -- Thus the construct $($(test):s/joe/mary/) is defined and -- modifies the value of $($(test)) -- -- Also the construct $(m:d:f) is not the same as $(m:df) -- the first applies d to the value of $(m) and then -- applies f to the value of that whereas the second form -- applies df to the value of $(m). -- -- AUTHOR -- Dennis Vadura, dvadura@watdragon.uwaterloo.ca -- CS DEPT, University of Waterloo, Waterloo, Ont., Canada -- -- COPYRIGHT -- Copyright (c) 1990 by Dennis Vadura. All rights reserved. -- -- This program is free software; you can redistribute it and/or -- modify it under the terms of the GNU General Public License -- (version 1), as published by the Free Software Foundation, and -- found in the file 'LICENSE' included with this distribution. -- -- This program is distributed in the hope that it will be useful, -- but WITHOUT ANY WARRANTY; without even the implied warrant of -- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -- GNU General Public License for more details. -- -- You should have received a copy of the GNU General Public License -- along with this program; if not, write to the Free Software -- Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -- -- LOG -- $Log: expand.c,v $ X * Revision 1.1 91/05/06 15:23:10 dvadura X * dmake Release Version 3.7 X * */ X #include "extern.h" X /* Microsoft BRAINDAMAGE ALERT!!!! X * This #ifdef is here only to satisfy stupid bugs in MSC5.0 and MSC5.1 X * it isn't needed for anything else. It turns loop optimization off. */ #if defined(_MSC_VER) #include "optoff.h" #endif X static char* _scan_token ANSI((char*, char**)); static char* _scan_macro ANSI((char*, char**)); static char* _scan_brace ANSI((char*, char**, int*)); static char* _cross_prod ANSI((char*, char*)); X X PUBLIC char * Expand( src )/* =============== 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 char *src; /* pointer to source string */ { 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 PUBLIC char * Apply_edit( src, pat, subst, fr, anchor )/* =========================================== 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 char *src; /* the source string */ char *pat; /* pattern to find */ char *subst; /* substitute string */ int fr; /* if TRUE free src */ int anchor; /* if TRUE anchor */ { 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 PUBLIC void Map_esc( tok )/* ================ 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. */ char *tok; { 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 PUBLIC char* Apply_modifiers( mod, src )/* ============================= X This routine applies the appropriate modifiers to the string src X and returns the proper result string */ X int mod; char *src; { 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 PUBLIC char* Tokenize( src, separator )/* ============================ 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 char *src; char *separator; { 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( "" ); SHAR_EOF true || echo 'restore of dmake/expand.c failed' fi echo 'End of part 8, continue with part 9' echo 9 > _shar_seq_.tmp exit 0 exit 0 # Just in case... -- Kent Landfield INTERNET: kent@sparky.IMD.Sterling.COM Sterling Software, IMD UUCP: uunet!sparky!kent Phone: (402) 291-8300 FAX: (402) 291-4362 Please send comp.sources.misc-related mail to kent@uunet.uu.net.