13e12c5d1SDavid du Colombier #include <u.h> 23e12c5d1SDavid du Colombier #include <libc.h> 33e12c5d1SDavid du Colombier #include <bio.h> 43e12c5d1SDavid du Colombier #include "diff.h" 53e12c5d1SDavid du Colombier 6*9a747e4fSDavid du Colombier #define DIRECTORY(s) ((s)->qid.type&QTDIR) 7*9a747e4fSDavid du Colombier #define REGULAR_FILE(s) ((s)->type == 'M' && !DIRECTORY(s)) 83e12c5d1SDavid du Colombier 93e12c5d1SDavid du Colombier Biobuf stdout; 103e12c5d1SDavid du Colombier 113e12c5d1SDavid du Colombier static char *tmp[] = {"/tmp/diff1", "/tmp/diff2"}; 123e12c5d1SDavid du Colombier static int whichtmp; 133e12c5d1SDavid du Colombier static char *progname; 147dd7cddfSDavid du Colombier static char usage[] = "diff [ -efmnbwr ] file1 ... file2\n"; 153e12c5d1SDavid du Colombier 163e12c5d1SDavid du Colombier static void 173e12c5d1SDavid du Colombier rmtmpfiles(void) 183e12c5d1SDavid du Colombier { 193e12c5d1SDavid du Colombier while (whichtmp > 0) { 203e12c5d1SDavid du Colombier whichtmp--; 213e12c5d1SDavid du Colombier remove(tmp[whichtmp]); 223e12c5d1SDavid du Colombier } 233e12c5d1SDavid du Colombier } 243e12c5d1SDavid du Colombier 253e12c5d1SDavid du Colombier void 263e12c5d1SDavid du Colombier done(int status) 273e12c5d1SDavid du Colombier { 283e12c5d1SDavid du Colombier rmtmpfiles(); 293e12c5d1SDavid du Colombier switch(status) 303e12c5d1SDavid du Colombier { 313e12c5d1SDavid du Colombier case 0: 323e12c5d1SDavid du Colombier exits(""); 333e12c5d1SDavid du Colombier case 1: 343e12c5d1SDavid du Colombier exits("some"); 353e12c5d1SDavid du Colombier default: 363e12c5d1SDavid du Colombier exits("error"); 373e12c5d1SDavid du Colombier } 383e12c5d1SDavid du Colombier /*NOTREACHED*/ 393e12c5d1SDavid du Colombier } 403e12c5d1SDavid du Colombier 413e12c5d1SDavid du Colombier void 427dd7cddfSDavid du Colombier panic(int status, char *fmt, ...) 433e12c5d1SDavid du Colombier { 447dd7cddfSDavid du Colombier va_list arg; 453e12c5d1SDavid du Colombier 463e12c5d1SDavid du Colombier Bflush(&stdout); 477dd7cddfSDavid du Colombier 48*9a747e4fSDavid du Colombier fprint(2, "%s: ", progname); 497dd7cddfSDavid du Colombier va_start(arg, fmt); 50*9a747e4fSDavid du Colombier vfprint(2, fmt, arg); 517dd7cddfSDavid du Colombier va_end(arg); 523e12c5d1SDavid du Colombier if (status) 533e12c5d1SDavid du Colombier done(status); 543e12c5d1SDavid du Colombier /*NOTREACHED*/ 553e12c5d1SDavid du Colombier } 563e12c5d1SDavid du Colombier 573e12c5d1SDavid du Colombier static int 583e12c5d1SDavid du Colombier catch(void *a, char *msg) 593e12c5d1SDavid du Colombier { 603e12c5d1SDavid du Colombier USED(a); 613e12c5d1SDavid du Colombier panic(2, msg); 623e12c5d1SDavid du Colombier return 1; 633e12c5d1SDavid du Colombier } 643e12c5d1SDavid du Colombier 653e12c5d1SDavid du Colombier int 663e12c5d1SDavid du Colombier mkpathname(char *pathname, char *path, char *name) 673e12c5d1SDavid du Colombier { 683e12c5d1SDavid du Colombier if (strlen(path) + strlen(name) > MAXPATHLEN) { 693e12c5d1SDavid du Colombier panic(0, "pathname %s/%s too long\n", path, name); 703e12c5d1SDavid du Colombier return 1; 713e12c5d1SDavid du Colombier } 723e12c5d1SDavid du Colombier sprint(pathname, "%s/%s", path, name); 733e12c5d1SDavid du Colombier return 0; 743e12c5d1SDavid du Colombier } 753e12c5d1SDavid du Colombier 763e12c5d1SDavid du Colombier static char * 77*9a747e4fSDavid du Colombier mktmpfile(int input, Dir **sb) 783e12c5d1SDavid du Colombier { 793e12c5d1SDavid du Colombier int fd, i; 803e12c5d1SDavid du Colombier char *p; 813e12c5d1SDavid du Colombier char buf[8192]; 823e12c5d1SDavid du Colombier 833e12c5d1SDavid du Colombier atnotify(catch, 1); 843e12c5d1SDavid du Colombier p = tmp[whichtmp++]; 853e12c5d1SDavid du Colombier fd = create(p, OWRITE, 0600); 863e12c5d1SDavid du Colombier if (fd < 0) { 87bd389b36SDavid du Colombier panic(mflag ? 0: 2, "cannot create %s: %r\n", p); 883e12c5d1SDavid du Colombier return 0; 893e12c5d1SDavid du Colombier } 903e12c5d1SDavid du Colombier while ((i = read(input, buf, sizeof(buf))) > 0) { 913e12c5d1SDavid du Colombier if ((i = write(fd, buf, i)) < 0) 923e12c5d1SDavid du Colombier break; 933e12c5d1SDavid du Colombier } 94*9a747e4fSDavid du Colombier *sb = dirfstat(fd); 953e12c5d1SDavid du Colombier close(fd); 963e12c5d1SDavid du Colombier if (i < 0) { 97bd389b36SDavid du Colombier panic(mflag ? 0: 2, "cannot read/write %s: %r\n", p); 983e12c5d1SDavid du Colombier return 0; 993e12c5d1SDavid du Colombier } 1003e12c5d1SDavid du Colombier return p; 1013e12c5d1SDavid du Colombier } 1023e12c5d1SDavid du Colombier 1033e12c5d1SDavid du Colombier static char * 104*9a747e4fSDavid du Colombier statfile(char *file, Dir **sb) 1053e12c5d1SDavid du Colombier { 106*9a747e4fSDavid du Colombier Dir *dir; 1073e12c5d1SDavid du Colombier int input; 1083e12c5d1SDavid du Colombier 109*9a747e4fSDavid du Colombier dir = dirstat(file); 110*9a747e4fSDavid du Colombier if(dir == nil) { 111*9a747e4fSDavid du Colombier if (strcmp(file, "-") || (dir = dirfstat(0)) == nil) { 112bd389b36SDavid du Colombier panic(mflag ? 0: 2, "cannot stat %s: %r\n", file); 1133e12c5d1SDavid du Colombier return 0; 1143e12c5d1SDavid du Colombier } 115*9a747e4fSDavid du Colombier free(dir); 116*9a747e4fSDavid du Colombier return mktmpfile(0, sb); 1173e12c5d1SDavid du Colombier } 118*9a747e4fSDavid du Colombier else if (!REGULAR_FILE(dir) && !DIRECTORY(dir)) { 119*9a747e4fSDavid du Colombier free(dir); 1203e12c5d1SDavid du Colombier if ((input = open(file, OREAD)) == -1) { 121bd389b36SDavid du Colombier panic(mflag ? 0: 2, "cannot open %s: %r\n", file); 1223e12c5d1SDavid du Colombier return 0; 1233e12c5d1SDavid du Colombier } 1243e12c5d1SDavid du Colombier file = mktmpfile(input, sb); 1253e12c5d1SDavid du Colombier close(input); 1263e12c5d1SDavid du Colombier } 127*9a747e4fSDavid du Colombier else 128*9a747e4fSDavid du Colombier *sb = dir; 1293e12c5d1SDavid du Colombier return file; 1303e12c5d1SDavid du Colombier } 1313e12c5d1SDavid du Colombier 1323e12c5d1SDavid du Colombier void 1333e12c5d1SDavid du Colombier diff(char *f, char *t, int level) 1343e12c5d1SDavid du Colombier { 1353e12c5d1SDavid du Colombier char *fp, *tp, *p, fb[MAXPATHLEN+1], tb[MAXPATHLEN+1]; 136*9a747e4fSDavid du Colombier Dir *fsb, *tsb; 1373e12c5d1SDavid du Colombier 1383e12c5d1SDavid du Colombier if ((fp = statfile(f, &fsb)) == 0) 1393e12c5d1SDavid du Colombier return; 140*9a747e4fSDavid du Colombier if ((tp = statfile(t, &tsb)) == 0){ 141*9a747e4fSDavid du Colombier free(fsb); 1423e12c5d1SDavid du Colombier return; 143*9a747e4fSDavid du Colombier } 1443e12c5d1SDavid du Colombier if (DIRECTORY(fsb) && DIRECTORY(tsb)) { 1453e12c5d1SDavid du Colombier if (rflag || level == 0) 1463e12c5d1SDavid du Colombier diffdir(fp, tp, level); 1473e12c5d1SDavid du Colombier else 1483e12c5d1SDavid du Colombier Bprint(&stdout, "Common subdirectories: %s and %s\n", 1493e12c5d1SDavid du Colombier fp, tp); 1503e12c5d1SDavid du Colombier } 1513e12c5d1SDavid du Colombier else if (REGULAR_FILE(fsb) && REGULAR_FILE(tsb)) 1523e12c5d1SDavid du Colombier diffreg(fp, tp); 1533e12c5d1SDavid du Colombier else { 1543e12c5d1SDavid du Colombier if (REGULAR_FILE(fsb)) { 1553e12c5d1SDavid du Colombier if ((p = utfrrune(f, '/')) == 0) 1563e12c5d1SDavid du Colombier p = f; 1573e12c5d1SDavid du Colombier else 1583e12c5d1SDavid du Colombier p++; 159*9a747e4fSDavid du Colombier if (mkpathname(tb, tp, p) == 0) 1603e12c5d1SDavid du Colombier diffreg(fp, tb); 1613e12c5d1SDavid du Colombier } 1623e12c5d1SDavid du Colombier else { 1633e12c5d1SDavid du Colombier if ((p = utfrrune(t, '/')) == 0) 1643e12c5d1SDavid du Colombier p = t; 1653e12c5d1SDavid du Colombier else 1663e12c5d1SDavid du Colombier p++; 167*9a747e4fSDavid du Colombier if (mkpathname(fb, fp, p) == 0) 1683e12c5d1SDavid du Colombier diffreg(fb, tp); 1693e12c5d1SDavid du Colombier } 1703e12c5d1SDavid du Colombier } 171*9a747e4fSDavid du Colombier free(fsb); 172*9a747e4fSDavid du Colombier free(tsb); 1733e12c5d1SDavid du Colombier } 1743e12c5d1SDavid du Colombier 1753e12c5d1SDavid du Colombier void 1763e12c5d1SDavid du Colombier main(int argc, char *argv[]) 1773e12c5d1SDavid du Colombier { 1783e12c5d1SDavid du Colombier char *p; 1793e12c5d1SDavid du Colombier int i; 180*9a747e4fSDavid du Colombier Dir *fsb, *tsb; 1813e12c5d1SDavid du Colombier 1823e12c5d1SDavid du Colombier Binit(&stdout, 1, OWRITE); 1833e12c5d1SDavid du Colombier progname = *argv; 1843e12c5d1SDavid du Colombier while (--argc && (*++argv)[0] == '-' && (*argv)[1]) { 1853e12c5d1SDavid du Colombier for (p = *argv+1; *p; p++) { 1863e12c5d1SDavid du Colombier switch (*p) { 1873e12c5d1SDavid du Colombier 1883e12c5d1SDavid du Colombier case 'e': 1893e12c5d1SDavid du Colombier case 'f': 1907dd7cddfSDavid du Colombier case 'n': 1913e12c5d1SDavid du Colombier mode = *p; 1923e12c5d1SDavid du Colombier break; 1933e12c5d1SDavid du Colombier 1943e12c5d1SDavid du Colombier case 'w': 1953e12c5d1SDavid du Colombier bflag = 2; 1963e12c5d1SDavid du Colombier break; 1973e12c5d1SDavid du Colombier 1983e12c5d1SDavid du Colombier case 'b': 1993e12c5d1SDavid du Colombier bflag = 1; 2003e12c5d1SDavid du Colombier break; 2013e12c5d1SDavid du Colombier 2023e12c5d1SDavid du Colombier case 'r': 2033e12c5d1SDavid du Colombier rflag = 1; 2043e12c5d1SDavid du Colombier break; 2053e12c5d1SDavid du Colombier 2067dd7cddfSDavid du Colombier case 'm': 2077dd7cddfSDavid du Colombier mflag = 1; 2087dd7cddfSDavid du Colombier break; 2097dd7cddfSDavid du Colombier 2103e12c5d1SDavid du Colombier case 'h': 2113e12c5d1SDavid du Colombier default: 2123e12c5d1SDavid du Colombier progname = "Usage"; 2133e12c5d1SDavid du Colombier panic(2, usage); 2143e12c5d1SDavid du Colombier } 2153e12c5d1SDavid du Colombier } 2163e12c5d1SDavid du Colombier } 2173e12c5d1SDavid du Colombier if (argc < 2) 2183e12c5d1SDavid du Colombier panic(2, usage, progname); 219*9a747e4fSDavid du Colombier if ((tsb = dirstat(argv[argc-1])) == nil) 2203e12c5d1SDavid du Colombier panic(2, "can't stat %s\n", argv[argc-1]); 2213e12c5d1SDavid du Colombier if (argc > 2) { 2223e12c5d1SDavid du Colombier if (!DIRECTORY(tsb)) 2233e12c5d1SDavid du Colombier panic(2, usage, progname); 2243e12c5d1SDavid du Colombier mflag = 1; 2253e12c5d1SDavid du Colombier } 2263e12c5d1SDavid du Colombier else { 227*9a747e4fSDavid du Colombier if ((fsb = dirstat(argv[0])) == nil) 2283e12c5d1SDavid du Colombier panic(2, "can't stat %s\n", argv[0]); 2293e12c5d1SDavid du Colombier if (DIRECTORY(fsb) && DIRECTORY(tsb)) 2303e12c5d1SDavid du Colombier mflag = 1; 231*9a747e4fSDavid du Colombier free(fsb); 2323e12c5d1SDavid du Colombier } 233*9a747e4fSDavid du Colombier free(tsb); 2343e12c5d1SDavid du Colombier for (i = 0; i < argc-1; i++) { 2353e12c5d1SDavid du Colombier diff(argv[i], argv[argc-1], 0); 2363e12c5d1SDavid du Colombier rmtmpfiles(); 2373e12c5d1SDavid du Colombier } 2383e12c5d1SDavid du Colombier done(anychange); 2393e12c5d1SDavid du Colombier /*NOTREACHED*/ 2403e12c5d1SDavid du Colombier } 2413e12c5d1SDavid du Colombier 2423e12c5d1SDavid du Colombier static char noroom[] = "out of memory - try diff -h\n"; 2433e12c5d1SDavid du Colombier 2443e12c5d1SDavid du Colombier void * 2453e12c5d1SDavid du Colombier emalloc(unsigned n) 2463e12c5d1SDavid du Colombier { 2473e12c5d1SDavid du Colombier register void *p; 2483e12c5d1SDavid du Colombier 2493e12c5d1SDavid du Colombier if ((p = malloc(n)) == 0) 2503e12c5d1SDavid du Colombier panic(2, noroom); 2513e12c5d1SDavid du Colombier return p; 2523e12c5d1SDavid du Colombier } 2533e12c5d1SDavid du Colombier 2543e12c5d1SDavid du Colombier void * 2553e12c5d1SDavid du Colombier erealloc(void *p, unsigned n) 2563e12c5d1SDavid du Colombier { 2573e12c5d1SDavid du Colombier register void *rp; 2583e12c5d1SDavid du Colombier 2593e12c5d1SDavid du Colombier if ((rp = realloc(p, n)) == 0) 2603e12c5d1SDavid du Colombier panic(2, noroom); 2613e12c5d1SDavid du Colombier return rp; 2623e12c5d1SDavid du Colombier } 263