caret@tictoc.UUCP (07/11/86)
Enough coaxing... Here it is. It will need work to work on most other systems, but the work should be minor. I went though the source just now, and here is a list of things which I noticed that will need changing. make.c: * Fix dosh() for your system. * Call to getstat() in modtime() is like a fstat() on unix, so it needs fixing. main.c: * You can have fun in main(). That call to initalloc() is really special to EON. rules.c: * Fix makerules() to suit you compilers for the auto suffix stuff. It supports most features of the UNIX make, the notable exceptions being libraries, and some subtleties with quoting. I will support problems with it to a degree. Good luck. P.S. I never actually got around to writing a manual entry for it, so the best course of action is to refer to the UNIX manual entry, or the source. Neil Russell ACSnet: caret@tictoc.oz UUCP: ...!seismo!munnari!tictoc.oz!caret ARPA: caret%tictoc.oz@seismo.arpa ------------------------------ snip ------------------------------ # This is a shell archive. Remove anything before this line, # then unpack it by saving it in a file and typing "sh file". # # Wrapped by caret on Fri Jul 11 20:15:58 EST 1986 # Contents: Makefile h.h check.c input.c macro.c main.c make.c reader.c # rules.c echo x - Makefile sed 's/^@//' > "Makefile" <<'@//E*O*F Makefile//' # Makefile for make! @.SUFFIXES: .obj @.c.obj: c -c $(CFLAGS) $< OBJS = check.obj input.obj macro.obj main.obj \ make.obj reader.obj rules.obj m: $(OBJS) c -a 4000h -o m $(OBJS) $(OBJS): h.h @//E*O*F Makefile// chmod u=rw,g=r,o=r Makefile echo x - h.h sed 's/^@//' > "h.h" <<'@//E*O*F h.h//' /* * Include header for make */ #ifndef uchar #define uchar unsigned char #endif #define bool uchar #define time_t long #define TRUE (1) #define FALSE (0) #define max(a,b) ((a)>(b)?(a):(b)) #define DEFN1 "makefile" /* Default names */ #define DEFN2 "Makefile" #define LZ (1024) /* Line size */ /* * A name. This represents a file, either to be made, or existant */ struct name { struct name * n_next; /* Next in the list of names */ char * n_name; /* Called */ struct line * n_line; /* Dependencies */ time_t n_time; /* Modify time of this name */ uchar n_flag; /* Info about the name */ }; #define N_MARK 0x01 /* For cycle check */ #define N_DONE 0x02 /* Name looked at */ #define N_TARG 0x04 /* Name is a target */ #define N_PREC 0x08 /* Target is precious */ /* * Definition of a target line. */ struct line { struct line * l_next; /* Next line (for ::) */ struct depend * l_dep; /* Dependents for this line */ struct cmd * l_cmd; /* Commands for this line */ }; /* * List of dependents for a line */ struct depend { struct depend * d_next; /* Next dependent */ struct name * d_name; /* Name of dependent */ }; /* * Commands for a line */ struct cmd { struct cmd * c_next; /* Next command line */ char * c_cmd; /* Command line */ }; /* * Macro storage */ struct macro { struct macro * m_next; /* Next variable */ char * m_name; /* Called ... */ char * m_val; /* Its value */ uchar m_flag; /* Infinite loop check */ }; extern char * myname; extern struct name namehead; extern struct macro * macrohead; extern struct name * firstname; extern bool silent; extern bool ignore; extern bool rules; extern bool dotouch; extern bool quest; extern bool domake; extern char str1[]; extern char str2[]; extern int lineno; char * fgets(); char * index(); char * rindex(); char * malloc(); extern int errno; char * getmacro(); struct macro * setmacro(); void input(); void error(); void fatal(); int make(); struct name * newname(); struct depend * newdep(); struct cmd * newcmd(); void newline(); char * suffix(); void touch(); void makerules(); char * gettok(); void precious(); @//E*O*F h.h// chmod u=rw,g=r,o=r h.h echo x - check.c sed 's/^@//' > "check.c" <<'@//E*O*F check.c//' /* * Check structures for make. */ #include <stdio.h> #include "h.h" /* * Prints out the structures as defined in memory. Good for check * that you make file does what you want (and for debugging make). */ void prt() { register struct name * np; register struct depend * dp; register struct line * lp; register struct cmd * cp; register struct macro * mp; for (mp = macrohead; mp; mp = mp->m_next) fprintf(stderr, "%s = %s\n", mp->m_name, mp->m_val); fputc('\n', stderr); for (np = namehead.n_next; np; np = np->n_next) { fprintf(stderr, "%s:\n", np->n_name); for (lp = np->n_line; lp; lp = lp->l_next) { fputc(':', stderr); for (dp = lp->l_dep; dp; dp = dp->d_next) fprintf(stderr, " %s", dp->d_name->n_name); fputc('\n', stderr); for (cp = lp->l_cmd; cp; cp = cp->c_next) fprintf(stderr, "-\t%s\n", cp->c_cmd); fputc('\n', stderr); } fputc('\n', stderr); } } /* * Recursive routine that does the actual checking. */ void check(np) struct name * np; { register struct depend * dp; register struct line * lp; if (np->n_flag & N_MARK) fatal("Circular dependency from %s", np->n_name); np->n_flag |= N_MARK; for (lp = np->n_line; lp; lp = lp->l_next) for (dp = lp->l_dep; dp; dp = dp->d_next) check(dp->d_name); np->n_flag &= ~N_MARK; } /* * Look for circular dependancies. * ie. * a: b * b: a * is a circular dep */ void circh() { register struct name * np; for (np = namehead.n_next; np; np = np->n_next) check(np); } /* * Check the target .PRECIOUS, and mark its dependentd as precious */ void precious() { register struct depend * dp; register struct line * lp; register struct name * np; if (!((np = newname(".PRECIOUS"))->n_flag & N_TARG)) return; for (lp = np->n_line; lp; lp = lp->l_next) for (dp = lp->l_dep; dp; dp = dp->d_next) dp->d_name->n_flag |= N_PREC; } @//E*O*F check.c// chmod u=rw,g=r,o=r check.c echo x - input.c sed 's/^@//' > "input.c" <<'@//E*O*F input.c//' /* * Parse a makefile */ #include <stdio.h> #include "h.h" struct name namehead; struct name * firstname; char str1[LZ]; /* General store */ char str2[LZ]; /* * Intern a name. Return a pointer to the name struct */ struct name * newname(name) char * name; { register struct name * rp; register struct name * rrp; register char * cp; for ( rp = namehead.n_next, rrp = &namehead; rp; rp = rp->n_next, rrp = rrp->n_next ) if (strcmp(name, rp->n_name) == 0) return rp; if ((rp = (struct name *)malloc(sizeof (struct name))) == (struct name *)0) fatal("No memory for name"); rrp->n_next = rp; rp->n_next = (struct name *)0; if ((cp = malloc(strlen(name)+1)) == (char *)0) fatal("No memory for name"); strcpy(cp, name); rp->n_name = cp; rp->n_line = (struct line *)0; rp->n_time = (time_t)0; rp->n_flag = 0; return rp; } /* * Add a dependant to the end of the supplied list of dependants. * Return the new head pointer for that list. */ struct depend * newdep(np, dp) struct name * np; struct depend * dp; { register struct depend * rp; register struct depend * rrp; if ((rp = (struct depend *)malloc(sizeof (struct depend))) == (struct depend *)0) fatal("No memory for dependant"); rp->d_next = (struct depend *)0; rp->d_name = np; if (dp == (struct depend *)0) return rp; for (rrp = dp; rrp->d_next; rrp = rrp->d_next) ; rrp->d_next = rp; return dp; } /* * Add a command to the end of the supplied list of commands. * Return the new head pointer for that list. */ struct cmd * newcmd(str, cp) char * str; struct cmd * cp; { register struct cmd * rp; register struct cmd * rrp; register char * rcp; if (rcp = rindex(str, '\n')) *rcp = '\0'; /* Loose newline */ while (isspace(*str)) str++; if (*str == '\0') /* If nothing left, the exit */ return; if ((rp = (struct cmd *)malloc(sizeof (struct cmd))) == (struct cmd *)0) fatal("No memory for command"); rp->c_next = (struct cmd *)0; if ((rcp = malloc(strlen(str)+1)) == (char *)0) fatal("No memory for command"); strcpy(rcp, str); rp->c_cmd = rcp; if (cp == (struct cmd *)0) return rp; for (rrp = cp; rrp->c_next; rrp = rrp->c_next) ; rrp->c_next = rp; return cp; } /* * Add a new 'line' of stuff to a target. This check to see * if commands already exist for the target. */ void newline(np, dp, cp) struct name * np; struct depend * dp; struct cmd * cp; { bool hascmds = FALSE; /* Target has commands */ register struct line * rp; register struct line * rrp; for ( rp = np->n_line, rrp = (struct line *)0; rp; rrp = rp, rp = rp->l_next ) if (rp->l_cmd) hascmds = TRUE; if (hascmds && cp) error("Commands defined twice for target %s", np->n_name); if ((rp = (struct line *)malloc(sizeof (struct line))) == (struct line *)0) fatal("No memory for line"); rp->l_next = (struct line *)0; rp->l_dep = dp; rp->l_cmd = cp; if (rrp) rrp->l_next = rp; else np->n_line = rp; np->n_flag |= N_TARG; } /* * Parse input from the makefile, and construct a tree structure * of it. */ void input(fd) FILE * fd; { char * p; /* General */ char * q; struct name * np; struct depend * dp; struct cmd * cp; if (getline(str1, fd)) /* Read the first line */ return; for(;;) { if (*str1 == '\t') /* Rules without targets */ error("Rules not allowed here"); p = str1; while (isspace(*p)) /* Find first target */ p++; while (((q = index(p, '=')) != (char *)0) && (p != q) && (q[-1] == '\\')) /* Find value */ { register char * a; a = q - 1; /* Del \ chr; move rest back */ p = q; while(*a++ = *q++) ; } if (q != (char *)0) { register char * a; *q++ = '\0'; /* Separate name and val */ while (isspace(*q)) q++; if (p = rindex(q, '\n')) *p = '\0'; p = str1; if ((a = gettok(&p)) == (char *)0) error("No macro name"); setmacro(a, q); if (getline(str1, fd)) return; continue; } expand(str1); p = str1; while (((q = index(p, ':')) != (char *)0) && (p != q) && (q[-1] == '\\')) /* Find dependents */ { register char * a; a = q - 1; /* Del \ chr; move rest back */ p = q; while(*a++ = *q++) ; } if (q == (char *)0) error("No targets provided"); *q++ = '\0'; /* Separate targets and dependents */ for (dp = (struct depend *)0; ((p = gettok(&q)) != (char *)0);) /* get list of dep's */ { np = newname(p); /* Intern name */ dp = newdep(np, dp); /* Add to dep list */ } *((q = str1) + strlen(str1) + 1) = '\0'; /* Need two nulls for gettok (Remember separation) */ cp = (struct cmd *)0; if (getline(str2, fd) == FALSE) /* Get commands */ { while (*str2 == '\t') { cp = newcmd(&str2[0], cp); if (getline(str2, fd)) break; } } while ((p = gettok(&q)) != (char *)0) /* Get list of targ's */ { np = newname(p); /* Intern name */ newline(np, dp, cp); if (!firstname) firstname = np; } if (feof(fd)) /* EOF? */ return; strcpy(str1, str2); } } @//E*O*F input.c// chmod u=rw,g=r,o=r input.c echo x - macro.c sed 's/^@//' > "macro.c" <<'@//E*O*F macro.c//' /* * Macro control for make */ #include "h.h" struct macro * macrohead; struct macro * getmp(name) char * name; { register struct macro * rp; for (rp = macrohead; rp; rp = rp->m_next) if (strcmp(name, rp->m_name) == 0) return rp; return (struct macro *)0; } char * getmacro(name) char * name; { struct macro * mp; if (mp = getmp(name)) return mp->m_val; else return ""; } struct macro * setmacro(name, val) char * name; char * val; { register struct macro * rp; register char * cp; /* Replace macro definition if it exists */ for (rp = macrohead; rp; rp = rp->m_next) if (strcmp(name, rp->m_name) == 0) { free(rp->m_val); /* Free space from old */ break; } if (!rp) /* If not defined, allocate space for new */ { if ((rp = (struct macro *)malloc(sizeof (struct macro))) == (struct macro *)0) fatal("No memory for macro"); rp->m_next = macrohead; macrohead = rp; rp->m_flag = FALSE; if ((cp = malloc(strlen(name)+1)) == (char *)0) fatal("No memory for macro"); strcpy(cp, name); rp->m_name = cp; } if ((cp = malloc(strlen(val)+1)) == (char *)0) fatal("No memory for macro"); strcpy(cp, val); /* Copy in new value */ rp->m_val = cp; return rp; } /* * Do the dirty work for expand */ void doexp(to, from, len, buf) char ** to; char * from; int * len; char * buf; { register char * rp; register char * p; register char * q; register struct macro * mp; rp = from; p = *to; while (*rp) { if (*rp != '$') { *p++ = *rp++; (*len)--; } else { q = buf; if (*++rp == '(') while (*++rp && *rp != ')') *q++ = *rp; else if (!*rp) { *p++ = '$'; break; } else *q++ = *rp; *q = '\0'; if (*rp) rp++; if (!(mp = getmp(buf))) mp = setmacro(buf, ""); if (mp->m_flag) fatal("Infinitely recursive macro %s", mp->m_name); mp->m_flag = TRUE; *to = p; doexp(to, mp->m_val, len, buf); p = *to; mp->m_flag = FALSE; } if (*len <= 0) error("Expanded line too line"); } *p = '\0'; *to = p; } /* * Expand any macros in str. */ void expand(str) char * str; { static char a[LZ]; static char b[LZ]; char * p = str; int len = LZ-1; strcpy(a, str); doexp(&p, a, &len, b); } @//E*O*F macro.c// chmod u=rw,g=r,o=r macro.c echo x - main.c sed 's/^@//' > "main.c" <<'@//E*O*F main.c//' /* * make [-f makefile] [-ins] [target(s) ...] * * (Better than EON mk but not quite as good as UNIX make) * * -f makefile name * -i ignore exit status * -n Pretend to make * -p Print all macros & targets * -q Question up-to-dateness of target. Return exit status 1 if not * -r Don't not use inbuilt rules * -s Make silently * -t Touch files instead of making them * -m Change memory requirements */ #include <stdio.h> #include <sys/stat.h> #include <sys/err.h> #include "h.h" #define MEMSPACE (16384) char * myname; char * makefile; /* The make file */ unsigned memspace = MEMSPACE; FILE * ifd; /* Input file desciptor */ bool domake = TRUE; /* Go through the motions option */ bool ignore = FALSE; /* Ignore exit status option */ bool silent = FALSE; /* Silent option */ bool print = FALSE; /* Print debuging information */ bool rules = TRUE; /* Use inbuilt rules */ bool dotouch = FALSE;/* Touch files instead of making */ bool quest = FALSE; /* Question up-to-dateness of file */ void main(argc, argv) char ** argv; int argc; { register char * p; /* For argument processing */ int estat; /* For question */ register struct name * np; myname = (argc-- < 1) ? "make" : *argv++; while ((argc > 0) && (**argv == '-')) { argc--; /* One less to process */ p = *argv++; /* Now processing this one */ while (*++p != '\0') { switch(*p) { case 'f': /* Alternate file name */ if (*++p == '\0') { if (argc-- <= 0) usage(); p = *argv++; } makefile = p; goto end_of_args; case 'm': /* Change space requirements */ if (*++p == '\0') { if (argc-- <= 0) usage(); p = *argv++; } memspace = atoi(p); goto end_of_args; case 'n': /* Pretend mode */ domake = FALSE; break; case 'i': /* Ignore fault mode */ ignore = TRUE; break; case 's': /* Silent about commands */ silent = TRUE; break; case 'p': print = TRUE; break; case 'r': rules = FALSE; break; case 't': dotouch = TRUE; break; case 'q': quest = TRUE; break; default: /* Wrong option */ usage(); } } end_of_args:; } if (initalloc(memspace) == 0xffff) /* Must get memory for alloc */ fatal("Cannot initalloc memory"); if (strcmp(makefile, "-") == 0) /* Can use stdin as makefile */ ifd = stdin; else if (!makefile) /* If no file, then use default */ { if ((ifd = fopen(DEFN1, "r")) == (FILE *)0) if (errno != ER_NOTF) fatal("Can't open %s; error %02x", DEFN1, errno); if ((ifd == (FILE *)0) && ((ifd = fopen(DEFN2, "r")) == (FILE *)0)) fatal("Can't open %s", DEFN2); } else if ((ifd = fopen(makefile, "r")) == (FILE *)0) fatal("Can't open %s", makefile); makerules(); setmacro("$", "$"); while (argc && (p = index(*argv, '='))) { char c; c = *p; *p = '\0'; setmacro(*argv, p+1); *p = c; argv++; argc--; } input(ifd); /* Input all the gunga */ fclose(ifd); /* Finished with makefile */ lineno = 0; /* Any calls to error now print no line number */ if (print) prt(); /* Print out structures */ np = newname(".SILENT"); if (np->n_flag & N_TARG) silent = TRUE; np = newname(".IGNORE"); if (np->n_flag & N_TARG) ignore = TRUE; precious(); if (!domake) silent = FALSE; if (!firstname) fatal("No targets defined"); circh(); /* Check circles in target definitions */ if (!argc) estat = make(firstname, 0); else while (argc--) { if (!print && !silent && strcmp(*argv, "love") == 0) printf("Not war!\n"); estat |= make(newname(*argv++), 0); } if (quest) exit(estat); else exit(0); } usage() { fprintf(stderr, "Usage: %s [-f makefile] [-inpqrst] [macro=val ...] [target(s) ...]\n", myname); exit(1); } void fatal(msg, a1, a2, a3) char *msg; { fprintf(stderr, "%s: ", myname); fprintf(stderr, msg, a1, a2, a3); fputc('\n', stderr); exit(1); } @//E*O*F main.c// chmod u=rw,g=r,o=r main.c echo x - make.c sed 's/^@//' > "make.c" <<'@//E*O*F make.c//' /* * Do the actual making for make */ #include <stdio.h> #include <sys/stat.h> #include <sys/err.h> #include "h.h" /* * Exec a shell that returns exit status correctly (/bin/esh). * The standard EON shell returns the process number of the last * async command, used by the debugger (ugg). * [exec on eon is like a fork+exec on unix] */ int dosh(string, shell) char * string; char * shell; { int number; return ((number = execl(shell, shell,"-c", string, 0)) == -1) ? -1: /* couldn't start the shell */ wait(number); /* return its exit status */ } /* * Do commands to make a target */ void docmds(np) struct name * np; { bool ssilent = silent; bool signore = ignore; int estat; register char * q; register char * p; char * shell; register struct line * lp; register struct cmd * cp; if (*(shell = getmacro("SHELL")) == '\0') shell = ":bin/esh"; for (lp = np->n_line; lp; lp = lp->l_next) for (cp = lp->l_cmd; cp; cp = cp->c_next) { strcpy(str1, cp->c_cmd); expand(str1); q = str1; while ((*q == '@') || (*q == '-')) { if (*q == '@') /* Specific silent */ ssilent = TRUE; else /* Specific ignore */ signore = TRUE; q++; /* Not part of the command */ } if (!ssilent) fputs(" ", stdout); for (p=q; *p; p++) { if (*p == '\n' && p[1] != '\0') { *p = ' '; if (!ssilent) fputs("\\\n", stdout); } else if (!ssilent) putchar(*p); } if (!ssilent) putchar('\n'); if (domake) { /* Get the shell to execute it */ if ((estat = dosh(q, shell)) != 0) { if (estat == -1) fatal("Couldn't execute %s", shell); else { printf("%s: Error code %d", myname, estat); if (signore) fputs(" (Ignored)\n", stdout); else { putchar('\n'); if (!(np->n_flag & N_PREC)) if (unlink(np->n_name) == 0) printf("%s: '%s' removed.\n", myname, np->n_name); exit(estat); } } } } } } /* * Get the modification time of a file. If the first * doesn't exist, it's modtime is set to 0. */ void modtime(np) struct name * np; { struct stat info; int fd; if ((fd = open(np->n_name, 0)) < 0) { if (errno != ER_NOTF) fatal("Can't open %s; error %02x", np->n_name, errno); np->n_time = 0L; } else if (getstat(fd, &info) < 0) fatal("Can't getstat %s; error %02x", np->n_name, errno); else np->n_time = info.st_mod; close(fd); } /* * Update the mod time of a file to now. */ void touch(np) struct name * np; { char c; int fd; if (!domake || !silent) printf(" touch %s\n", np->n_name); if (domake) { if ((fd = open(np->n_name, 0)) < 0) printf("%s: '%s' no touched - non-existant\n", myname, np->n_name); else { uread(fd, &c, 1, 0); uwrite(fd, &c, 1); } close(fd); } } /* * Recursive routine to make a target. */ int make(np, level) struct name * np; int level; { register struct depend * dp; register struct line * lp; time_t dtime = 1; if (np->n_flag & N_DONE) return 0; if (!np->n_time) modtime(np); /* Gets modtime of this file */ if (rules) { for (lp = np->n_line; lp; lp = lp->l_next) if (lp->l_cmd) break; if (!lp) dyndep(np); } if (!(np->n_flag & N_TARG) && np->n_time == 0L) fatal("Don't know how to make %s", np->n_name); for (lp = np->n_line; lp; lp = lp->l_next) for (dp = lp->l_dep; dp; dp = dp->d_next) { make(dp->d_name, level+1); dtime = max(dtime, dp->d_name->n_time); } np->n_flag |= N_DONE; if (quest) { rtime(&np->n_time); return np->n_time < dtime; } else if (np->n_time < dtime) { if (dotouch) touch(np); else { setmacro("@", np->n_name); docmds(np); } rtime(&np->n_time); } else if (level == 0) printf("%s: '%s' is up to date\n", myname, np->n_name); return 0; } @//E*O*F make.c// chmod u=rw,g=r,o=r make.c echo x - reader.c sed 's/^@//' > "reader.c" <<'@//E*O*F reader.c//' /* * Read in makefile */ #include <stdio.h> #include "h.h" int lineno; /* * Syntax error handler. Print message, with line number, and exits. */ void error(msg, a1, a2, a3) char * msg; { fprintf(stderr, "%s: ", myname); fprintf(stderr, msg, a1, a2, a3); if (lineno) fprintf(stderr, " on line %d", lineno); fputc('\n', stderr); exit(1); } /* * Read a line into the supplied string of length LZ. Remove * comments, ignore blank lines. Deal with quoted (\) #, and * quoted newlines. If EOF return TRUE. */ bool getline(str, fd) char * str; FILE * fd; { register char * p; char * q; int pos = 0; for (;;) { if (fgets(str+pos, LZ-pos, fd) == (char *)0) return TRUE; /* EOF */ lineno++; if ((p = index(str+pos, '\n')) == (char *)0) error("Line too long"); if (p[-1] == '\\') { p[-1] = '\n'; pos = p - str; continue; } p = str; while (((q = index(p, '#')) != (char *)0) && (p != q) && (q[-1] == '\\')) { char *a; a = q - 1; /* Del \ chr; move rest back */ p = q; while (*a++ = *q++) ; } if (q != (char *)0) { q[0] = '\n'; q[1] = '\0'; } p = str; while (isspace(*p)) /* Checking for blank */ p++; if (*p != '\0') return FALSE; pos = 0; } } /* * Get a word from the current line, surounded by white space. * return a pointer to it. String returned has no white spaces * in it. */ char * gettok(ptr) char **ptr; { register char * p; while (isspace(**ptr)) /* Skip spaces */ (*ptr)++; if (**ptr == '\0') /* Nothing after spaces */ return NULL; p = *ptr; /* word starts here */ while ((**ptr != '\0') && (!isspace(**ptr))) (*ptr)++; /* Find end of word */ *(*ptr)++ = '\0'; /* Terminate it */ return(p); } @//E*O*F reader.c// chmod u=rw,g=r,o=r reader.c echo x - rules.c sed 's/^@//' > "rules.c" <<'@//E*O*F rules.c//' /* * Control of the implicit suffix rules */ #include "h.h" /* * Return a pointer to the suffix of a name */ char * suffix(name) char * name; { return rindex(name, '.'); } /* * Dynamic dependency. This routine applies the suffis rules * to try and find a source and a set of rules for a missing * target. If found, np is made into a target with the implicit * source name, and rules. Returns TRUE if np was made into * a target. */ bool dyndep(np) struct name * np; { register char * p; register char * q; register char * suff; /* Old suffix */ register char * basename; /* Name without suffix */ struct name * op; /* New dependent */ struct name * sp; /* Suffix */ struct line * lp; struct depend * dp; char * newsuff; p = str1; q = np->n_name; suff = suffix(q); while (q < suff) *p++ = *q++; *p = '\0'; basename = setmacro("*", str1)->m_val; if (!((sp = newname(".SUFFIXES"))->n_flag & N_TARG)) return FALSE; for (lp = sp->n_line; lp; lp = lp->l_next) for (dp = lp->l_dep; dp; dp = dp->d_next) { newsuff = dp->d_name->n_name; if (strlen(suff)+strlen(newsuff)+1 >= LZ) fatal("Suffix rule too long"); p = str1; q = newsuff; while (*p++ = *q++) ; p--; q = suff; while (*p++ = *q++) ; sp = newname(str1); if (sp->n_flag & N_TARG) { p = str1; q = basename; if (strlen(basename) + strlen(newsuff)+1 >= LZ) fatal("Implicit name too long"); while (*p++ = *q++) ; p--; q = newsuff; while (*p++ = *q++) ; op = newname(str1); if (!op->n_time) modtime(op); if (op->n_time) { dp = newdep(op, 0); newline(np, dp, sp->n_line->l_cmd); setmacro("<", op->n_name); return TRUE; } } } return FALSE; } /* * Make the default rules */ void makerules() { struct cmd * cp; struct name * np; struct depend * dp; setmacro("BDSCC", "asm"); /* setmacro("BDSCFLAGS", ""); */ cp = newcmd("$(BDSCC) $(BDSCFLAGS) -n $<", 0); np = newname(".c.o"); newline(np, 0, cp); setmacro("CC", "c"); setmacro("CFLAGS", "-O"); cp = newcmd("$(CC) $(CFLAGS) -c $<", 0); np = newname(".c.obj"); newline(np, 0, cp); setmacro("M80", "asm -n"); /* setmacro("M80FLAGS", ""); */ cp = newcmd("$(M80) $(M80FLAGS) $<", 0); np = newname(".mac.o"); newline(np, 0, cp); setmacro("AS", "zas"); /* setmacro("ASFLAGS", ""); */ cp = newcmd("$(ZAS) $(ASFLAGS) -o $@ $<", 0); np = newname(".as.obj"); newline(np, 0, cp); np = newname(".as"); dp = newdep(np, 0); np = newname(".obj"); dp = newdep(np, dp); np = newname(".c"); dp = newdep(np, dp); np = newname(".o"); dp = newdep(np, dp); np = newname(".mac"); dp = newdep(np, dp); np = newname(".SUFFIXES"); newline(np, dp, 0); } @//E*O*F rules.c// chmod u=rw,g=r,o=r rules.c exit 0