| main.c - 9base - revived minimalist port of Plan 9 userland to Unix | |
| git clone git://git.suckless.org/9base | |
| Log | |
| Files | |
| Refs | |
| README | |
| LICENSE | |
| --- | |
| 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' && !DIRE… | |
| 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 %… | |
| 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 } |