v14i025: dmake version 3.5 part 15/21
Dennis Vadura
dvadura at watdragon.waterloo.edu
Fri Jul 27 09:47:05 AEST 1990
Posting-number: Volume 14, Issue 25
Submitted-by: dvadura at watdragon.waterloo.edu (Dennis Vadura)
Archive-name: dmake/part15
#!/bin/sh
# this is part 15 of a multipart archive
# do not concatenate these parts, unpack them in order with /bin/sh
# file make.c continued
#
CurArch=15
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 make.c"
sed 's/^X//' << 'SHAR_EOF' >> make.c
X * that fact for all of the prerequisites that we will be making. */
X
X cp->ce_setdir = setdirroot;
X
X if( cp->ce_attr & A_SETDIR ) {
X /* Change directory only if the previous .SETDIR is a different
X /* directory from the current one. ie. all cells with the same .SETDIR
X /* attribute are assumed to come from the same directory. */
X
X if( (setdirroot == NIL(CELL) || setdirroot->ce_dir != cp->ce_dir) &&
X (push = Push_dir(cp, (cp->ce_attr | Glob_attr) & A_IGNORE)))
X setdirroot = cp;
X }
X
X DB_PRINT( "mem", ("%s:-A mem %ld", cp->CE_NAME, (long) coreleft()) );
X if( (how->hw_recipe == NIL(STRING) && !(how->hw_flag & F_INFER)) ) {
X HOWPTR thp;
X
X if( Verbose )
X printf( "%s: Infering prerequisite(s) and recipe for [%s]\n", Pname,
X cp->CE_NAME );
X
X thp = how->hw_next;
X (void) Infer_recipe( cp, how, NIL(DFASET), setdirroot );
X
X /* If we inferred a new set of prerequisites then make
X * them before the current list represented by the current how pointer */
X if( thp != how->hw_next )
X if( (rval = Make(cp, how->hw_next, cp->ce_setdir)) == -1 ||
X !(how->hw_next->hw_flag & F_MADE) )
X goto stop_making_it;
X }
X
X DB_PRINT( "mem", ("%s:-A mem %ld", cp->CE_NAME, (long) coreleft()) );
X /* If we have not yet statted the target then do so. */
X if( !(cp->ce_flag & F_STAT) ) {
X time_t itime = cp->ce_time;
X Stat_target( cp, TRUE );
X
X if( cp->ce_time == (time_t)0L ) {
X if( cp->ce_flag & F_INFER )
X cp->ce_time = itime;
X }
X else
X cp->ce_attr |= A_PRECIOUS; /* File exists so don't remove it later. */
X
X if( Verbose )
X printf("%s: Time stamp of [%s] is %ld\n",Pname,cp->CE_NAME,
X cp->ce_time);
X }
X
X DB_PRINT( "make", ("(%s, %ld, 0x%04x, 0x%04x)", cp->CE_NAME,
X cp->ce_time, cp->ce_attr, cp->ce_flag) );
X
X if( !(cp->ce_flag & F_TARGET) && (cp->ce_time == (time_t) 0L) )
X if( Makemkf )
X DB_RETURN( -1 );
X else
X Fatal( "`%s' not found, and can't be made", cp->CE_NAME );
X
X DB_PRINT( "mem", ("%s:-A mem %ld", cp->CE_NAME, (long) coreleft()) );
X
X /* set value of $* if we have not infered a recipe, in this case $* is
X * the same as $(@:db), this allows us to be compatible with BSD make */
X if( how->hw_per == NIL(char) ) how->hw_per = "$(@:db)";
X
X for( dp = how->hw_prq; dp != NIL(LINK); dp = dp->cl_next ) {
X int seq;
X
X /* Make the prerequisite, note that if the current target has the
X * .LIBRARY attribute set we pass on to the prerequisite the .LIBRARYM
X * attribute and pass on the name of the current target as the library
X * name, and we take it away when we are done. */
X
X tcp = dp->cl_prq;
X seq = (cp->ce_attr | how->hw_attr | Glob_attr) & A_SEQ;
X
X if( (tcp->ce_flag & F_VISITED) && !(tcp->ce_flag & F_MADE) )
X goto stop_making_it;
X else if( tcp->ce_flag & F_MADE )
X continue;
X
X if( strchr(tcp->CE_NAME, '$') ) {
X /* Make this prerequisite link point at the real prerequisite we
X * are after, ie figure out what the dynamic one is and point at it. */
X
X m_at = Def_macro( "@", cp->ce_fname, M_MULTI );
X name = Expand( tcp->CE_NAME );
X
X tcp = dp->cl_prq = Def_cell( name, setdirroot );
X FREE( name );
X }
X
X if( cp->ce_attr & A_LIBRARY ) {
X tcp->ce_attr |= A_LIBRARYM;
X tcp->ce_lib = cp->ce_fname;
X }
X
X if( (tcp->ce_flag & (F_INFER | F_STAT)) == F_INFER )
X tcp->ce_time = cp->ce_time;
X
X /* Propagate parents F_REMOVE and F_INFER attribute to children.
X * Make certain you do this AFTER propagating the time, since the
X * time propagation test above uses the F_INFER flag to decide if
X * it should do so. */
X tcp->ce_flag |= cp->ce_flag & (F_REMOVE|F_INFER);
X
X rval |= Make(tcp, tcp->CE_HOW, setdirroot);
X
X if( cp->ce_attr & A_LIBRARY )
X tcp->ce_attr ^= A_LIBRARYM;
X
X if( rval == -1 )
X goto stop_making_it;
X else if( seq && (rval == 1) )
X goto stop_making_it;
X }
X
X /* Do the loop again. We are most definitely going to make the current
X * how cell now. NOTE: doing this loop here also results in a reduction
X * in peak memory usage by the algorithm. */
X
X for( dp = how->hw_prq; dp != NIL(LINK); dp = dp->cl_next ) {
X char *dir;
X int tgflg;
X tcp = dp->cl_prq;
X name = tcp->ce_fname;
X
X /* make certain that all prerequisites are made prior to advancing. */
X if( !(tcp->ce_flag & F_MADE) ) goto stop_making_it;
X
X /* If the target is a library, then check to make certain that a member
X * is newer than an object file sitting on disk. If the disk version
X * is newer then set the time stamps so that the archived member is
X * replaced. */
X if( cp->ce_attr & A_LIBRARY )
X if( tcp->ce_time < cp->ce_time ) {
X time_t mtime = Do_stat( tcp->ce_fname, tcp->ce_lib, NIL(char *) );
X if( mtime < tcp->ce_time ) tcp->ce_time = cp->ce_time+1L;
X }
X
X if( tcp->ce_time > otime ) otime = tcp->ce_time;
X
X /* Note: If the prerequisite was made using a SETDIR
X * directory then we will include the directory in the name
X * of the prerequisite when we build the $?, $&, $^ and $< lists
X */
X
X if( (dir = tcp->ce_dir ) != NIL(char) )
X name = Build_path( dir, name );
X
X all = _strapp( all, name );
X if( tgflg = (dp->cl_flag & F_TARGET) ) inf = _strapp( inf, name );
X
X if((cp->ce_time<tcp->ce_time) || ((tcp->ce_flag & F_TARGET) && Force)) {
X outall = _strapp( outall, name );
X if( tgflg ) imm = _strapp( imm, name );
X }
X }
X
X DB_PRINT( "mem", ("%s:-C mem %ld", cp->CE_NAME, (long) coreleft()) );
X DB_PRINT( "make", ("I make '%s' if %ld > %ld", cp->CE_NAME, otime,
X cp->ce_time) );
X
X /* mark the how cell as visited since we are making it for certain now. */
X how->hw_flag |= F_VISITED;
X if( Verbose ) printf( "%s: >>>> Making [%s]\n", Pname, cp->CE_NAME );
X
X if( Check && (cp->ce_time < otime) ) {
X /* Only checking so stop as soon as we determine we will make something */
X rval = -1;
X goto stop_making_it;
X }
X
X if( (cp->ce_time < otime) || ((cp->ce_flag & F_TARGET) && Force) ) {
X if( Verbose )
X printf( "%s: Updating [%s], (%ld > %ld)\n", Pname,
X cp->CE_NAME, otime, cp->ce_time );
X
X cp->ce_attr |= A_UPDATED;
X
X if( Touch ) {
X name = cp->ce_fname;
X lib = cp->ce_lib;
X
X if( !(Glob_attr & A_SILENT) || !Trace )
X if( lib == NIL(char) )
X printf("touch(%s)", name );
X else if( cp->ce_attr & A_SYMBOL )
X printf("touch(%s((%s)))", lib, name );
X else
X printf("touch(%s(%s))", lib, name );
X
X if( !Trace )
X if( Do_touch( name, lib,
X (cp->ce_attr & A_SYMBOL) ? &name : NIL(char *) ) != 0 )
X printf( " not touched - non-existant" );
X
X printf( "\n" );
X Update_time_stamp( cp, how );
X }
X else if( how->hw_recipe != NIL(STRING) ) {
X HASHPTR m_q, m_b, m_g, m_l, m_bb, m_up;
X TKSTR tk;
X
X m_at = Def_macro( "@", cp->ce_fname,M_MULTI );
X m_g = Def_macro( ">", cp->ce_lib, M_MULTI );
X m_q = Def_macro( "?", outall, M_MULTI );
X m_b = Def_macro( "<", inf, M_MULTI );
X m_l = Def_macro( "&", all, M_MULTI );
X m_bb = Def_macro( "*", how->hw_per, M_MULTI );
X m_up = Def_macro( "^", imm, M_MULTI );
X
X _recipes[ RP_RECIPE ] = how->hw_recipe;
X
X if( !(how->hw_flag & F_SINGLE) )
X rval = _exec_commands( cp, how );
X else {
X _drop_mac( m_q );
X SET_TOKEN( &tk, outall );
X
X Doing_bang = TRUE;
X name = Get_token( &tk, "", FALSE );
X do {
X m_q->ht_value = name;
X
X Wait_for_completion = TRUE; /* Reset in _exec_commands */
X rval = _exec_commands( cp, how );
X Unlink_temp_files(how);
X }
X while( *(name = Get_token( &tk, "", FALSE )) != '\0' );
X Doing_bang = FALSE;
X Update_time_stamp( cp, how );
X
X m_q->ht_value = NIL(char);
X }
X
X _drop_mac( m_g );
X _drop_mac( m_q );
X _drop_mac( m_b );
X _drop_mac( m_l );
X _drop_mac( m_bb );
X _drop_mac( m_up );
X }
X else if( !(cp->ce_flag & F_RULES) &&
X ((cp != Root) || !(cp->ce_flag & F_EXPLICIT)) )
X Fatal( "Don't know how to make `%s'",cp->CE_NAME );
X else {
X /* Empty recipe, set the how flag as MADE and update the time stamp */
X Update_time_stamp( cp, how );
X }
X }
X else {
X /* Make sure everyone gets remade if Force is set */
X if( !(cp->ce_flag & F_TARGET) && Force ) cp->ce_time = Do_time();
X
X /* Set how to MADE since it is done, it was not out of date */
X how->hw_flag |= F_MADE;
X if( cp->CE_HOW == how ) {
X tcp = cp;
X do {
X tcp->ce_flag |= F_MADE;
X tcp = tcp->ce_all;
X }
X while( tcp != NIL(CELL) && tcp != cp );
X }
X }
X
X if( cp->CE_HOW == how ) cp->ce_flag |= F_VISITED;
X
Xstop_making_it:
X if( m_at != NIL(HASH) ) _drop_mac( m_at );
X
X if( push ) Pop_dir(FALSE);
X
X if( inf != NIL(char) ) FREE( inf );
X if( all != NIL(char) ) FREE( all );
X if( imm != NIL(char) ) FREE( imm );
X if( outall != NIL(char) ) FREE( outall );
X
X DB_PRINT( "mem", ("%s:-< mem %ld", cp->CE_NAME, (long) coreleft()) );
X DB_RETURN( rval );
X}
X
X
X
Xstatic void
X_drop_mac( hp )/*
X================ set a macro value to zero. */
XHASHPTR hp;
X{
X if( hp->ht_value != NIL(char) ) {
X FREE( hp->ht_value );
X hp->ht_value = NIL(char);
X }
X}
X
X
X
Xstatic int
X_exec_commands( cp, how )/*
X===========================
X Execute the commands one at a time that are pointed to by the rules pointer
X of the target cp. If a group is indicated, then the hw_attr determines
X .IGNORE and .SILENT treatment for the group.
X
X The function returns 0, if the command is executed and has successfully
X returned, and returns 1 if the command is executing but has not yet
X returned (for parallel makes).
X
X The F_MADE bit in the how cell is guaranteed set when the command has
X successfully completed. */
XCELLPTR cp;
XHOWPTR how;
X{
X register STRINGPTR rp;
X char *cmnd;
X char *groupfile;
X char *ap;
X char *hold = NIL(char);
X FILE *tmpfile;
X FILE *here_doc = NIL(FILE);
X int do_it;
X int attr;
X int group;
X int trace;
X int rval = 0;
X
X DB_ENTER( "_exec_commands" );
X
X Current_target = how;
X attr = Glob_attr | cp->ce_attr;
X trace = Trace || !(attr & A_SILENT);
X group = how->hw_flag & F_GROUP;
X
X if( group ) {
X attr |= how->hw_attr;
X trace = Trace || !(attr & A_SILENT);
X
X if( !Trace ) tmpfile = Start_temp( Grp_suff, cp, how, &groupfile );
X if( trace ) fputs( "[\n", stdout );
X
X /* Emit group prolog */
X if( attr & A_PROLOG )
X _append_file( _recipes[RP_GPPROLOG], tmpfile, cp->CE_NAME, trace );
X }
X
X
X /* Process commands in recipe. If in group, merely append to file.
X * Otherwise, run them. If a text diversion indicated, expand
X * that document as required into a temporary file */
X
X for( rp = _recipes[RP_RECIPE]; rp != NIL(STRING); rp=rp->st_next,FREE(cmnd)){
X char *savecmnd;
X int done = 0;
X
X do_it = !Trace;
X
X if( !group && Trace && _strstr(rp->st_string,"$(MAKE)") ) {
X Wait_for_completion |= Trace;
X do_it = TRUE;
X }
X
X savecmnd = cmnd = Expand( rp->st_string );
X
X/******* TEXT DIVERSION PROCESSING START ********/
X /* Look for a text diversion surrounded by <+ and +>. Note that the
X * diversion may be on a single line or span multiple lines. Note that
X * if a diversion is started with <+ and never finished with +> an error
X * is issued. */
X
X /* Check for the start of a new diversion */
X do {
X if( here_doc == NIL(FILE) && (ap = _strstr(cmnd, "<+")) != NIL(char)) {
X char *t;
X char *fname;
X here_doc = Start_temp( "", cp, how, &fname );
X *ap = '\0';
X hold = _strjoin( hold, t = _strjoin(cmnd,fname,-1,FALSE),-1,TRUE);
X FREE(t);
X cmnd = ap+2;
X }
X
X if( here_doc != NIL(FILE) ) {
X if( (ap = _strstr(cmnd, "+>")) == NIL(char) ) {
X _add_here(cmnd, here_doc, TRUE);
X done = TRUE;
X }
X else {
X *ap = '\0';
X if( *_strspn(cmnd, " \t") != '\0' )
X _add_here(cmnd, here_doc, FALSE);
X
X cmnd = ap+2;
X Close_temp( how, here_doc );
X here_doc = NIL(FILE);
X }
X }
X else if( hold != NIL(char) ) {
X cmnd = _strjoin( hold, cmnd, -1, TRUE );
X done = TRUE;
X hold = NIL(char);
X FREE( savecmnd );
X }
X else
X done = TRUE;
X }
X while( *cmnd && !done );
X
X if( here_doc != NIL(FILE) ) continue;
X if( hold != NIL(char) ) {
X FREE(savecmnd);
X cmnd = hold;
X }
X/******* TEXT DIVERSION PROCESSING END ********/
X
X
X if( group )
X _append_line( cmnd, TRUE, tmpfile, cp->CE_NAME, trace );
X else {
X if( *_strspn(cmnd, " \t") != '\0' )
X _print_cmnd(cmnd, !(do_it && ((rp->st_attr | attr) & A_SILENT)), 0);
X else
X do_it = FALSE;
X
X rval=Do_cmnd(cmnd,FALSE,do_it,cp,how,((attr|rp->st_attr)&A_IGNORE),
X rp->st_next == NIL(STRING) );
X }
X }
X
X if( here_doc != NIL(FILE) )
X Fatal( "Unterminated text diversion while making `%s'", cp->CE_NAME );
X
X /* If it is a group then output the EPILOG if required and possibly
X * execute the command */
X if( group ) {
X if( attr & A_EPILOG ) /* emit epilog */
X _append_file( _recipes[RP_GPEPILOG], tmpfile, cp->CE_NAME, trace );
X
X if( trace ) fputs("]\n", stdout);
X
X if( do_it = !Trace ) Close_temp( how, tmpfile );
X rval = Do_cmnd(groupfile, TRUE, do_it, cp, how, attr & A_IGNORE, TRUE);
X }
X
X Wait_for_completion = FALSE;
X DB_RETURN( rval );
X}
X
X
X
Xstatic void
X_print_cmnd( cmnd, echo, map )/*
X================================
X This routine is called to print out the command to stdout. If echo is
X false the printing to stdout is supressed, but the new lines in the command
X are still deleted. */
Xchar *cmnd;
Xint echo;
Xint map;
X{
X register char *p;
X register char *n;
X
X DB_ENTER( "_print_cmnd" );
X
X if( echo ) printf( "%s\n", cmnd );
X
X for( p=cmnd; (n = strchr(p, CONTINUATION_CHAR)) != NIL(char); p=n+1 )
X if(n[1] == '\n') {
X DB_PRINT( "make", ("fixing [%s]", p) );
X strcpy( n, n+2 );
X }
X else if( map )
X Map_esc( n );
X
X DB_VOID_RETURN;
X}
X
X
X
X/* These routines are used to maintain a stack of directories when making
X * the targets. If a target cd's to the directory then it is assumed that
X * it will undo it when it is finished making itself. */
X
Xstatic STRINGPTR dir_stack = NIL(STRING);
X
Xint
XPush_dir( cp, ignore )/*
X==========================
X Change the current working directory to dir and save the current
X working directory on the stack so that we can come back.
X
X If ignore is TRUE then do not complain about _ch_dir if not possible.*/
XCELLPTR cp;
Xint ignore;
X{
X STRINGPTR new_dir;
X char *dir;
X
X DB_ENTER( "Push_dir" );
X
X if( (dir = cp->ce_dir) == NIL(char) ) dir = Pwd;
X if( *dir == '\'' && dir[strlen(dir)-1] == '\'' ) {
X dir = _strdup(dir+1);
X dir[strlen(dir)-1]='\0';
X }
X else
X dir = Expand(dir);
X
X if( Set_dir(dir) ) {
X if( !ignore )
X Fatal( "Unable to change to directory `%s', target is [%s]",
X dir, cp->CE_NAME );
X FREE(dir);
X DB_RETURN( 0 );
X }
X
X DB_PRINT( "dir", ("Push: [%s]", dir) );
X if( Verbose ) printf( "%s: Changed to directory [%s]\n", Pname, dir );
X
X FREE( dir );
X TALLOC( new_dir, 1, STRING );
X new_dir->st_next = dir_stack;
X dir_stack = new_dir;
X new_dir->st_string = _strdup( Pwd );
X
X Def_macro( "PWD", Get_current_dir(), M_MULTI | M_EXPANDED );
X _set_tmd();
X
X DB_RETURN( 1 );
X}
X
X
X
Xvoid
XPop_dir(ignore)/*
X=================
X Change the current working directory to the previous saved dir. */
Xint ignore;
X{
X STRINGPTR old_dir;
X char *dir;
X
X DB_ENTER( "Pop_dir" );
X
X if( dir_stack == NIL(STRING) )
X if( ignore ) {
X DB_VOID_RETURN;
X }
X else
X Error( "Directory stack empty for return from .SETDIR" );
X
X if( Set_dir(dir = dir_stack->st_string) )
X Fatal( "Could not change to directory `%s'", dir );
X
X Def_macro( "PWD", dir, M_MULTI | M_EXPANDED );
X DB_PRINT( "dir", ("Pop: [%s]", dir) );
X if( Verbose ) printf( "%s: Changed back to directory [%s]\n", Pname, dir);
X
X old_dir = dir_stack;
X dir_stack = dir_stack->st_next;
X
X FREE( old_dir->st_string );
X FREE( old_dir );
X _set_tmd();
X
X DB_VOID_RETURN;
X}
X
X
X
Xstatic void
X_set_tmd()/*
X============
X Set the TWD Macro */
X{
X TKSTR md, pd;
X char *m, *p;
X char *tmd;
X int is_sep;
X int first = 1;
X
X SET_TOKEN( &md, Makedir );
X SET_TOKEN( &pd, Pwd );
X
X m = Get_token( &md, DirBrkStr, FALSE );
X (void) Get_token( &pd, DirBrkStr, FALSE );
X is_sep = (strchr(DirBrkStr, *m) != NIL(char));
X tmd = _strdup( "" );
X
X do {
X m = Get_token( &md, DirBrkStr, FALSE );
X p = Get_token( &pd, DirBrkStr, FALSE );
X
X if( !is_sep && strcmp(m, p) ) { /* they differ */
X char *tmp;
X if( first ) { /* They differ in the first component */
X tmd = Makedir; /* In this case use the full path */
X break;
X }
X
X if( *p ) tmp = Build_path( "..", tmd );
X if( *m ) tmp = Build_path( tmd, m );
X FREE( tmd );
X tmd = _strdup( tmp );
X }
X
X is_sep = 1-is_sep;
X first = 0;
X } while (*m || *p);
X
X CLEAR_TOKEN( &md );
X CLEAR_TOKEN( &pd );
X
X Def_macro( "TMD", tmd, M_MULTI | M_EXPANDED );
X if( tmd != Makedir ) FREE( tmd );
X}
X
X
Xstatic void
X_set_recipe( target, ind )/*
X============================
X Set up the _recipes static variable so that the slot passed in points
X at the rules corresponding to the target supplied. */
Xchar *target;
Xint ind;
X{
X CELLPTR cp;
X HASHPTR hp;
X
X if( (hp = Get_name( target, Defs, FALSE, NIL(CELL) )) != NIL(HASH) ) {
X cp = hp->CP_OWNR;
X if( cp->CE_HOW != NIL(HOW) ) _recipes[ ind ] = cp->CE_RECIPE;
X }
X else
X _recipes[ ind ] = NIL(STRING);
X}
X
X
X
Xstatic void
X_append_line( cmnd, newline, tmpfile, name, printit )
Xchar *cmnd;
Xint newline;
XFILE *tmpfile;
Xchar *name;
Xint printit;
X{
X _print_cmnd( cmnd, printit, 0 );
X
X if( Trace ) return;
X
X fputs(cmnd, tmpfile);
X if( newline ) fputc('\n', tmpfile);
X fflush(tmpfile);
X
X if( ferror(tmpfile) )
X Fatal("Write error on temporary group file, for target `%s'", name);
X}
X
X
X
Xstatic void
X_append_file( rp, tmpfile, name, printit )
Xregister STRINGPTR rp;
XFILE *tmpfile;
Xchar *name;
Xint printit;
X{
X char *cmnd;
X
X while( rp != NIL(STRING) ) {
X _append_line(cmnd = Expand(rp->st_string), TRUE, tmpfile, name, printit);
X FREE(cmnd);
X rp = rp->st_next;
X }
X}
X
X
X
Xstatic void
X_add_here( line, file, newline )
Xchar *line;
XFILE *file;
Xint newline;
X{
X while( *line == '\t' ) /* skip initial tabs */
X line++;
X
X _print_cmnd( line, FALSE, TRUE );
X fputs(line, file);
X if( newline ) fputc('\n', file);
X fflush(file);
X
X if( ferror(file) )
X Fatal("Write error on temporary file for text diversion");
X}
SHAR_EOF
echo "File make.c is complete"
chmod 0440 make.c || echo "restore of make.c fails"
echo "x - extracting make.bat (Text)"
sed 's/^X//' << 'SHAR_EOF' > make.bat &&
Xecho off
Xrem *** This is the make batchfile that is used under MSDOS to make the
Xrem *** first version of dmake. It isn't pretty but it does work, assuming
Xrem *** the compilers have been correctly setup. See the warning below
Xrem *** concerning tlink, if you are making the Turbo C version.
Xrem
Xecho Running make.bat script to make a %1 copy of dmake.
X
Xif %0%1 == %0 goto error
Xif %1 == mscdos goto makemsc
Xif %1 == tccdos goto maketcc
X
Xrem label the possible DOS variations for dmake here.
X:error
Xecho ERROR: You must specify one of:
Xecho tccdos - Turbo C 2.0, compile.
Xecho mscdos - Microsoft C 4.0 or higher, compile.
Xgoto end
X
Xrem This is the script that makes dmake using Microsoft C 4.0 or higher.
X:makemsc
Xmsdos\mscdos\make.bat
Xgoto end
X
Xrem This is the script that makes dmake using Turbo C 2.0 or higher.
X:maketcc
Xcls
Xecho WARNING:
Xecho The default response files msdos\tccdos\tccobj.rsp
Xecho and msdos\tccdos\tcclib.rsp contain absolute paths to TURBO-C
Xecho runtime startup objects, and to the standard libraries. You should
Xecho check that these files point to the right places before proceeding.
Xecho --
Xecho Continue if ok, or abort and edit the response files.
Xpause
Xmsdos\tccdos\make.bat
X
Xrem All done!
X:end
SHAR_EOF
chmod 0440 make.bat || echo "restore of make.bat fails"
echo "x - extracting macparse.c (Text)"
sed 's/^X//' << 'SHAR_EOF' > macparse.c &&
X/* RCS -- $Header: /u2/dvadura/src/generic/dmake/src/RCS/macparse.c,v 1.1 90/07/19 13:53:20 dvadura Exp $
X-- SYNOPSIS -- parse a macro definition
X--
X-- DESCRIPTION
X-- This file contains the code that parses a macro definition
X-- stored in a buffer. If the string in buffer is not a valid
X-- macro definition the routie Parse_macro returns 0, otherwise it
X-- returns 1 to indicate success.
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: macparse.c,v $
X * Revision 1.1 90/07/19 13:53:20 dvadura
X * Initial Revision of Version 3.5
X *
X*/
X
X#include <ctype.h>
X#include "extern.h"
X#include "alloc.h"
X#include "db.h"
X
Xint
XParse_macro( buffer, flag )/*
X=============================
X Parse the string in buffer and define it as a macro if it is a valid macro.
X Note especially the string .SETDIR= since it is an attribute, but looks a
X lot like a macro definition. This would not be a problem if make used
X white space as token separators, since this is not the case we must do
X something about it. */
Xchar *buffer;
Xint flag;
X{
X register char *tok1; /* temporary place to keep a token */
X register char *tok2; /* temporary place to keep a token */
X char *result; /* temporary pointer for strings */
X TKSTR input; /* place to scan the buffer from */
X HASHPTR hv; /* pointer to hash table value */
X int operator; /* what macro operator do we have */
X
X DB_ENTER( "Parse_macro" );
X
X SET_TOKEN( &input, buffer );
X tok1 = Get_token( &input, "=+:", FALSE );
X
X if( Macro_op( tok1 ) ) {
X Error( "No macro name" );
X CLEAR_TOKEN( &input );
X DB_RETURN( 1 );
X }
X
X tok1 = _strdup( tok1 );
X tok2 = Get_token( &input, "=+:", FALSE );
X if( !(operator = Macro_op( tok2 )) || !strcmp( tok1, ".SETDIR") )
X {
X CLEAR_TOKEN( &input );
X FREE( tok1 );
X DB_RETURN( 0 );
X }
X
X tok2 = Expand(tok1); FREE(tok1); tok1 = tok2;
X tok2 = Get_token( &input, NIL( char ), FALSE );
X
X switch( operator ) {
X case M_OP_PLCL:
X tok2 = Expand( tok2 );
X
X case M_OP_PL:
X /* Add to an existing macro, if it is not defined, though, then
X * fall through and define a new macro */
X
X if( (hv = GET_MACRO(tok1)) != NIL(HASH) ) {
X if( hv->ht_value != NIL(char) ) {
X result = _stradd( hv->ht_value, tok2, FALSE );
X Def_macro( tok1, result, flag );
X FREE( result );
X }
X else
X Def_macro( tok1, tok2, flag );
X
X if( operator == M_OP_PLCL ) FREE(tok2);
X break;
X }
X /*FALLTRHOUGH*/
X
X case M_OP_EQ:
X Def_macro( tok1, tok2, flag );
X if( operator == M_OP_PLCL ) FREE(tok2);
X break;
X
X case M_OP_CL:
X /* If the macro we are assigning from is a single control
X * macro with nothing else, then we propagate the M_MULTI
X * flag to the macro we are assigning the value to so that
X * the same macro can be used to do this over and over. */
X If_multi = 0;
X tok2 = Expand( tok2 );
X Def_macro( tok1, tok2, M_EXPANDED | flag | If_multi );
X FREE( tok2 );
X break;
X }
X
X FREE( tok1 );
X
X DB_RETURN( 1 );
X}
X
X
X
Xint
XMacro_op( op )/*
X================
X Check the passed in op string and map it to one of the macro operators */
Xchar *op;
X{
X int ret = 0;
X
X DB_ENTER( "macro_op" );
X
X switch( *op ) {
X case '=': ret = M_OP_EQ; break;
X case ':': ret = M_OP_CL; op++; break;
X
X case '+':
X if( *op == '+' ) { ret = M_OP_PL; op++; }
X if( *op == ':' ) { ret = M_OP_PLCL; op++; }
X break;
X }
X
X if( *op++ != '=' )
X ret = 0;
X else if( *op != '\0' )
X ret = 0;
X
X DB_RETURN( ret );
X}
X
SHAR_EOF
chmod 0440 macparse.c || echo "restore of macparse.c fails"
echo "x - extracting infer.c (Text)"
sed 's/^X//' << 'SHAR_EOF' > infer.c &&
X/* RCS -- $Header: /u2/dvadura/src/generic/dmake/src/RCS/infer.c,v 1.1 90/07/21 11:06:32 dvadura Exp $
X-- SYNOPSIS -- infer how to make a target.
X--
X-- DESCRIPTION
X-- This file contains the code to infer a recipe, and possibly some new
X-- prerequisites for a target which dmake does not know how to make, or
X-- has no explicit recipe.
X--
X-- The inference fails if no path through the inference graph can be
X-- found by which we can make the target.
X--
X-- AUTHOR
X-- Dennis Vadura, dvadura at watdragon.uwaterloo.ca
X-- CS DEPT, University of Waterloo, Waterloo, Ont., Canada
X--
X-- COPYRIGHT
X-- Copyright (c) 1990 by Dennis Vadura. All rights reserved.
X--
X-- This program is free software; you can redistribute it and/or
X-- modify it under the terms of the GNU General Public License
X-- (version 1), as published by the Free Software Foundation, and
X-- found in the file 'LICENSE' included with this distribution.
X--
X-- This program is distributed in the hope that it will be useful,
X-- but WITHOUT ANY WARRANTY; without even the implied warrant of
X-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
X-- GNU General Public License for more details.
X--
X-- You should have received a copy of the GNU General Public License
X-- along with this program; if not, write to the Free Software
X-- Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
X--
X-- LOG
X-- $Log: infer.c,v $
X * Revision 1.1 90/07/21 11:06:32 dvadura
X * Initial Revision Version 3.5
X *
X*/
X
X#include "extern.h"
X#include "alloc.h"
X#include "db.h"
X
X/* attributes that get transfered from the % start cell to the inferred
X * cells. */
X
X#define A_TRANSFER (A_EPILOG | A_PRECIOUS | A_SILENT |\
X A_LIBRARY | A_IGNORE | A_PROLOG)
X
X/* Define local static functions */
Xstatic DFALINKPTR _dfa_subset ANSI((DFALINKPTR, DFASETPTR));
Xstatic void _free_dfas ANSI((DFALINKPTR));
Xstatic int _count_dots ANSI((char *));
Xstatic char * _build_name ANSI((char *, char *, char *));
X
Xstatic int _prep = -1; /* Integer value of Prep variable */
Xstatic int _dmax;
X
XCELLPTR
XInfer_recipe( cp, how, dfa_stack, setdirroot )/*
X================================================
X Infer a set of rules for making a target. We know we have a HOW
X cell attached, but it's prerequisite list may be NIL as is its
X recipe! A NIL recipe is a prerequisite for calling this routine. */
XCELLPTR cp;
XHOWPTR how;
XDFASETPTR dfa_stack;
XCELLPTR setdirroot;
X{
X DFALINKPTR pdfa;
X DFALINKPTR dfas;
X CELLPTR infcell;
X CELLPTR meta;
X DFASET top_dfa_stack;
X EDGEPTR pedge;
X
X DB_ENTER( "Infer_recipe" );
X DB_PRINT( "inf", (">>> Infer for target [%s]", cp->CE_NAME) );
X DB_PRINT( "mem", ("%s:-> mem %ld", cp->CE_NAME, (long)coreleft()));
X
X /* If no further transitive closure on this cell then don't perform
X * any more inferences */
X if( cp->ce_attr & A_NOINFER ) DB_RETURN(NIL(CELL));
X if( _prep == -1 ) _prep = atoi(Prep); /* _dfa_subset needs _prep */
X
X if( dfa_stack == NIL(DFASET) )
X _dmax = _prep + _count_dots(cp->CE_NAME);
X
X /* If none of the inference nodes match then forget about the inference.
X * The user did not tell us how to make such a target. We also stop the
X * Inference if the new set of DFA's is a proper subset of a previous
X * subset and it's PREP counts exceed the value of Prep.
X */
X dfas = _dfa_subset( Match_dfa(cp->CE_NAME), dfa_stack );
X
X#ifdef DBUG
X { char *tmp;
X DFASETPTR ds;
X
X tmp = _strdup("");
X for( pdfa = dfas; pdfa != NIL(DFALINK); pdfa = pdfa->dl_next )
X tmp = _strapp( tmp, pdfa->dl_meta->CE_NAME );
X
X DB_PRINT( "inf", ("Working DFA subset [%s]", tmp) );
X FREE( tmp );
X
X tmp = _strdup( "{" );
X for( ds = dfa_stack; ds != NIL(DFASET); ds = ds->df_next ) {
X tmp = _strapp( tmp, "[" );
X for( pdfa = ds->df_set; pdfa != NIL(DFALINK); pdfa = pdfa->dl_next )
X tmp = _strapp( tmp, pdfa->dl_meta->CE_NAME );
X tmp = _strapp( tmp, "]" );
X }
X tmp = _strapp( tmp, "}" );
X
X DB_PRINT( "inf", ("DFA stack: %s", tmp) );
X FREE(tmp);
X }
X#endif
X
X if( dfas == NIL(DFALINK) ) {
X DB_PRINT( "mem", ("%s:<- mem %ld",cp->CE_NAME, (long)coreleft()));
X DB_PRINT( "inf", ("<<< Exit, no dfas, cp = %04x", NIL(CELL)) );
X DB_RETURN( NIL(CELL) );
X }
X
X
X /* We have a set of %-meta's that have not previously been considered, or
X * whose counts do not violate the Prep count. So we should consider
X * them, and put them on the top of the stack.
X */
X top_dfa_stack.df_set = dfas;
X top_dfa_stack.df_next = dfa_stack;
X
X
X /* Run through the %-meta cells, build the prerequisite cells. If we are
X * performing transitive closure, then call Infer_recipe with the new
X * prerequisite.
X */
X for( pdfa = dfas, infcell = NIL(CELL), pedge = NIL(EDGE);
X pdfa != NIL(DFALINK);
X pdfa = pdfa->dl_next ) {
X int push = 0;
X int _trans = 0;
X EDGEPTR edge;
X EDGEPTR edge_noprq; /* No prerequisite for this edge */
X
X DB_PRINT( "inf", ("Using dfa: [%s]", pdfa->dl_meta->CE_NAME) );
X meta = pdfa->dl_meta;
X
X
X /* Change to the required directory prior to checking the prerequisites
X * Only if the meta has a directory and we haven't changed dir's
X * for the CELL already.
X *
X * Ignore the %-meta if we had to change to a dir, and the dir
X * did not exist.
X */
X if( !(cp->ce_attr & A_SETDIR) && meta->ce_dir != NIL(char) )
X if( (setdirroot == NIL(CELL) || setdirroot->ce_dir != meta->ce_dir) &&
X (push = Push_dir(meta, TRUE)) )
X setdirroot = cp;
X else {
X DB_PRINT( "inf", ("Failed PUSH of [%s]", meta->ce_dir) );
X continue;
X }
X
X
X /* Now run through the list of prerequisite edge's for the %-meta.
X * Build each prerequisite in turn, and then see if it needs to be
X * inferred. We treat the edge that has NO prerequisites last, as
X * it gives a recipe for making a %-meta from no prerequisites, and
X * we should really check all NON-NULL prerequisites first.
X */
X edge = meta->CE_EDGES;
X edge_noprq = NIL(EDGE);
X
X do {
X pedge = edge;
X
X if( edge->ed_prq == NIL(CELL) )
X edge_noprq = edge;
X else {
X HASHPTR thp; /* temporary hash table pointer */
X HASH iprqh; /* hash cell for new prerequisite */
X CELL iprq; /* inferred prerequisite to look for */
X CELLPTR sdir; /* local setdir root for inference */
X STRINGPTR sp = NIL(STRING); /* pointer to rcp of inferred target*/
X int ipush = 0; /* flag for push on inferred prereq */
X char *name = edge->ed_prq->CE_NAME;
X int _dmax_fix;
X
X DB_PRINT( "inf", ("Trying edge from [%s] to [%s] for [%s]",
X meta->CE_NAME, name, cp->CE_NAME) );
X
X _trans = Transitive &&
X !((Glob_attr | edge->ed_prq->ce_attr) & A_NOINFER);
X
X /* Set the temp CELL used for building prerequisite candidates to
X * all zero so that we don't have to keep initializing all the
X * fields. */
X {
X register char *s = (char *) &iprq;
X register int n = sizeof(CELL);
X while( n ) { *s++ = '\0'; n--; }
X }
X
X
X /* Build the prerequisite name from the %-meta prerequisite given
X * for the %-meta rule. */
X iprqh.ht_name = _build_name( cp->CE_NAME, name, pdfa->dl_per );
X if( strcmp(cp->CE_NAME, iprqh.ht_name) == 0 )
X goto try_next_edge;
X if((_dmax_fix = (_count_dots(name)-_count_dots(meta->CE_NAME))) < 0)
X _dmax_fix = 0;
X if( _count_dots(iprqh.ht_name) > _dmax + _dmax_fix )
X goto try_next_edge;
X
X DB_PRINT( "inf", ("Checking prerequisite [%s]", iprqh.ht_name) );
X
X if( Verbose )
X printf( "%s: Trying prerequisite [%s] for [%s]\n", Pname,
X iprqh.ht_name, cp->CE_NAME );
X
X
X /* See if the prerequisite CELL has been previously defined. If
X * it has, then make a copy of it into iprq, and use it to try
X * the inference. We make the copy so that we don't modify the
X * stat of the inferred cell if the inference fails.
X */
X thp = Get_name( iprqh.ht_name, Defs, FALSE, setdirroot );
X if(thp != NIL(HASH)) {
X iprq = *thp->CP_OWNR;
X if( iprq.CE_HOW != NIL(HOW) ) sp = iprq.CE_HOW->hw_recipe;
X }
X else
X iprq.ce_name = &iprqh;
X
X
X /* If the prerequisite has the .SETDIR attr set, then we
X * should try to CD to the directory, if it is really different
X * from the one we are currently in. If the CD fails we ignore
X * the edge and go try another edge.
X */
X sdir = setdirroot;
X if( iprq.ce_dir != NIL(char) )
X if( sdir==NIL(CELL) || sdir->ce_dir != iprq.ce_dir )
X if( ipush = Push_dir(&iprq, TRUE) )
X sdir = &iprq;
X else
X goto try_next_edge;
X
X
X /* Stat the inferred prerequisite.
X */
X if( !(iprq.ce_flag & F_STAT) ) Stat_target( &iprq, FALSE );
X
X
X /* If the STAT succeeded or if the prerequisite has a recipe for
X * making it, then infer it. We may later try to perform a
X * second inference on this prerequisite when we actually go to
X * make it.
X */
X if( (iprq.ce_time != (time_t)0L) || (sp != NIL(STRING)) ) {
X infcell = Def_cell( iprqh.ht_name, setdirroot );
X infcell->ce_flag |= F_REMOVE;
X }
X else
X /* The STAT did not succeed, so call Infer_recipe recursively
X * to see if we know how to make the prerequisite. If it
X * returns not NULL, then we have an inferred prerequisite
X * and we should Define it and attach it to the CELL pointed at
X * by cp. This recursive inference is performed only if
X * Transitive closure is enabled.
X */
X if( _trans ) {
X int _save = _dmax;
X if( !_dmax ) _dmax += _dmax_fix;
X infcell = Infer_recipe( &iprq, iprq.CE_HOW, &top_dfa_stack,
X sdir);
X _dmax = _save;
X
X if( infcell != NIL(CELL) ) {
X /* We found we can make the prerequisite, so make it into
X * a real node. This means, mark it for possible
X * removal, and when you make it into a node make sure
X * you don't clobber the Def_cell name.
X */
X infcell = Def_cell( iprqh.ht_name, setdirroot );
X thp = infcell->ce_name;
X *infcell = iprq;
X infcell->ce_name = thp;
X infcell->ce_flag |= F_REMOVE;
X }
X }
X
X /* If we pushed a directory for the inferred prerequisite then
X * pop it.
X */
X if( ipush ) Pop_dir(FALSE);
X
Xtry_next_edge:
X FREE( iprqh.ht_name );
X }
X
X edge = edge->ed_next;
X }
X while( infcell == NIL(CELL) && edge != meta->CE_EDGES );
X
X
X /* If none of the previous edges were any good, and there was an
X * edge with no prerequsite, then use it.
X */
X if( infcell == NIL(CELL) )
X if( edge_noprq != NIL(EDGE) )
X pedge = edge_noprq;
X else
X pedge = NIL(EDGE);
X else {
X /* We have a match, so make the edge's pointer for the corresponding
X * %-meta target point at the matched prerequisite so that the next
X * time we perform an inference we will check this edge first.
X */
X meta->CE_EDGES = pedge;
X if( !_trans ) infcell->ce_attr |= A_NOINFER;
X }
X
X
X /* If we pushed a dir when we treated this %-meta, then
X * pop it.
X */
X if( push ) Pop_dir(FALSE);
X
X
X /* Need this so that pdfa does not get advanced, and remains pointing
X * to the dfa, that just resulted in a successful match.
X */
X if( pedge != NIL(EDGE) ) break;
X }
X
X
X /* If pedge is not NIL then we have found an edge and possibly inferred
X * a prerequisite. In any case we should definitely attach the recipe to
X * the HOW node of the cell pointed at by cp. If the CELL has no HOW node
X * the we allocate one.
X */
X if( pedge != NIL(EDGE) ) {
X LINKPTR lp;
X HOWPTR nhow, ihow;
X
X DB_PRINT("inf", ("taking edge [%s] to [%s]", pedge->ed_tg->CE_NAME,
X (pedge->ed_prq == NIL(CELL)) ? "(none)":pedge->ed_prq->CE_NAME));
X
X if( Verbose )
X printf("%s: Inferred recipe using edge from [%s] to [%s]\n",
X Pname, pedge->ed_tg->CE_NAME,
X (pedge->ed_prq == NIL(CELL)) ? "(none)":pedge->ed_prq->CE_NAME);
X
X if( how == NIL(HOW) ) {
X /* Get a new HOW node, this should happen only for inferred
X * cells, as such they have no prior HOW node */
X TALLOC( how, 1, HOW );
X cp->CE_HOW = how;
X }
X
X
X /* Attach the recipe to the HOW node. Note that if the %-meta recipe
X * is a :: recipe then we will attach all of the HOW cells belonging to
X * the %-meta :: rule that we matched to the CELL, and we will place
X * them so that they preceed subsequent HOW cells in the list. Under
SHAR_EOF
echo "End of part 15"
echo "File infer.c is continued in part 16"
echo "16" > s2_seq_.tmp
exit 0
More information about the Comp.sources.misc
mailing list