/* File MAKE.C. */ /* BDS-C Version 1.2 6/14/85 */ #define VERSION "V1.2 6/14/85" /* v 1.2 [bmm] * compatible with DateStamper v 2.0 * fixed relative time display in prtree * coded alloc() and free() in ASM * read entire time&date file on first drive * omit script file if no actual commands to execute */ #include #include "make.h" /* * MAKE - Maintain seperate source files * * SYNOPSIS * MAKE [-f file] [-a] [-n] [-d] [name] ... * f: use 'file' instead of default makefile * a: assume all modules are obsolete (recompile everything) * n: don't recompile, just list steps to recompile * d: debugging (print tree, file info) * name: module name to recompile * * 'secret' options (not to be used by humans): * -ofile 'file' is the script file to write to * * AUTHOR * Landon M. Dyer, Atari Inc. * * MODIFICATIONS * Neil Maron: Converted to CP/M 80 (tm), BDS-C(tm), using * DateStamper(tm). * v 1.2 Bridger Mitchell (Plu*Perfect Systems) */ #define SCRIPTFILE "make$$$$.sub" /* (default) script-listing file */ #define INIT "~INIT" /* initialization macro */ #define DEINIT "~DEINIT" /* de-init macro */ #define BEFORE "~BEFORE" /* the per-root 'startup' method */ #define AFTER "~AFTER" /* the per-root 'wrapup' method */ #define BATCH "~BATCH" /* the batch processor to run */ /*MACRO *mroot;*/ /* root of macro-list */ /*FILENODE *froot;*/ /* root of filenode-list */ FILENODE *firstf; /* the very first filenode */ char mkfpbuf[BUFSIZ]; /* output file buffer */ FILE *mkfp; /* script file */ char *modnames[MAXMODS]; /* module-names mentioned in commandline */ int modcount; /* #of module-names */ int debug; /* nonzero: turn on debugging */ int obsolete; /* nonzero: every file should be recompiled */ int noscript; /* nonzero: print methods on standard output */ char *scriptf; /* default script file */ /*DATE *bigbang;*/ /* a date, the very earliest possible */ /*DATE *endoftime;*/ /* a date, the very last possible */ main(argc, argv) int argc; char **argv; { int arg, i; char *mfile; DATE *adate(); char *gdsadate(); char *m; /* Inits */ mfile=NULL; mroot=NULL; froot=NULL; firstf=NULL; mkfp=NULL; modcount=debug=obsolete=noscript=0; scriptf=SCRIPTFILE; datesdisk = -1; /* signal initial read to getfdate() */ havedates = somechanges = FALSE; /* End of inits */ bigbang = adate("\000\000\000\000\000"); /* init root dates */ endoftime = adate("\377\377\377\377\377"); if (bdos(12) != 0x0022) { printf("\7Requires CP/M 2.2\nAborting\n"); exit(); } /* Get the date for output of version string.*/ ascidate=gdsadate(); if(!ascidate) ascidate="No Date"; printf("MAKE %s on %s\n", VERSION, ascidate); if(argc < 2) { printf("Usage: MAKE [-f file] [-a] [-n] [-d] [name] ...\n"); printf("\tf: use 'file' instead of default MAKEFILE.\n"); printf("\ta: assume all modules are obsolete (recompile everything)\n"); printf("\tn: don't recompile, just list steps to recompile\n"); printf("\td: debugging (print tree, file info)\n"); printf("\tname: module name to recompile\n"); exit(); } for(arg = 1; arg < argc; ++arg) if(*argv[arg] == '-') switch(tolower(argv[arg][1])) { case 'f': if(++arg >= argc || argv[arg][0]=='-') { printf("\7-f needs filename argument.\n"); return; } mfile = argv[arg]; break; case 'a': obsolete = 1; break; case 'n': noscript = 1; break; case 'd': debug = 1; break; case 'o': scriptf = argv[arg] + 2; break; default: printf("Unknown switch: %c\n", argv[arg][1]); break; } else if(modcount < MAXMODS) modnames[modcount++] = argv[arg]; else { printf("Too many module names.\n"); return; } mfilename = (mfile != NULL) ? mfile : "MAKEFILE"; if(fmakesb(mfilename) == -1) printf("Cannot open makefile '%s'.\n", mfilename); if(debug) prtree(); if ((m=gmacro(BATCH)) != NULL && !noscript && somechanges) { execl(m, scriptf,0); printf("Can't start %s\n", m); } exit(1); } /* * Construct dependency tree from the makefile 'fn'. * Figure out what has to be recompiled, and write a script file to do that. */ fmakesb(fn) char *fn; { FILE *fp; char fpbuf[BUFSIZ]; if((fp = fopen(fn, fpbuf)) == ERROR) return -1; fp=&fpbuf; /* BDS-C buffered I/O */ fparse(fp); determ(); fclose(fp); return 0; } /* * Parse the input file, defining macros and building the dependency tree. */ fparse(fp) FILE *fp; { char ibuf[STRSIZ], ebuf[STRSIZ]; char *strp, *tok1, *tok2, *s; FILENODE *lastf; FILENODE *sf; lastf=NULL; for(;;) { if(fgets(ibuf, fp) == NULL) break; mexpand(ibuf, ebuf, STRSIZ, MACCHAR); escape(ebuf, COMCHAR); /* clobber last newline in string */ s = ebuf + strlen(ebuf) - 1; if(s >= ebuf && *s == '\n') *s = '\0'; if(*ebuf == '\t') { addmeth(lastf, ebuf+1); continue; } strp = ebuf; if((tok1 = token(&strp)) == NULL) continue; if((tok2 = token(&strp)) != NULL) if(strcieq(tok2, DEFMAC)) { if(*strp) defmac(tok1, strp); else if(undefmac(tok1) < 0) printf( "Can't undefine macro '%s'\n", tok1); continue; } else if(strcieq(tok2, DEPEND)) { addmeth(lastf, gmacro(AFTER)); lastf = filenode(tok1); if(firstf == NULL) firstf = lastf; lastf->fmake = NULL; addmeth(lastf, gmacro(BEFORE)); lastf->fflag |= ROOTP; while((tok1 = token(&strp)) != NULL) addfile(lastf, tok1); continue; } else addfile(lastf, tok2); do { addfile(lastf, tok1); } while((tok1 = token(&strp)) != NULL); } addmeth(lastf, gmacro(AFTER)); } /* * Determine sequence of recompiles from the creation dates. * If there's anything to recompile, then create a script file of commands. */ determ() { FILENODE *f; int i; char *m; if(firstf == NULL) /* empty tree */ { nochanges(); somechanges = FALSE; return; } if(modcount == 0) examine(firstf, endoftime); else for(i = 0; i < modcount; ++i) { if((f = gfile(modnames[i])) == NULL) { printf("Can't find root '%s'.\n", modnames[i]); continue; } if(f->fflag & ROOTP == 0) { printf("'%s' is not a root!\n", f->fname); continue; } examine(f, endoftime); } if(mkfp != NULL) { if((m = gmacro(DEINIT)) != NULL) { if (mkfp == 1) puts(m); else fputs(m, mkfp); putc('\r', mkfp); putc('\n', mkfp); } if (mkfp != 1) { putc('\032', mkfp); /* CPM e-o-f */ fflush(mkfp); fclose(mkfp); if (!somechanges) { unlink(scriptf); nochanges();} } else if (!somechanges) nochanges(); } else nochanges(); } nochanges() { printf("No changes.\n"); } /* * Examine filenode 'fnd' and see if it has to be recompiled. * 'date' is the last-touched date of the node's father * (or 'endoftime' if its a root file.) * Root files with NO dependencies are assumed not to be up to date. */ examine(fnd, date) FILENODE *fnd; DATE *date; { int rebuildp; NODE *n; rebuildp=0; getdate(fnd); if(fnd->fnode == NULL && fnd->fflag & ROOTP) rebuildp = 1; else for(n = fnd->fnode; n != NULL; n = n->nnext) if(examine(n->nfile, fnd->fdate)) rebuildp = 1; if(rebuildp) recomp(fnd); if(obsolete || laterdt(fnd->fdate, date) >= 0) rebuildp = 1; return rebuildp; } /* * Make sure a filenode gets recompiled. */ recomp(f) FILENODE *f; { FILENODE *sf; char *m; if(mkfp == NULL) { if(noscript) mkfp=1; else if((mkfp = fcreat(scriptf, mkfpbuf)) == NULL) printf("Cannot create: '%s'\n", scriptf); else { mkfp=&mkfpbuf; /* Install current time as a comment in the file. [nm] */ fprintf(mkfp,"; script created from %s at %s\r\n", mfilename,ascidate); } if((m = gmacro(INIT)) != NULL) { if (mkfp == 1) puts(m); else fputs(m, mkfp); putc('\r', mkfp); putc('\n', mkfp); } } if(f->fflag & REBUILT) return; if(f->fmake != NULL) { if (mkfp == 1) puts(f->fmake); else { fputs(f->fmake, mkfp); somechanges = TRUE; } } f->fflag |= REBUILT; } /* * Complain about being out of memory, and then die. */ allerr() { printf("Can't alloc -- no space left (I give up!)\n"); exit(1); } /*-- v 1.2 in csm library --- /* Case independant string equality. * Return TRUE is same, FALSE if not. */ strcieq(str1, str2) char *str1, *str2; { char toupper(); while (*str1 && *str2) if (toupper(*str1++) != toupper(*str2++)) return FALSE; if (*str1 == *str2) return TRUE; return FALSE; } --- --*/