modern syntax for asgops & inits cause Donn's latest ccom rejects the old.
[unix-history] / usr / src / local / sccscmds / sccscmds.2 / cmd / bdiff.c
CommitLineData
c3f5f708
EA
1# include "../hdr/defines.h"
2
38c01699 3static 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
23int seglim; /* limit of size of file segment to be generated */
24
38c01699
JL
25char diff[] = "/bin/diff";
26char tempskel[] = "/tmp/bdXXXXX"; /* used to generate temp file names */
c3f5f708
EA
27char tempfile[32];
28char otmp[32], ntmp[32];
29int linenum;
30
31main(argc,argv)
32int argc;
33char *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*/
243saverest(line,iptr)
244char *line;
245FILE *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*/
267putsave(line,type)
268char *line;
269char 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
284fixnum(lp)
285char *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
310addgen(lp,fp)
311char *lp;
312FILE *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
332delgen(lp,fp)
333char *lp;
334FILE *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
357clean_up()
358{
359 unlink(tempfile);
360 unlink(otmp);
361 unlink(ntmp);
362}
363
364
365maket(file)
366char *file;
367{
368 FILE *iop;
369
370 copy(tempskel,file);
371 iop = xfcreat(mktemp(file),0644);
372
373 return(iop);
374}