123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347 |
- /*
- * 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.
- */
- /*
- * interactive diff, inspired/stolen from
- * kernighan and pike, _unix programming environment_.
- */
- #include <u.h>
- #include <libc.h>
- #include <bio.h>
- int diffbflag;
- int diffwflag;
- void copy(Biobuf*, char*, Biobuf*, char*);
- void idiff(Biobuf*, char*, Biobuf*, char*, Biobuf*, char*, Biobuf*,
- char*);
- int opentemp(char*, int, int32_t);
- void rundiff(char*, char*, int);
- void
- usage(void)
- {
- fprint(2, "usage: idiff [-bw] file1 file2\n");
- exits("usage");
- }
- void
- main(int argc, char **argv)
- {
- int fd, ofd;
- char diffout[40], idiffout[40];
- Biobuf *b1, *b2, bdiff, bout, bstdout;
- Dir *d;
- ARGBEGIN{
- default:
- usage();
- case 'b':
- diffbflag++;
- break;
- case 'w':
- diffwflag++;
- break;
- }ARGEND
- if(argc != 2)
- usage();
- if((d = dirstat(argv[0])) == nil)
- sysfatal("stat %s: %r", argv[0]);
- if(d->mode&DMDIR)
- sysfatal("%s is a directory", argv[0]);
- free(d);
- if((d = dirstat(argv[1])) == nil)
- sysfatal("stat %s: %r", argv[1]);
- if(d->mode&DMDIR)
- sysfatal("%s is a directory", argv[1]);
- free(d);
- if((b1 = Bopen(argv[0], OREAD)) == nil)
- sysfatal("open %s: %r", argv[0]);
- if((b2 = Bopen(argv[1], OREAD)) == nil)
- sysfatal("open %s: %r", argv[1]);
- strcpy(diffout, "/tmp/idiff.XXXXXX");
- fd = opentemp(diffout, ORDWR|ORCLOSE, 0);
- strcpy(idiffout, "/tmp/idiff.XXXXXX");
- ofd = opentemp(idiffout, ORDWR|ORCLOSE, 0);
- rundiff(argv[0], argv[1], fd);
- seek(fd, 0, 0);
- Binit(&bdiff, fd, OREAD);
- Binit(&bout, ofd, OWRITE);
- idiff(b1, argv[0], b2, argv[1], &bdiff, diffout, &bout, idiffout);
- Bterm(&bdiff);
- Bflush(&bout);
- seek(ofd, 0, 0);
- Binit(&bout, ofd, OREAD);
- Binit(&bstdout, 1, OWRITE);
- copy(&bout, idiffout, &bstdout, "<stdout>");
- exits(nil);
- }
- int
- opentemp(char *template, int mode, int32_t perm)
- {
- int fd, i;
- char *p;
- p = strdup(template);
- if(p == nil)
- sysfatal("strdup out of memory");
- fd = -1;
- for(i=0; i<10; i++){
- mktemp(p);
- if(access(p, 0) < 0 && (fd=create(p, mode, perm)) >= 0)
- break;
- strcpy(p, template);
- }
- if(fd < 0)
- sysfatal("could not create temporary file");
- strcpy(template, p);
- free(p);
- return fd;
- }
- void
- rundiff(char *arg1, char *arg2, int outfd)
- {
- char *arg[10], *p;
- int narg, pid;
- Waitmsg *w;
- narg = 0;
- arg[narg++] = "/bin/diff";
- arg[narg++] = "-n";
- if(diffbflag)
- arg[narg++] = "-b";
- if(diffwflag)
- arg[narg++] = "-w";
- arg[narg++] = arg1;
- arg[narg++] = arg2;
- arg[narg] = nil;
- switch(pid = fork()){
- case -1:
- sysfatal("fork: %r");
- case 0:
- dup(outfd, 1);
- close(0);
- exec("/bin/diff", arg);
- sysfatal("exec: %r");
- default:
- w = wait();
- if(w==nil)
- sysfatal("wait: %r");
- if(w->pid != pid)
- sysfatal("wait got unexpected pid %d", w->pid);
- if((p = strchr(w->msg, ':')) && strcmp(p, ": some") != 0)
- sysfatal("%s", w->msg);
- free(w);
- }
- }
- void
- runcmd(char *cmd)
- {
- char *arg[10];
- int narg, pid, wpid;
- narg = 0;
- arg[narg++] = "/bin/rc";
- arg[narg++] = "-c";
- arg[narg++] = cmd;
- arg[narg] = nil;
- switch(pid = fork()){
- case -1:
- sysfatal("fork: %r");
- case 0:
- exec("/bin/rc", arg);
- sysfatal("exec: %r");
- default:
- wpid = waitpid();
- if(wpid < 0)
- sysfatal("wait: %r");
- if(wpid != pid)
- sysfatal("wait got unexpected pid %d", wpid);
- }
- }
- void
- parse(char *s, int *pfrom1, int *pto1, int *pcmd, int *pfrom2,
- int *pto2)
- {
- *pfrom1 = *pto1 = *pfrom2 = *pto2 = 0;
- s = strchr(s, ':');
- if(s == nil)
- sysfatal("bad diff output0");
- s++;
- *pfrom1 = strtol(s, &s, 10);
- if(*s == ','){
- s++;
- *pto1 = strtol(s, &s, 10);
- }else
- *pto1 = *pfrom1;
- if(*s++ != ' ')
- sysfatal("bad diff output1");
- *pcmd = *s++;
- if(*s++ != ' ')
- sysfatal("bad diff output2");
- s = strchr(s, ':');
- if(s == nil)
- sysfatal("bad diff output3");
- s++;
- *pfrom2 = strtol(s, &s, 10);
- if(*s == ','){
- s++;
- *pto2 = strtol(s, &s, 10);
- }else
- *pto2 = *pfrom2;
- }
- void
- skiplines(Biobuf *b, char *name, int n)
- {
- int i;
- for(i=0; i<n; i++){
- while(Brdline(b, '\n')==nil){
- if(Blinelen(b) <= 0)
- sysfatal("early end of file on %s", name);
- Bseek(b, Blinelen(b), 1);
- }
- }
- }
- void
- copylines(Biobuf *bin, char *nin, Biobuf *bout, char *nout, int n)
- {
- char buf[4096], *p;
- int i, m;
- for(i=0; i<n; i++){
- while((p=Brdline(bin, '\n'))==nil){
- if(Blinelen(bin) <= 0)
- sysfatal("early end of file on %s", nin);
- m = Blinelen(bin);
- if(m > sizeof buf)
- m = sizeof buf;
- m = Bread(bin, buf, m);
- if(Bwrite(bout, buf, m) != m)
- sysfatal("error writing %s: %r", nout);
- }
- if(Bwrite(bout, p, Blinelen(bin)) != Blinelen(bin))
- sysfatal("error writing %s: %r", nout);
- }
- }
- void
- copy(Biobuf *bin, char *nin, Biobuf *bout, char *nout)
- {
- char buf[4096];
- int m;
- USED(nin);
- while((m = Bread(bin, buf, sizeof buf)) > 0)
- if(Bwrite(bout, buf, m) != m)
- sysfatal("error writing %s: %r", nout);
- }
- void
- idiff(Biobuf *b1, char *name1, Biobuf *b2, char *name2, Biobuf *bdiff,
- char *namediff, Biobuf *bout, char *nameout)
- {
- char buf[256], *p;
- int interactive, defaultanswer, cmd, diffoffset;
- int n, from1, to1, from2, to2, nf1, nf2;
- Biobuf berr;
- nf1 = 1;
- nf2 = 1;
- interactive = 1;
- defaultanswer = 0;
- Binit(&berr, 2, OWRITE);
- while(diffoffset = Boffset(bdiff), p = Brdline(bdiff, '\n')){
- p[Blinelen(bdiff)-1] = '\0';
- parse(p, &from1, &to1, &cmd, &from2, &to2);
- p[Blinelen(bdiff)-1] = '\n';
- n = to1-from1 + to2-from2 + 1; /* #lines from diff */
- if(cmd == 'c')
- n += 2;
- else if(cmd == 'a')
- from1++;
- else if(cmd == 'd')
- from2++;
- to1++; /* make half-open intervals */
- to2++;
- if(interactive){
- p[Blinelen(bdiff)-1] = '\0';
- fprint(2, "%s\n", p);
- p[Blinelen(bdiff)-1] = '\n';
- copylines(bdiff, namediff, &berr, "<stderr>", n);
- Bflush(&berr);
- }else
- skiplines(bdiff, namediff, n);
- do{
- if(interactive){
- fprint(2, "? ");
- memset(buf, 0, sizeof buf);
- if(read(0, buf, sizeof buf - 1) < 0)
- sysfatal("read console: %r");
- }else
- buf[0] = defaultanswer;
- switch(buf[0]){
- case '>':
- copylines(b1, name1, bout, nameout, from1-nf1);
- skiplines(b1, name1, to1-from1);
- skiplines(b2, name2, from2-nf2);
- copylines(b2, name2, bout, nameout, to2-from2);
- break;
- case '<':
- copylines(b1, name1, bout, nameout, to1-nf1);
- skiplines(b2, name2, to2-nf2);
- break;
- case '=':
- copylines(b1, name1, bout, nameout, from1-nf1);
- skiplines(b1, name1, to1-from1);
- skiplines(b2, name2, to2-nf2);
- if(Bseek(bdiff, diffoffset, 0) != diffoffset)
- sysfatal("seek in diff output: %r");
- copylines(bdiff, namediff, bout, nameout, n+1);
- break;
- case '!':
- runcmd(buf+1);
- break;
- case 'q':
- if(buf[1]=='<' || buf[1]=='>' || buf[1]=='='){
- interactive = 0;
- defaultanswer = buf[1];
- }else
- fprint(2, "must be q<, q>, or q=\n");
- break;
- default:
- fprint(2, "expect: <, >, =, q<, q>, q=, !cmd\n");
- break;
- }
- }while(buf[0] != '<' && buf[0] != '>' && buf[0] != '=');
- nf1 = to1;
- nf2 = to2;
- }
- copy(b1, name1, bout, nameout);
- }
|