#include #include #include #include #include #include #include #define USAGE "usage: %s file [...]\n", argv[0] extern char *optarg; extern int optind; int main(int argc, char *argv[]) { char *b, *bb, *bbb, buf[1024], *cmd[32], dep[1024], *t, *tt, tgt[64]; FILE *fp; int c, dflag, i, icmd, j, max; struct stat sb, ssb; tgt[0] = dep[0] = 0; /* process arguments */ dflag = 0; while ((c = getopt(argc, argv, "d")) != -1) switch (c) { case 'd': dflag++; break; default: fprintf(stderr, USAGE); return 1; } argc -= optind; argv += optind; if (argc == 0) { fprintf(stderr, USAGE); return 1; } /* allocate memory */ for (i = 0; i < 32; i++) { cmd[i] = malloc(1024*sizeof(char)); if (!cmd[i]) err(1, "malloc"); } /* process each file */ for (i = icmd = 0; i < argc; i++, icmd = 0) { fp = fopen(argv[i], "r"); if (!fp) err(1, "fopen"); /* read line by line */ for (j = 0; j < 20 && fgets(buf, sizeof(buf), fp); j++) { buf[strcspn(buf, "\n")] = 0; /* parse line */ b = buf; for (b++; *b; b++) { if (!(*(b+1) && *(b+2) && *(b+3))) continue; if (!(*b == ' ' || *b == ' ')) continue; /* command line */ if (*(b+1) == '$' && *(b+2) == ' ') { strncpy(cmd[icmd++],b+3,sizeof(buf)-1); /* find target */ for (b = b+3; *b; b++) { if (!(*b+1)) continue; if (*b != '>') continue; strncpy(tgt,b+1,sizeof(tgt)-1); } if (dflag < 3) continue; fprintf(stderr, "%s: command line '%s'\n", argv[i], buf); continue; } /* depends line */ if (*(b+1) == '%' && *(b+2) == ' ') { strncpy(dep, b+3, sizeof(dep)-1); if (dflag < 3) continue; fprintf(stderr, "%s: depends line '%s'\n", argv[i], buf); continue; } } } if (!icmd) { fprintf(stderr, "%s: no command line found\n", argv[i]); continue; } if (!*tgt) goto build; /* compare source > target */ for (t = tgt; *t; t++) if (!isspace(*t)) break; for (tt = tgt; *tt; tt++) if (isspace(*tt)) { *tt = 0; break; } if (stat(t, &ssb)) err(1, t); if (stat(argv[i], &sb)) err(1, argv[i]); if (sb.st_mtime > ssb.st_mtime) { if (dflag) fprintf(stderr, "%s: building because " "%s is modified\n", argv[i], argv[i]); goto build; } if (!*dep) goto uptodate; /* compare dependencies > target */ for (t = dep; *t; t++) if (!isspace(*t)) break; for (j = 0; t[j]; j++) { if (isspace(t[j]) || t[j+1] == 0) { tt = strdup(t); tt[j+(t[j+1]==0)] = 0; if (dflag > 1) fprintf(stderr, "%s: depend '%s'\n", argv[i], tt); if (stat(tt, &sb)) err(1, tt); free(tt); if (sb.st_mtime > ssb.st_mtime) { if (dflag) fprintf(stderr, "%s: building because " "%s is modified\n", argv[i], tt); goto build; } for (; t[j]; j++) if (!isspace(t[j])) break; t += j; j = 0; } } uptodate: fprintf(stderr, "%s: already up-to-date\n", argv[i]); goto done; build: /* run commands */ for (j = 0; j < icmd; j++) { fprintf(stderr, "%s: %s\n", argv[i], cmd[j]); system(cmd[j]); } done: fclose(fp); } }