/* pmake -- bring a system of files up to date */ /* Portions copyright 1984 Michael M Rubenstein */ /* Portions copyright 1984 John M Sellens */ /* based on pc-make by John M Sellens. Significant portions have been */ /* copied almost verbatim from pc-make. Mr. Sellens has requested the */ /* following notice be included in all copies of his program: */ /* Written by John M Sellens, April, 1984 Until August, 1984: jmsellens@watrose.UUCP 107 - 180 Brybeck Cres. Kitchener, Ontario N2M 5G4 After August, 1984: c/o 1135 Lansdowne Ave. SW Calgary, Alberta T2S 1A4 (c) Copyright 1984 John M Sellens Permission is granted to use, distribute and/or modify this code unless done for direct commercial profit. If you find these routines useful, modest contributions (monetary or otherwise) will be gratefully accepted. Author's name, address and this notice must be included in any copies. */ #define PGMNAME "pmake" #include #include "pmake.h" int modbit = MODBIT; unsigned submax = SUBMAX; char submit[9] = SUBMIT; struct howrec { char *howcom; struct howrec *nexthow; }; struct deprec { char *name; char *def; /* really struct defnrec * */ struct deprec *nextdep; }; struct defnrec { char *name; int uptodate; int modified; struct deprec *dependson; struct howrec *howto; struct defnrec *nextdefn; }; struct dorec { char *name; struct dorec *nextdo; }; struct setrec { char *name; struct setrec *nextset; }; struct defnrec *defnlist = NULL; struct dorec *dolist = NULL; struct defnrec *initrec = NULL, *finrec = NULL; struct setrec *setlist = NULL; int subsize; int stopOnErr = TRUE; int madesomething; int knowhow; int noinit = FALSE; FILE *outfile; int outnum = 0; char *vars; char *endvars; #ifdef DEBUG int debug = 0; #endif int xargc; char **xargv; char *findvar(); main(argc, argv) int argc; char *argv[]; { static int didsomething = FALSE; char vars_[MAXLVAR + 1]; vars = endvars = vars_; *vars = '\0'; xargc = argc; xargv = argv; init(); /* now fall down the dolist and do them all */ while (dolist != NULL) { madesomething = FALSE; make(dolist->name); didsomething |= madesomething; if (!madesomething) { if (knowhow) fprintf(stderr,"pmake: '%s' is up to date\n",dolist->name); else { fprintf(stderr,"pmake: Don't know how to make '%s'\n", dolist->name); if (stopOnErr) exit(1); } } dolist = dolist->nextdo; } if (didsomething || setlist != NULL) { setdone(); if (finrec != NULL && didsomething) { finrec->uptodate = FALSE; make(".FIN"); } } else { setflg(outfile, "d"); fclose(outfile); exit(1); } fclose(outfile); } init() { static int usedefault = TRUE; static int argind = 0; static int i; static int done = FALSE; extern int optind; extern char *optarg; #ifdef DEBUG #define OPTFLAGS "-DF:IN:O:V:" #else #define OPTFLAGS "-F:IN:O:V:" #endif do { switch (getopt(xargc, xargv, OPTFLAGS)) { #ifdef DEBUG case 'D': /* debug */ ++debug; break; #endif case 'F': /* arg following is a makefile */ if (*optarg == '\0') error("'-f' requires filename"); readmakefile(optarg); usedefault = FALSE; break; case 'I': /* ignore errors on execution */ stopOnErr = FALSE; break; case 'N': if ((submax = atoi(optarg)) == 0) submax = 0xffff; break; case 'V': addvar(optarg); break; case '?': break; case EOF: if (optind < xargc) add_do(xargv[optind++]); else done = TRUE; break; default: error("dryrot -- invalid option parse"); } } while (!done); if (dolist == NULL) add_do(DEFDO); if (usedefault) readmakefile(DEFAULT); opnout(); } opnout() { char outname[13]; if (outnum) { fprintf(outfile, "%s MAKEF%03d\n", submit, outnum); fclose(outfile); } sprintf(outname, "MAKEF%03d.SUB", outnum++); if ((outfile = fopen(outname, "w")) == NULL) error("Cannot create output file"); subsize = 0; #ifdef DEBUG if (debug) setflg(outfile, "e"); #endif delfil(outname); } make(s) char *s; { struct defnrec *defnp; struct deprec *depp; struct howrec *howp; int latest; #ifdef DEBUG if (debug > 1) fprintf(stderr, "***Making %s\n", s); #endif /* look for the definition */ for (defnp = defnlist; defnp != NULL && strcmp(defnp->name, s); defnp = defnp->nextdefn) ; if (defnp == NULL) /* don't know how to make it */ { knowhow = FALSE; latest = getmod(s); if (latest == 0) /* doesn't exist */ { /* but don't know how to make */ fprintf(stderr,"pmake: Can't make '%s'\n",s); if (stopOnErr) exit(1); return NOTTHERE; } else /* exists - assume it's up to date */ { if (latest == CHANGED) { addset(s); return THISRUN; } return latest; /* since we don't know */ } } if (defnp->uptodate) return defnp->modified; /* now make sure everything that it depends on is up to date */ latest = 0; depp = defnp->dependson; while (depp != NULL) { latest = max(make(depp->name),latest); depp = depp->nextdep; } knowhow = TRUE; /* has dependencies -- we know how */ /* if necessary, execute all of the commands to make it */ /* if (out of date) || (depends on nothing) */ if (latest > defnp->modified || defnp->dependson == NULL) { /* make those suckers */ if ((defnp->howto != NULL || defnp->modified == CHANGED) && initrec != NULL) { initrec->uptodate = FALSE; initrec = NULL; make(".INIT"); } for (howp = defnp->howto; howp != NULL; howp = howp->nexthow) { if (subsize >= submax) opnout(); fputs(howp->howcom, outfile); putc('\n', outfile); ++subsize; } if (*s == '.') defnp->modified = (defnp->dependson == NULL) ? THISRUN : latest; else { defnp->modified = THISRUN; addset(s); } defnp->uptodate = TRUE; if (defnp->howto != NULL) /* we had instructions */ madesomething = TRUE; } if (defnp->modified == CHANGED) { addset(s); defnp->modified = THISRUN; defnp->uptodate = TRUE; } return defnp->modified; } add_do(s) char *s; { struct dorec *ptr1, *ptr2; char *getmem(); #ifdef DEBUG if (debug > 1) fprintf(stderr, "***Adding %s to do-list\n", s); #endif ptr1 = getmem(sizeof(struct dorec)); ptr1->name = s; /* okay since only called with */ ptr1->nextdo = NULL; /* an argv or constant */ upcase(ptr1->name); /* now go down the dolist */ if (dolist == NULL) dolist = ptr1; else { ptr2 = dolist; while (ptr2->nextdo != NULL) ptr2 = ptr2->nextdo; ptr2->nextdo = ptr1; } } addset(s) char *s; { struct setrec *setp, *setp2; char *getmem(); if (setlist == NULL) setlist = setp = getmem(sizeof(struct setrec)); else { for (setp = setlist; setp != NULL; setp = setp->nextset) { if (strcmp(s, setp->name) == 0) return; setp2 = setp; } setp2->nextset = setp = getmem(sizeof(struct setrec)); } setp->name = s; setp->nextset = NULL; } readmakefile(s) char *s; { static FILE *fil; static int doneline, pos, i, j, c; char inline[INMAX + 1], info[INMAX + 1]; char *getmem(); static struct defnrec *defnp, *defnp2; static struct deprec *depp, *depp2; static struct howrec *howp, *howp2; if ( (fil = fopen(s,"r")) == NULL) { fprintf(stderr,"pmake: Couldn't open '%s'\n",s); return; } #ifdef DEBUG if (debug > 1) fprintf(stderr, "***Reading make file %s\n", s); #endif while (fgets(inline, INMAX, fil) != NULL) { if (inline[0] == COMMENT) continue; inline[strlen(inline)-1] = '\0'; /* strip trailing newline */ if (inline[0] == '\0') /* ignore blank lines */ continue; if (inline[0] == VARCHAR) { addvar(inline + 1); continue; } xlate(inline); if (inline[0] != '\t') /* start of a new definition */ { upcase(inline); /* get what we're defining into info */ for (pos = 0; isspace(inline[pos]); ++pos) ; i = 0; while (!isspace(inline[pos]) && inline[pos]!='\0') info[i++] = inline[pos++]; info[i] = '\0'; /* get a new struct */ defnp = getmem(sizeof(struct defnrec)); /* add it to the end of defnlist */ if (defnlist == NULL) defnlist = defnp; else { defnp2 = defnlist; while (defnp2->nextdefn != NULL) defnp2 = defnp2->nextdefn; defnp2->nextdefn = defnp; } /* initialize it */ defnp->name = getmem(strlen(info)+1); strcpy(defnp->name,info); if (!noinit && strcmp(info, ".INIT") == 0) { initrec = defnp; defnp->uptodate = TRUE; defnp->modified = THISRUN; } else if (strcmp(info, ".FIN") == 0) { finrec = defnp; defnp->uptodate = TRUE; defnp->modified = THISRUN; } else { defnp->uptodate = FALSE; /* actually unknown */ defnp->modified = getmod(defnp->name); } defnp->dependson = NULL; defnp->howto = NULL; defnp->nextdefn = NULL; /* now go through all of its dependecies */ /* first move past the first name */ /* now loop through those suckers */ doneline = FALSE; while (!doneline) { while (isspace(inline[pos])) pos++; if (inline[pos] == '\0') { doneline = TRUE; continue; } for(i = 0; !isspace(inline[pos]) && inline[pos]!='\0';) info[i++] = inline[pos++]; info[i] = '\0'; /* get a new struct */ depp = getmem(sizeof(struct deprec)); /* add it to the end of deplist */ if (defnp->dependson == NULL) defnp->dependson = depp; else { depp2 = defnp->dependson; while (depp2->nextdep != NULL) depp2 = depp2->nextdep; depp2->nextdep = depp; } depp->name = getmem(strlen(info)+1); strcpy(depp->name,info); depp->nextdep = NULL; } } else { /* a how to line */ if (defnp == NULL) { fprintf(stderr,"pmake: Howto line without a definition:\n"); fprintf(stderr,"pmake: '%s'\n",inline); } /* remove leading & trailing spaces */ for (pos=0;isspace(inline[pos]); pos++); ; for (i=strlen(inline); i>pos && isspace(inline[i-1]); --i) ; /* if there is something there, allocate mem and copy */ if (i > pos) { /* get a new struct */ howp = getmem(sizeof(struct howrec)); /* add it to the end of howlist */ if (defnp->howto == NULL) defnp->howto = howp; else { howp2 = defnp->howto; while (howp2->nexthow != NULL) howp2 = howp2->nexthow; howp2->nexthow = howp; } /* copy command filename */ howp->howcom = getmem(i-pos+1); for(j=0; pos < i;) howp->howcom[j++] = inline[pos++]; howp->howcom[j] = '\0'; howp->nexthow = NULL; } } } } setdone() { static struct setrec *setp; static FILE *setfile; if ((setfile = fopen(SETFILE, "w")) == NULL) error("cannot open set file"); for (setp = setlist; setp != NULL; setp = setp->nextset) { fputs(setp->name, setfile); putc('\n', setfile); } fclose(setfile); } addvar(vdef) char *vdef; { char name[VNAMELEN + 1]; static int i; static char *s; for (s = vdef; isspace(*s); ++s) ; i = 0; for (;issymch(*s); ++s) if (i < VNAMELEN) name[i++] = toupper(*s); name[i] = '\0'; while (isspace(*s)) ++s; if (!name[0]) { fprintf(stderr, "pmake: Illegal variable definition: %s\n", vdef); exit(1); } if (findvar(name) != NULL) return; for (i = 0; name[i];) addchar(name[i++]); addchar('\0'); s = (*s == '=') ? (s + 1) : name; while (*s) addchar(*(s++)); addchar('\0'); *endvars = '\0'; } addchar(c) int c; { if (endvars - vars >= MAXLVAR) error("Variable space exhausted"); *(endvars++) = c; } char *findvar(s) register char *s; { static char *p; if (!*s) return NULL; for (p = vars; *p; p += strlen(p) + 1, p += strlen(p) + 1) if (strcmp(s, p) == 0) return p + strlen(p) + 1; return NULL; } xlate(line) register char *line; { char wkline[INMAX + 1]; static int i, j; static char *p, *q; char name[VNAMELEN + 1]; static int changed; #ifdef DEBUG if (debug >1) fprintf(stderr, "***TRANSLATING: %s\n", line); #endif do { changed = FALSE; strcpy(wkline, line); for (p = wkline, i = 0; *p;) { if (*p != VARCHAR || *++p == VARCHAR) { if (i >= INMAX) { fprintf("pmake: Line too long:\n%s\n", stderr); exit(1); } line[i++] = *(p++); continue; } j = 0; changed = TRUE; for (; issymch(*p); ++p) { if (j < VNAMELEN) name[j++] = toupper(*p); } name[j] = '\0'; if (*p == '%') ++p; if ((q = findvar(name)) == NULL) continue; if (i + (j = strlen(q)) > INMAX) { fprintf("pmake: Line too long:\n%s\n", stderr); exit(1); } strcpy(&line[i], q); i += j; } line[i] = '\0'; } while (changed); #ifdef DEBUG if (debug >1) fprintf(stderr, "***NEW VALUE: %s\n", line); #endif } issymch(c) register int c; { return isalpha(c) || isdigit(c) || c == '-' || c == '_' || c == '.'; }