2 * interactive diff, inspired/stolen from
3 * kernighan and pike, _unix programming environment_.
10 #define opentemp idiffopentemp
15 void copy(Biobuf*, char*, Biobuf*, char*);
16 void idiff(Biobuf*, char*, Biobuf*, char*, Biobuf*, char*, Biobuf*, char*);
17 int opentemp(char*, int, long);
18 void rundiff(char*, char*, int);
23 fprint(2, "usage: idiff [-bw] file1 file2\n");
28 main(int argc, char **argv)
31 char diffout[40], idiffout[40];
32 Biobuf *b1, *b2, bdiff, bout, bstdout;
49 if((d = dirstat(argv[0])) == nil)
50 sysfatal("stat %s: %r", argv[0]);
52 sysfatal("%s is a directory", argv[0]);
54 if((d = dirstat(argv[1])) == nil)
55 sysfatal("stat %s: %r", argv[1]);
57 sysfatal("%s is a directory", argv[1]);
60 if((b1 = Bopen(argv[0], OREAD)) == nil)
61 sysfatal("open %s: %r", argv[0]);
62 if((b2 = Bopen(argv[1], OREAD)) == nil)
63 sysfatal("open %s: %r", argv[1]);
65 strcpy(diffout, "/tmp/idiff.XXXXXX");
66 fd = opentemp(diffout, ORDWR|ORCLOSE, 0);
67 strcpy(idiffout, "/tmp/idiff.XXXXXX");
68 ofd = opentemp(idiffout, ORDWR|ORCLOSE, 0);
69 rundiff(argv[0], argv[1], fd);
71 Binit(&bdiff, fd, OREAD);
72 Binit(&bout, ofd, OWRITE);
73 idiff(b1, argv[0], b2, argv[1], &bdiff, diffout, &bout, idiffout);
77 Binit(&bout, ofd, OREAD);
78 Binit(&bstdout, 1, OWRITE);
79 copy(&bout, idiffout, &bstdout, "<stdout>");
84 opentemp(char *template, int mode, long perm)
89 fd = mkstemp(template);
91 sysfatal("could not create temporary file");
100 rundiff(char *arg1, char *arg2, int outfd)
107 arg[narg++] = "diff";
117 switch(pid = fork()){
119 sysfatal("fork: %r");
125 sysfatal("exec: %r");
130 sysfatal("wait: %r");
132 sysfatal("wait got unexpected pid %d", w->pid);
133 if((p = strchr(w->msg, ':')) && strcmp(p, ": some") != 0)
134 sysfatal("%s", w->msg);
151 switch(pid = fork()){
153 sysfatal("fork: %r");
157 sysfatal("exec: %r");
162 sysfatal("wait: %r");
164 sysfatal("wait got unexpected pid %d", wpid);
169 parse(char *s, int *pfrom1, int *pto1, int *pcmd, int *pfrom2, int *pto2)
171 *pfrom1 = *pto1 = *pfrom2 = *pto2 = 0;
175 sysfatal("bad diff output0");
177 *pfrom1 = strtol(s, &s, 10);
180 *pto1 = strtol(s, &s, 10);
184 sysfatal("bad diff output1");
187 sysfatal("bad diff output2");
190 sysfatal("bad diff output3");
192 *pfrom2 = strtol(s, &s, 10);
195 *pto2 = strtol(s, &s, 10);
201 skiplines(Biobuf *b, char *name, int n)
206 while(Brdline(b, '\n')==nil){
208 sysfatal("early end of file on %s", name);
209 Bseek(b, Blinelen(b), 1);
215 copylines(Biobuf *bin, char *nin, Biobuf *bout, char *nout, int n)
221 while((p=Brdline(bin, '\n'))==nil){
222 if(Blinelen(bin) <= 0)
223 sysfatal("early end of file on %s", nin);
227 m = Bread(bin, buf, m);
228 if(Bwrite(bout, buf, m) != m)
229 sysfatal("error writing %s: %r", nout);
231 if(Bwrite(bout, p, Blinelen(bin)) != Blinelen(bin))
232 sysfatal("error writing %s: %r", nout);
237 copy(Biobuf *bin, char *nin, Biobuf *bout, char *nout)
243 while((m = Bread(bin, buf, sizeof buf)) > 0)
244 if(Bwrite(bout, buf, m) != m)
245 sysfatal("error writing %s: %r", nout);
249 idiff(Biobuf *b1, char *name1, Biobuf *b2, char *name2, Biobuf *bdiff, char *namediff, Biobuf *bout, char *nameout)
252 int interactive, defaultanswer, cmd, diffoffset;
253 int n, from1, to1, from2, to2, nf1, nf2;
260 Binit(&berr, 2, OWRITE);
261 while(diffoffset = Boffset(bdiff), p = Brdline(bdiff, '\n')){
262 p[Blinelen(bdiff)-1] = '\0';
263 parse(p, &from1, &to1, &cmd, &from2, &to2);
264 p[Blinelen(bdiff)-1] = '\n';
265 n = to1-from1 + to2-from2 + 1; /* #lines from diff */
272 to1++; /* make half-open intervals */
275 p[Blinelen(bdiff)-1] = '\0';
276 fprint(2, "%s\n", p);
277 p[Blinelen(bdiff)-1] = '\n';
278 copylines(bdiff, namediff, &berr, "<stderr>", n);
281 skiplines(bdiff, namediff, n);
285 memset(buf, 0, sizeof buf);
286 if(read(0, buf, sizeof buf - 1) < 0)
287 sysfatal("read console: %r");
289 buf[0] = defaultanswer;
293 copylines(b1, name1, bout, nameout, from1-nf1);
294 skiplines(b1, name1, to1-from1);
295 skiplines(b2, name2, from2-nf2);
296 copylines(b2, name2, bout, nameout, to2-from2);
299 copylines(b1, name1, bout, nameout, to1-nf1);
300 skiplines(b2, name2, to2-nf2);
303 copylines(b1, name1, bout, nameout, from1-nf1);
304 skiplines(b1, name1, to1-from1);
305 skiplines(b2, name2, to2-nf2);
306 if(Bseek(bdiff, diffoffset, 0) != diffoffset)
307 sysfatal("seek in diff output: %r");
308 copylines(bdiff, namediff, bout, nameout, n+1);
314 if(buf[1]=='<' || buf[1]=='>' || buf[1]=='='){
316 defaultanswer = buf[1];
318 fprint(2, "must be q<, q>, or q=\n");
321 fprint(2, "expect: <, >, =, q<, q>, q=, !cmd\n");
324 }while(buf[0] != '<' && buf[0] != '>' && buf[0] != '=');
328 copy(b1, name1, bout, nameout);