/* * DMAKE.C * * (c)Copyright 1989 by Matthew Dillon, All Rights Reserved. * * ONLY AN APPROPRIATE AMIGA EXECUTABLE MAY BE DISTRIBUTED. DO * NOT DISTRIBUTE SOURCE! * * This is a new try at makefiles ... read the documentation. */ #include "defs.h" MLIST DepList; /* Dependancies */ short Verbose; short Silent; short LineNo; short XDebug; short ForceAll; short ListOnly; short Order; long SaveLock; char MakeFile[128]; main(ac, av) char *av[]; { short dofirst = 1; short error = 0; NewList(&DepList); strcpy(MakeFile, "DMakefile"); SaveLock = CurrentDir(Lock("", SHARED_LOCK)); { register short i; short notenoughargs = 0; for (i = 1; i < ac; ++i) { register char *ptr = av[i]; if (*ptr != '-') continue; while (*++ptr) { switch(*ptr) { case 's': ++Silent; break; case 'v': ++Verbose; break; case 'd': ++XDebug; break; case 'n': ListOnly = 1; break; case 'a': ForceAll = 1; break; case 'f': if (i + 1 < ac) { strcpy(MakeFile, av[++i]); av[i][0] = '-'; /* kill it */ } else { notenoughargs = 1; } break; } } } if (notenoughargs) { puts("Not enough args for option!"); xexit(20); } } if (!Silent) { puts("DMake Beta V0.6 26-Jan-89"); puts("(c)Copyright 1989 by Matthew Dillon, All Rights Reserved"); } { FILE *fi; if (fi = fopen(MakeFile, "r")) { ScanFile(fi); fclose(fi); } else { printf("Unable to open %s\n", MakeFile); xexit(25); } } { register short i; for (i = 1; i < ac; ++i) { register char *ptr = av[i]; register DEPEND *dep; if (*ptr == '-') continue; dofirst = 0; for (dep = GetHead(&DepList); dep; dep = GetSucc(dep)) { if (strcmp(ptr, dep->Left) == 0) { /* XXX ? */ Order = FindBeginPoint(dep, Order, 1); break; } } if (dep == NULL) { printf("Could not find %s dependancy\n", ptr); error = 10; } } } if (dofirst) { register DEPEND *dep = GetHead(&DepList); if (dep) Order = FindBeginPoint(dep, Order, 1); } CombineRefCnts(NULL); if (XDebug) PrintDepList(&DepList); ExecuteDepList(); xexit(error); } xexit(error) { UnLock(CurrentDir(SaveLock)); exit(error); } ScanFile(fi) FILE *fi; { char *ptr; LineNo = 0; while (ptr = getline(fi, NULL)) { MLIST *cmdlist = malloc(sizeof(MLIST)); NewList(cmdlist); ++LineNo; if (*ptr == 0) { free(cmdlist); continue; } { register char *str = ptr; while ((*str >= 'a' && *str <= 'z') || (*str >= 'A' && *str <= 'Z') || (*str >= '0' && *str <= '9') || *str == '_' || *str == ' ' || *str == '\t') ++str; if (*str == '=') { /* macro assignment */ MacroAssign(ptr, str); continue; } } { short ac; register char **av; register short i; av = parseline(ptr, &ac); for (i = 0; i < ac; ++i) { if (av[i][0] == ':' && av[i][1] == 0) break; } if (i == ac) { /* could be blah: */ register char *str = av[0]; register short len = strlen(str); if (len && str[len-1] == ':') { /* blah: */ str[len-1] = 0; CreateDependancies(cmdlist, av, 0, 1, 1, ac); } else { short cmmnt; printf("Badly formed command line %ld\n", LineNo); while (ptr = getline(fi, &cmmnt)) { if (ptr[0] == 0 && !cmmnt) break; } } } else { CreateDependancies(cmdlist, av, 0, i, i + 1, ac); } } { register NODE *node; short cmmnt; while (ptr = getline(fi, &cmmnt)) { if (ptr[0] == 0 && !cmmnt) break; if (ptr[0]) { node = malloc(sizeof(NODE) + strlen(ptr) + 1); node->ln_Name = (char *)(node + 1); strcpy(node->ln_Name, ptr); AddTail(cmdlist, node); } } } } if (XDebug) PrintDepList(&DepList); } /* * COMBINEREFCNTS() * * All dependancies with the same left hand side are supposed to have * the same (shared) common structure. This ensures they do and is * called after operations which might invalidate the rule. */ CombineRefCnts(newlist) MLIST *newlist; { register DEPEND *d1, *d2; /* * First combine references within a new list, then combine references * from the new list to the master list, then combine references in * the master list. */ if (newlist) { for (d1 = GetHead(newlist); d1; d1 = GetSucc(d1)) { for (d2 = GetSucc(d1); d2; d2 = GetSucc(d2)) { if (strcmp(d1->Left, d2->Left) == 0 && d1->Common != d2->Common) Combine(d1, d2); } } for (d1 = GetHead(newlist); d1; d1 = GetSucc(d1)) { for (d2 = GetHead(&DepList); d2; d2 = GetSucc(d2)) { if (strcmp(d1->Left, d2->Left) == 0 && d1->Common != d2->Common) Combine(d1, d2); /* deplist's gets it */ } } } for (d1 = GetHead(&DepList); d1; d1 = GetSucc(d1)) { for (d2 = GetSucc(d1); d2; d2 = GetSucc(d2)) { if (strcmp(d1->Left, d2->Left) == 0 && d1->Common != d2->Common) Combine(d1, d2); } } } Combine(d1, d2) DEPEND *d1, *d2; { register COMMON *c1 = d1->Common; register COMMON *c2 = d2->Common; if (XDebug) { printf("Combine (%s : %s -> %s : %s) com %08lx %08lx (%ld+%ld) %02lx|%02lx\n", d1->Left, d1->Right, d2->Left, d2->Right, c1, c2, c1->RefCnt, c2->RefCnt, c1->Flags, c2->Flags ); } c2->RefCnt += c1->RefCnt; c2->Flags |= c1->Flags; c1->RefCnt = 0; c1->Flags = 0; d1->Common = c2; } /* * FINDBEGINPOINT() * * The specified left side was requested to execute. Search the list for * common points (left side the same) * * Find those entries whos left sides match this entry's right side * (depth first, recursively) and assign an ordering number. The ordering * number is essential to guarentee proper execution order of dependancies * since their list positions are random. */ FindBeginPoint(db, order, add) register DEPEND *db; { register DEPEND *dep; db->Flags |= DF_ALLOWED; db->Order = order; order += add; for (dep = GetHead(&DepList); dep; dep = GetSucc(dep)) { if (dep->Flags & DF_ALLOWED) continue; if (strcmp(dep->Left, db->Right) == 0) order = FindBeginPoint(dep, order, add); /* DEPTH FIRST */ } for (dep = GetHead(&DepList); dep; dep = GetSucc(dep)) { if (dep->Flags & DF_ALLOWED) continue; if (dep->Common == db->Common) /* BREADTH SECOND */ order = FindBeginPoint(dep, order, add); } return(order); } /* * EXECUTEDEPLIST() * MAIN EXECUTION LOOP * * This is the main execution loop for DMake. It scans the dependancy * list calling appropriate functions, determining associations, and * doing timestamp comparisons if necessary. * * (1) For all dependancies which have yet to be handled by this loop * (DF_DIDTHIS is NOT set). * * (i) does the right side exist as the left side of some other * dependancy? If not * * (ii) unless forced or a wildcard, check the file timestamps * on the left vs right side and set appropriate flags. * * (2) Execution phase. Take the highest priority (lowest Ordered) * dependancy and attempt to execute it. Collect all dependancies * with a common left side. At this time any dependancies marked * DF_EXPANDRIGHT must be expanded (this may result in the reference * count becomming non-zero in which case we must abort the execution * phase until the new dependancies have been resolved). * * If all non-special (the 'meat', not the exhausted wildcarded * dependancies) timestamp flag checks out, execute the command * list. * * */ ExecuteDepList() { register DEPEND *dep, *dp; register short changed = 1; DEPEND *lowdep; if (Verbose == 1) { puts("\nINITIAL DEPLIST"); PrintDepList(&DepList); puts(""); } if (XDebug) puts("ExecuteDepList"); while (changed) { char identchanged = 1; /* * (1) Determine highest priority ready dependancy to execute and * handle datestamp checking. */ changed = 0; if (XDebug) puts("while-changed-loop"); while (identchanged) { if (XDebug) puts("while-ident-changed-loop"); identchanged = 0; lowdep = NULL; for (dep = GetHead(&DepList); dep; dep = GetSucc(dep)) { if (dep->Common->RefCnt < 0 || !(dep->Flags & DF_ALLOWED)) continue; if (!(dep->Flags & DF_DIDTHIS)) { /* * (i) does the right side exist as the left side of * some other dependancy? If not, decrement the * reference count and if a wildcard handle * expansion. */ for (dp = GetHead(&DepList); dp; dp = GetSucc(dp)) { if (strcmp(dep->Right, dp->Left) == 0) break; /* valid references exist */ } if (dp == NULL) { /* don't exist, dec. ref cnt*/ identchanged = 1; --dep->Common->RefCnt; dep->Flags |= DF_DIDTHIS; if (XDebug) printf("EDL1: DECREMENT REF: %s : %s (%08lx) -> %ld\n", dep->Left, dep->Right, dep->Common, dep->Common->RefCnt ); /* * handling expansion. If the right side is a wild * card defer expansion until the execution phase * (2). This is in case files have yet to be * created that will effect the expansion. If not * a wildcard, and not APPLYALL, then we must * expand the left side (a rare occurance but what * if somebody does this?: *.c : charlie) */ if (IsWildCard(dep->Right)) /* defer expansion unless a-a */ dep->Flags |= DF_EXPANDRIGHT; else if (dep->Common->RefCnt == 0) { if (IsWildCard(dep->Left) && !(dep->Flags & DF_APPLYALL)) DirectoryWildScan(dep, NULL, 1); else ;/*AddCollect(dep, dep);*/ } } /* * (ii) * Unless forced or a wildcard, we do a time-date comparison * on the left and right side. If the right side does not * exist as a file, nothing changes. If the right side * DOES exist as a file, the time-date comparison overides * anything propogated from below. This allows: * * $(OBJS) : $(SRCS) * cc .. * * $(SRCS) : ram:symbols.m */ if (!(dep->Flags & DF_OUTDATED) && !ForceAll && IsWildCard(dep->Left) == 0) { short validright; short od = OutDated(dep->Left, dep->Right, &validright); if (Verbose == 2) printf("COMPARE %s : %s, od = %ld vr = %ld\n", dep->Left, dep->Right, od, validright); if (validright && !(dep->Flags & DF_OUTDATED)) { if (od) dep->Flags |= DF_OUTDATED; else dep->Flags |= DF_DATEDOK; } } } if (dep->Common->RefCnt != 0) continue; if (lowdep == NULL || dep->Order < lowdep->Order) lowdep = dep; } } if (Verbose == 1) { puts("\nSTABLE DEPLIST:"); PrintDepList(&DepList); puts(""); } /* * (2) Execution phase. ************** * */ dep = lowdep; if (dep == NULL || dep->Common->RefCnt != 0) continue; changed = 1; if (Verbose) printf("PICKED: %s : %s (seq# %d)\n", dep->Left, dep->Right, dep->Order); /* * References have fallen to zero. We must scan the dependancies * for all common nodes (common to left hand side), combine * various collected variables (i.e. *.c etc..) and do a single * execution run. * * But, if a right hand side is a wildcard and therefore has * not been determined yet, we must do a DirectoryWildScan() * and if the refcnt is no longer 0 abort the execution. */ if (XDebug) { printf("\nEDL: Refs have fallen to 0 %s : %s (%08lx)\n", dep->Left, dep->Right, dep->Common ); PrintDepList(&DepList); } { MLIST exelist; DEPEND *nextdp; char numdatedok = 0; char numdeps = 0; NewList(&exelist); for (dp = GetHead(&DepList); dp; dp = nextdp) { nextdp = GetSucc(dp); /* * Gather the common entries together into a list. * Look at the time stamp information and handle that. * Collect all non-wildcarded entries into a separate list * in preparation for execution. */ if (dep->Common == dp->Common && (dp->Flags & DF_DIDTHIS)) { if (XDebug) printf("ready exe date: %s : %s %02lx\n", dp->Left, dp->Right, dp->Flags & DF_DATEDOK); if (dp->Flags & DF_EXPANDRIGHT) { dp->Flags &= ~DF_EXPANDRIGHT; DirectoryWildScan(dp, NULL, 0); } if (IsWildCard(dp->Right)) { if (XDebug) printf("Warn: IsWildCard! %s : %s\n", dp->Left, dp->Right); } else { /* remove into separate list */ ++numdeps; if ((dp->Flags & DF_DATEDOK) && !(dp->Flags & DF_OUTDATED)) ++numdatedok; Remove(dp); AddTail(&exelist, dp); } } } /* * If there are any dependancies in the list, the reference * count is still 0, the left side is not a wildcard, and the * date doesn't checkout, execute the list. Set the common * flags according to whether the list was executed or not * (propogation upwards of the timestamp comparison results). */ if (dep->Common->RefCnt == 0 && GetHead(&exelist) && !IsWildCard(dep->Left)) { if (numdeps != numdatedok || numdeps == 0) { ExecuteCmdCollection(&exelist); dep->Common->Flags |= DF_OUTDATED; } else { dep->Common->Flags |= DF_DATEDOK; } } while (dp = RemHead(&exelist)) AddTail(&DepList, dp); } /* * RefCnt != 0, abort cleanup */ if (dep->Common->RefCnt != 0) continue; dep->Common->RefCnt = -1; /* RAN! */ /* * After execution has completed, decrement any occurances * of our left side (now complete) on the right of other * dependancies. */ for (dp = GetHead(&DepList); dp; dp = GetSucc(dp)) { if (strcmp(dep->Left, dp->Right) == 0 && !(dp->Flags & DF_DIDTHIS)) { --dp->Common->RefCnt; dp->Flags |= DF_DIDTHIS; if (XDebug) printf("EDL2: DECREMENT REF (RHR): %s : %s (%08lx) -> %ld\n", dp->Left, dp->Right, dp->Common, dp->Common->RefCnt ); /* * If all of the dependancies for dep->Left had a valid * time (nothing needed to be executed), propogate the * information upwards. */ dp->Flags |= dep->Common->Flags & (DF_DATEDOK | DF_OUTDATED); if (Verbose == 2) { if (dep->Common->Flags & DF_OUTDATED) printf("Propogate outdated (%s:%s) -> (%s:%s)\n", dep->Left, dep->Right, dp->Left, dp->Right); else if (dep->Common->Flags & DF_DATEDOK) printf("Propogate date ok (%s:%s) -> (%s:%s)\n", dep->Left, dep->Right, dp->Left, dp->Right); } if (IsWildCard(dp->Right)) /* defer expansion ??APPLYALL */ dp->Flags |= DF_EXPANDRIGHT; if (dp->Common->RefCnt == 0) { if (IsWildCard(dp->Left) && !(dp->Flags & DF_APPLYALL)) DirectoryWildScan(dp, NULL, 1); } } if (XDebug) PrintDepList(&DepList); } } if (XDebug) { puts("ExecuteDepList End"); PrintDepList(&DepList); } } /* * ExecuteCmdCollect() * * Given a list of dependancies (all with the same left side), add * their right sides into the %(variable) table under the name * specified by their collection entry. This is how all those object * modules in all : *.o get combined to so the programmer can * specify %(*.o) in the command list. * */ ExecuteCmdCollection(list) MLIST *list; { register DEPEND *dep = GetHead(list); if (XDebug) { printf("EXECUTE %s :", dep->Left); for (; dep; dep = GetSucc(dep)) printf("<%s> ", dep->Right); puts(""); } ResetVarCollector(); for (dep = GetHead(list); dep; dep = GetSucc(dep)) { if (dep->ColDep) AddVarCollector(dep->Right, dep->ColDep->Right, 1); else AddVarCollector(dep->Right, dep->Right, 1); AddVarCollector(dep->Right, "right", 0); } dep = GetHead(list); AddVarCollector(dep->Left, "left", 0); ExecuteCmdList(dep->CmdList); } /* * Test if a file contains a wildcard or not. */ IsWildCard(str) register char *str; { while (*str) { if (*str == '*' || *str == '?') return(1); ++str; } return(0); } /* * DirectoryWildScan(dep, autolist, scanleft) * * This is the major wildcard dependancy handling call. * * (1) If we have *.o : which is flagged DF_APPLYALL (any must * depend on each derived .o file), we cannot handle the dependancy * at this point so we undo the DF_DIDTHIS flag and return. * * (2) Either the right side is expanded and the left side derived or * the left side is expanded and the right side derived. When one * side is expanded, if the other side is NOT a wildcard it is left * alone ( all:*.c -> all:a.c, all:b.c, all:c.c etc.. ). * * (3) * */ DirectoryWildScan(dep, autolist, scanleft) DEPEND *dep; MLIST *autolist; { MLIST DList; register DEPEND *dp; short iswcleft = IsWildCard(dep->Left); if (XDebug) printf("DirectoryWildScan: %s : %s (%ld)\n", dep->Left, dep->Right, scanleft); NewList(&DList); /* * (1) Unless scanleft is set (set when we must expand ONE side because * it *IS* DF_APPLYALL, i.e. *.c : *.h -> a.c : *.h, b.c : *.h), * we defer DF_APPLYALL operation until all other associated * dependancies have been resolved. Otherwise we would be forced * to evaluate the left-side wildcard too early .. perhaps before * the files have been created. */ if (!scanleft && iswcleft && (dep->Flags & DF_APPLYALL)) { ++dep->Common->RefCnt; dep->Flags &= ~DF_DIDTHIS; return(0); } /* * (2) Expand either the left side or the right side. Do either * a directory scan or use a predetermined list. Handle the * three cases: :, :, * * The only time : will occur is with the DF_APPLYALL * case. */ { char *left = (iswcleft) ? dep->Left : dep->Right; char *right= (scanleft) ? dep->Left : dep->Right; if (autolist) AutoExpandRightSide(&DList, left, right, autolist); else ExpandRightSide(&DList, left, right); /* * if not wc must set left side all the same (cause we did a hack * above so we could call the Virtuo routine). Also, assign the * * if scanleft (left side guarenteed to be a wildcard), we need * to set the right side all the same (cause... ) */ for (dp = GetHead(&DList); dp; dp = GetSucc(dp)) { dp->Flags |= DF_ALLOWED; dp->Order = dep->Order; if (iswcleft == 0) dp->Left = dep->Left; else if (scanleft) dp->Right= dep->Right; AddCollect(dp, dep); } CombineRefCnts(&DList); /* combine reference counts for new left sides */ } /* * (3) If the left side is not a wildcard we are done for now. */ if (XDebug) puts("Main Combinational complete"); if (iswcleft == 0) { if (XDebug) puts("Left side not wc, end"); while (dp = RemHead(&DList)) { dp->CmdList = dep->CmdList; Order = FindBeginPoint(dp, Order, 1); AddTail(&DepList, dp); } return(1); } /* * (3) If the left side IS a wildcard, then scan the list for two cases * (a) if the left wildcard appears on the LEFT side of any other * dependancy in which DF_APPLYALL is set, we must break up * those dependancies. * * *.o : *.c *.h -> *.o : *.c and *.o : *.h (APPLYALL), * when *.o : *.c is resolved in (1)&(2), we must break up * the apply all case *.o : *.h -> a.o : *.h, b.o : *.h * etc... * * (b) if the left wildcard appears on the RIGHT side of any * other dependancy we must expand them as well: * * all : *.o * *.o : *.c when *.o : *.c is resolved, we must also * resolve all : *.o -> all : a.o, all : b.o * * NOTE: all : *.o is allowed to DF_DIDTHIS since several * dependancies might reference it: * * *.o : *.c * *.o : *.asm * * There are THREE cases in this expansion. (i) the left side * of the found dep (i.e. all : *.o in the example above) is * NOT a wildcard (simple). (ii) the left side IS a wildcard * and DF_APPLYALL is set, (iii) the left side IS a wildcard * and DF_APPLYALL is not set. * * (i) all : *.o -> all : a.o, all : b.o * (ii) *.x : *.h -> *.x : mike.h, *.x : ben.h * ^DF_APPLYALL (ii) * (iii) *.x : *.o -> a.x : a.o, b.x : b.o */ for (dp = GetHead(&DepList); dp; dp = GetSucc(dp)) { /* * (3a) */ if (strcmp(dep->Left, dp->Left) == 0 && (dp->Flags & DF_APPLYALL)) { DEPEND *dp2, *newdep; if (!(dp->Flags & DF_DIDTHIS)) { --dp->Common->RefCnt; dp->Flags |= DF_DIDTHIS; } dp->Flags &= ~(DF_APPLYALL | DF_EXPANDRIGHT); if (XDebug) printf("DidThis FLAG SET (DWS1) for %s : %s (%ld)\n", dp->Left, dp->Right, dp->Common->RefCnt ); /* * For each expanded left side, generate left : wildright */ for (dp2 = GetHead(&DList); dp2; dp2 = GetSucc(dp2)) { newdep = MakeOneDepend(dp2->Common, &DepList, dp2->Left, dp->Right); newdep->Order = dp2->Order; newdep->Flags |= DF_ALLOWED; newdep->CmdList = dp->CmdList; AddCollect(newdep, dp); if (XDebug) printf("*** Created APPLYALL dep: %s : %s\n", newdep->Left, newdep->Right); } } /* * If our wild left side appears on the right side of anybody * else, we must expand them. How we expand them depends whether * they are wildcarded &| APPLYALL. * * (3b.i,ii,iii) */ if (strcmp(dep->Left, dp->Right) == 0 && (dp->Flags & DF_ALLOWED)) { if (XDebug) printf("DidThis FLAG SET (DWS2) for %s : %s (%ld)(%08lx)\n", dp->Left, dp->Right, dp->Common->RefCnt, dp ); if (!(dp->Flags & DF_DIDTHIS)) { if (XDebug) printf("SET %08lx ref %08lx\n", dp, dp->Common); --dp->Common->RefCnt; dp->Flags |= DF_DIDTHIS; } else { if (XDebug) printf("NOTSET %08lx ref %08lx\n", dp, dp->Common); } if (dp->Common->RefCnt < 0) { puts("INTERNAL ERROR #Directory-1"); xexit(30); } /* * (3b. i, ii, iii). Here (i) is taken care of by checking * if the left side is a wildcard... we skip the if. Inside * the if (ii) and (iii) are handled. */ if (IsWildCard(dp->Left)) { /* create mult refs to mult objects */ /* * (ii) APPLYALL flagged */ if (dp->Flags & DF_APPLYALL) { DEPEND *dp2, *newdep; if (!(dp->Flags & DF_DIDTHIS)) { dp->Flags |= DF_DIDTHIS; --dp->Common->RefCnt; for (dp2 = GetHead(&DList); dp2; dp2 = GetSucc(dp2)) { newdep = MakeOneDepend(dp->Common, &DepList, dp->Left, dp2->Left); newdep->Order = dp->Order; if (XDebug) printf("Common: %s : %s now %d\n", dp->Left, dp->Right, dp->Common->RefCnt); newdep->Flags |= DF_ALLOWED | DF_APPLYALL; newdep->CmdList = dp->CmdList; AddCollect(newdep, dp); /* RefCnt must be stable */ } } } else { /* * (iii) *.o : *.c -> a.o : a.c, b.o : b.c etc... * Simple recurse. */ DirectoryWildScan(dp, &DList, 0); } } else { /* create multiple refs to one object */ /* * (i) left side is not a wildcard, all : *.o */ DEPEND *dp2, *newdep; for (dp2 = GetHead(&DList); dp2; dp2 = GetSucc(dp2)) { newdep = MakeOneDepend(dp->Common, &DepList, dp->Left, dp2->Left); newdep->Order = dp->Order; if (XDebug) printf("Common: %s : %s now %d\n", dp->Left, dp->Right, dp->Common->RefCnt); newdep->Flags |= DF_ALLOWED; newdep->CmdList = dp->CmdList; AddCollect(newdep, dp); /* RefCnt must be stable */ } } } } /* * For each of the new dependancies, FindBeginPoint() them (to handle * special cases for wildcarded objects) and add them to the main list. * Also note that we must CombineRefCnts() to combine the common * structures (all dependancies with the same left side must point * to the same shared common structure). * * (4) i.e. you have *.o : *.c and also have a special case like * charlie.o : cook_takes_the_cake * */ CombineRefCnts(&DList); while (dp = RemHead(&DList)) { dp->CmdList = dep->CmdList; FindBeginPoint(dp, dep->Order, 0); AddTail(&DepList, dp); } return(1); } /* * AutoExpandRightSide() * * This routine works like ExpandRightSide(), but instead of scanning a * directory it derives the results from a passed list of dependancies. * The reasoning behind this follows: ram:*.o : *.c , DMake will * scan the directory for *.c and derive ram:*.o without scaning ram:. * After all, there might be additional .o files in ram: that we do NOT * want to include. * * The previously found file's left side matches the new right side. */ AutoExpandRightSide(newlist, left, right, oldlist) MLIST *newlist; char *left; char *right; MLIST *oldlist; { register DEPEND *dp; if (XDebug) printf("AutoExpandRightSide %s : %s\n", left, right); for (dp = GetHead(oldlist); dp; dp = GetSucc(dp)) { MakeOneDepend(NULL, newlist, VirtuoExpand(left, right, dp->Left), dp->Left); } if (XDebug) puts("AutoExpandRightSide done"); } /* * ExpandRightSide() * * This routine does a directory scan of the right side and creates * a set of dependancies, placing them in the specified list. */ ExpandRightSide(newlist, left, right) MLIST *newlist; char *left; char *right; { char *ptr; int ac; register char **av; register short i; char **expand(); if (XDebug) printf("ExpandRightSide <%s> : <%s>\n", left, right); av = expand(right, &ac); if (XDebug) { for (i = 0; i < ac; ++i) printf("(%s)", av[i]); puts(""); } for (i = 0; i < ac; ++i) MakeOneDepend(NULL, newlist, VirtuoExpand(left, right, av[i]), av[i]); if (XDebug) puts("ExpandRightSide done"); } /* * VirtuoExpand("x*.poof", "*.o", "charlie.o") -> xcharlie.poof * * This converts a filename from one name to another using the two * provided wildcards (old and new). */ char * VirtuoExpand(newwc, oldwc, filename) register char *newwc, *oldwc, *filename; { char *newbase = newwc; if (XDebug) printf("VEIN: <%s> <%s> <%s>\n", newwc, oldwc, filename); { /* skip non-wildcards */ register char *old = oldwc; register char *name = filename; while (*old && *old != '*' && *old != '?') { if (*name != *old) /* failure! */ return(NULL); ++name; ++old; } oldwc = old; filename = name; } { /* skip non wildcards in new */ register char *new = newwc; while (*new && *new != '*' && *new != '?') ++new; newwc = new; } if (*newwc != *oldwc) /* new pattern must match old */ return(NULL); if (*oldwc == 0 && *filename == 0) return(newbase); /* success! */ /* * at this point, *oldwc == *newwc == '*' or '?' */ if (*oldwc == '?') { /* match a single char in *filename */ char *last = VirtuoExpand(newwc + 1, oldwc + 1, filename + 1); char *str; short i; if (!last) return(NULL); /* * combine (newbase..newwc) with *filename with last */ i = newwc - newbase; str = malloc(i + strlen(last) + 2); movmem(newbase, str, i); str[i] = *filename; strcpy(str+i+1, last); return(str); } /* * *oldwc == *newwc == '*', we must try to match all or part of * the remaining filename. */ { char *fi = filename + strlen(filename); while (fi >= filename) { char *last; char *str; short i, j; if (last = VirtuoExpand(newwc + 1, oldwc + 1, fi)) { /* * combine (newbase..newwc with filename..fi with last */ i = newwc - newbase; j = fi - filename; str = malloc(i + j + strlen(last) + 1); movmem(newbase, str, i); movmem(filename, str + i, j); strcpy(str + i + j, last); return(str); } --fi; } } return(NULL); } /* * CreateDependancies() * * Given a just-parsed line from the initial file scan, this routine * breaks it up into individual dependancies with a left and right side. * * It is pretty straight forward (see the dmake rules). Note that the * APPLYALL flag must be set for dependancies like this: * *.o : *.c *.h (set APPLYALL for *.o : *.h to prevent * it from being misinterpreted later) * * each .c files depends on its .o file, but each .o files depends on * ALL the .h files. */ CreateDependancies(cmdlist, av, ls, le, rs, re) MLIST *cmdlist; char **av; short ls, le, rs, re; { register short i; MLIST deplist; NewList(&deplist); if (Verbose == 4) { printf("CreateDependancies %08lx %08lx %ld %ld %ld %ld\n", cmdlist, av, ls, le, rs, re ); for (i = 0; i + ls < le; ++i) printf("left: %08lx <%s>\n", av[ls+i], av[ls+i]); for (i = 0; i + rs < re; ++i) printf("rght: %08lx <%s>\n", av[rs+i], av[rs+i]); } for (i = 0; ls + i < le && rs + i < re; ++i) { MakeOneDepend(NULL, &deplist, av[ls+i], av[rs+i]); } while (ls + i < le) { /* only left guys remain */ if (rs == re) { /* special case, right side was empty */ MakeOneDepend(NULL, &deplist, av[ls + i], NULL); } else if (rs + 1 == re) { MakeOneDepend(NULL, &deplist, av[ls + i], av[rs]); } else { printf("Error line %ld. Under normal conditions one has the\n", LineNo); puts("same number of dependancies on the left as on the right,"); puts("or more on the right. The only two cases allowed for more"); puts("on the left is when the right has 0 or 1 arguments"); xexit(25); } ++i; } { /* only right guys remain. Make all left's dep. on them. */ /* note: operation must be defered for wildcards on left */ register DEPEND *dbase = GetTail(&deplist); if (dbase) { while (rs + i < re) { register DEPEND *dep, *new; for (dep = dbase; dep; dep = GetPred(dep)) { new = MakeOneDepend(dep->Common, &deplist, dep->Left, av[rs + i]); if (IsWildCard(new->Left) /*&& !IsWildCard(new->Right)*/) new->Flags |= DF_APPLYALL; } ++i; } } } { register DEPEND *dep; while (dep = RemHead(&deplist)) { dep->CmdList = cmdlist; AddTail(&DepList, dep); } } } /* * MakeOneDepend() * * Note: the fact that it adds to the tail of the list is counted on in * an earlier routine. This creates a new dependancy. Note, however, * that the common node might be allocated thus invalidating the rule * that all dependancies with the same dep->Left have the same common * structure. This is dealt with by calling CombineRefCnts(). */ DEPEND * MakeOneDepend(common, list, left, right) register COMMON *common; MLIST *list; char *left; char *right; { register DEPEND *dep = malloc(sizeof(DEPEND)); if (!common) { common = malloc(sizeof(COMMON)); clrmem(common, sizeof(COMMON)); } clrmem(dep, sizeof(DEPEND)); ++common->RefCnt; dep->Common = common; dep->Left = left; dep->Right= (right) ? right : ""; AddTail(list, dep); if (XDebug) printf("MakeOneDepend dep %08lx com %08lx %d %s : %s\n", dep, common, common->RefCnt, left, right); return(dep); } /* * ADDCOLLECT() * * Set dep's collection to dp (always dp->Right). I.E. when you have * something like: *.o : *.c *.h, cc %(*.c) -o %(left). The individual * C files get placed in the *.c collection one at a time so they can be * referenced by a % variable */ AddCollect(dep, dp) register DEPEND *dep; DEPEND *dp; { dep->Flags |= DF_COLLECT; dep->Common->Flags |= DF_COLLECT; dep->ColDep = dp; } /* * low level routines */ char LineBuf[4096]; char * getline(fi, pcmmnt) FILE *fi; short *pcmmnt; { register short i = 0; if (pcmmnt) *pcmmnt = 0; while (fgets(LineBuf + i, sizeof(LineBuf) - i, fi)) { if (i == 0 && LineBuf[i] == '#') { LineBuf[i] = 0; if (pcmmnt) *pcmmnt = 1; } i += MacroReplace(0, LineBuf + i, strlen(LineBuf + i)); while (i-- && (LineBuf[i] == '\n' || LineBuf[i] == '\t' || LineBuf[i] == ' ')) LineBuf[i] = 0; if (LineBuf[i] == '\\') /* line continuance */ continue; if (XDebug) printf("LINE: %s\n", LineBuf); return(LineBuf); } return(NULL); } char ** parseline(ptr, pac) register char *ptr; short *pac; { char *pbuf = malloc(strlen(ptr)+1); static char *av[1024]; register short ac = 0; strcpy(pbuf, ptr); ptr = pbuf; while (*ptr) { while (*ptr == ' ' || *ptr == '\t') ++ptr; av[ac++] = ptr; while (*ptr && *ptr != ' ' && *ptr != '\t') ++ptr; if (*ptr) *ptr++ = 0; } *pac = ac; return(av); } PrintDepList(list) MLIST *list; { register DEPEND *dep; puts("(DEP LIST)"); for (dep = GetHead(list); dep; dep = GetSucc(dep)) { printf("dep: %02lx %2ld (#%2ld)(%08lx) %s : %s", dep->Flags, dep->Common->RefCnt, dep->Order, dep->Common, dep->Left, dep->Right ); if (dep->Flags & DF_COLLECT) { printf(" (collect to %s)", dep->ColDep->Right); } puts(""); } puts("(END OF DEP LIST)"); }