1*3e12c5d1SDavid du Colombier #include <u.h> 2*3e12c5d1SDavid du Colombier #include <libc.h> 3*3e12c5d1SDavid du Colombier #include <bio.h> 4*3e12c5d1SDavid du Colombier #include "diff.h" 5*3e12c5d1SDavid du Colombier 6*3e12c5d1SDavid du Colombier #define DIRECTORY(s) ((s).qid.path&CHDIR) 7*3e12c5d1SDavid du Colombier #define REGULAR_FILE(s) ((s).type == 'M' && !DIRECTORY(s)) 8*3e12c5d1SDavid du Colombier 9*3e12c5d1SDavid du Colombier Biobuf stdout; 10*3e12c5d1SDavid du Colombier 11*3e12c5d1SDavid du Colombier static char *tmp[] = {"/tmp/diff1", "/tmp/diff2"}; 12*3e12c5d1SDavid du Colombier static int whichtmp; 13*3e12c5d1SDavid du Colombier static char *progname; 14*3e12c5d1SDavid du Colombier static char usage[] = "diff [ -efbwr ] file1 ... file2\n"; 15*3e12c5d1SDavid du Colombier 16*3e12c5d1SDavid du Colombier static void 17*3e12c5d1SDavid du Colombier rmtmpfiles(void) 18*3e12c5d1SDavid du Colombier { 19*3e12c5d1SDavid du Colombier while (whichtmp > 0) { 20*3e12c5d1SDavid du Colombier whichtmp--; 21*3e12c5d1SDavid du Colombier remove(tmp[whichtmp]); 22*3e12c5d1SDavid du Colombier } 23*3e12c5d1SDavid du Colombier } 24*3e12c5d1SDavid du Colombier 25*3e12c5d1SDavid du Colombier void 26*3e12c5d1SDavid du Colombier done(int status) 27*3e12c5d1SDavid du Colombier { 28*3e12c5d1SDavid du Colombier rmtmpfiles(); 29*3e12c5d1SDavid du Colombier switch(status) 30*3e12c5d1SDavid du Colombier { 31*3e12c5d1SDavid du Colombier case 0: 32*3e12c5d1SDavid du Colombier exits(""); 33*3e12c5d1SDavid du Colombier case 1: 34*3e12c5d1SDavid du Colombier exits("some"); 35*3e12c5d1SDavid du Colombier default: 36*3e12c5d1SDavid du Colombier exits("error"); 37*3e12c5d1SDavid du Colombier } 38*3e12c5d1SDavid du Colombier /*NOTREACHED*/ 39*3e12c5d1SDavid du Colombier } 40*3e12c5d1SDavid du Colombier 41*3e12c5d1SDavid du Colombier void 42*3e12c5d1SDavid du Colombier panic(int status, char *format, ...) 43*3e12c5d1SDavid du Colombier { 44*3e12c5d1SDavid du Colombier char buf[1024], *out; 45*3e12c5d1SDavid du Colombier 46*3e12c5d1SDavid du Colombier Bflush(&stdout); 47*3e12c5d1SDavid du Colombier out = doprint(buf, buf+sizeof(buf), "%s: ", &progname); 48*3e12c5d1SDavid du Colombier out = doprint(out, buf+sizeof(buf), format, ((long*)&format)+1); 49*3e12c5d1SDavid du Colombier write(2, buf, out-buf); 50*3e12c5d1SDavid du Colombier if (status) 51*3e12c5d1SDavid du Colombier done(status); 52*3e12c5d1SDavid du Colombier /*NOTREACHED*/ 53*3e12c5d1SDavid du Colombier } 54*3e12c5d1SDavid du Colombier 55*3e12c5d1SDavid du Colombier static int 56*3e12c5d1SDavid du Colombier catch(void *a, char *msg) 57*3e12c5d1SDavid du Colombier { 58*3e12c5d1SDavid du Colombier USED(a); 59*3e12c5d1SDavid du Colombier panic(2, msg); 60*3e12c5d1SDavid du Colombier return 1; 61*3e12c5d1SDavid du Colombier } 62*3e12c5d1SDavid du Colombier 63*3e12c5d1SDavid du Colombier int 64*3e12c5d1SDavid du Colombier mkpathname(char *pathname, char *path, char *name) 65*3e12c5d1SDavid du Colombier { 66*3e12c5d1SDavid du Colombier if (strlen(path) + strlen(name) > MAXPATHLEN) { 67*3e12c5d1SDavid du Colombier panic(0, "pathname %s/%s too long\n", path, name); 68*3e12c5d1SDavid du Colombier return 1; 69*3e12c5d1SDavid du Colombier } 70*3e12c5d1SDavid du Colombier sprint(pathname, "%s/%s", path, name); 71*3e12c5d1SDavid du Colombier return 0; 72*3e12c5d1SDavid du Colombier } 73*3e12c5d1SDavid du Colombier 74*3e12c5d1SDavid du Colombier static char * 75*3e12c5d1SDavid du Colombier mktmpfile(int input, Dir *sb) 76*3e12c5d1SDavid du Colombier { 77*3e12c5d1SDavid du Colombier int fd, i; 78*3e12c5d1SDavid du Colombier char *p; 79*3e12c5d1SDavid du Colombier char buf[8192]; 80*3e12c5d1SDavid du Colombier 81*3e12c5d1SDavid du Colombier atnotify(catch, 1); 82*3e12c5d1SDavid du Colombier p = tmp[whichtmp++]; 83*3e12c5d1SDavid du Colombier fd = create(p, OWRITE, 0600); 84*3e12c5d1SDavid du Colombier if (fd < 0) { 85*3e12c5d1SDavid du Colombier panic(mflag ? 0: 2, "cannot create %s\n", p); 86*3e12c5d1SDavid du Colombier return 0; 87*3e12c5d1SDavid du Colombier } 88*3e12c5d1SDavid du Colombier while ((i = read(input, buf, sizeof(buf))) > 0) { 89*3e12c5d1SDavid du Colombier if ((i = write(fd, buf, i)) < 0) 90*3e12c5d1SDavid du Colombier break; 91*3e12c5d1SDavid du Colombier } 92*3e12c5d1SDavid du Colombier dirfstat(fd, sb); 93*3e12c5d1SDavid du Colombier close(fd); 94*3e12c5d1SDavid du Colombier if (i < 0) { 95*3e12c5d1SDavid du Colombier panic(mflag ? 0: 2, "cannot read/write %s\n", p); 96*3e12c5d1SDavid du Colombier return 0; 97*3e12c5d1SDavid du Colombier } 98*3e12c5d1SDavid du Colombier return p; 99*3e12c5d1SDavid du Colombier } 100*3e12c5d1SDavid du Colombier 101*3e12c5d1SDavid du Colombier static char * 102*3e12c5d1SDavid du Colombier statfile(char *file, Dir *sb) 103*3e12c5d1SDavid du Colombier { 104*3e12c5d1SDavid du Colombier int input; 105*3e12c5d1SDavid du Colombier 106*3e12c5d1SDavid du Colombier if (dirstat(file, sb) == -1) { 107*3e12c5d1SDavid du Colombier if (strcmp(file, "-") || dirfstat(0, sb) == -1) { 108*3e12c5d1SDavid du Colombier panic(mflag ? 0: 2, "cannot stat %s\n", file); 109*3e12c5d1SDavid du Colombier return 0; 110*3e12c5d1SDavid du Colombier } 111*3e12c5d1SDavid du Colombier file = mktmpfile(0, sb); 112*3e12c5d1SDavid du Colombier } 113*3e12c5d1SDavid du Colombier else if (!REGULAR_FILE(*sb) && !DIRECTORY(*sb)) { 114*3e12c5d1SDavid du Colombier if ((input = open(file, OREAD)) == -1) { 115*3e12c5d1SDavid du Colombier panic(mflag ? 0: 2, "cannot open %s\n", file); 116*3e12c5d1SDavid du Colombier return 0; 117*3e12c5d1SDavid du Colombier } 118*3e12c5d1SDavid du Colombier file = mktmpfile(input, sb); 119*3e12c5d1SDavid du Colombier close(input); 120*3e12c5d1SDavid du Colombier } 121*3e12c5d1SDavid du Colombier return file; 122*3e12c5d1SDavid du Colombier } 123*3e12c5d1SDavid du Colombier 124*3e12c5d1SDavid du Colombier void 125*3e12c5d1SDavid du Colombier diff(char *f, char *t, int level) 126*3e12c5d1SDavid du Colombier { 127*3e12c5d1SDavid du Colombier char *fp, *tp, *p, fb[MAXPATHLEN+1], tb[MAXPATHLEN+1]; 128*3e12c5d1SDavid du Colombier Dir fsb, tsb; 129*3e12c5d1SDavid du Colombier 130*3e12c5d1SDavid du Colombier if ((fp = statfile(f, &fsb)) == 0) 131*3e12c5d1SDavid du Colombier return; 132*3e12c5d1SDavid du Colombier if ((tp = statfile(t, &tsb)) == 0) 133*3e12c5d1SDavid du Colombier return; 134*3e12c5d1SDavid du Colombier if (DIRECTORY(fsb) && DIRECTORY(tsb)) { 135*3e12c5d1SDavid du Colombier if (rflag || level == 0) 136*3e12c5d1SDavid du Colombier diffdir(fp, tp, level); 137*3e12c5d1SDavid du Colombier else 138*3e12c5d1SDavid du Colombier Bprint(&stdout, "Common subdirectories: %s and %s\n", 139*3e12c5d1SDavid du Colombier fp, tp); 140*3e12c5d1SDavid du Colombier } 141*3e12c5d1SDavid du Colombier else if (REGULAR_FILE(fsb) && REGULAR_FILE(tsb)) 142*3e12c5d1SDavid du Colombier diffreg(fp, tp); 143*3e12c5d1SDavid du Colombier else { 144*3e12c5d1SDavid du Colombier if (REGULAR_FILE(fsb)) { 145*3e12c5d1SDavid du Colombier if ((p = utfrrune(f, '/')) == 0) 146*3e12c5d1SDavid du Colombier p = f; 147*3e12c5d1SDavid du Colombier else 148*3e12c5d1SDavid du Colombier p++; 149*3e12c5d1SDavid du Colombier if (mkpathname(tb, tp, p)) 150*3e12c5d1SDavid du Colombier return; 151*3e12c5d1SDavid du Colombier diffreg(fp, tb); 152*3e12c5d1SDavid du Colombier } 153*3e12c5d1SDavid du Colombier else { 154*3e12c5d1SDavid du Colombier if ((p = utfrrune(t, '/')) == 0) 155*3e12c5d1SDavid du Colombier p = t; 156*3e12c5d1SDavid du Colombier else 157*3e12c5d1SDavid du Colombier p++; 158*3e12c5d1SDavid du Colombier if (mkpathname(fb, fp, p)) 159*3e12c5d1SDavid du Colombier return; 160*3e12c5d1SDavid du Colombier diffreg(fb, tp); 161*3e12c5d1SDavid du Colombier } 162*3e12c5d1SDavid du Colombier } 163*3e12c5d1SDavid du Colombier } 164*3e12c5d1SDavid du Colombier 165*3e12c5d1SDavid du Colombier void 166*3e12c5d1SDavid du Colombier main(int argc, char *argv[]) 167*3e12c5d1SDavid du Colombier { 168*3e12c5d1SDavid du Colombier char *p; 169*3e12c5d1SDavid du Colombier int i; 170*3e12c5d1SDavid du Colombier Dir fsb, tsb; 171*3e12c5d1SDavid du Colombier 172*3e12c5d1SDavid du Colombier Binit(&stdout, 1, OWRITE); 173*3e12c5d1SDavid du Colombier progname = *argv; 174*3e12c5d1SDavid du Colombier while (--argc && (*++argv)[0] == '-' && (*argv)[1]) { 175*3e12c5d1SDavid du Colombier for (p = *argv+1; *p; p++) { 176*3e12c5d1SDavid du Colombier switch (*p) { 177*3e12c5d1SDavid du Colombier 178*3e12c5d1SDavid du Colombier case 'e': 179*3e12c5d1SDavid du Colombier case 'f': 180*3e12c5d1SDavid du Colombier mode = *p; 181*3e12c5d1SDavid du Colombier break; 182*3e12c5d1SDavid du Colombier 183*3e12c5d1SDavid du Colombier case 'w': 184*3e12c5d1SDavid du Colombier bflag = 2; 185*3e12c5d1SDavid du Colombier break; 186*3e12c5d1SDavid du Colombier 187*3e12c5d1SDavid du Colombier case 'b': 188*3e12c5d1SDavid du Colombier bflag = 1; 189*3e12c5d1SDavid du Colombier break; 190*3e12c5d1SDavid du Colombier 191*3e12c5d1SDavid du Colombier case 'r': 192*3e12c5d1SDavid du Colombier rflag = 1; 193*3e12c5d1SDavid du Colombier break; 194*3e12c5d1SDavid du Colombier 195*3e12c5d1SDavid du Colombier case 'h': 196*3e12c5d1SDavid du Colombier default: 197*3e12c5d1SDavid du Colombier progname = "Usage"; 198*3e12c5d1SDavid du Colombier panic(2, usage); 199*3e12c5d1SDavid du Colombier } 200*3e12c5d1SDavid du Colombier } 201*3e12c5d1SDavid du Colombier } 202*3e12c5d1SDavid du Colombier if (argc < 2) 203*3e12c5d1SDavid du Colombier panic(2, usage, progname); 204*3e12c5d1SDavid du Colombier if (dirstat(argv[argc-1], &tsb) == -1) 205*3e12c5d1SDavid du Colombier panic(2, "can't stat %s\n", argv[argc-1]); 206*3e12c5d1SDavid du Colombier if (argc > 2) { 207*3e12c5d1SDavid du Colombier if (!DIRECTORY(tsb)) 208*3e12c5d1SDavid du Colombier panic(2, usage, progname); 209*3e12c5d1SDavid du Colombier mflag = 1; 210*3e12c5d1SDavid du Colombier } 211*3e12c5d1SDavid du Colombier else { 212*3e12c5d1SDavid du Colombier if (dirstat(argv[0], &fsb) == -1) 213*3e12c5d1SDavid du Colombier panic(2, "can't stat %s\n", argv[0]); 214*3e12c5d1SDavid du Colombier if (DIRECTORY(fsb) && DIRECTORY(tsb)) 215*3e12c5d1SDavid du Colombier mflag = 1; 216*3e12c5d1SDavid du Colombier } 217*3e12c5d1SDavid du Colombier for (i = 0; i < argc-1; i++) { 218*3e12c5d1SDavid du Colombier diff(argv[i], argv[argc-1], 0); 219*3e12c5d1SDavid du Colombier rmtmpfiles(); 220*3e12c5d1SDavid du Colombier } 221*3e12c5d1SDavid du Colombier done(anychange); 222*3e12c5d1SDavid du Colombier /*NOTREACHED*/ 223*3e12c5d1SDavid du Colombier } 224*3e12c5d1SDavid du Colombier 225*3e12c5d1SDavid du Colombier static char noroom[] = "out of memory - try diff -h\n"; 226*3e12c5d1SDavid du Colombier 227*3e12c5d1SDavid du Colombier void * 228*3e12c5d1SDavid du Colombier emalloc(unsigned n) 229*3e12c5d1SDavid du Colombier { 230*3e12c5d1SDavid du Colombier register void *p; 231*3e12c5d1SDavid du Colombier 232*3e12c5d1SDavid du Colombier if ((p = malloc(n)) == 0) 233*3e12c5d1SDavid du Colombier panic(2, noroom); 234*3e12c5d1SDavid du Colombier return p; 235*3e12c5d1SDavid du Colombier } 236*3e12c5d1SDavid du Colombier 237*3e12c5d1SDavid du Colombier void * 238*3e12c5d1SDavid du Colombier erealloc(void *p, unsigned n) 239*3e12c5d1SDavid du Colombier { 240*3e12c5d1SDavid du Colombier register void *rp; 241*3e12c5d1SDavid du Colombier 242*3e12c5d1SDavid du Colombier if ((rp = realloc(p, n)) == 0) 243*3e12c5d1SDavid du Colombier panic(2, noroom); 244*3e12c5d1SDavid du Colombier return rp; 245*3e12c5d1SDavid du Colombier } 246