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