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
69a747e4fSDavid du Colombier #define DIRECTORY(s) ((s)->qid.type&QTDIR)
79a747e4fSDavid du Colombier #define REGULAR_FILE(s) ((s)->type == 'M' && !DIRECTORY(s))
83e12c5d1SDavid du Colombier
93e12c5d1SDavid du Colombier Biobuf stdout;
103e12c5d1SDavid du Colombier
11756ec291SDavid du Colombier static char *tmp[] = {"/tmp/diff1XXXXXXXXXXX", "/tmp/diff2XXXXXXXXXXX"};
123e12c5d1SDavid du Colombier static int whichtmp;
133e12c5d1SDavid du Colombier static char *progname;
14754a2748SDavid du Colombier static char usage[] = "diff [-abcefmnrw] file1 ... file2\n";
153e12c5d1SDavid du Colombier
163e12c5d1SDavid du Colombier static void
rmtmpfiles(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
done(int status)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
panic(int status,char * fmt,...)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
489a747e4fSDavid du Colombier fprint(2, "%s: ", progname);
497dd7cddfSDavid du Colombier va_start(arg, fmt);
509a747e4fSDavid 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
catch(void * a,char * msg)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
mkpathname(char * pathname,char * path,char * name)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 *
mktmpfile(int input,Dir ** sb)779a747e4fSDavid 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);
84756ec291SDavid du Colombier p = mktemp(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 }
949a747e4fSDavid 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 *
statfile(char * file,Dir ** sb)1049a747e4fSDavid du Colombier statfile(char *file, Dir **sb)
1053e12c5d1SDavid du Colombier {
1069a747e4fSDavid du Colombier Dir *dir;
1073e12c5d1SDavid du Colombier int input;
1083e12c5d1SDavid du Colombier
1099a747e4fSDavid du Colombier dir = dirstat(file);
1109a747e4fSDavid du Colombier if(dir == nil) {
1119a747e4fSDavid 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 }
1159a747e4fSDavid du Colombier free(dir);
1169a747e4fSDavid du Colombier return mktmpfile(0, sb);
1173e12c5d1SDavid du Colombier }
1189a747e4fSDavid du Colombier else if (!REGULAR_FILE(dir) && !DIRECTORY(dir)) {
1199a747e4fSDavid 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 }
1279a747e4fSDavid du Colombier else
1289a747e4fSDavid du Colombier *sb = dir;
1293e12c5d1SDavid du Colombier return file;
1303e12c5d1SDavid du Colombier }
1313e12c5d1SDavid du Colombier
1323e12c5d1SDavid du Colombier void
diff(char * f,char * t,int level)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];
1369a747e4fSDavid du Colombier Dir *fsb, *tsb;
1373e12c5d1SDavid du Colombier
1383e12c5d1SDavid du Colombier if ((fp = statfile(f, &fsb)) == 0)
13915174232SDavid du Colombier goto Return;
1409a747e4fSDavid du Colombier if ((tp = statfile(t, &tsb)) == 0){
1419a747e4fSDavid du Colombier free(fsb);
14215174232SDavid du Colombier goto Return;
1439a747e4fSDavid 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++;
1599a747e4fSDavid 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++;
1679a747e4fSDavid du Colombier if (mkpathname(fb, fp, p) == 0)
1683e12c5d1SDavid du Colombier diffreg(fb, tp);
1693e12c5d1SDavid du Colombier }
1703e12c5d1SDavid du Colombier }
1719a747e4fSDavid du Colombier free(fsb);
1729a747e4fSDavid du Colombier free(tsb);
17315174232SDavid du Colombier Return:
17415174232SDavid du Colombier rmtmpfiles();
1753e12c5d1SDavid du Colombier }
1763e12c5d1SDavid du Colombier
1773e12c5d1SDavid du Colombier void
main(int argc,char * argv[])1783e12c5d1SDavid du Colombier main(int argc, char *argv[])
1793e12c5d1SDavid du Colombier {
1803e12c5d1SDavid du Colombier char *p;
1813e12c5d1SDavid du Colombier int i;
1829a747e4fSDavid du Colombier Dir *fsb, *tsb;
1833e12c5d1SDavid du Colombier
1843e12c5d1SDavid du Colombier Binit(&stdout, 1, OWRITE);
185*56e2d73cSDavid du Colombier progname = argv0 = *argv;
1863e12c5d1SDavid du Colombier while (--argc && (*++argv)[0] == '-' && (*argv)[1]) {
1873e12c5d1SDavid du Colombier for (p = *argv+1; *p; p++) {
1883e12c5d1SDavid du Colombier switch (*p) {
1893e12c5d1SDavid du Colombier
1903e12c5d1SDavid du Colombier case 'e':
1913e12c5d1SDavid du Colombier case 'f':
1927dd7cddfSDavid du Colombier case 'n':
193a7534c1eSDavid du Colombier case 'c':
19427e10919SDavid du Colombier case 'a':
1953e12c5d1SDavid du Colombier mode = *p;
1963e12c5d1SDavid du Colombier break;
1973e12c5d1SDavid du Colombier
1983e12c5d1SDavid du Colombier case 'w':
1993e12c5d1SDavid du Colombier bflag = 2;
2003e12c5d1SDavid du Colombier break;
2013e12c5d1SDavid du Colombier
2023e12c5d1SDavid du Colombier case 'b':
2033e12c5d1SDavid du Colombier bflag = 1;
2043e12c5d1SDavid du Colombier break;
2053e12c5d1SDavid du Colombier
2063e12c5d1SDavid du Colombier case 'r':
2073e12c5d1SDavid du Colombier rflag = 1;
2083e12c5d1SDavid du Colombier break;
2093e12c5d1SDavid du Colombier
2107dd7cddfSDavid du Colombier case 'm':
2117dd7cddfSDavid du Colombier mflag = 1;
2127dd7cddfSDavid du Colombier break;
2137dd7cddfSDavid du Colombier
2143e12c5d1SDavid du Colombier case 'h':
2153e12c5d1SDavid du Colombier default:
2163e12c5d1SDavid du Colombier progname = "Usage";
2173e12c5d1SDavid du Colombier panic(2, usage);
2183e12c5d1SDavid du Colombier }
2193e12c5d1SDavid du Colombier }
2203e12c5d1SDavid du Colombier }
2213e12c5d1SDavid du Colombier if (argc < 2)
2223e12c5d1SDavid du Colombier panic(2, usage, progname);
2239a747e4fSDavid du Colombier if ((tsb = dirstat(argv[argc-1])) == nil)
2243e12c5d1SDavid du Colombier panic(2, "can't stat %s\n", argv[argc-1]);
2253e12c5d1SDavid du Colombier if (argc > 2) {
2263e12c5d1SDavid du Colombier if (!DIRECTORY(tsb))
2273e12c5d1SDavid du Colombier panic(2, usage, progname);
2283e12c5d1SDavid du Colombier mflag = 1;
2293e12c5d1SDavid du Colombier }
2303e12c5d1SDavid du Colombier else {
2319a747e4fSDavid du Colombier if ((fsb = dirstat(argv[0])) == nil)
2323e12c5d1SDavid du Colombier panic(2, "can't stat %s\n", argv[0]);
2333e12c5d1SDavid du Colombier if (DIRECTORY(fsb) && DIRECTORY(tsb))
2343e12c5d1SDavid du Colombier mflag = 1;
2359a747e4fSDavid du Colombier free(fsb);
2363e12c5d1SDavid du Colombier }
2379a747e4fSDavid du Colombier free(tsb);
23815174232SDavid du Colombier for (i = 0; i < argc-1; i++)
2393e12c5d1SDavid du Colombier diff(argv[i], argv[argc-1], 0);
2403e12c5d1SDavid du Colombier done(anychange);
2413e12c5d1SDavid du Colombier /*NOTREACHED*/
2423e12c5d1SDavid du Colombier }
2433e12c5d1SDavid du Colombier
2443e12c5d1SDavid du Colombier static char noroom[] = "out of memory - try diff -h\n";
2453e12c5d1SDavid du Colombier
2463e12c5d1SDavid du Colombier void *
emalloc(unsigned n)2473e12c5d1SDavid du Colombier emalloc(unsigned n)
2483e12c5d1SDavid du Colombier {
2493e12c5d1SDavid du Colombier register void *p;
2503e12c5d1SDavid du Colombier
2513e12c5d1SDavid du Colombier if ((p = malloc(n)) == 0)
2523e12c5d1SDavid du Colombier panic(2, noroom);
2533e12c5d1SDavid du Colombier return p;
2543e12c5d1SDavid du Colombier }
2553e12c5d1SDavid du Colombier
2563e12c5d1SDavid du Colombier void *
erealloc(void * p,unsigned n)2573e12c5d1SDavid du Colombier erealloc(void *p, unsigned n)
2583e12c5d1SDavid du Colombier {
2593e12c5d1SDavid du Colombier register void *rp;
2603e12c5d1SDavid du Colombier
2613e12c5d1SDavid du Colombier if ((rp = realloc(p, n)) == 0)
2623e12c5d1SDavid du Colombier panic(2, noroom);
2633e12c5d1SDavid du Colombier return rp;
2643e12c5d1SDavid du Colombier }
265