main.c (4447B)
1 #include <u.h> 2 #include <libc.h> 3 #include <bio.h> 4 #include "diff.h" 5 6 #define DIRECTORY(s) ((s)->qid.type&QTDIR) 7 #define REGULAR_FILE(s) ((s)->type == 'M' && !DIRECTORY(s)) 8 9 Biobuf stdout; 10 11 static char *tmp[] = {"/tmp/diff1XXXXXXXXXXX", "/tmp/diff2XXXXXXXXXXX"}; 12 static int whichtmp; 13 static char *progname; 14 static char usage[] = "diff [ -acefmnbwr ] 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 *fmt, ...) 43 { 44 va_list arg; 45 46 Bflush(&stdout); 47 48 fprint(2, "%s: ", progname); 49 va_start(arg, fmt); 50 vfprint(2, fmt, arg); 51 va_end(arg); 52 if (status) 53 done(status); 54 /*NOTREACHED*/ 55 } 56 57 static int 58 catch(void *a, char *msg) 59 { 60 USED(a); 61 panic(2, msg); 62 return 1; 63 } 64 65 int 66 mkpathname(char *pathname, char *path, char *name) 67 { 68 if (strlen(path) + strlen(name) > MAXPATHLEN) { 69 panic(0, "pathname %s/%s too long\n", path, name); 70 return 1; 71 } 72 sprint(pathname, "%s/%s", path, name); 73 return 0; 74 } 75 76 static char * 77 mktmpfile(int input, Dir **sb) 78 { 79 int fd, i; 80 char *p; 81 char buf[8192]; 82 83 atnotify(catch, 1); 84 /* 85 p = mktemp(tmp[whichtmp++]); 86 fd = create(p, OWRITE, 0600); 87 */ 88 fd = mkstemp(p=tmp[whichtmp++]); 89 if (fd < 0) { 90 panic(mflag ? 0: 2, "cannot create %s: %r\n", p); 91 return 0; 92 } 93 while ((i = read(input, buf, sizeof(buf))) > 0) { 94 if ((i = write(fd, buf, i)) < 0) 95 break; 96 } 97 *sb = dirfstat(fd); 98 close(fd); 99 if (i < 0) { 100 panic(mflag ? 0: 2, "cannot read/write %s: %r\n", p); 101 return 0; 102 } 103 return p; 104 } 105 106 static char * 107 statfile(char *file, Dir **sb) 108 { 109 Dir *dir; 110 int input; 111 112 dir = dirstat(file); 113 if(dir == nil) { 114 if (strcmp(file, "-") || (dir = dirfstat(0)) == nil) { 115 panic(mflag ? 0: 2, "cannot stat %s: %r\n", file); 116 return 0; 117 } 118 free(dir); 119 return mktmpfile(0, sb); 120 } 121 else if (!REGULAR_FILE(dir) && !DIRECTORY(dir)) { 122 free(dir); 123 if ((input = open(file, OREAD)) == -1) { 124 panic(mflag ? 0: 2, "cannot open %s: %r\n", file); 125 return 0; 126 } 127 file = mktmpfile(input, sb); 128 close(input); 129 } 130 else 131 *sb = dir; 132 return file; 133 } 134 135 void 136 diff(char *f, char *t, int level) 137 { 138 char *fp, *tp, *p, fb[MAXPATHLEN+1], tb[MAXPATHLEN+1]; 139 Dir *fsb, *tsb; 140 141 if ((fp = statfile(f, &fsb)) == 0) 142 goto Return; 143 if ((tp = statfile(t, &tsb)) == 0){ 144 free(fsb); 145 goto Return; 146 } 147 if (DIRECTORY(fsb) && DIRECTORY(tsb)) { 148 if (rflag || level == 0) 149 diffdir(fp, tp, level); 150 else 151 Bprint(&stdout, "Common subdirectories: %s and %s\n", 152 fp, tp); 153 } 154 else if (REGULAR_FILE(fsb) && REGULAR_FILE(tsb)) 155 diffreg(fp, tp); 156 else { 157 if (REGULAR_FILE(fsb)) { 158 if ((p = utfrrune(f, '/')) == 0) 159 p = f; 160 else 161 p++; 162 if (mkpathname(tb, tp, p) == 0) 163 diffreg(fp, tb); 164 } 165 else { 166 if ((p = utfrrune(t, '/')) == 0) 167 p = t; 168 else 169 p++; 170 if (mkpathname(fb, fp, p) == 0) 171 diffreg(fb, tp); 172 } 173 } 174 free(fsb); 175 free(tsb); 176 Return: 177 rmtmpfiles(); 178 } 179 180 void 181 main(int argc, char *argv[]) 182 { 183 char *p; 184 int i; 185 Dir *fsb, *tsb; 186 extern int _p9usepwlibrary; 187 188 _p9usepwlibrary = 0; 189 Binit(&stdout, 1, OWRITE); 190 progname = *argv; 191 while (--argc && (*++argv)[0] == '-' && (*argv)[1]) { 192 for (p = *argv+1; *p; p++) { 193 switch (*p) { 194 195 case 'e': 196 case 'f': 197 case 'n': 198 case 'c': 199 case 'a': 200 mode = *p; 201 break; 202 203 case 'w': 204 bflag = 2; 205 break; 206 207 case 'b': 208 bflag = 1; 209 break; 210 211 case 'r': 212 rflag = 1; 213 mflag = 1; 214 break; 215 216 case 'm': 217 mflag = 1; 218 break; 219 220 case 'h': 221 default: 222 progname = "Usage"; 223 panic(2, usage); 224 } 225 } 226 } 227 if (argc < 2) 228 panic(2, usage, progname); 229 if ((tsb = dirstat(argv[argc-1])) == nil) 230 panic(2, "can't stat %s\n", argv[argc-1]); 231 if (argc > 2) { 232 if (!DIRECTORY(tsb)) 233 panic(2, usage, progname); 234 mflag = 1; 235 } 236 else { 237 if ((fsb = dirstat(argv[0])) == nil) 238 panic(2, "can't stat %s\n", argv[0]); 239 if (DIRECTORY(fsb) && DIRECTORY(tsb)) 240 mflag = 1; 241 free(fsb); 242 } 243 free(tsb); 244 for (i = 0; i < argc-1; i++) 245 diff(argv[i], argv[argc-1], 0); 246 done(anychange); 247 /*NOTREACHED*/ 248 } 249 250 static char noroom[] = "out of memory - try diff -h\n"; 251 252 void * 253 emalloc(unsigned n) 254 { 255 register void *p; 256 257 if ((p = malloc(n)) == 0) 258 panic(2, noroom); 259 return p; 260 } 261 262 void * 263 erealloc(void *p, unsigned n) 264 { 265 register void *rp; 266 267 if ((rp = realloc(p, n)) == 0) 268 panic(2, noroom); 269 return rp; 270 }