home *** CD-ROM | disk | FTP | other *** search
- /*
- * simple make program
- *
- * make [options] [targets]
- *
- * options are
- * -i ignore non-zero program returns
- * -f file makefile name (default is "makefile")
- * -n don't execute any commands
- * -t just touch the targets, don't build
- * -r ignore built-in rules
- * -d debug flag (noisy output)
- * -h hold the screen
- *
- * this program reads a makefile to build the named targets
- * a makefile contains rules, macro definitions, or dependencies
- * an example makefile might be:
- *
- * # this is a sample makefile for a spreadsheet
- * OBJ = main.s io.s calc.s
- * ss: $(OBJ) ss.h
- * d:as.ttp d:ttp.s $(OBJ) -L d:lib.a
- *
- * there are built-in rules to convert .c to .s, .c to .ttp, and .c to .prg
- */
-
- #include <stdio.h>
-
- #define MAXLINE 256
- #define MAXSYM 300
- #define MAXRULE 100
- #define MAXSPC 20000
-
- #define TIME 0x2C
- #define DATE 0x2A
- #define EXEC 0x4B
- #define RENAME 0x56
- #define GSDTOF 0x57
-
- typedef struct x0 { /* structure for command lists */
- char *cmd; /* pointer to the command line */
- struct x0 *next; /* pointer to the next one */
- } Command;
-
- typedef struct x1 { /* structure for dependencies */
- int dep; /* name of a parent */
- struct x1 *next; /* pointer to next parent */
- } Depend;
-
- typedef struct { /* structure for rules */
- int from; /* the extension of the parent */
- int to; /* the extension of the child */
- Command *cmd; /* the commands to make the child */
- } Rule;
-
- FILE *in; /* makefile input file handle */
- int eof; /* eof flag for makefile input stream */
- int no_exec = 0; /* don't execute the commands */
- int debug = 0; /* debug output flag */
- int ignore = 0; /* ignore non-zero returns */
- int norules = 0; /* no built-in rules */
- int hold = 0; /* hold the screen (for GEM users */
- char line[MAXLINE]; /* buffer containing current input line */
- char extra[MAXLINE]; /* extra buffer for macro expansion */
- char name[MAXLINE]; /* space for making up names */
- char *macro[MAXSYM]; /* pointer to the macros */
- char *sym[MAXSYM]; /* pointer to the symbol names */
- Depend *depend[MAXSYM]; /* pointer to dependencies */
- Command *command[MAXSYM]; /* index into commands */
- Rule rules[MAXRULE]; /* rules */
- int lrule = 0; /* last rule used */
- char space[MAXSPC]; /* free space (poor person's alloc) */
- int lspc = 0; /* last entry in space */
- int firstsym = -1; /* what's first dependency declared */
- char base[MAXLINE]; /* buffer for '*' macro */
- char target[MAXLINE]; /* buffer for '@' macro */
-
- char *save(); /* save a string */
- char *alloc(); /* allocate space */
- Command *cmdlist(); /* make up a command list */
- Command *add_cmd(); /* add a command to a command list */
- long date(); /* get the date of a file */
-
- main(argc, argv) char *argv[]; {
- int i, err, tch;
- char *name;
- i = 1;
- name = "makefile";
- tch = err = 0;
- for (i = 1; i < argc && *argv[i] == '-'; i++) {
- switch (argv[i][1]) {
- case 'f': case 'F':
- i++;
- name = argv[i];
- break;
- case 'i': case 'I':
- ignore = 1;
- break;
- case 'd': case 'D':
- debug = 1;
- break;
- case 't': case 'T':
- tch = 1;
- break;
- case 'n': case 'N':
- no_exec = 1;
- break;
- case 'r': case 'R':
- norules = 1;
- break;
- case 'h': case 'H':
- hold = 1;
- break;
- default:
- printf("unknown option: %s\n", argv[i]);
- err = 1;
- break;
- }
- }
- if (err) error("usage: make [-i -n -t -r -d -h -f file] [targets]\n");
- if (tch) {
- while (i < argc)
- touch(argv[i++]);
- }
- else {
- init();
- input(name);
- if (i == argc && firstsym >= 0)
- make(firstsym);
- else while (i < argc)
- make(lookup(argv[i++]));
- }
- bye(0);
- }
-
- /* initialize the symbol table and add built-in rules */
-
- init() {
- int i;
- Command *cp;
- rules[0].cmd = NULL;
- for (i = 0; i < MAXSYM; i++)
- sym[i] = NULL;
- if (norules) return;
- /* built-in rules */
- cp = NULL;
- cp = add_cmd(cp, " d:cc.ttp $*.c");
- cp = add_cmd(cp, " d:as.ttp -o $*.ttp d:ttp.s yc.out -L d:lib.a");
- cp = add_cmd(cp, " rm yc.out");
- add_rule(".c", ".ttp", cp);
- cp = NULL;
- cp = add_cmd(cp, " d:cc.ttp $*.c");
- cp = add_cmd(cp, " d:as.ttp -o $*.prg d:prg.s yc.out -L d:gem.a d:lib.a");
- cp = add_cmd(cp, " rm yc.out");
- add_rule(".c", ".prg", cp);
- cp = NULL;
- cp = add_cmd(cp, " d:cc.ttp -o $*.s $*.c");
- add_rule(".c", ".s", cp);
- }
-
- /* read in and parse the makefile */
-
- input(filename) char *filename; {
- if (!(in = fopen(filename, "r")))
- return;
- getline();
- while (!eof) {
- if (*line == '#')
- getline();
- else if (macdef())
- getline();
- else if (*line == '.')
- rule();
- else if (*line > ' ')
- dependency();
- else getline();
- }
- fclose(in);
- }
-
- /* read in a line from the makefile */
-
- getline() {
- int c;
- char *l;
- l = line;
- while ((c = getc(in)) != EOF && c != '\n') {
- if (c == '\\') {
- c = getc(in);
- if (c != '\n' && c != '\r')
- *l++ = '\\';
- }
- if (c != '\r')
- *l++ = c;
- }
- *l = 0;
- eof = (c == EOF);
- }
-
- /* expand all the macro's in the current line */
-
- expand() {
- int done;
- char *e, *l, *m;
- while (1) {
- e = extra;
- l = line;
- done = 1;
- while (*e++ = *l++)
- if (*l == '$')
- done = 0;
- if (done)
- break;
- e = extra;
- l = line;
- while (*e) {
- if (*e == '$') {
- e++;
- m = name;
- if (*e == '(') { /* multi letter macro */
- e++;
- while (*e != ')')
- *m++ = *e++;
- e++;
- }
- else *m++ = *e++; /* one letter macro */
- *m = 0;
- if (m = macro[lookup(name)]) {
- while (*m)
- *l++ = *m++;
- }
- else error("$(%s) not defined", name);
- }
- else *l++ = *e++;
- }
- *l = 0;
- }
- }
-
- /* read in a rule, ".from.to:" followed by command lines */
-
- rule() {
- int i, j;
- char to[10], from[10], *l;
- l = line;
- i = j = 0;
- if (*l != '.')
- error("bad rule entry");
- do { from[j++] = *l++; } while (*l && *l != '.');
- from[j] = 0;
- if (*l != '.')
- error("bad rule entry");
- j = 0;
- do { to[j++] = *l++; } while (*l && *l != ':');
- to[j] = 0;
- add_rule(from, to, cmdlist());
- }
-
- /* build a list of commands, return pointer to them */
-
- Command *
- cmdlist() {
- Command *r;
- r = NULL;
- getline();
- while (*line && *line <= ' ') {
- r = add_cmd(r, save(line));
- getline();
- }
- return r;
- }
-
- /* check for a macro def and process if there */
-
- macdef() {
- char *l, *b, *e;
- l = line;
- while (*l && *l <= ' ') l++;
- b = l;
- while (*l && *l > ' ') l++;
- e = l;
- while (*l && *l <= ' ') l++;
- if (*l++ == '=') { /* got a macro */
- *e = 0;
- add_mac(b, save(l));
- return 1;
- }
- else return 0;
- }
-
- /* parse a dependency, "child [children]*: [parents]*" */
-
- dependency() {
- int i, j, target[20], depend[20];
- Command *cmd;
- expand();
- i = namelist(target, 0);
- if (line[i] != ':')
- error("bad dependency rule");
- i = namelist(depend, i+1);
- cmd = cmdlist();
- for (i = 0; target[i]; i++) {
- for (j = 0; depend[j]; j++)
- add_dep(target[i], depend[j]);
- set_cmd(target[i], cmd);
- }
- if (firstsym < 0)
- firstsym = target[0];
- }
-
- /* gather up a list of names in the input line */
-
- namelist(list, i) int *list; {
- int t, j;
- t = 0;
- while (line[i] && line[i] != ':') {
- while (line[i] && line[i] <= ' ')
- i++;
- j = 0;
- if (line[i]) {
- while (line[i] && line[i] > ' ' && line[i] != ':')
- name[j++] = line[i++];
- name[j] = 0;
- list[t++] = lookup(name);
- }
- }
- list[t] = 0;
- return i;
- }
-
- /* add a new command to the end of a command list */
-
- Command *
- add_cmd(cp, cmd) Command *cp; char *cmd; {
- Command *p, *r;
- p = alloc((short)sizeof(Command));
- p->cmd = cmd;
- p->next = NULL;
- if (cp == NULL)
- r = p;
- else {
- r = cp;
- while (cp->next)
- cp = cp->next;
- cp->next = p;
- }
- return r;
- }
-
- /* add a parent (target) to a child (dependency) */
-
- add_dep(target, dep) {
- Depend *p;
- if (debug) printf("add_dep(%s,%s)\n", sym[target], sym[dep]);
- p = alloc((short)sizeof(Depend));
- p->dep = dep;
- p->next = depend[target];
- depend[target] = p;
- }
-
- /* add a macro */
-
- add_mac(name, str) char *name, *str; {
- if (debug) printf("add_mac(%s,%s)\n", name, str);
- macro[lookup(name)] = str;
- }
-
- /* add a command list to a target */
-
- set_cmd(target, cp) Command *cp; {
- if (debug) printf("set_cmd(%s,%lx)\n", sym[target], cp);
- command[target] = cp;
- }
-
- /* add a rule */
-
- add_rule(from, to, cp) char *from, *to; Command *cp; {
- if (debug) printf("add_rule(%s,%s,%lx)\n", from, to, cp);
- rules[lrule].from = lookup(from);
- rules[lrule].to = lookup(to);
- rules[lrule].cmd = cp;
- if (++lrule >= MAXRULE)
- error("too many rules");
- rules[lrule].cmd = NULL;
- }
-
- /* build a child by first building the parents */
-
- make(child) {
- int mkflag;
- long chdate;
- Command *cp;
- Depend *dp;
-
- if (debug) printf("make(%s)\n", sym[child]);
- chdate = date(sym[child]);
- mkflag = 0;
-
- if (dp = depend[child]) {
- while (dp) {
- make(dp->dep);
- if (check(dp->dep, chdate))
- mkflag = 1;
- dp = dp->next;
- }
- }
- else mkflag = 1;
-
- if (mkflag) {
- strcpy(target, sym[child]);
- add_mac("@", target);
- if (cp = command[child]) {
- rm(target);
- execute(cp);
- }
- else chkrule(child, chdate);
- }
- }
-
- /* set the date/time of the named file to the present */
-
- touch(name) char *name; {
- int fd, r;
- long dt;
- if ((fd = open(name, 2)) >= 0) {
- dt = (trap(1, DATE) && 0xFFFF) | (trap(1, TIME) << 16);
- if (r = trap(1, GSDTOF, &dt, fd, 1))
- error("cannot touch %s (%d)\n", name, r);
- close(fd);
- }
- else error("cannot open %s (%d)\n", name, fd);
- }
-
- /* get the date/time of the named file */
-
- long
- date(name) char *name; {
- int fd;
- unsigned long dt;
- if ((fd = open(name, 0)) >= 0) {
- trap(1, GSDTOF, &dt, fd, 0);
- dt = ((dt >> 16) & 0xFFFFL) | (dt << 16); /* swap words */
- close(fd);
- }
- else dt = 0L;
- if (debug) printf("date of %s is %lx\n", name, dt);
- return dt;
- }
-
- /* compare the date/time of the named file against the child date */
-
- check(parent, chdt) long chdt; {
- long pardt;
- pardt = date(sym[parent]);
- return (pardt > chdt);
- }
-
- /* see if there are any rules that we can use to build the child */
-
- chkrule(child, chdate) long chdate; {
- Rule *r;
- char *s, *e;
- int i, j, ext, parent, parbase;
- s = sym[child];
- for (j = i = 0; base[i] = s[i]; i++)
- if (s[i] == '.')
- j = i;
- if (j == 0)
- return 0;
- e = &s[j];
- base[j] = 0;
- parbase = lookup(base);
- ext = lookup(e);
- for (i = lrule; --i >= 0; ) {
- r = &rules[i];
- if (r->to == ext) {
- strcpy(extra, base);
- strcat(extra, sym[r->from]);
- parent = lookup(extra);
- make(parent);
- add_mac("*", sym[parbase]);
- if (check(parent, chdate)) {
- rm(sym[child]);
- execute(r->cmd);
- return;
- }
- }
- }
- }
-
- /* execute a list of commands */
-
- execute(cp) Command *cp; {
- int r;
- while (cp) {
- strcpy(line, cp->cmd);
- expand();
- printf(" %s\n", line);
- if (!no_exec && (r = system(line)) && !ignore)
- error("command failed (%d)", r);
- cp = cp->next;
- }
- }
-
- /* do something, either built-in (rm, mv) or exec a program */
-
- system(s) char *s; {
- int r;
- char *first, *sec;
- while (*s && *s <= ' ') s++;
- first = s;
- while (*s && *s > ' ') s++;
- if (*s) *s++ = 0;
- if (strcmp(first, "rm") == 0) {
- r = rm(s);
- }
- else if (strcmp(first, "mv") == 0) {
- r = mvcp(1, s);
- }
- else if (strcmp(first, "cp") == 0) {
- r = mvcp(0, s);
- }
- else {
- r = strlen(s--);
- *s = r;
- r = trap(1, EXEC, 0, first, s, "");
- }
- return r;
- }
-
- /* remove a file */
-
- rm(name) char *name; {
- int r;
- r = unlink(name);
- if (r == -33) r = 0; /* name not found same as deleted */
- return r;
- }
-
- /* move or copy a src file to a destination file */
-
- mvcp(mv, s) char *s; {
- int r, c;
- char *src, *dst;
- FILE *in, *out;
- src = strtok(s, " ");
- dst = strtok(NULL, " ");
- if (src == NULL || dst == NULL || *src == 0 || *dst == 0)
- return 1;
- if (mv) {
- unlink(dst);
- if (r = trap(1, RENAME, 0, src, dst))
- error("can't move %s to %s (%d)\n", src, dst, r);
- }
- else {
- if (in = fopen(src, "r")) {
- if (out = fopen(dst, "w")) {
- while ((c = getc(in)) != EOF)
- putc(c, out);
- fclose(out);
- }
- else error("can't create %s\n", dst);
- fclose(in);
- }
- else error("can't read %s\n", src);
- }
- return 0;
- }
-
- /* symbol table lookup */
-
- lookup(s) char *s; {
- int i, start;
- upper(s); /* too bad TOS filenames are always uppercase */
- start = i = *s;
- while (sym[i]) {
- if (strcmp(s, sym[i]) == 0)
- return i;
- if (++i >= MAXSYM)
- i = 0;
- if (i == start)
- error("too many symbols");
- }
- sym[i] = save(s);
- command[i] = macro[i] = depend[i] = 0L;
- return i;
- }
-
- /* convert a string to all uppercase in place */
-
- upper(s) char *s; {
- register int c;
- for ( ; c = *s; s++) {
- if (c >= 'a' && c <= 'z')
- *s = c - 'a' + 'A';
- }
- }
-
- /* save a string */
-
- char *
- save(s) char *s; {
- char *r;
- r = &space[lspc];
- while (space[lspc++] = *s++)
- if (lspc >= MAXSPC)
- error("out of free space");
- return r;
- }
-
- /* allocate some space */
-
- char *
- alloc(n) {
- char *r;
- if (lspc & 1)
- lspc++;
- r = &space[lspc];
- lspc = lspc + n;
- if (lspc >= MAXSPC)
- error("out of free space");
- return r;
- }
-
- bye(n) {
- if (hold) {
- printf("(press any char)\n");
- getchar();
- }
- exit(n);
- }
-
- /* complain and get out */
-
- error(s, a, b, c, d) {
- printf("** ");
- printf(s, a, b, c, d);
- printf("\n");
- bye(1);
- }
-