home *** CD-ROM | disk | FTP | other *** search
- /* make - do minimum work to update a file */
-
- #include <stdio.h>
-
- /*---------------------------------------------------------------------------*/
- #ifdef NEVER
- #define DEBUG 1 /* include for debug diagnostics in make() */
- #endif
-
- #define MAXLINE (80*10) /* maximum input line length */
- #define MAXBLOCK 64 /* max number of lines in an action */
- #define MAXDEP 32 /* max number of dependancies */
- #define COMMENT '#' /* delimits a comment */
- #define MAKEFILE "mkfile" /* name of makefile */
- #define OPEN 0x3d /* dos function call to open a file */
- #define CLOSE 0x3e /* dos function call to close a file */
- #define DATETIME 0x57 /* " to get/set file's date & time */
- #define DEFTIME 0x0 /* the default time returned by
- gtime when a file doesn't exist */
-
- /*---------------------------------------------------------------------------
- iswhite(c) evaluates true if c is white space.
- skipwhite(s) skips the character pointer s past any white space
- skipnonwhite(s) skips s past any non-white characters. */
-
- #define iswhite(c) ((c)==' '||(c)=='\t')
- #define skipwhite(s) while(iswhite(*s) ) ++s;
- #define skipnonwhite(s) while(*s&& !iswhite(*s) ) ++s;
-
- /*---------------------------------------------------------------------------
- The entire makefile is read into memory before it's processed.
- It's stored in a binary tree composed of the following structures:
- depends_on and do_this are argv-like arrays of pointers to
- character pointers. The arrays are null terminated so no count is
- required. The time field is a 32 bit long consisting of the date
- and time fields returned from a DOS 0x57 call. The date and time
- are concataneted with the date in the most significant 16 bits and
- the time in the least significant. This way they can be compared
- as a single number.
- */
-
- typedef struct _tn
- {struct _tn *lnode; /* pointer to left sub-tree */
- struct _tn *rnode; /* pointer to right sub-tree */
- char *being_made; /* name of file being made */
- char **depends_on; /* names of dependant files */
- char **do_this; /* Actions to be done to make file */
- long time; /* time & date last modified */
- } TNODE;
-
- /*---------------------------------------------------------------------------*/
-
- static TNODE *Root =0 ; /* root of file-name tree */
- static FILE *Makefile ; /* pointer to opened makefile */
- static int Inputline =0 ; /* current input line number */
- static char *First ="" ; /* default file to make */
-
- extern char *malloc() ; /* from standard library */
- extern char **getblock() ; /* declared in this module */
- extern char *getline() ; /* declared in this module */
- extern TNODE *find() ; /* declared in this module */
-
- /*---------------------------------------------------------------------------*/
-
- char *gmem( numbytes )
- {
- /* Get numbytes from malloc. Print an error message and abort if
- malloc fails, otherwise return a pointer to the memory. */
- extern char *calloc();
- char *p;
-
- if( !( p=calloc(1,numbytes) ))
- err("Out of memory");
- return p;
- }
-
- /*---------------------------------------------------------------------------*/
-
- char **stov(str, maxvect )
- char *str;
- {
- /* "Str" is a string of words separated from each other by white
- space. Stov returns an argv-like array of pointers to
- character pointers, one to each word in the original string.
- The white-space in the original string is replaced with nulls.
- The array of pointers is null-terminated. "Maxvect" is the
- number of vectors in the returned array. The program is
- aborted if it can't get memory.
- */
-
- char **vect, **vp;
-
- vp = vect = (char **) gmem( (maxvect + 1) * sizeof(str) );
- while( *str && --maxvect >= 0 )
- {skipwhite(str);
- *vp++ = str;
- skipnonwhite(str);
- if( *str ) *str++=0;
- }
- *vp=0;
- return (vect);
- }
-
- /*---------------------------------------------------------------------------*/
-
- long gtime( file ) char *file;
- {
- /* Return the time and date for a file.
-
- The DOS time and date are concatenated to form one large
- number. Note that the high bit of this number will be set to 1
- for all dates after 2043, which will cause the date comparisons
- done in make() to fail. THIS ROUTINE IS NOT PORTABLE (because
- it assumes a 32 bit long).
- */
- extern unsigned _rax,_rbx,_rcx,_rdx,_rsi,_rdi,_res,_rds,_doint();
- extern char _carryf,_zerof;
- short handle = 0 ; /* place to remember file handle */
- long time ;
-
- _rds=-1;
- _rax=(OPEN<<8)|0; /* open the file */
- _rdx=(short) file;
- _doint(0x21);
- if(_carryf) return DEFTIME; /* file doesn't exist */
- handle=_rbx=_rax;
- _rax=(DATETIME<<8)|0; /* get the time */
- _doint(0x21);
- if(_carryf) err("DOS returned error from date/time request");
- time=(((long)(_rdx))<<16) | ((long)(_rcx)&0xffffL);
- _rax=CLOSE<<8; /* close the file */
- _doint(0x21);
- if(_carryf) err("DOS returned error from file close request");
- return time;
- }
-
- /*--------------------------------------------------------------------------*/
-
- TNODE *makenode()
- {
- /* Create a TNODE, filling it from the makefile and returning a
- pointer to it. Return NULL if there are no more objects in the
- makefile. */
-
- char *line, *lp;
- TNODE *nodep;
- unsigned date, time;
-
- /* First, skip past any blank lines or comment lines.
- Return NULL if we reach end of file. */
-
- do
- {if( (line=getline(MAXLINE,Makefile)) == NULL) return (NULL);
- } while ( *line == 0 || *line == COMMENT );
-
- /* At this point we've gotten what should be the dependancy
- line. Position lp to point at the colon. */
-
- for( lp = line; *lp && *lp != ':' ; lp++) {}
-
- /* If we find the colon position, adjust lp to point at the first
- non-white character following the colon. */
-
- if( *lp != ':' ) {err( "missing ':'" );} /* This will abort the program */
- else for( *lp++ = 0; iswhite(*lp) ; lp++) {}
-
- /* Allocate and initialize the TNODE */
-
- nodep = (TNODE *) gmem( sizeof(TNODE) );
- nodep->being_made = line;
- nodep->time = gtime( line );
- nodep->depends_on = stov( lp, MAXDEP );
- nodep->do_this = getblock( Makefile );
- #ifdef DEBUG
- printf("making...\n"); pnode(nodep); getchar();
- #endif
- return (nodep);
- }
-
- /*--------------------------------------------------------------------------*/
-
- dependancies()
- {
- /* Manufacture the binary tree of objects to make. First is a
- pointer to the first target file listed in the makefile (i.e.
- the one to make if one isn't explicitly given on the command
- line. Root is the tree's root pointer. */
-
- TNODE *node;
-
- if( node = makenode() )
- {First = node->being_made ;
- if( !tree(node, &Root) )
- err("Can't insert first node into tree !!!\n");
- while( node = makenode() )
- if( !tree( node, &Root ) )
- free( node );
- return 1;
- }
- return 0;
- }
-
- /*---------------------------------------------------------------------------*/
-
- char *getline( maxline, fp )
- FILE *fp;
- {
- /* Get a line from the stream pointed to by fp. "Maxline" is the
- maximum input line size (including the terminating null). A \
- at the end of line is recognized as a line continuation, (the
- lines are concatenated). Buffer space is gotten from malloc.
- If a line is longer than maxline, it is truncated (i.e. all
- characters from the maxlineth until a \n or EOF is encountered
- are discarded. */
-
- static char *buf ;
- register char *bp ;
- register int c, lastc;
-
- /* Two buffers are used. Here, we are getting a worst-case buffer
- that will hold the longest possible line. Later on we'll copy
- the string into a buffer that's the correct size. */
-
- if( !(bp = buf = malloc(maxline)) )
- return NULL;
-
- while(1)
- {/* Get the line from fp. Terminate after maxline characters
- and ignore \n following a \ */
-
- Inputline++; /* update input line number */
- for( lastc=0; (c = filter(fp)) != EOF && c!='\n'; lastc = c)
- if( --maxline > 0)
- *bp++ = c;
- if( !( c == '\n' && lastc == '\\' ) )
- break;
- else if( maxline > 0) /* erase the \ */
- --bp;
- }
- *bp=0;
-
- if( (c == EOF && bp == buf) || !(bp = malloc((bp-buf)+1)) )
- {
- /* If EOF was the first character on the line or
- malloc fails when we try to get a buffer, quit. */
-
- free(buf);
- return (NULL);
- }
-
- strcpy ( bp, buf ); /* Copy the worst-case buffer to the one
- that is the correct size and... */
- free ( buf ); /* free the original, worst-case buffer, */
- #ifdef DEBUG
- /* printf("line %d: \n",Inputline); */
- #endif
- return ( bp ); /* returning a pointer to the copy. */
- }
-
- /* With DeSmet C, the program hiccups unless CRs are filtered out */
- filter(fp) FILE *fp;
- { int c;
- while((c=fgetc(fp))=='\015') {}
- return c;
- }
-
- /*---------------------------------------------------------------------------*/
-
- char **getblock( fp )
- FILE *fp;
- {
- /* Get a block from standard input. A block is a sequence of lines
- terminated by a blank line. The block is returned as an array
- of pointers to strings. At most MAXBLOCK lines can be in a
- block. Leading white space is stripped. */
-
- char *p, *lines[MAXBLOCK], **blockv=lines ;
- int blockc = 0;
-
- do {if( !( p = getline(MAXLINE,Makefile) ))
- break;
- skipwhite(p);
- if( ++blockc <= MAXBLOCK )
- *blockv++ = p;
- else
- err("action too long (max = %d lines)", MAXBLOCK);
- } while ( *p );
-
- /* Copy the blockv array into a safe place. Since the array
- returned by getblock is NULL terminated, we need to increment
- blockc first. */
-
- blockv = (char **) gmem( (blockc + 1) * sizeof(blockv[0]) );
- movmem( lines, blockv, blockc * sizeof(blockv[0]) );
- blockv[blockc]=NULL;
-
- return blockv;
- }
-
- /* move n bytes from s to t */
- movmem(s,t,n) char *s,*t; int n;
- { while(n--) *t++=*s++;
- }
- /*---------------------------------------------------------------------------*/
-
- err( msg, param)
- char *msg;
- {
- /* Print the error message and exit the program. */
-
- fprintf(stderr,"Mk (%s line %d): ",MAKEFILE, Inputline );
- fprintf(stderr, msg, param );
- exit(1);
- }
-
- serr( msg, param )
- char *msg, *param;
- {
- /* Same as err() except the parameter is a string pointer
- instead of an int. */
-
- fprintf(stderr,"Mk (%s line %d): ", MAKEFILE, Inputline );
- fprintf(stderr, msg, param );
- exit(1);
- }
-
- /*---------------------------------------------------------------------------*/
-
- make(what)
- char *what;
- {
- /* Actually do the make. The dependancy tree is descended
- recursively and if required, the dependancies are adjusted.
- Return 1 if anything was done, 0 otherwise. */
-
- TNODE *snode ; /* source file node pointer */
- TNODE *dnode ; /* dependant file node pointer */
- int doaction = 0 ; /* if true do the action */
- static char *zero = (char *) 0 ;
- char **linev = &zero ;
-
- #ifdef DEBUG
- static int recurlev = 0 ; /* recursion level */
- printf("make (lev %d): making <%s>\n",recurlev, what);
- #endif
-
- if( !(snode = find(what, Root)) )
- serr("Don't know how to make source <%s>\n", what );
-
- if( !*(linev = snode->depends_on)) /* If no dependancies */
- doaction++; /* always do the action */
-
- for( ; *linev ; linev++ ) /* Process each dependancy */
- {
- #ifdef DEBUG
- recurlev++;
- #endif
- make( *linev );
- #ifdef DEBUG
- recurlev--;
- #endif
- if( !(dnode = find(*linev, Root)) )
- serr("Don't know how to make dependent <%s>\n", *linev );
- #ifdef DEBUG
- printf("make (lev %d): source file ",recurlev);
- ptime( what, snode->time);
- printf("make (lev %d): dependant file ",recurlev);
- ptime( *linev, dnode->time );
- #endif
- if( snode->time <= dnode->time )
- {
- /* If source node is older than (time is less than)
- dependant node, do something. If the times are
- equal, assume that neither file exists but that
- the action will create them, and do the action */
- #ifdef DEBUG
- printf("make (lev %d): %s older than %s\n",
- recurlev, what, *linev );
- #endif
- doaction++;
- }
- #ifdef DEBUG
- else printf("make (lev %d): %s younger than %s\n",
- recurlev, what, *linev);
- #endif
- }
- if (doaction )
- {
- #ifdef DEBUG
- printf("make (lev %d): doing action:\n",
- recurlev, *linev, what);
- #endif
- for( linev = snode->do_this; *linev; linev++ )
- {printf("%s\n", *linev); /* echo action to screen */
- if( system(*linev) )
- serr("Can't process <%s>\n", *linev );
- /* Change the source file's time to
- reflect any modification */
- snode->time = gtime( snode->being_made );
- }
- }
- #ifdef DEBUG
- printf("make (lev %d): exiting\n", recurlev );
- #endif
- return doaction;
- }
-
- /* system() isn't supplied in the DeSmet library.
- This implementation by J. R. Van Zandt */
- static char *(extension[])={".COM",".EXE",".BAT"};
-
- system(s) char *s;
- { int i;
- char program[40],directory[30],path[200];
- char *tail,*dp,*pp;
- FILE file;
-
- tail=s;
- skipnonwhite(tail);
- if(*tail)
- {*tail++=0;
- envsearch("path",path);
- pp=path;
- dp=directory;
- while(1)
- {*dp=0;
- /* We don't permit i=2 because exec() can't execute a .BAT file */
- for (i=0; i<2; i++)
- {program[0]=0;
- if(directory[0])
- {strcat(program,directory);
- strcat(program,"\\");
- }
- strcat(program,s);
- strcat(program,extension[i]);
- if(file=fopen(program,"r")) break;
- }
- if(file)break;
- if( !(*pp) ) return (-1);
- dp=directory;
- while(*pp && *pp!=';') *dp++=*pp++; /* copy next directory in path */
- if(*pp) pp++;
- }
- fclose(file);
- return exec(program,tail);
- }
- else return 0;
- }
-
- /* envsearch - search environment for given string
-
- usage...
- char buf[25];
- envsearch("ALPHA",buf); puts value of the environment
- variable ALPHA into buf
- */
-
- envsearch(target,value) char *target,*value;
- { char buf[100],*s,t[25],*env;
- int nt,offset;
-
- s=t;
- while(*target) *s++=toupper(*target++);
- *s++= '='; *s=0;
- nt = strlen(t);
- offset=0;
-
- /* DeSmet C sets up cs register to point 100H past the Program Segment
- Prefix. The word at offset 44 in the PSP points to the segment with
- the environment */
-
- _lmove(2,44,_showcs()-0x10,&env,_showds()); /* get env. pointer */
- while(1)
- {_lmove(100,offset,env,buf,_showds()); /* get (part of) env. */
- s=buf;
- if(*s)
- {/* printf("examining entry: %s \n",s); getchar(); */
- if (strncmp(t,s,nt)==0) return (strcpy(value,s+nt));
- }
- else
- {*value=0; /* no value found */
- return;
- }
- offset+=strlen(buf)+1;
- }
- }
-
- /*--------------------------------------------------------------------------*/
-
- /* Tree routines: */
-
- TNODE *find( key, root )
- char *key;
- TNODE *root;
- {
- /* If key is in the tree pointed to by root, return
- a pointer to it, else return 0. */
-
- register int notequal ;
- register TNODE *rval ;
-
- if( !root )
- return 0;
- if( !(notequal = strcmp(root->being_made,key)) )
- return( root );
- return( find( key, (notequal > 0) ? root->lnode : root->rnode) );
- }
-
- /*---------------------------------------------------------------------------*/
-
- tree( node, rootp )
- TNODE *node, **rootp ;
- {
- /* If node's key is in the tree pointed to by rootp, return 0
- else put it into the tree and return 1. */
-
- register int notequal ;
- register TNODE *rval ;
-
- if( *rootp == NULL )
- {*rootp = node;
- return 1;
- }
- if( !(notequal = strcmp( (*rootp)->being_made, node->being_made)))
- return 0;
- return( tree( node, notequal > 0 ? &(*rootp)->lnode
- : &(*rootp)->rnode ) );
- }
-
- /*--------------------------------------------------------------------------*/
-
- main( argc, argv )
- int argc;
- char **argv;
- { /* A stupid version of the Unix make facility */
-
- if( !(Makefile = fopen(MAKEFILE, "r")) )
- err("can't open %s\n", MAKEFILE );
- if( !dependancies() )
- err("Nothing to make");
- else
- make( argc > 1 ? argv[1] : First );
- }
-
-
-
- #ifdef DEBUG
- /*--------------------------------------------------------------------------*/
-
- /* Misc. debugging routines */
-
- ptime( file, t )
- char *file;
- long t;
- {
- /* Print out the time and date field of a TNODE as
- "mm-dd-yy hh:mm:ss"
- File is the file name. */
-
- int date, time;
-
- date = (t >> 16) & 0xffffL ;
- time = t & 0xffffL ;
- printf("%s: file: ",file);
- printf("%02d-%02d-%02d, ", (date >> 5 ) & 0x0f, date & 0x1f,
- 80 + ((date >> 9) & 0x7f) );
- printf ("%02d:%02d:%02d, ", (time >> 11) & 0x1f, (time >> 5) & 0x3f,
- (time << 1) & 0x3d );
- printf("\n");
- }
-
- /*--------------------------------------------------------------------------*/
-
- pnode( node )
- TNODE *node;
- {
- /* Print out the tree node pointed to by "node" */
-
- char **linev;
- printf("+-----------------------------\n" );
- printf("| node at 0x%x\n", node );
- printf("+-----------------------------\n" );
- printf("| lnode = 0x%x, rnode = 0x%x\n" ,node->lnode,node->rnode);
- printf("| time = 0x%lx =\n" , node->time );
- ptime( "", node->time );
- printf("| target = <%s>\n" , node->being_made );
- printf("| dependancies:\n" );
- for( linev = node->depends_on; *linev; printf("|\t<%s>\n", *linev++)) {}
- printf("| actions:\n" );
- for( linev = node->do_this; *linev; printf("|\t<%s>\n", *linev++)) {}
- printf("+-----------------------------\n" );
- }
-
- /*--------------------------------------------------------------------------*/
-
- trav( root )
- TNODE *root;
- {
- /* Do an in-order traversal of the tree, printing the node's
- contents as you go */
-
- if( root == NULL )
- return;
- trav( root->lnode );
- pnode( root );
- trav( root->rnode );
- }
- #endif
-