Commit | Line | Data |
---|---|---|
c3f5f708 EA |
1 | # include "../hdr/defines.h" |
2 | ||
38c01699 | 3 | static char Sccsid[] = "@(#)bdiff.c 4.3 %G%"; |
c3f5f708 EA |
4 | |
5 | /* | |
6 | This program segments two files into pieces of <= seglim lines | |
7 | (which is passed as a third argument or defaulted to some number) | |
8 | and then executes diff upon the pieces. The output of | |
9 | 'diff' is then processed to make it look as if 'diff' had | |
10 | processed the files whole. The reason for all this is that seglim | |
11 | is a reasonable upper limit on the size of files that diff can | |
12 | process. | |
13 | NOTE -- by segmenting the files in this manner, it cannot be | |
14 | guaranteed that the 'diffing' of the segments will generate | |
15 | a minimal set of differences. | |
16 | This process is most definitely not equivalent to 'diffing' | |
17 | the files whole, assuming 'diff' could handle such large files. | |
18 | ||
19 | 'diff' is executed by a child process, generated by forking, | |
20 | and communicates with this program through pipes. | |
21 | */ | |
22 | ||
23 | int seglim; /* limit of size of file segment to be generated */ | |
24 | ||
38c01699 JL |
25 | char diff[] = "/bin/diff"; |
26 | char tempskel[] = "/tmp/bdXXXXX"; /* used to generate temp file names */ | |
c3f5f708 EA |
27 | char tempfile[32]; |
28 | char otmp[32], ntmp[32]; | |
29 | int linenum; | |
30 | ||
31 | main(argc,argv) | |
32 | int argc; | |
33 | char *argv[]; | |
34 | { | |
35 | FILE *poldfile, *pnewfile, *tptr; | |
36 | char oline[BUFSIZ], nline[BUFSIZ], diffline[BUFSIZ]; | |
37 | char *olp, *nlp, *dp; | |
38 | int i, otcnt, ntcnt; | |
39 | int pfd[2]; | |
40 | FILE *poldtemp, *pnewtemp, *pipeinp; | |
41 | int status; | |
42 | ||
43 | /* | |
44 | Set flags for 'fatal' so that it will clean up, | |
45 | produce a message, and terminate. | |
46 | */ | |
47 | Fflags = FTLMSG | FTLCLN | FTLEXIT; | |
48 | ||
49 | setsig(); | |
50 | ||
51 | if (argc < 3 || argc > 5) | |
52 | fatal("arg count (bd1)"); | |
53 | ||
54 | if (equal(argv[1],"-") && equal(argv[2],"-")) | |
55 | fatal("both files standard input (bd2)"); | |
56 | if (equal(argv[1],"-")) | |
57 | poldfile = stdin; | |
58 | else | |
59 | poldfile = xfopen(argv[1],0); | |
60 | if (equal(argv[2],"-")) | |
61 | pnewfile = stdin; | |
62 | else | |
63 | pnewfile = xfopen(argv[2],0); | |
64 | ||
65 | seglim = 3500; | |
66 | ||
67 | if (argc > 3) { | |
68 | if (argv[3][0] == '-' && argv[3][1] == 's') | |
38c01699 | 69 | Fflags &= ~FTLMSG; |
c3f5f708 EA |
70 | else { |
71 | if ((seglim = patoi(argv[3])) == -1) | |
72 | fatal("non-numeric limit (bd4)"); | |
73 | if (argc == 5 && argv[4][0] == '-' && | |
74 | argv[4][1] == 's') | |
38c01699 | 75 | Fflags &= ~FTLMSG; |
c3f5f708 EA |
76 | } |
77 | } | |
78 | ||
79 | linenum = 0; | |
80 | ||
81 | /* | |
82 | The following while-loop will prevent any lines | |
83 | common to the beginning of both files from being | |
84 | sent to 'diff'. Since the running time of 'diff' is | |
85 | non-linear, this will help improve performance. | |
86 | If, during this process, both files reach EOF, then | |
87 | the files are equal and the program will terminate. | |
88 | If either file reaches EOF before the other, the | |
89 | program will generate the appropriate 'diff' output | |
90 | itself, since this can be easily determined and will | |
91 | avoid executing 'diff' completely. | |
92 | */ | |
93 | while (1) { | |
94 | olp = fgets(oline,BUFSIZ,poldfile); | |
95 | nlp = fgets(nline,BUFSIZ,pnewfile); | |
96 | ||
97 | if (!olp && !nlp) /* files are equal */ | |
98 | exit(0); | |
99 | ||
100 | if (!olp) { | |
101 | /* | |
102 | The entire old file is a prefix of the | |
103 | new file. Generate the appropriate "append" | |
104 | 'diff'-like output, which is of the form: | |
105 | nan,n | |
106 | where 'n' represents a line-number. | |
107 | */ | |
108 | addgen(nline,pnewfile); | |
109 | } | |
110 | ||
111 | if (!nlp) { | |
112 | /* | |
113 | The entire new file is a prefix of the | |
114 | old file. Generate the appropriate "delete" | |
115 | 'diff'-like output, which is of the form: | |
116 | n,ndn | |
117 | where 'n' represents a line-number. | |
118 | */ | |
119 | delgen(oline,poldfile); | |
120 | } | |
121 | ||
122 | if (equal(olp,nlp)) | |
123 | linenum++; | |
124 | else | |
125 | break; | |
126 | } | |
127 | ||
128 | /* | |
129 | Here, first 'linenum' lines are equal. | |
130 | The following while-loop segments both files into | |
131 | seglim segments, forks and executes 'diff' on the | |
132 | segments, and processes the resulting output of | |
133 | 'diff', which is read from a pipe. | |
134 | */ | |
135 | while (1) { | |
136 | /* | |
137 | If both files are at EOF, everything is done. | |
138 | */ | |
139 | if (!olp && !nlp) /* finished */ | |
140 | exit(0); | |
141 | ||
142 | if (!olp) { | |
143 | /* | |
144 | Generate appropriate "append" | |
145 | output without executing 'diff'. | |
146 | */ | |
147 | addgen(nline,pnewfile); | |
148 | } | |
149 | ||
150 | if (!nlp) { | |
151 | /* | |
152 | Generate appropriate "delete" | |
153 | output without executing 'diff'. | |
154 | */ | |
155 | delgen(oline,poldfile); | |
156 | } | |
157 | ||
158 | /* | |
159 | Create a temporary file to hold a segment | |
160 | from the old file, and write it. | |
161 | */ | |
162 | poldtemp = maket(otmp); | |
163 | otcnt = 0; | |
164 | while(olp && otcnt < seglim) { | |
165 | fputs(oline,poldtemp); | |
166 | olp = fgets(oline,BUFSIZ,poldfile); | |
167 | otcnt++; | |
168 | } | |
169 | fclose(poldtemp); | |
170 | ||
171 | /* | |
172 | Create a temporary file to hold a segment | |
173 | from the new file, and write it. | |
174 | */ | |
175 | pnewtemp = maket(ntmp); | |
176 | ntcnt = 0; | |
177 | while(nlp && ntcnt < seglim) { | |
178 | fputs(nline,pnewtemp); | |
179 | nlp = fgets(nline,BUFSIZ,pnewfile); | |
180 | ntcnt++; | |
181 | } | |
182 | fclose(pnewtemp); | |
183 | ||
184 | /* | |
185 | Create pipes and fork. | |
186 | */ | |
187 | xpipe(pfd); | |
188 | if ((i = fork()) < 0) { | |
189 | close(pfd[0]); | |
190 | close(pfd[1]); | |
191 | fatal("cannot fork, try again (bd3)"); | |
192 | } | |
193 | else if (i == 0) { /* child process */ | |
194 | close(pfd[0]); | |
5409addc SL |
195 | dup2(pfd[1], 1); |
196 | if (pfd[1] != 1) | |
197 | close(pfd[1]); | |
c3f5f708 EA |
198 | |
199 | /* | |
200 | Execute 'diff' on the segment files. | |
201 | */ | |
202 | execl(diff,diff,otmp,ntmp,0); | |
203 | close(1); | |
204 | fatal(sprintf(Error,"cannot execute '%s' (bd5)",diff)); | |
205 | } | |
206 | else { /* parent process */ | |
207 | close(pfd[1]); | |
5409addc | 208 | pipeinp = fdopen(pfd[0],"r"); |
c3f5f708 EA |
209 | |
210 | /* | |
211 | Process 'diff' output. | |
212 | */ | |
213 | while ((dp = fgets(diffline,BUFSIZ,pipeinp))) { | |
214 | if (numeric(*dp)) | |
215 | fixnum(diffline); | |
216 | else | |
217 | printf("%s",diffline); | |
218 | } | |
219 | ||
220 | fclose(pipeinp); | |
221 | ||
222 | /* | |
223 | EOF on pipe. | |
224 | */ | |
225 | wait(&status); | |
226 | if (status&~0x100) | |
227 | fatal(sprintf(Error,"'%s' failed (bd6)",diff)); | |
228 | } | |
38c01699 | 229 | linenum += seglim; |
c3f5f708 EA |
230 | |
231 | /* | |
232 | Remove temporary files. | |
233 | */ | |
234 | unlink(otmp); | |
235 | unlink(ntmp); | |
236 | } | |
237 | } | |
238 | ||
239 | ||
240 | /* | |
241 | Routine to save remainder of a file. | |
242 | */ | |
243 | saverest(line,iptr) | |
244 | char *line; | |
245 | FILE *iptr; | |
246 | { | |
247 | register char *lp; | |
248 | FILE *temptr; | |
249 | ||
250 | temptr = maket(tempfile); | |
251 | ||
252 | lp = line; | |
253 | ||
254 | while (lp) { | |
255 | fputs(line,temptr); | |
256 | linenum++; | |
257 | lp = fgets(line,BUFSIZ,iptr); | |
258 | } | |
259 | fclose(temptr); | |
260 | } | |
261 | ||
262 | ||
263 | /* | |
264 | Routine to write out data saved by | |
265 | 'saverest' routine and to remove the file. | |
266 | */ | |
267 | putsave(line,type) | |
268 | char *line; | |
269 | char type; | |
270 | { | |
271 | FILE *temptr; | |
272 | ||
273 | temptr = xfopen(tempfile,0); | |
274 | ||
275 | while (fgets(line,BUFSIZ,temptr)) | |
276 | printf("%c %s",type,line); | |
277 | ||
278 | fclose(temptr); | |
279 | ||
280 | xunlink(tempfile); | |
281 | } | |
282 | ||
283 | ||
284 | fixnum(lp) | |
285 | char *lp; | |
286 | { | |
287 | int num; | |
288 | ||
289 | while (*lp) { | |
290 | switch (*lp) { | |
291 | ||
292 | case 'a': | |
293 | case 'c': | |
294 | case 'd': | |
295 | case ',': | |
296 | case '\n': | |
297 | printf("%c",*lp); | |
298 | lp++; | |
299 | break; | |
300 | ||
301 | default: | |
302 | lp = satoi(lp,&num); | |
38c01699 | 303 | num += linenum; |
c3f5f708 EA |
304 | printf("%d",num); |
305 | } | |
306 | } | |
307 | } | |
308 | ||
309 | ||
310 | addgen(lp,fp) | |
311 | char *lp; | |
312 | FILE *fp; | |
313 | { | |
314 | printf("%da%d,",linenum,linenum+1); | |
315 | ||
316 | /* | |
317 | Save lines of new file. | |
318 | */ | |
319 | saverest(lp,fp); | |
320 | ||
321 | printf("%d\n",linenum); | |
322 | ||
323 | /* | |
324 | Output saved lines, as 'diff' would. | |
325 | */ | |
326 | putsave(lp,'>'); | |
327 | ||
328 | exit(0); | |
329 | } | |
330 | ||
331 | ||
332 | delgen(lp,fp) | |
333 | char *lp; | |
334 | FILE *fp; | |
335 | { | |
336 | int savenum; | |
337 | ||
338 | printf("%d,",linenum+1); | |
339 | savenum = linenum; | |
340 | ||
341 | /* | |
342 | Save lines of old file. | |
343 | */ | |
344 | saverest(lp,fp); | |
345 | ||
346 | printf("%dd%d\n",linenum,savenum); | |
347 | ||
348 | /* | |
349 | Output saved lines, as 'diff' would. | |
350 | */ | |
351 | putsave(lp,'<'); | |
352 | ||
353 | exit(0); | |
354 | } | |
355 | ||
356 | ||
357 | clean_up() | |
358 | { | |
359 | unlink(tempfile); | |
360 | unlink(otmp); | |
361 | unlink(ntmp); | |
362 | } | |
363 | ||
364 | ||
365 | maket(file) | |
366 | char *file; | |
367 | { | |
368 | FILE *iop; | |
369 | ||
370 | copy(tempskel,file); | |
371 | iop = xfcreat(mktemp(file),0644); | |
372 | ||
373 | return(iop); | |
374 | } |