diffreg.c (37101B)
1 /* 2 * This code contains changes by 3 * Gunnar Ritter, Freiburg i. Br., Germany, March 2003. All rights reserved. 4 * 5 * Conditions 1, 2, and 4 and the no-warranty notice below apply 6 * to these changes. 7 * 8 * 9 * Copyright (c) 1991 10 * The Regents of the University of California. All rights reserved. 11 * 12 * Redistribution and use in source and binary forms, with or without 13 * modification, are permitted provided that the following conditions 14 * are met: 15 * 1. Redistributions of source code must retain the above copyright 16 * notice, this list of conditions and the following disclaimer. 17 * 2. Redistributions in binary form must reproduce the above copyright 18 * notice, this list of conditions and the following disclaimer in the 19 * documentation and/or other materials provided with the distribution. 20 * 3. All advertising materials mentioning features or use of this software 21 * must display the following acknowledgement: 22 * This product includes software developed by the University of 23 * California, Berkeley and its contributors. 24 * 4. Neither the name of the University nor the names of its contributors 25 * may be used to endorse or promote products derived from this software 26 * without specific prior written permission. 27 * 28 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 29 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 30 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 31 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 32 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 33 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 34 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 35 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 36 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 37 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 38 * SUCH DAMAGE. 39 * 40 * 41 * Copyright(C) Caldera International Inc. 2001-2002. All rights reserved. 42 * 43 * Redistribution and use in source and binary forms, with or without 44 * modification, are permitted provided that the following conditions 45 * are met: 46 * Redistributions of source code and documentation must retain the 47 * above copyright notice, this list of conditions and the following 48 * disclaimer. 49 * Redistributions in binary form must reproduce the above copyright 50 * notice, this list of conditions and the following disclaimer in the 51 * documentation and/or other materials provided with the distribution. 52 * All advertising materials mentioning features or use of this software 53 * must display the following acknowledgement: 54 * This product includes software developed or owned by Caldera 55 * International, Inc. 56 * Neither the name of Caldera International, Inc. nor the names of 57 * other contributors may be used to endorse or promote products 58 * derived from this software without specific prior written permission. 59 * 60 * USE OF THE SOFTWARE PROVIDED FOR UNDER THIS LICENSE BY CALDERA 61 * INTERNATIONAL, INC. AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR 62 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 63 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 64 * ARE DISCLAIMED. IN NO EVENT SHALL CALDERA INTERNATIONAL, INC. BE 65 * LIABLE FOR ANY DIRECT, INDIRECT INCIDENTAL, SPECIAL, EXEMPLARY, OR 66 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 67 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR 68 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 69 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE 70 * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, 71 * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 72 */ 73 74 /* Sccsid @(#)diffreg.c 1.30 (gritter) 3/15/07> */ 75 /* from 4.3BSD diffreg.c 4.16 3/29/86 */ 76 77 #include "diff.h" 78 #include <sys/types.h> 79 #include <sys/stat.h> 80 #include <fcntl.h> 81 #include <unistd.h> 82 #include <time.h> 83 #include <signal.h> 84 #include "sigset.h" 85 #include <wchar.h> 86 #include <wctype.h> 87 #include <inttypes.h> 88 #include "mbtowi.h" 89 /* 90 * diff - compare two files. 91 */ 92 93 /* 94 * Uses an algorithm due to Harold Stone, which finds 95 * a pair of longest identical subsequences in the two 96 * files. 97 * 98 * The major goal is to generate the match vector J. 99 * J[i] is the index of the line in file1 corresponding 100 * to line i file0. J[i] = 0 if there is no 101 * such line in file1. 102 * 103 * Lines are hashed so as to work in core. All potential 104 * matches are located by sorting the lines of each file 105 * on the hash (called ``value''). In particular, this 106 * collects the equivalence classes in file1 together. 107 * Subroutine equiv replaces the value of each line in 108 * file0 by the index of the first element of its 109 * matching equivalence in (the reordered) file1. 110 * To save space equiv squeezes file1 into a single 111 * array member in which the equivalence classes 112 * are simply concatenated, except that their first 113 * members are flagged by changing sign. 114 * 115 * Next the indices that point into member are unsorted into 116 * array class according to the original order of file0. 117 * 118 * The cleverness lies in routine stone. This marches 119 * through the lines of file0, developing a vector klist 120 * of "k-candidates". At step i a k-candidate is a matched 121 * pair of lines x,y (x in file0 y in file1) such that 122 * there is a common subsequence of length k 123 * between the first i lines of file0 and the first y 124 * lines of file1, but there is no such subsequence for 125 * any smaller y. x is the earliest possible mate to y 126 * that occurs in such a subsequence. 127 * 128 * Whenever any of the members of the equivalence class of 129 * lines in file1 matable to a line in file0 has serial number 130 * less than the y of some k-candidate, that k-candidate 131 * with the smallest such y is replaced. The new 132 * k-candidate is chained (via pred) to the current 133 * k-1 candidate so that the actual subsequence can 134 * be recovered. When a member has serial number greater 135 * that the y of all k-candidates, the klist is extended. 136 * At the end, the longest subsequence is pulled out 137 * and placed in the array J by unravel 138 * 139 * With J in hand, the matches there recorded are 140 * check'ed against reality to assure that no spurious 141 * matches have crept in due to hashing. If they have, 142 * they are broken, and "jackpot" is recorded--a harmless 143 * matter except that a true match for a spuriously 144 * mated line may now be unnecessarily reported as a change. 145 * 146 * Much of the complexity of the program comes simply 147 * from trying to minimize core utilization and 148 * maximize the range of doable problems by dynamically 149 * allocating what is needed and reusing what is not. 150 * The core requirements for problems larger than somewhat 151 * are (in words) 2*length(file0) + length(file1) + 152 * 3*(number of k-candidates installed), typically about 153 * 6n words for files of length n. 154 */ 155 156 #define prints(s) fputs(s,stdout) 157 158 static FILE *input[2]; 159 static char mbuf[2][MB_LEN_MAX+1]; 160 static char *mcur[2]; 161 static char *mend[2]; 162 static int incompl[2]; 163 164 struct cand { 165 long x; 166 long y; 167 long pred; 168 } cand; 169 static struct line { 170 long serial; 171 long value; 172 } *file[2], line; 173 static long len[2]; 174 static struct line *sfile[2];/*shortened by pruning common prefix and suffix*/ 175 static long slen[2]; 176 static long pref, suff; /* length of prefix and suffix */ 177 static long *class; /* will be overlaid on file[0] */ 178 static long *member; /* will be overlaid on file[1] */ 179 static long *klist; /* will be overlaid on file[0] after class */ 180 static struct cand *clist; /* merely a free storage pot for candidates */ 181 static long clen = 0; 182 static long *J; /* will be overlaid on class */ 183 static off_t *ixold; /* will be overlaid on klist */ 184 static off_t *ixnew; /* will be overlaid on file[1] */ 185 static int (*chrtran)(int);/* translation for case-folding */ 186 static long pstart; /* start of last search for -p */ 187 static long plast; /* match of last search for -p */ 188 static long *saveJ; /* saved J for -p */ 189 190 /* chrtran points to one of 3 translation functions: 191 * cup2low if folding upper to lower case 192 * clow2low if not folding case 193 * wlow2low if not folding case and MB_CUR_MAX > 1 194 */ 195 static int 196 clow2low(int c) 197 { 198 return c; 199 } 200 201 static int 202 cup2low(int c) 203 { 204 return tolower(c); 205 } 206 207 static int 208 wup2low(int c) 209 { 210 return c & ~(wchar_t)0177 ? towlower(c) : tolower(c); 211 } 212 213 static char *copytemp(char **, const char *); 214 #undef splice 215 #define splice xxsplice 216 static char *splice(const char *, char *); 217 static void prepare(int); 218 static void prune(void); 219 static void equiv(struct line *, long, struct line *, long, long *); 220 static long stone(long *, long, long *, long *); 221 static long newcand(long, long, long); 222 static long search(long *, long, long); 223 static void unravel(long); 224 static void check_sb(void); 225 static void check_mb(void); 226 static void sort(struct line *, long); 227 static void unsort(struct line *, long, long *); 228 static long skipline(int); 229 static long wskipline(int); 230 static void output(void); 231 static void change(long, long, long, long); 232 static void range(long, long, const char *); 233 static void fetch(off_t *, long, long, FILE *, const char *, int); 234 static int readhash(int); 235 static int asciifile(FILE *); 236 static void dump_context_vec(void); 237 static void sdone(int); 238 static char *wcget(int, wint_t *, int *); 239 static void missnl(int); 240 static void pdump(long); 241 242 #define notseekable(m) (((m)&S_IFMT) != S_IFREG && ((m)&S_IFMT) != S_IFBLK) 243 244 void 245 diffreg(void) 246 { 247 register long i, j; 248 char buf1[BUFSIZ], buf2[BUFSIZ]; 249 250 if (hflag) { 251 diffargv[0] = "diffh"; 252 execvp(diffh, diffargv); 253 if (sysv3) 254 fprintf(stderr, "%s: cannot find diffh\n", progname); 255 else 256 fprintf(stderr, "%s: %s: %s\n", progname, diffh, 257 strerror(errno)); 258 done(); 259 } 260 chrtran = (iflag? mb_cur_max>1 ? wup2low : cup2low : clow2low); 261 if ((stb1.st_mode & S_IFMT) == S_IFDIR) { 262 file1 = splice(file1, file2); 263 if (stat(file1, &stb1) < 0) { 264 if (sysv3) 265 stb1.st_mode = S_IFREG; 266 else { 267 fprintf(stderr, "%s: %s: %s\n", progname, file1, 268 strerror(errno)); 269 done(); 270 } 271 } 272 } else if ((stb2.st_mode & S_IFMT) == S_IFDIR) { 273 file2 = splice(file2, file1); 274 if (stat(file2, &stb2) < 0) { 275 if (sysv3) 276 stb2.st_mode = S_IFREG; 277 else { 278 fprintf(stderr, "%s: %s: %s\n", progname, file2, 279 strerror(errno)); 280 done(); 281 } 282 } 283 } 284 if (!strcmp(file1, "-") || (notseekable(stb1.st_mode) && 285 strcmp(file1, "/dev/null"))) { 286 if (!strcmp(file2, "-")) { 287 fprintf(stderr, "%s: can't specify - -\n", progname); 288 done(); 289 } 290 file1 = copytemp(&tempfile1, file1); 291 if (stat(file1, &stb1) < 0) { 292 fprintf(stderr, "%s: %s: %s\n", progname, file1, 293 strerror(errno)); 294 done(); 295 } 296 } else if (!strcmp(file2, "-") || (notseekable(stb2.st_mode) && 297 strcmp(file2, "/dev/null"))) { 298 file2 = copytemp(&tempfile2, file2); 299 if (stat(file2, &stb2) < 0) { 300 fprintf(stderr, "%s: %s: %s\n", progname, file2, 301 strerror(errno)); 302 done(); 303 } 304 } 305 if ((input[0] = fopen(file1, "r")) == NULL) { 306 if (sysv3) 307 fprintf(stderr, "%s: cannot open %s\n", 308 progname, file1); 309 else 310 fprintf(stderr, "%s: %s: %s\n", progname, file1, 311 strerror(errno)); 312 done(); 313 } 314 mcur[0] = mend[0] = NULL; 315 if ((input[1] = fopen(file2, "r")) == NULL) { 316 if (sysv3) 317 fprintf(stderr, "%s: cannot open %s\n", 318 progname, file2); 319 else 320 fprintf(stderr, "%s: %s: %s\n", progname, file2, 321 strerror(errno)); 322 fclose(input[0]); 323 done(); 324 } 325 mcur[1] = mend[1] = NULL; 326 if (stb1.st_size != stb2.st_size) 327 goto notsame; 328 for (;;) { 329 i = fread(buf1, 1, BUFSIZ, input[0]); 330 j = fread(buf2, 1, BUFSIZ, input[1]); 331 if (i < 0 || j < 0 || i != j) 332 goto notsame; 333 if (i == 0 && j == 0) { 334 fclose(input[0]); 335 fclose(input[1]); 336 status = 0; /* files don't differ */ 337 goto same; 338 } 339 for (j = 0; j < i; j++) 340 if (buf1[j] != buf2[j]) 341 goto notsame; 342 } 343 notsame: 344 /* 345 * Files certainly differ at this point; set status accordingly 346 */ 347 status = 1; 348 if (!aflag && (!asciifile(input[0]) || !asciifile(input[1]))) { 349 printf("Binary files %s and %s differ\n", file1, file2); 350 fclose(input[0]); 351 fclose(input[1]); 352 done(); 353 } 354 prepare(0); 355 prepare(1); 356 fclose(input[0]); 357 fclose(input[1]); 358 prune(); 359 sort(sfile[0],slen[0]); 360 sort(sfile[1],slen[1]); 361 362 member = (long *)file[1]; 363 equiv(sfile[0], slen[0], sfile[1], slen[1], member); 364 member = ralloc(member,(slen[1]+2)*sizeof(*member)); 365 366 class = (long *)file[0]; 367 unsort(sfile[0], slen[0], class); 368 class = ralloc(class,(slen[0]+2)*sizeof(*class)); 369 370 klist = talloc((slen[0]+2)*sizeof(*klist)); 371 clist = talloc(sizeof(cand)); 372 i = stone(class, slen[0], member, klist); 373 tfree(member); 374 tfree(class); 375 376 J = talloc((len[0]+2)*sizeof(*J)); 377 unravel(klist[i]); 378 tfree(clist); 379 tfree(klist); 380 381 ixold = talloc((len[0]+2)*sizeof(*ixold)); 382 ixnew = talloc((len[1]+2)*sizeof(*ixnew)); 383 if (mb_cur_max > 1) 384 check_mb(); 385 else 386 check_sb(); 387 pstart = plast = 0; 388 output(); 389 status = anychange; 390 same: 391 if (opt == D_CONTEXT && anychange == 0) 392 printf("No differences encountered\n"); 393 done(); 394 } 395 396 static char * 397 copytemp(char **tf, const char *fn) 398 { 399 const char templ[] = "/tmp/dXXXXXX"; 400 char buf[BUFSIZ]; 401 register int i, f, sfd; 402 403 if (*tf) { 404 unlink(*tf); 405 strcpy(*tf, templ); 406 } else { 407 sigset(SIGHUP,sdone); 408 sigset(SIGINT,sdone); 409 sigset(SIGPIPE,sdone); 410 sigset(SIGTERM,sdone); 411 *tf = strdup(templ); 412 } 413 f = mkstemp(*tf); 414 if (f < 0) { 415 fprintf(stderr, "%s: cannot create %s\n", progname, *tf); 416 done(); 417 } 418 if (strcmp(fn, "-")) { 419 if ((sfd = open(fn, O_RDONLY)) < 0) { 420 fprintf(stderr, "%s: %s: %s\n", progname, fn, 421 strerror(errno)); 422 done(); 423 } 424 } else 425 sfd = 0; 426 while ((i = read(sfd,buf,BUFSIZ)) > 0) 427 if (write(f,buf,i) != i) { 428 fprintf(stderr, "%s: write failed %s\n", progname, *tf); 429 done(); 430 } 431 close(f); 432 if (sfd > 0) 433 close(sfd); 434 return (*tf); 435 } 436 437 static char * 438 splice(const char *dir, char *file) 439 { 440 const char *tail; 441 char *buf; 442 443 if (!strcmp(file, "-")) { 444 fprintf(stderr, 445 "%s: can't specify - with other arg directory\n", 446 progname); 447 done(); 448 } 449 tail = basename(file); 450 buf = talloc(strlen(dir) + strlen(tail) + 2); 451 sprintf(buf, "%s/%s", dir, tail); 452 return (buf); 453 } 454 455 static void 456 prepare(int i) 457 { 458 register struct line *p; 459 register long j; 460 register long h; 461 462 fseeko(input[i], 0, SEEK_SET); 463 mcur[i] = mend[i] = NULL; 464 p = talloc(3*sizeof(line)); 465 for(j=0; h=readhash(i);) { 466 p = ralloc(p,(++j+3)*sizeof(line)); 467 p[j].value = h; 468 } 469 len[i] = j; 470 file[i] = p; 471 } 472 473 static void 474 prune(void) 475 { 476 register long i; 477 register int j; 478 for(pref=0;pref<len[0]&&pref<len[1]&& 479 file[0][pref+1].value==file[1][pref+1].value; 480 pref++ ) ; 481 for(suff=0;suff<len[0]-pref&&suff<len[1]-pref&& 482 file[0][len[0]-suff].value==file[1][len[1]-suff].value; 483 suff++) ; 484 for(j=0;j<2;j++) { 485 sfile[j] = file[j]+pref; 486 slen[j] = len[j]-pref-suff; 487 for(i=0;i<=slen[j];i++) 488 sfile[j][i].serial = i; 489 } 490 } 491 492 static void 493 equiv(struct line *a,long n,struct line *b,long m,long *c) 494 { 495 register long i, j; 496 i = j = 1; 497 while(i<=n && j<=m) { 498 if(a[i].value <b[j].value) 499 a[i++].value = 0; 500 else if(a[i].value == b[j].value) 501 a[i++].value = j; 502 else 503 j++; 504 } 505 while(i <= n) 506 a[i++].value = 0; 507 b[m+1].value = 0; 508 j = 0; 509 while(++j <= m) { 510 c[j] = -b[j].serial; 511 while(b[j+1].value == b[j].value) { 512 j++; 513 c[j] = b[j].serial; 514 } 515 } 516 c[j] = -1; 517 } 518 519 static long 520 stone(long *a,long n,long *b,register long *c) 521 { 522 register long i, k,y; 523 long j, l; 524 long oldc, tc; 525 long oldl; 526 k = 0; 527 c[0] = newcand(0,0,0); 528 for(i=1; i<=n; i++) { 529 j = a[i]; 530 if(j==0) 531 continue; 532 y = -b[j]; 533 oldl = 0; 534 oldc = c[0]; 535 do { 536 if(y <= clist[oldc].y) 537 continue; 538 l = search(c, k, y); 539 if(l!=oldl+1) 540 oldc = c[l-1]; 541 if(l<=k) { 542 if(clist[c[l]].y <= y) 543 continue; 544 tc = c[l]; 545 c[l] = newcand(i,y,oldc); 546 oldc = tc; 547 oldl = l; 548 } else { 549 c[l] = newcand(i,y,oldc); 550 k++; 551 break; 552 } 553 } while((y=b[++j]) > 0); 554 } 555 return(k); 556 } 557 558 static long 559 newcand(long x,long y,long pred) 560 { 561 register struct cand *q; 562 clist = ralloc(clist,++clen*sizeof(cand)); 563 q = clist + clen -1; 564 q->x = x; 565 q->y = y; 566 q->pred = pred; 567 return(clen-1); 568 } 569 570 static long 571 search(long *c, long k, long y) 572 { 573 register long i, j, l; 574 long t; 575 if(clist[c[k]].y<y) /*quick look for typical case*/ 576 return(k+1); 577 i = 0; 578 j = k+1; 579 while (1) { 580 l = i + j; 581 if ((l >>= 1) <= i) 582 break; 583 t = clist[c[l]].y; 584 if(t > y) 585 j = l; 586 else if(t < y) 587 i = l; 588 else 589 return(l); 590 } 591 return(l+1); 592 } 593 594 static void 595 unravel(long p) 596 { 597 register long i; 598 register struct cand *q; 599 for(i=0; i<=len[0]; i++) 600 J[i] = i<=pref ? i: 601 i>len[0]-suff ? i+len[1]-len[0]: 602 0; 603 for(q=clist+p;q->y!=0;q=clist+q->pred) 604 J[q->x+pref] = q->y+pref; 605 } 606 607 /* check does double duty: 608 1. ferret out any fortuitous correspondences due 609 to confounding by hashing (which result in "jackpot") 610 2. collect random access indexes to the two files */ 611 612 static void 613 check_sb(void) 614 { 615 register long i, j; 616 long jackpot; 617 off_t ctold, ctnew; 618 register int c,d; 619 620 if ((input[0] = fopen(file1,"r")) == NULL) { 621 perror(file1); 622 done(); 623 } 624 if ((input[1] = fopen(file2,"r")) == NULL) { 625 perror(file2); 626 fclose(input[0]); 627 done(); 628 } 629 j = 1; 630 ixold[0] = ixnew[0] = 0; 631 jackpot = 0; 632 ctold = ctnew = 0; 633 for(i=1;i<=len[0];i++) { 634 if(J[i]==0) { 635 ixold[i] = ctold += skipline(0); 636 continue; 637 } 638 while(j<J[i]) { 639 ixnew[j] = ctnew += skipline(1); 640 j++; 641 } 642 if(bflag || wflag || iflag) { 643 for(;;) { 644 c = getc(input[0]); 645 d = getc(input[1]); 646 ctold++; 647 ctnew++; 648 if(bflag && isspace(c) && isspace(d)) { 649 do { 650 if(c=='\n') 651 break; 652 ctold++; 653 } while(isspace(c=getc(input[0]))); 654 do { 655 if(d=='\n') 656 break; 657 ctnew++; 658 } while(isspace(d=getc(input[1]))); 659 } else if ( wflag ) { 660 while( isspace(c) && c!='\n' ) { 661 c=getc(input[0]); 662 ctold++; 663 } 664 while( isspace(d) && d!='\n' ) { 665 d=getc(input[1]); 666 ctnew++; 667 } 668 } 669 if(chrtran(c) != chrtran(d)) { 670 jackpot++; 671 J[i] = 0; 672 if(c!='\n') 673 ctold += skipline(0); 674 if(d!='\n') 675 ctnew += skipline(1); 676 break; 677 } 678 if(c=='\n' || c==EOF) 679 break; 680 } 681 } else { 682 for(;;) { 683 ctold++; 684 ctnew++; 685 if((c=getc(input[0])) != (d=getc(input[1]))) { 686 /* jackpot++; */ 687 J[i] = 0; 688 if(c!='\n') 689 ctold += skipline(0); 690 if(d!='\n') 691 ctnew += skipline(1); 692 break; 693 } 694 if(c=='\n' || c==EOF) 695 break; 696 } 697 } 698 ixold[i] = ctold; 699 ixnew[j] = ctnew; 700 j++; 701 } 702 for(;j<=len[1];j++) { 703 ixnew[j] = ctnew += skipline(1); 704 } 705 fclose(input[0]); 706 fclose(input[1]); 707 /* 708 if(jackpot) 709 fprintf(stderr, "jackpot\n"); 710 */ 711 } 712 713 static void 714 check_mb(void) 715 { 716 register long i, j; 717 long jackpot; 718 off_t ctold, ctnew; 719 wint_t wc, wd; 720 int nc, nd; 721 char *cc, *cd; 722 723 if ((input[0] = fopen(file1,"r")) == NULL) { 724 perror(file1); 725 done(); 726 } 727 mcur[0] = mend[0] = NULL; 728 if ((input[1] = fopen(file2,"r")) == NULL) { 729 perror(file2); 730 fclose(input[0]); 731 done(); 732 } 733 mcur[1] = mend[1] = NULL; 734 j = 1; 735 ixold[0] = ixnew[0] = 0; 736 jackpot = 0; 737 ctold = ctnew = 0; 738 for(i=1;i<=len[0];i++) { 739 if(J[i]==0) { 740 ixold[i] = ctold += wskipline(0); 741 continue; 742 } 743 while(j<J[i]) { 744 ixnew[j] = ctnew += wskipline(1); 745 j++; 746 } 747 if(bflag || wflag || iflag) { 748 for(;;) { 749 cc = wcget(0, &wc, &nc); 750 cd = wcget(1, &wd, &nd); 751 if(bflag && iswspace(wc) && iswspace(wd)) { 752 do { 753 if(wc=='\n') 754 break; 755 ctold += nc; 756 } while(cc = wcget(0, &wc, &nc), 757 iswspace(wc)); 758 do { 759 if(wd=='\n') 760 break; 761 ctnew += nd; 762 } while(cd = wcget(1, &wd, &nd), 763 iswspace(wd)); 764 ctold += nc; 765 ctnew += nd; 766 } else if ( wflag ) { 767 ctold += nc; 768 ctnew += nd; 769 while( iswspace(wc) && wc!='\n' && cc) { 770 cc = wcget(0, &wc, &nc); 771 ctold += nc; 772 } 773 while( iswspace(wd) && wd!='\n' && cd) { 774 cd = wcget(1, &wd, &nd); 775 ctnew += nd; 776 } 777 } else { 778 ctold += nc; 779 ctnew += nd; 780 } 781 if(chrtran(wc) != chrtran(wd) || 782 wc == WEOF && wd == WEOF && 783 (cc == NULL && cd && *cd || 784 cc && *cc && cd == NULL || 785 cc && cd && *cc != *cd)) { 786 jackpot++; 787 J[i] = 0; 788 if(wc!='\n') 789 ctold += wskipline(0); 790 if(wd!='\n') 791 ctnew += wskipline(1); 792 break; 793 } 794 if(wc=='\n' || cc == NULL) 795 break; 796 } 797 } else { 798 for(;;) { 799 cc = wcget(0, &wc, &nc); 800 cd = wcget(1, &wd, &nd); 801 ctold += nc; 802 ctnew += nd; 803 if (wc != wd || wc == WEOF && wd == WEOF && 804 (cc == NULL && cd && *cd || 805 cc && *cc && cd == NULL || 806 cc && cd && *cc != *cd)) { 807 /* jackpot++; */ 808 J[i] = 0; 809 if(wc!='\n') 810 ctold += wskipline(0); 811 if(wd!='\n') 812 ctnew += wskipline(1); 813 break; 814 } 815 if(wc=='\n' || cc == NULL) 816 break; 817 } 818 } 819 ixold[i] = ctold; 820 ixnew[j] = ctnew; 821 j++; 822 } 823 for(;j<=len[1];j++) { 824 ixnew[j] = ctnew += wskipline(1); 825 } 826 fclose(input[0]); 827 fclose(input[1]); 828 /* 829 if(jackpot) 830 fprintf(stderr, "jackpot\n"); 831 */ 832 } 833 834 static void 835 sort(struct line *a,long n) /*shellsort CACM #201*/ 836 { 837 struct line w; 838 register long j,m = 0; 839 struct line *ai; 840 register struct line *aim; 841 long k; 842 843 if (n == 0) 844 return; 845 for(j=1;j<=n;j*= 2) 846 m = 2*j - 1; 847 for(m/=2;m!=0;m/=2) { 848 k = n-m; 849 for(j=1;j<=k;j++) { 850 for(ai = &a[j]; ai > a; ai -= m) { 851 aim = &ai[m]; 852 if(aim < ai) 853 break; /*wraparound*/ 854 if(aim->value > ai[0].value || 855 aim->value == ai[0].value && 856 aim->serial > ai[0].serial) 857 break; 858 w.value = ai[0].value; 859 ai[0].value = aim->value; 860 aim->value = w.value; 861 w.serial = ai[0].serial; 862 ai[0].serial = aim->serial; 863 aim->serial = w.serial; 864 } 865 } 866 } 867 } 868 869 static void 870 unsort(struct line *f, long l, long *b) 871 { 872 register long *a; 873 register long i; 874 a = talloc((l+1)*sizeof(*a)); 875 for(i=1;i<=l;i++) 876 a[f[i].serial] = f[i].value; 877 for(i=1;i<=l;i++) 878 b[i] = a[i]; 879 tfree(a); 880 } 881 882 static long 883 skipline(int f) 884 { 885 register long i; 886 register int c; 887 888 for(i=1;(c=getc(input[f]))!='\n';i++) 889 if (c == EOF) 890 return(i); 891 return(i); 892 } 893 894 static long 895 wskipline(int f) 896 { 897 long i; 898 int n; 899 wint_t wc; 900 char *cp; 901 902 for (i = 1; cp = wcget(f, &wc, &n), wc != '\n'; i += n) 903 if (cp == NULL) 904 return (i); 905 return (i); 906 } 907 908 static void 909 output(void) 910 { 911 long m; 912 register long i0, i1, j1; 913 long j0; 914 if ((input[0] = fopen(file1,"r")) == NULL) { 915 perror(file1); 916 done(); 917 } 918 if ((input[1] = fopen(file2,"r")) == NULL) { 919 perror(file2); 920 fclose(input[0]); 921 done(); 922 } 923 m = len[0]; 924 J[0] = 0; 925 J[m+1] = len[1]+1; 926 if (pflag) { 927 saveJ = talloc((len[0]+2)*sizeof(*saveJ)); 928 memcpy(saveJ, J, (len[0]+2)*sizeof(*saveJ)); 929 } 930 if(opt!=D_EDIT) for(i0=1;i0<=m;i0=i1+1) { 931 while(i0<=m&&J[i0]==J[i0-1]+1) i0++; 932 j0 = J[i0-1]+1; 933 i1 = i0-1; 934 while(i1<m&&J[i1+1]==0) i1++; 935 j1 = J[i1+1]-1; 936 J[i1] = j1; 937 change(i0,i1,j0,j1); 938 } else for(i0=m;i0>=1;i0=i1-1) { 939 while(i0>=1&&J[i0]==J[i0+1]-1&&J[i0]!=0) i0--; 940 j0 = J[i0+1]-1; 941 i1 = i0+1; 942 while(i1>1&&J[i1-1]==0) i1--; 943 j1 = J[i1-1]+1; 944 J[i1] = j1; 945 change(i1,i0,j1,j0); 946 } 947 if(m==0) 948 change(1,0,1,len[1]); 949 if (opt==D_IFDEF) { 950 for (;;) { 951 #define c i0 952 c = getc(input[0]); 953 if (c == EOF) 954 goto end; 955 putchar(c); 956 } 957 #undef c 958 } 959 if (anychange && (opt == D_CONTEXT || opt == D_UNIFIED)) 960 dump_context_vec(); 961 end: fclose(input[0]); 962 fclose(input[1]); 963 } 964 965 static int 966 allblank(off_t *f, long a, long b, FILE *lb) 967 { 968 long i; 969 970 if (a > b) 971 return 1; 972 for (i = a; i <= b; i++) 973 if (f[i]-f[i-1] != 1) 974 return 0; 975 return 1; 976 } 977 978 /* 979 * The following struct is used to record change information when 980 * doing a "context" diff. (see routine "change" to understand the 981 * highly mneumonic field names) 982 */ 983 struct context_vec { 984 long a; /* start line in old file */ 985 long b; /* end line in old file */ 986 long c; /* start line in new file */ 987 long d; /* end line in new file */ 988 }; 989 990 static struct context_vec *context_vec_start, 991 *context_vec_end, 992 *context_vec_ptr; 993 994 #define MAX_CONTEXT 129 995 996 /* indicate that there is a difference between lines a and b of the from file 997 to get to lines c to d of the to file. 998 If a is greater then b then there are no lines in the from file involved 999 and this means that there were lines appended (beginning at b). 1000 If c is greater than d then there are lines missing from the to file. 1001 */ 1002 static void 1003 change(long a,long b,long c,long d) 1004 { 1005 int ch; 1006 struct stat stbuf; 1007 1008 if (opt != D_IFDEF && a>b && c>d) 1009 return; 1010 if (Bflag && allblank(ixold,a,b,input[0]) && 1011 allblank(ixnew,c,d,input[1])) 1012 return; 1013 if (anychange == 0) { 1014 anychange = 1; 1015 if(opt == D_CONTEXT || opt == D_UNIFIED) { 1016 if (opt == D_CONTEXT) { 1017 printf("*** %s\t", file1); 1018 stat(file1, &stbuf); 1019 printf("%s--- %s\t", 1020 ctime(&stbuf.st_mtime), file2); 1021 stat(file2, &stbuf); 1022 printf("%s", ctime(&stbuf.st_mtime)); 1023 } else { /* opt == D_UNIFIED */ 1024 printf("--- %s\t", file1); 1025 stat(file1, &stbuf); 1026 printf("%s+++ %s\t", 1027 ctime(&stbuf.st_mtime), file2); 1028 stat(file2, &stbuf); 1029 printf("%s", ctime(&stbuf.st_mtime)); 1030 } 1031 1032 context_vec_start = talloc(MAX_CONTEXT * 1033 sizeof(*context_vec_start)); 1034 context_vec_end = context_vec_start + MAX_CONTEXT; 1035 context_vec_ptr = context_vec_start - 1; 1036 } 1037 } 1038 if (a <= b && c <= d) 1039 ch = 'c'; 1040 else 1041 ch = (a <= b) ? 'd' : 'a'; 1042 if(opt == D_CONTEXT || opt == D_UNIFIED) { 1043 /* 1044 * if this new change is within 'context' lines of 1045 * the previous change, just add it to the change 1046 * record. If the record is full or if this 1047 * change is more than 'context' lines from the previous 1048 * change, dump the record, reset it & add the new change. 1049 */ 1050 if ( context_vec_ptr >= context_vec_end-1 || 1051 ( context_vec_ptr >= context_vec_start && 1052 a > (context_vec_ptr->b + 2*context) && 1053 c > (context_vec_ptr->d + 2*context) ) ) 1054 dump_context_vec(); 1055 1056 context_vec_ptr++; 1057 context_vec_ptr->a = a; 1058 context_vec_ptr->b = b; 1059 context_vec_ptr->c = c; 1060 context_vec_ptr->d = d; 1061 return; 1062 } 1063 switch (opt) { 1064 1065 case D_NORMAL: 1066 case D_EDIT: 1067 range(a,b,","); 1068 putchar(a>b?'a':c>d?'d':'c'); 1069 if(opt==D_NORMAL) 1070 range(c,d,","); 1071 putchar('\n'); 1072 break; 1073 case D_REVERSE: 1074 putchar(a>b?'a':c>d?'d':'c'); 1075 range(a,b," "); 1076 putchar('\n'); 1077 break; 1078 case D_NREVERSE: 1079 if (a>b) 1080 printf("a%ld %ld\n",b,d-c+1); 1081 else { 1082 printf("d%ld %ld\n",a,b-a+1); 1083 if (!(c>d)) 1084 /* add changed lines */ 1085 printf("a%ld %ld\n",b, d-c+1); 1086 } 1087 break; 1088 } 1089 if(opt == D_NORMAL || opt == D_IFDEF) { 1090 fetch(ixold,a,b,input[0],"< ", 1); 1091 if(a<=b&&c<=d && opt == D_NORMAL) 1092 prints("---\n"); 1093 } 1094 fetch(ixnew,c,d,input[1],opt==D_NORMAL?"> ":"", 0); 1095 if ((opt ==D_EDIT || opt == D_REVERSE) && c<=d) 1096 prints(".\n"); 1097 if (inifdef) { 1098 fprintf(stdout, "#endif %s\n", endifname); 1099 inifdef = 0; 1100 } 1101 } 1102 1103 static void 1104 range(long a,long b,const char *separator) 1105 { 1106 printf("%ld", a>b?b:a); 1107 if(a<b || opt==D_UNIFIED) { 1108 printf("%s%ld", separator, opt==D_UNIFIED ? b-a+1 : b); 1109 } 1110 } 1111 1112 static void 1113 fetch(off_t *f,long a,long b,FILE *lb,const char *s,int oldfile) 1114 { 1115 register long i, j; 1116 register int c; 1117 register long col; 1118 register long nc; 1119 int oneflag = (*ifdef1!='\0') != (*ifdef2!='\0'); 1120 1121 /* 1122 * When doing #ifdef's, copy down to current line 1123 * if this is the first file, so that stuff makes it to output. 1124 */ 1125 if (opt == D_IFDEF && oldfile){ 1126 off_t curpos = ftello(lb); 1127 /* print through if append (a>b), else to (nb: 0 vs 1 orig) */ 1128 nc = f[a>b? b : a-1 ] - curpos; 1129 for (i = 0; i < nc; i++) { 1130 c = getc(lb); 1131 if (c == EOF) 1132 break; 1133 putchar(c); 1134 } 1135 } 1136 if (a > b) 1137 return; 1138 if (opt == D_IFDEF) { 1139 if (inifdef) 1140 fprintf(stdout, "#else %s%s\n", oneflag && oldfile==1 ? "!" : "", ifdef2); 1141 else { 1142 if (oneflag) { 1143 /* There was only one ifdef given */ 1144 endifname = ifdef2; 1145 if (oldfile) 1146 fprintf(stdout, "#ifndef %s\n", endifname); 1147 else 1148 fprintf(stdout, "#ifdef %s\n", endifname); 1149 } 1150 else { 1151 endifname = oldfile ? ifdef1 : ifdef2; 1152 fprintf(stdout, "#ifdef %s\n", endifname); 1153 } 1154 } 1155 inifdef = 1+oldfile; 1156 } 1157 1158 for(i=a;i<=b;i++) { 1159 fseeko(lb,f[i-1],SEEK_SET); 1160 nc = f[i]-f[i-1]; 1161 if (opt != D_IFDEF) 1162 prints(s); 1163 col = 0; 1164 for(j=0;j<nc;j++) { 1165 c = getc(lb); 1166 if (c == '\t' && tflag) 1167 do 1168 putchar(' '); 1169 while (++col & 7); 1170 else if (c == EOF) { 1171 if (aflag) 1172 printf("\n\\ No newline at " 1173 "end of file\n"); 1174 else 1175 putchar('\n'); 1176 break; 1177 } else { 1178 putchar(c); 1179 col++; 1180 } 1181 } 1182 } 1183 1184 if (inifdef && !wantelses) { 1185 fprintf(stdout, "#endif %s\n", endifname); 1186 inifdef = 0; 1187 } 1188 } 1189 1190 #define POW2 /* define only if HALFLONG is 2**n */ 1191 #define HALFLONG 16 1192 #define low(x) (x&((1L<<HALFLONG)-1)) 1193 #define high(x) (x>>HALFLONG) 1194 1195 /* 1196 * hashing has the effect of 1197 * arranging line in 7-bit bytes and then 1198 * summing 1-s complement in 16-bit hunks 1199 */ 1200 static int 1201 readhash(register int f) 1202 { 1203 register int32_t sum; 1204 register unsigned shift; 1205 register int t; 1206 register int space; 1207 int content; 1208 wint_t wt; 1209 int n; 1210 char *cp; 1211 1212 sum = 1; 1213 space = 0; 1214 content = 0; 1215 if(!bflag && !wflag) { 1216 if(iflag) { 1217 if (mb_cur_max > 1) { 1218 for (shift = 0; cp = wcget(f, &wt, &n), 1219 wt != '\n'; shift += 7) { 1220 if (cp == NULL) { 1221 if (content) { 1222 missnl(f); 1223 break; 1224 } 1225 return (0); 1226 } 1227 content = 1; 1228 sum += (int32_t)chrtran(wt) << (shift 1229 #ifdef POW2 1230 &= HALFLONG - 1); 1231 #else 1232 %= HALFLONG); 1233 #endif 1234 } 1235 } else { 1236 for(shift=0;(t=getc(input[f]))!='\n';shift+=7) { 1237 if(t==EOF) { 1238 if (content) { 1239 missnl(f); 1240 break; 1241 } 1242 return(0); 1243 } 1244 content = 1; 1245 sum += (int32_t)chrtran(t) << (shift 1246 #ifdef POW2 1247 &= HALFLONG - 1); 1248 #else 1249 %= HALFLONG); 1250 #endif 1251 } 1252 } 1253 } else { 1254 for(shift=0;(t=getc(input[f]))!='\n';shift+=7) { 1255 if(t==EOF) { 1256 if (content) { 1257 missnl(f); 1258 break; 1259 } 1260 return(0); 1261 } 1262 content = 1; 1263 sum += (int32_t)t << (shift 1264 #ifdef POW2 1265 &= HALFLONG - 1); 1266 #else 1267 %= HALFLONG); 1268 #endif 1269 } 1270 } 1271 } else { 1272 if (mb_cur_max > 1) { 1273 for(shift=0;;) { 1274 if ((cp = wcget(f, &wt, &n)) == NULL) { 1275 if (content) { 1276 missnl(f); 1277 break; 1278 } 1279 return(0); 1280 } 1281 content = 1; 1282 switch (wt) { 1283 default: 1284 if (iswspace(wt)) { 1285 space++; 1286 continue; 1287 } 1288 if(space && !wflag) { 1289 shift += 7; 1290 space = 0; 1291 } 1292 sum += (int32_t)chrtran(wt) << (shift 1293 #ifdef POW2 1294 &= HALFLONG - 1); 1295 #else 1296 %= HALFLONG); 1297 #endif 1298 shift += 7; 1299 continue; 1300 case '\n': 1301 break; 1302 } 1303 break; 1304 } 1305 } else { 1306 for(shift=0;;) { 1307 switch(t=getc(input[f])) { 1308 case EOF: 1309 if (content) { 1310 missnl(f); 1311 break; 1312 } 1313 return(0); 1314 default: 1315 content = 1; 1316 if (isspace(t)) { 1317 space++; 1318 continue; 1319 } 1320 if(space && !wflag) { 1321 shift += 7; 1322 space = 0; 1323 } 1324 sum += (int32_t)chrtran(t) << (shift 1325 #ifdef POW2 1326 &= HALFLONG - 1); 1327 #else 1328 %= HALFLONG); 1329 #endif 1330 shift += 7; 1331 continue; 1332 case '\n': 1333 break; 1334 } 1335 break; 1336 } 1337 } 1338 } 1339 sum = low(sum) + high(sum); 1340 return((int16_t)low(sum) + (int16_t)high(sum)); 1341 } 1342 1343 static int 1344 asciifile(FILE *f) 1345 { 1346 char buf[BUFSIZ]; 1347 register int cnt; 1348 register char *cp; 1349 1350 fseeko(f, 0, SEEK_SET); 1351 cnt = fread(buf, 1, BUFSIZ, f); 1352 cp = buf; 1353 while (--cnt >= 0) 1354 if (*cp++ == '\0') 1355 return (0); 1356 return (1); 1357 } 1358 1359 1360 /* dump accumulated "context" diff changes */ 1361 static void 1362 dump_context_vec(void) 1363 { 1364 register long a, b = 0, c, d = 0; 1365 register char ch; 1366 register struct context_vec *cvp = context_vec_start; 1367 register long lowa, upb, lowc, upd; 1368 register int do_output; 1369 1370 if ( cvp > context_vec_ptr ) 1371 return; 1372 1373 lowa = max(1, cvp->a - context); 1374 upb = min(len[0], context_vec_ptr->b + context); 1375 lowc = max(1, cvp->c - context); 1376 upd = min(len[1], context_vec_ptr->d + context); 1377 1378 if (opt == D_UNIFIED) { 1379 printf("@@ -"); 1380 range(lowa, upb, ","); 1381 printf(" +"); 1382 range(lowc, upd, ","); 1383 printf(" @@"); 1384 if (pflag) 1385 pdump(lowa-1); 1386 printf("\n"); 1387 1388 while (cvp <= context_vec_ptr) { 1389 a = cvp->a; b = cvp->b; c = cvp->c; d = cvp->d; 1390 1391 if (a <= b && c <= d) 1392 ch = 'c'; 1393 else 1394 ch = (a <= b) ? 'd' : 'a'; 1395 1396 switch (ch) { 1397 case 'a': 1398 fetch(ixold,lowa,b,input[0]," ", 0); 1399 fetch(ixnew,c,d,input[1],"+",0); 1400 break; 1401 case 'c': 1402 fetch(ixold,lowa,a-1,input[0]," ", 0); 1403 fetch(ixold,a,b,input[0],"-",0); 1404 fetch(ixnew,c,d,input[1],"+",0); 1405 break; 1406 case 'd': 1407 fetch(ixold,lowa,a-1,input[0]," ", 0); 1408 fetch(ixold,a,b,input[0],"-",0); 1409 break; 1410 } 1411 lowa = b + 1; 1412 cvp++; 1413 } 1414 fetch(ixold, b+1, upb, input[0], " ", 0); 1415 } 1416 1417 if (opt == D_CONTEXT) { 1418 printf("***************"); 1419 if (pflag) 1420 pdump(lowa-1); 1421 printf("\n*** "); 1422 range(lowa,upb,","); 1423 printf(" ****\n"); 1424 1425 /* 1426 * output changes to the "old" file. The first loop suppresses 1427 * output if there were no changes to the "old" file (we'll see 1428 * the "old" lines as context in the "new" list). 1429 */ 1430 do_output = 0; 1431 for ( ; cvp <= context_vec_ptr; cvp++) 1432 if (cvp->a <= cvp->b) { 1433 cvp = context_vec_start; 1434 do_output++; 1435 break; 1436 } 1437 1438 if ( do_output ) { 1439 while (cvp <= context_vec_ptr) { 1440 a = cvp->a; b = cvp->b; c = cvp->c; d = cvp->d; 1441 1442 if (a <= b && c <= d) 1443 ch = 'c'; 1444 else 1445 ch = (a <= b) ? 'd' : 'a'; 1446 1447 if (ch == 'a') 1448 fetch(ixold,lowa,b,input[0]," ", 0); 1449 else { 1450 fetch(ixold,lowa,a-1,input[0]," ", 0); 1451 fetch(ixold,a,b,input[0], 1452 ch == 'c' ? "! " : "- ", 1453 0); 1454 } 1455 lowa = b + 1; 1456 cvp++; 1457 } 1458 fetch(ixold, b+1, upb, input[0], " ", 0); 1459 } 1460 1461 /* output changes to the "new" file */ 1462 printf("--- "); 1463 range(lowc,upd,","); 1464 printf(" ----\n"); 1465 1466 do_output = 0; 1467 for (cvp = context_vec_start; cvp <= context_vec_ptr; cvp++) 1468 if (cvp->c <= cvp->d) { 1469 cvp = context_vec_start; 1470 do_output++; 1471 break; 1472 } 1473 1474 if (do_output) { 1475 while (cvp <= context_vec_ptr) { 1476 a = cvp->a; b = cvp->b; c = cvp->c; d = cvp->d; 1477 1478 if (a <= b && c <= d) 1479 ch = 'c'; 1480 else 1481 ch = (a <= b) ? 'd' : 'a'; 1482 1483 if (ch == 'd') 1484 fetch(ixnew,lowc,d,input[1]," ", 0); 1485 else { 1486 fetch(ixnew,lowc,c-1,input[1]," ", 0); 1487 fetch(ixnew,c,d,input[1], 1488 ch == 'c' ? "! " : "+ ", 1489 0); 1490 } 1491 lowc = d + 1; 1492 cvp++; 1493 } 1494 fetch(ixnew, d+1, upd, input[1], " ", 0); 1495 } 1496 } 1497 1498 context_vec_ptr = context_vec_start - 1; 1499 } 1500 1501 /*ARGSUSED*/ 1502 static void 1503 sdone(int signo) 1504 { 1505 done(); 1506 } 1507 1508 static char * 1509 wcget(int f, wint_t *wc, int *len) 1510 { 1511 size_t rest; 1512 int c, i, n; 1513 1514 i = 0; 1515 rest = mend[f] - mcur[f]; 1516 if (rest && mcur[f] > mbuf[f]) { 1517 do 1518 mbuf[f][i] = mcur[f][i]; 1519 while (i++, --rest); 1520 } else if (incompl[f]) { 1521 incompl[f] = 0; 1522 *wc = WEOF; 1523 mend[f] = mcur[f] = NULL; 1524 return NULL; 1525 } 1526 if (i == 0) { 1527 c = getc(input[f]); 1528 if (c == EOF) { 1529 *wc = WEOF; 1530 mend[f] = mcur[f] = NULL; 1531 return NULL; 1532 } 1533 mbuf[f][i++] = c; 1534 } 1535 if (mbuf[f][0] & 0200) { 1536 while (mbuf[f][i-1] != '\n' && i < mb_cur_max && 1537 incompl[f] == 0) { 1538 c = getc(input[f]); 1539 if (c != EOF) 1540 mbuf[f][i++] = c; 1541 else 1542 incompl[f] = 1; 1543 } 1544 n = mbtowi(wc, mbuf[f], i); 1545 if (n < 0) { 1546 *len = 1; 1547 *wc = WEOF; 1548 } else if (n == 0) { 1549 *len = 1; 1550 *wc = '\0'; 1551 } else 1552 *len = n; 1553 } else { 1554 *wc = mbuf[f][0]; 1555 *len = n = 1; 1556 } 1557 mcur[f] = &mbuf[f][*len]; 1558 mend[f] = &mcur[f][i - *len]; 1559 return mbuf[f]; 1560 } 1561 1562 static void 1563 missnl(int f) 1564 { 1565 if (aflag == 0) 1566 fprintf(stderr, "Warning: missing newline at end of file %s\n", 1567 f == 0 ? file1 : file2); 1568 } 1569 1570 /* 1571 * Find and dump the name of the C function with the -p option. The 1572 * search begins at line sa. 1573 */ 1574 static void 1575 pdump(long sa) 1576 { 1577 #define psize 40 1578 static char lbuf[psize*MB_LEN_MAX+1]; 1579 char mbuf[MB_LEN_MAX+1]; 1580 int c, i, j; 1581 wchar_t wc; 1582 long a = sa; 1583 1584 while (a-- > pstart) { 1585 if (saveJ[a+1] == 0) 1586 continue; 1587 fseeko(input[0], ixold[a], SEEK_SET); 1588 i = 0; 1589 do { 1590 if ((c=getc(input[0])) == EOF || c == '\n') 1591 break; 1592 mbuf[i] = c; 1593 } while (++i<mb_cur_max); 1594 if (mb_cur_max>1) { 1595 mbuf[i] = 0; 1596 if (((c=mbuf[0])&0200)==0) 1597 wc = mbuf[0]; 1598 else if (mbtowc(&wc, mbuf, i) < 0) 1599 continue; 1600 } 1601 if ((mb_cur_max>1 && mbuf[0]&0200 ? iswalpha(wc):isalpha(c)) || 1602 c == '$' || c == '_') { 1603 plast = a+1; 1604 for (j = 0; j < i; j++) 1605 lbuf[j] = mbuf[j]; 1606 while (i < sizeof lbuf - 1) { 1607 if ((c=getc(input[0])) == EOF || c == '\n') 1608 break; 1609 lbuf[i++] = c; 1610 } 1611 for (j=0;j<i&&j<psize;) { 1612 if (mb_cur_max==1 || (lbuf[j]&0200) == 0) 1613 j++; 1614 else { 1615 c = mbtowc(NULL, &lbuf[j], i-j); 1616 j += c>0 ? c:1; 1617 } 1618 } 1619 lbuf[j] = 0; 1620 break; 1621 } 1622 } 1623 pstart = sa; 1624 if (plast) { 1625 putchar(' '); 1626 for (i = 0; lbuf[i]; i++) 1627 putchar(lbuf[i] & 0377); 1628 } 1629 }