123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264 |
- #include <u.h>
- #include <libc.h>
- #include <bio.h>
- #include "diff.h"
- #define DIRECTORY(s) ((s)->qid.type&QTDIR)
- #define REGULAR_FILE(s) ((s)->type == 'M' && !DIRECTORY(s))
- Biobuf stdout;
- static char *tmp[] = {"/tmp/diff1XXXXXXXXXXX", "/tmp/diff2XXXXXXXXXXX"};
- static int whichtmp;
- static char *progname;
- static char usage[] = "diff [-abcefmnrw] file1 ... file2\n";
- static void
- rmtmpfiles(void)
- {
- while (whichtmp > 0) {
- whichtmp--;
- remove(tmp[whichtmp]);
- }
- }
- void
- done(int status)
- {
- rmtmpfiles();
- switch(status)
- {
- case 0:
- exits("");
- case 1:
- exits("some");
- default:
- exits("error");
- }
- /*NOTREACHED*/
- }
- void
- panic(int status, char *fmt, ...)
- {
- va_list arg;
- Bflush(&stdout);
- fprint(2, "%s: ", progname);
- va_start(arg, fmt);
- vfprint(2, fmt, arg);
- va_end(arg);
- if (status)
- done(status);
- /*NOTREACHED*/
- }
- static int
- catch(void *a, char *msg)
- {
- USED(a);
- panic(2, msg);
- return 1;
- }
- int
- mkpathname(char *pathname, char *path, char *name)
- {
- if (strlen(path) + strlen(name) > MAXPATHLEN) {
- panic(0, "pathname %s/%s too long\n", path, name);
- return 1;
- }
- sprint(pathname, "%s/%s", path, name);
- return 0;
- }
-
- static char *
- mktmpfile(int input, Dir **sb)
- {
- int fd, i;
- char *p;
- char buf[8192];
- atnotify(catch, 1);
- p = mktemp(tmp[whichtmp++]);
- fd = create(p, OWRITE, 0600);
- if (fd < 0) {
- panic(mflag ? 0: 2, "cannot create %s: %r\n", p);
- return 0;
- }
- while ((i = read(input, buf, sizeof(buf))) > 0) {
- if ((i = write(fd, buf, i)) < 0)
- break;
- }
- *sb = dirfstat(fd);
- close(fd);
- if (i < 0) {
- panic(mflag ? 0: 2, "cannot read/write %s: %r\n", p);
- return 0;
- }
- return p;
- }
- static char *
- statfile(char *file, Dir **sb)
- {
- Dir *dir;
- int input;
- dir = dirstat(file);
- if(dir == nil) {
- if (strcmp(file, "-") || (dir = dirfstat(0)) == nil) {
- panic(mflag ? 0: 2, "cannot stat %s: %r\n", file);
- return 0;
- }
- free(dir);
- return mktmpfile(0, sb);
- }
- else if (!REGULAR_FILE(dir) && !DIRECTORY(dir)) {
- free(dir);
- if ((input = open(file, OREAD)) == -1) {
- panic(mflag ? 0: 2, "cannot open %s: %r\n", file);
- return 0;
- }
- file = mktmpfile(input, sb);
- close(input);
- }
- else
- *sb = dir;
- return file;
- }
- void
- diff(char *f, char *t, int level)
- {
- char *fp, *tp, *p, fb[MAXPATHLEN+1], tb[MAXPATHLEN+1];
- Dir *fsb, *tsb;
- if ((fp = statfile(f, &fsb)) == 0)
- goto Return;
- if ((tp = statfile(t, &tsb)) == 0){
- free(fsb);
- goto Return;
- }
- if (DIRECTORY(fsb) && DIRECTORY(tsb)) {
- if (rflag || level == 0)
- diffdir(fp, tp, level);
- else
- Bprint(&stdout, "Common subdirectories: %s and %s\n",
- fp, tp);
- }
- else if (REGULAR_FILE(fsb) && REGULAR_FILE(tsb))
- diffreg(fp, tp);
- else {
- if (REGULAR_FILE(fsb)) {
- if ((p = utfrrune(f, '/')) == 0)
- p = f;
- else
- p++;
- if (mkpathname(tb, tp, p) == 0)
- diffreg(fp, tb);
- }
- else {
- if ((p = utfrrune(t, '/')) == 0)
- p = t;
- else
- p++;
- if (mkpathname(fb, fp, p) == 0)
- diffreg(fb, tp);
- }
- }
- free(fsb);
- free(tsb);
- Return:
- rmtmpfiles();
- }
- void
- main(int argc, char *argv[])
- {
- char *p;
- int i;
- Dir *fsb, *tsb;
- Binit(&stdout, 1, OWRITE);
- progname = *argv;
- while (--argc && (*++argv)[0] == '-' && (*argv)[1]) {
- for (p = *argv+1; *p; p++) {
- switch (*p) {
- case 'e':
- case 'f':
- case 'n':
- case 'c':
- case 'a':
- mode = *p;
- break;
- case 'w':
- bflag = 2;
- break;
- case 'b':
- bflag = 1;
- break;
- case 'r':
- rflag = 1;
- break;
- case 'm':
- mflag = 1;
- break;
- case 'h':
- default:
- progname = "Usage";
- panic(2, usage);
- }
- }
- }
- if (argc < 2)
- panic(2, usage, progname);
- if ((tsb = dirstat(argv[argc-1])) == nil)
- panic(2, "can't stat %s\n", argv[argc-1]);
- if (argc > 2) {
- if (!DIRECTORY(tsb))
- panic(2, usage, progname);
- mflag = 1;
- }
- else {
- if ((fsb = dirstat(argv[0])) == nil)
- panic(2, "can't stat %s\n", argv[0]);
- if (DIRECTORY(fsb) && DIRECTORY(tsb))
- mflag = 1;
- free(fsb);
- }
- free(tsb);
- for (i = 0; i < argc-1; i++)
- diff(argv[i], argv[argc-1], 0);
- done(anychange);
- /*NOTREACHED*/
- }
- static char noroom[] = "out of memory - try diff -h\n";
- void *
- emalloc(unsigned n)
- {
- register void *p;
- if ((p = malloc(n)) == 0)
- panic(2, noroom);
- return p;
- }
- void *
- erealloc(void *p, unsigned n)
- {
- register void *rp;
- if ((rp = realloc(p, n)) == 0)
- panic(2, noroom);
- return rp;
- }
|