/* * This file is part of the UCB release of Plan 9. It is subject to the license * terms in the LICENSE file found in the top-level directory of this * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No * part of the UCB release of Plan 9, including this file, may be copied, * modified, propagated, or distributed except according to the terms contained * in the LICENSE file. */ #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 voidrmtmpfiles(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*/} voidpanic(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 intcatch(void *a, char *msg){ USED(a); panic(2, msg); return 1;} intmkpathname(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;} voiddiff(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();} voidmain(int argc, char *argv[]){ char *p; int i; Dir *fsb, *tsb; Binit(&stdout, 1, OWRITE); progname = argv0 = *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;}
/*
* This file is part of the UCB release of Plan 9. It is subject to the license
* terms in the LICENSE file found in the top-level directory of this
* distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No
* part of the UCB release of Plan 9, including this file, may be copied,
* modified, propagated, or distributed except according to the terms contained
* in the LICENSE file.
*/
#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 = argv0 = *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;
}