1 # include "../hdr/defines.h" 2 3 SCCSID(@(#)bdiff.c 4.1); 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 25 char diff[] "/bin/diff"; 26 char tempskel[] "/tmp/bdXXXXX"; /* used to generate temp file names */ 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') 69 Fflags =& ~FTLMSG; 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') 75 Fflags =& ~FTLMSG; 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]); 195 close(1); 196 dup(pfd[1]); 197 close(pfd[1]); 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]); 208 pipeinp = fdfopen(pfd[0],0); 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 } 229 linenum =+ seglim; 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); 303 num =+ linenum; 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 } 375