Blob


1 #include <u.h>
2 #include <libc.h>
3 #include <bio.h>
4 #include "diff.h"
6 #define DIRECTORY(s) ((s)->qid.type&QTDIR)
7 #define REGULAR_FILE(s) ((s)->type == 'M' && !DIRECTORY(s))
9 Biobuf stdout;
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";
16 static void
17 rmtmpfiles(void)
18 {
19 while (whichtmp > 0) {
20 whichtmp--;
21 remove(tmp[whichtmp]);
22 }
23 }
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 }
41 void
42 panic(int status, char *fmt, ...)
43 {
44 va_list arg;
46 Bflush(&stdout);
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 }
57 static int
58 catch(void *a, char *msg)
59 {
60 USED(a);
61 panic(2, msg);
62 return 1;
63 }
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 }
76 static char *
77 mktmpfile(int input, Dir **sb)
78 {
79 int fd, i;
80 char *p;
81 char buf[8192];
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;
103 return p;
106 static char *
107 statfile(char *file, Dir **sb)
109 Dir *dir;
110 int input;
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;
118 free(dir);
119 return mktmpfile(0, sb);
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;
127 file = mktmpfile(input, sb);
128 close(input);
130 else
131 *sb = dir;
132 return file;
135 void
136 diff(char *f, char *t, int level)
138 char *fp, *tp, *p, fb[MAXPATHLEN+1], tb[MAXPATHLEN+1];
139 Dir *fsb, *tsb;
141 if ((fp = statfile(f, &fsb)) == 0)
142 goto Return;
143 if ((tp = statfile(t, &tsb)) == 0){
144 free(fsb);
145 goto Return;
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);
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);
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);
174 free(fsb);
175 free(tsb);
176 Return:
177 rmtmpfiles();
180 void
181 main(int argc, char *argv[])
183 char *p;
184 int i;
185 Dir *fsb, *tsb;
186 extern int _p9usepwlibrary;
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) {
195 case 'e':
196 case 'f':
197 case 'n':
198 case 'c':
199 case 'a':
200 mode = *p;
201 break;
203 case 'w':
204 bflag = 2;
205 break;
207 case 'b':
208 bflag = 1;
209 break;
211 case 'r':
212 rflag = 1;
213 mflag = 1;
214 break;
216 case 'm':
217 mflag = 1;
218 break;
220 case 'h':
221 default:
222 progname = "Usage";
223 panic(2, usage);
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;
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);
243 free(tsb);
244 for (i = 0; i < argc-1; i++)
245 diff(argv[i], argv[argc-1], 0);
246 done(anychange);
247 /*NOTREACHED*/
250 static char noroom[] = "out of memory - try diff -h\n";
252 void *
253 emalloc(unsigned n)
255 register void *p;
257 if ((p = malloc(n)) == 0)
258 panic(2, noroom);
259 return p;
262 void *
263 erealloc(void *p, unsigned n)
265 register void *rp;
267 if ((rp = realloc(p, n)) == 0)
268 panic(2, noroom);
269 return rp;