]> git.lizzy.rs Git - plan9front.git/blob - sys/src/cmd/diff/main.c
stats: show amount of reclaimable pages (add -r flag)
[plan9front.git] / sys / src / cmd / diff / main.c
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 [-abcefmnrw] 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         p = mktemp(tmp[whichtmp++]);
85         fd = create(p, OWRITE, 0600);
86         if (fd < 0) {
87                 panic(mflag ? 0: 2, "cannot create %s: %r\n", p);
88                 return 0;
89         }
90         while ((i = read(input, buf, sizeof(buf))) > 0) {
91                 if ((i = write(fd, buf, i)) < 0)
92                         break;
93         }
94         *sb = dirfstat(fd);
95         close(fd);
96         if (i < 0) {
97                 panic(mflag ? 0: 2, "cannot read/write %s: %r\n", p);
98                 return 0;
99         }
100         return p;
101 }
102
103 static char *
104 statfile(char *file, Dir **sb)
105 {
106         Dir *dir;
107         int input;
108
109         dir = dirstat(file);
110         if(dir == nil) {
111                 if (strcmp(file, "-") || (dir = dirfstat(0)) == nil) {
112                         panic(mflag ? 0: 2, "cannot stat %s: %r\n", file);
113                         return 0;
114                 }
115                 free(dir);
116                 return mktmpfile(0, sb);
117         }
118         else if (!REGULAR_FILE(dir) && !DIRECTORY(dir)) {
119                 free(dir);
120                 if ((input = open(file, OREAD)) == -1) {
121                         panic(mflag ? 0: 2, "cannot open %s: %r\n", file);
122                         return 0;
123                 }
124                 file = mktmpfile(input, sb);
125                 close(input);
126         }
127         else
128                 *sb = dir;
129         return file;
130 }
131
132 void
133 diff(char *f, char *t, int level)
134 {
135         char *fp, *tp, *p, fb[MAXPATHLEN+1], tb[MAXPATHLEN+1];
136         Dir *fsb, *tsb;
137
138         if ((fp = statfile(f, &fsb)) == 0)
139                 goto Return;
140         if ((tp = statfile(t, &tsb)) == 0){
141                 free(fsb);
142                 goto Return;
143         }
144         if (DIRECTORY(fsb) && DIRECTORY(tsb)) {
145                 if (rflag || level == 0)
146                         diffdir(fp, tp, level);
147                 else
148                         Bprint(&stdout, "Common subdirectories: %s and %s\n",
149                                 fp, tp);
150         }
151         else if (REGULAR_FILE(fsb) && REGULAR_FILE(tsb))
152                 diffreg(fp, tp);
153         else {
154                 if (REGULAR_FILE(fsb)) {
155                         if ((p = utfrrune(f, '/')) == 0)
156                                 p = f;
157                         else
158                                 p++;
159                         if (mkpathname(tb, tp, p) == 0)
160                                 diffreg(fp, tb);
161                 }
162                 else {
163                         if ((p = utfrrune(t, '/')) == 0)
164                                 p = t;
165                         else
166                                 p++;
167                         if (mkpathname(fb, fp, p) == 0)
168                                 diffreg(fb, tp);
169                 }
170         }
171         free(fsb);
172         free(tsb);
173 Return:
174         rmtmpfiles();
175 }
176
177 void
178 main(int argc, char *argv[])
179 {
180         char *p;
181         int i;
182         Dir *fsb, *tsb;
183
184         Binit(&stdout, 1, OWRITE);
185         progname = argv0 = *argv;
186         while (--argc && (*++argv)[0] == '-' && (*argv)[1]) {
187                 for (p = *argv+1; *p; p++) {
188                         switch (*p) {
189
190                         case 'e':
191                         case 'f':
192                         case 'n':
193                         case 'c':
194                         case 'a':
195                                 mode = *p;
196                                 break;
197
198                         case 'w':
199                                 bflag = 2;
200                                 break;
201
202                         case 'b':
203                                 bflag = 1;
204                                 break;
205
206                         case 'r':
207                                 rflag = 1;
208                                 break;
209
210                         case 'm':
211                                 mflag = 1;      
212                                 break;
213
214                         case 'h':
215                         default:
216                                 progname = "Usage";
217                                 panic(2, usage);
218                         }
219                 }
220         }
221         if (argc < 2)
222                 panic(2, usage, progname);
223         if ((tsb = dirstat(argv[argc-1])) == nil)
224                 panic(2, "can't stat %s\n", argv[argc-1]);
225         if (argc > 2) {
226                 if (!DIRECTORY(tsb))
227                         panic(2, usage, progname);
228                 mflag = 1;
229         }
230         else {
231                 if ((fsb = dirstat(argv[0])) == nil)
232                         panic(2, "can't stat %s\n", argv[0]);
233                 if (DIRECTORY(fsb) && DIRECTORY(tsb))
234                         mflag = 1;
235                 free(fsb);
236         }
237         free(tsb);
238         for (i = 0; i < argc-1; i++)
239                 diff(argv[i], argv[argc-1], 0);
240         done(anychange);
241         /*NOTREACHED*/
242 }
243
244 static char noroom[] = "out of memory - try diff -h\n";
245
246 void *
247 emalloc(unsigned n)
248 {
249         register void *p;
250
251         if ((p = malloc(n)) == 0)
252                 panic(2, noroom);
253         return p;
254 }
255
256 void *
257 erealloc(void *p, unsigned n)
258 {
259         register void *rp;
260
261         if ((rp = realloc(p, n)) == 0)
262                 panic(2, noroom);
263         return rp;
264 }