tidiff.c - plan9port - [fork] Plan 9 from user space | |
git clone git://src.adamsgaard.dk/plan9port | |
Log | |
Files | |
Refs | |
README | |
LICENSE | |
--- | |
tidiff.c (6460B) | |
--- | |
1 /* | |
2 * interactive diff, inspired/stolen from | |
3 * kernighan and pike, _unix programming environment_. | |
4 */ | |
5 | |
6 #include <u.h> | |
7 #include <libc.h> | |
8 #include <bio.h> | |
9 | |
10 int diffbflag; | |
11 int diffwflag; | |
12 | |
13 void copy(Biobuf*, char*, Biobuf*, char*); | |
14 void idiff(Biobuf*, char*, Biobuf*, char*, Biobuf*, char*, Biobuf*, char… | |
15 void rundiff(char*, char*, int); | |
16 | |
17 void | |
18 usage(void) | |
19 { | |
20 fprint(2, "usage: idiff [-bw] file1 file2\n"); | |
21 exits("usage"); | |
22 } | |
23 | |
24 void | |
25 main(int argc, char **argv) | |
26 { | |
27 int fd, ofd; | |
28 char diffout[40], idiffout[40]; | |
29 Biobuf *b1, *b2, bdiff, bout, bstdout; | |
30 Dir *d; | |
31 | |
32 ARGBEGIN{ | |
33 default: | |
34 usage(); | |
35 case 'b': | |
36 diffbflag++; | |
37 break; | |
38 case 'w': | |
39 diffwflag++; | |
40 break; | |
41 }ARGEND | |
42 | |
43 if(argc != 2) | |
44 usage(); | |
45 | |
46 if((d = dirstat(argv[0])) == nil) | |
47 sysfatal("stat %s: %r", argv[0]); | |
48 if(d->mode&DMDIR) | |
49 sysfatal("%s is a directory", argv[0]); | |
50 free(d); | |
51 if((d = dirstat(argv[1])) == nil) | |
52 sysfatal("stat %s: %r", argv[1]); | |
53 if(d->mode&DMDIR) | |
54 sysfatal("%s is a directory", argv[1]); | |
55 free(d); | |
56 | |
57 if((b1 = Bopen(argv[0], OREAD)) == nil) | |
58 sysfatal("open %s: %r", argv[0]); | |
59 if((b2 = Bopen(argv[1], OREAD)) == nil) | |
60 sysfatal("open %s: %r", argv[1]); | |
61 | |
62 strcpy(diffout, "/tmp/idiff.XXXXXX"); | |
63 fd = opentemp(diffout, ORDWR|ORCLOSE); | |
64 strcpy(idiffout, "/tmp/idiff.XXXXXX"); | |
65 ofd = opentemp(idiffout, ORDWR|ORCLOSE); | |
66 rundiff(argv[0], argv[1], fd); | |
67 seek(fd, 0, 0); | |
68 Binit(&bdiff, fd, OREAD); | |
69 Binit(&bout, ofd, OWRITE); | |
70 idiff(b1, argv[0], b2, argv[1], &bdiff, diffout, &bout, idiffout… | |
71 Bterm(&bdiff); | |
72 Bflush(&bout); | |
73 seek(ofd, 0, 0); | |
74 Binit(&bout, ofd, OREAD); | |
75 Binit(&bstdout, 1, OWRITE); | |
76 copy(&bout, idiffout, &bstdout, "<stdout>"); | |
77 exits(nil); | |
78 } | |
79 | |
80 void | |
81 rundiff(char *arg1, char *arg2, int outfd) | |
82 { | |
83 char *arg[10], *p; | |
84 int narg, pid; | |
85 Waitmsg *w; | |
86 | |
87 narg = 0; | |
88 arg[narg++] = "9"; | |
89 arg[narg++] = "diff"; | |
90 arg[narg++] = "-n"; | |
91 if(diffbflag) | |
92 arg[narg++] = "-b"; | |
93 if(diffwflag) | |
94 arg[narg++] = "-w"; | |
95 arg[narg++] = arg1; | |
96 arg[narg++] = arg2; | |
97 arg[narg] = nil; | |
98 | |
99 switch(pid = fork()){ | |
100 case -1: | |
101 sysfatal("fork: %r"); | |
102 | |
103 case 0: | |
104 dup(outfd, 1); | |
105 close(0); | |
106 exec("9", arg); | |
107 sysfatal("exec: %r"); | |
108 | |
109 default: | |
110 w = wait(); | |
111 if(w==nil) | |
112 sysfatal("wait: %r"); | |
113 if(w->pid != pid) | |
114 sysfatal("wait got unexpected pid %d", w->pid); | |
115 if((p = strchr(w->msg, ':')) && strcmp(p, ": some") != 0) | |
116 sysfatal("%s", w->msg); | |
117 free(w); | |
118 } | |
119 } | |
120 | |
121 void | |
122 runcmd(char *cmd) | |
123 { | |
124 char *arg[10]; | |
125 int narg, pid, wpid; | |
126 | |
127 narg = 0; | |
128 arg[narg++] = "rc"; | |
129 arg[narg++] = "-c"; | |
130 arg[narg++] = cmd; | |
131 arg[narg] = nil; | |
132 | |
133 switch(pid = fork()){ | |
134 case -1: | |
135 sysfatal("fork: %r"); | |
136 | |
137 case 0: | |
138 exec("rc", arg); | |
139 sysfatal("exec: %r"); | |
140 | |
141 default: | |
142 wpid = waitpid(); | |
143 if(wpid < 0) | |
144 sysfatal("wait: %r"); | |
145 if(wpid != pid) | |
146 sysfatal("wait got unexpected pid %d", wpid); | |
147 } | |
148 } | |
149 | |
150 void | |
151 parse(char *s, int *pfrom1, int *pto1, int *pcmd, int *pfrom2, int *pto2) | |
152 { | |
153 *pfrom1 = *pto1 = *pfrom2 = *pto2 = 0; | |
154 | |
155 s = strchr(s, ':'); | |
156 if(s == nil) | |
157 sysfatal("bad diff output0"); | |
158 s++; | |
159 *pfrom1 = strtol(s, &s, 10); | |
160 if(*s == ','){ | |
161 s++; | |
162 *pto1 = strtol(s, &s, 10); | |
163 }else | |
164 *pto1 = *pfrom1; | |
165 if(*s++ != ' ') | |
166 sysfatal("bad diff output1"); | |
167 *pcmd = *s++; | |
168 if(*s++ != ' ') | |
169 sysfatal("bad diff output2"); | |
170 s = strchr(s, ':'); | |
171 if(s == nil) | |
172 sysfatal("bad diff output3"); | |
173 s++; | |
174 *pfrom2 = strtol(s, &s, 10); | |
175 if(*s == ','){ | |
176 s++; | |
177 *pto2 = strtol(s, &s, 10); | |
178 }else | |
179 *pto2 = *pfrom2; | |
180 } | |
181 | |
182 void | |
183 skiplines(Biobuf *b, char *name, int n) | |
184 { | |
185 int i; | |
186 | |
187 for(i=0; i<n; i++){ | |
188 while(Brdline(b, '\n')==nil){ | |
189 if(Blinelen(b) <= 0) | |
190 sysfatal("early end of file on %s", name… | |
191 Bseek(b, Blinelen(b), 1); | |
192 } | |
193 } | |
194 } | |
195 | |
196 void | |
197 copylines(Biobuf *bin, char *nin, Biobuf *bout, char *nout, int n) | |
198 { | |
199 char buf[4096], *p; | |
200 int i, m; | |
201 | |
202 for(i=0; i<n; i++){ | |
203 while((p=Brdline(bin, '\n'))==nil){ | |
204 if(Blinelen(bin) <= 0) | |
205 sysfatal("early end of file on %s", nin); | |
206 m = Blinelen(bin); | |
207 if(m > sizeof buf) | |
208 m = sizeof buf; | |
209 m = Bread(bin, buf, m); | |
210 if(Bwrite(bout, buf, m) != m) | |
211 sysfatal("error writing %s: %r", nout); | |
212 } | |
213 if(Bwrite(bout, p, Blinelen(bin)) != Blinelen(bin)) | |
214 sysfatal("error writing %s: %r", nout); | |
215 } | |
216 } | |
217 | |
218 void | |
219 copy(Biobuf *bin, char *nin, Biobuf *bout, char *nout) | |
220 { | |
221 char buf[4096]; | |
222 int m; | |
223 | |
224 USED(nin); | |
225 while((m = Bread(bin, buf, sizeof buf)) > 0) | |
226 if(Bwrite(bout, buf, m) != m) | |
227 sysfatal("error writing %s: %r", nout); | |
228 } | |
229 | |
230 void | |
231 idiff(Biobuf *b1, char *name1, Biobuf *b2, char *name2, Biobuf *bdiff, c… | |
232 { | |
233 char buf[256], *p; | |
234 int interactive, defaultanswer, cmd, diffoffset; | |
235 int n, from1, to1, from2, to2, nf1, nf2; | |
236 Biobuf berr; | |
237 | |
238 nf1 = 1; | |
239 nf2 = 1; | |
240 interactive = 1; | |
241 defaultanswer = 0; | |
242 Binit(&berr, 2, OWRITE); | |
243 while(diffoffset = Boffset(bdiff), p = Brdline(bdiff, '\n')){ | |
244 p[Blinelen(bdiff)-1] = '\0'; | |
245 parse(p, &from1, &to1, &cmd, &from2, &to2); | |
246 p[Blinelen(bdiff)-1] = '\n'; | |
247 n = to1-from1 + to2-from2 + 1; /* #lines from dif… | |
248 if(cmd == 'c') | |
249 n += 2; | |
250 else if(cmd == 'a') | |
251 from1++; | |
252 else if(cmd == 'd') | |
253 from2++; | |
254 to1++; /* make half-open intervals */ | |
255 to2++; | |
256 if(interactive){ | |
257 p[Blinelen(bdiff)-1] = '\0'; | |
258 fprint(2, "%s\n", p); | |
259 p[Blinelen(bdiff)-1] = '\n'; | |
260 copylines(bdiff, namediff, &berr, "<stderr>", n); | |
261 Bflush(&berr); | |
262 }else | |
263 skiplines(bdiff, namediff, n); | |
264 do{ | |
265 if(interactive){ | |
266 fprint(2, "? "); | |
267 memset(buf, 0, sizeof buf); | |
268 if(read(0, buf, sizeof buf - 1) < 0) | |
269 sysfatal("read console: %r"); | |
270 }else | |
271 buf[0] = defaultanswer; | |
272 | |
273 switch(buf[0]){ | |
274 case '>': | |
275 copylines(b1, name1, bout, nameout, from… | |
276 skiplines(b1, name1, to1-from1); | |
277 skiplines(b2, name2, from2-nf2); | |
278 copylines(b2, name2, bout, nameout, to2-… | |
279 break; | |
280 case '<': | |
281 copylines(b1, name1, bout, nameout, to1-… | |
282 skiplines(b2, name2, to2-nf2); | |
283 break; | |
284 case '=': | |
285 copylines(b1, name1, bout, nameout, from… | |
286 skiplines(b1, name1, to1-from1); | |
287 skiplines(b2, name2, to2-nf2); | |
288 if(Bseek(bdiff, diffoffset, 0) != diffof… | |
289 sysfatal("seek in diff output: %… | |
290 copylines(bdiff, namediff, bout, nameout… | |
291 break; | |
292 case '!': | |
293 runcmd(buf+1); | |
294 break; | |
295 case 'q': | |
296 if(buf[1]=='<' || buf[1]=='>' || buf[1]=… | |
297 interactive = 0; | |
298 defaultanswer = buf[1]; | |
299 }else | |
300 fprint(2, "must be q<, q>, or q=… | |
301 break; | |
302 default: | |
303 fprint(2, "expect: <, >, =, q<, q>, q=, … | |
304 break; | |
305 } | |
306 }while(buf[0] != '<' && buf[0] != '>' && buf[0] != '='); | |
307 nf1 = to1; | |
308 nf2 = to2; | |
309 } | |
310 copy(b1, name1, bout, nameout); | |
311 } |