1: char rcsid[] = 2: "$Header: patch.c,v 2.0.1.6 88/06/22 20:46:39 lwall Locked $"; 3: 4: /* patch - a program to apply diffs to original files 5: * 6: * Copyright 1986, Larry Wall 7: * 8: * This program may be copied as long as you don't try to make any 9: * money off of it, or pretend that you wrote it. 10: * 11: * $Log: patch.c,v $ 12: * Revision 2.0.1.6 88/06/22 20:46:39 lwall 13: * patch12: rindex() wasn't declared 14: * 15: * Revision 2.0.1.5 88/06/03 15:09:37 lwall 16: * patch10: exit code improved. 17: * patch10: better support for non-flexfilenames. 18: * 19: * Revision 2.0.1.4 87/02/16 14:00:04 lwall 20: * Short replacement caused spurious "Out of sync" message. 21: * 22: * Revision 2.0.1.3 87/01/30 22:45:50 lwall 23: * Improved diagnostic on sync error. 24: * Moved do_ed_script() to pch.c. 25: * 26: * Revision 2.0.1.2 86/11/21 09:39:15 lwall 27: * Fuzz factor caused offset of installed lines. 28: * 29: * Revision 2.0.1.1 86/10/29 13:10:22 lwall 30: * Backwards search could terminate prematurely. 31: * 32: * Revision 2.0 86/09/17 15:37:32 lwall 33: * Baseline for netwide release. 34: * 35: * Revision 1.5 86/08/01 20:53:24 lwall 36: * Changed some %d's to %ld's. 37: * Linted. 38: * 39: * Revision 1.4 86/08/01 19:17:29 lwall 40: * Fixes for machines that can't vararg. 41: * Added fuzz factor. 42: * Generalized -p. 43: * General cleanup. 44: * 45: * 85/08/15 van%ucbmonet@berkeley 46: * Changes for 4.3bsd diff -c. 47: * 48: * Revision 1.3 85/03/26 15:07:43 lwall 49: * Frozen. 50: * 51: * Revision 1.2.1.9 85/03/12 17:03:35 lwall 52: * Changed pfp->_file to fileno(pfp). 53: * 54: * Revision 1.2.1.8 85/03/12 16:30:43 lwall 55: * Check i_ptr and i_womp to make sure they aren't null before freeing. 56: * Also allow ed output to be suppressed. 57: * 58: * Revision 1.2.1.7 85/03/12 15:56:13 lwall 59: * Added -p option from jromine@uci-750a. 60: * 61: * Revision 1.2.1.6 85/03/12 12:12:51 lwall 62: * Now checks for normalness of file to patch. 63: * 64: * Revision 1.2.1.5 85/03/12 11:52:12 lwall 65: * Added -D (#ifdef) option from joe@fluke. 66: * 67: * Revision 1.2.1.4 84/12/06 11:14:15 lwall 68: * Made smarter about SCCS subdirectories. 69: * 70: * Revision 1.2.1.3 84/12/05 11:18:43 lwall 71: * Added -l switch to do loose string comparison. 72: * 73: * Revision 1.2.1.2 84/12/04 09:47:13 lwall 74: * Failed hunk count not reset on multiple patch file. 75: * 76: * Revision 1.2.1.1 84/12/04 09:42:37 lwall 77: * Branch for sdcrdcf changes. 78: * 79: * Revision 1.2 84/11/29 13:29:51 lwall 80: * Linted. Identifiers uniqified. Fixed i_ptr malloc() bug. Fixed 81: * multiple calls to mktemp(). Will now work on machines that can only 82: * read 32767 chars. Added -R option for diffs with new and old swapped. 83: * Various cosmetic changes. 84: * 85: * Revision 1.1 84/11/09 17:03:58 lwall 86: * Initial revision 87: * 88: */ 89: 90: #include "INTERN.h" 91: #include "common.h" 92: #include "EXTERN.h" 93: #include "version.h" 94: #include "util.h" 95: #include "pch.h" 96: #include "inp.h" 97: 98: /* procedures */ 99: 100: void reinitialize_almost_everything(); 101: void get_some_switches(); 102: LINENUM locate_hunk(); 103: void abort_hunk(); 104: void apply_hunk(); 105: void init_output(); 106: void init_reject(); 107: void copy_till(); 108: void spew_output(); 109: void dump_line(); 110: bool patch_match(); 111: bool similar(); 112: void re_input(); 113: void my_exit(); 114: 115: /* Apply a set of diffs as appropriate. */ 116: 117: main(argc,argv) 118: int argc; 119: char **argv; 120: { 121: LINENUM where; 122: LINENUM newwhere; 123: LINENUM fuzz; 124: LINENUM mymaxfuzz; 125: int hunk = 0; 126: int failed = 0; 127: int failtotal = 0; 128: int i; 129: 130: setbuf(stderr, serrbuf); 131: for (i = 0; i<MAXFILEC; i++) 132: filearg[i] = Nullch; 133: Mktemp(TMPOUTNAME); 134: Mktemp(TMPINNAME); 135: Mktemp(TMPREJNAME); 136: Mktemp(TMPPATNAME); 137: 138: /* parse switches */ 139: Argc = argc; 140: Argv = argv; 141: get_some_switches(); 142: 143: /* make sure we clean up /tmp in case of disaster */ 144: set_signals(0); 145: 146: for ( 147: open_patch_file(filearg[1]); 148: there_is_another_patch(); 149: reinitialize_almost_everything() 150: ) { /* for each patch in patch file */ 151: 152: if (outname == Nullch) 153: outname = savestr(filearg[0]); 154: 155: /* initialize the patched file */ 156: if (!skip_rest_of_patch) 157: init_output(TMPOUTNAME); 158: 159: /* for ed script just up and do it and exit */ 160: if (diff_type == ED_DIFF) { 161: do_ed_script(); 162: continue; 163: } 164: 165: /* initialize reject file */ 166: init_reject(TMPREJNAME); 167: 168: /* find out where all the lines are */ 169: if (!skip_rest_of_patch) 170: scan_input(filearg[0]); 171: 172: /* from here on, open no standard i/o files, because malloc */ 173: /* might misfire and we can't catch it easily */ 174: 175: /* apply each hunk of patch */ 176: hunk = 0; 177: failed = 0; 178: out_of_mem = FALSE; 179: while (another_hunk()) { 180: hunk++; 181: fuzz = Nulline; 182: mymaxfuzz = pch_context(); 183: if (maxfuzz < mymaxfuzz) 184: mymaxfuzz = maxfuzz; 185: if (!skip_rest_of_patch) { 186: do { 187: where = locate_hunk(fuzz); 188: if (hunk == 1 && where == Nulline && !force) { 189: /* dwim for reversed patch? */ 190: if (!pch_swap()) { 191: if (fuzz == Nulline) 192: say1( 193: "Not enough memory to try swapped hunk! Assuming unswapped.\n"); 194: continue; 195: } 196: reverse = !reverse; 197: where = locate_hunk(fuzz); /* try again */ 198: if (where == Nulline) { /* didn't find it swapped */ 199: if (!pch_swap()) /* put it back to normal */ 200: fatal1("Lost hunk on alloc error!\n"); 201: reverse = !reverse; 202: } 203: else if (noreverse) { 204: if (!pch_swap()) /* put it back to normal */ 205: fatal1("Lost hunk on alloc error!\n"); 206: reverse = !reverse; 207: say1( 208: "Ignoring previously applied (or reversed) patch.\n"); 209: skip_rest_of_patch = TRUE; 210: } 211: else { 212: ask3( 213: "%seversed (or previously applied) patch detected! %s -R? [y] ", 214: reverse ? "R" : "Unr", 215: reverse ? "Assume" : "Ignore"); 216: if (*buf == 'n') { 217: ask1("Apply anyway? [n] "); 218: if (*buf != 'y') 219: skip_rest_of_patch = TRUE; 220: where = Nulline; 221: reverse = !reverse; 222: if (!pch_swap()) /* put it back to normal */ 223: fatal1("Lost hunk on alloc error!\n"); 224: } 225: } 226: } 227: } while (!skip_rest_of_patch && where == Nulline && 228: ++fuzz <= mymaxfuzz); 229: 230: if (skip_rest_of_patch) { /* just got decided */ 231: Fclose(ofp); 232: ofp = Nullfp; 233: } 234: } 235: 236: newwhere = pch_newfirst() + last_offset; 237: if (skip_rest_of_patch) { 238: abort_hunk(); 239: failed++; 240: if (verbose) 241: say3("Hunk #%d ignored at %ld.\n", hunk, newwhere); 242: } 243: else if (where == Nulline) { 244: abort_hunk(); 245: failed++; 246: if (verbose) 247: say3("Hunk #%d failed at %ld.\n", hunk, newwhere); 248: } 249: else { 250: apply_hunk(where); 251: if (verbose) { 252: say3("Hunk #%d succeeded at %ld", hunk, newwhere); 253: if (fuzz) 254: say2(" with fuzz %ld", fuzz); 255: if (last_offset) 256: say3(" (offset %ld line%s)", 257: last_offset, last_offset==1L?"":"s"); 258: say1(".\n"); 259: } 260: } 261: } 262: 263: if (out_of_mem && using_plan_a) { 264: Argc = Argc_last; 265: Argv = Argv_last; 266: say1("\n\nRan out of memory using Plan A--trying again...\n\n"); 267: continue; 268: } 269: 270: assert(hunk); 271: 272: /* finish spewing out the new file */ 273: if (!skip_rest_of_patch) 274: spew_output(); 275: 276: /* and put the output where desired */ 277: ignore_signals(); 278: if (!skip_rest_of_patch) { 279: if (move_file(TMPOUTNAME, outname) < 0) { 280: toutkeep = TRUE; 281: chmod(TMPOUTNAME, filemode); 282: } 283: else 284: chmod(outname, filemode); 285: } 286: Fclose(rejfp); 287: rejfp = Nullfp; 288: if (failed) { 289: failtotal += failed; 290: if (!*rejname) { 291: Strcpy(rejname, outname); 292: #ifndef FLEXFILENAMES 293: { 294: char *rindex(); 295: char *s = rindex(rejname,'/'); 296: 297: if (!s) 298: s = rejname; 299: if (strlen(s) > 13) 300: if (s[12] == '.') /* try to preserve difference */ 301: s[12] = s[13]; /* between .h, .c, .y, etc. */ 302: s[13] = '\0'; 303: } 304: #endif 305: Strcat(rejname, REJEXT); 306: } 307: if (skip_rest_of_patch) { 308: say4("%d out of %d hunks ignored--saving rejects to %s\n", 309: failed, hunk, rejname); 310: } 311: else { 312: say4("%d out of %d hunks failed--saving rejects to %s\n", 313: failed, hunk, rejname); 314: } 315: if (move_file(TMPREJNAME, rejname) < 0) 316: trejkeep = TRUE; 317: } 318: set_signals(1); 319: } 320: my_exit(failtotal); 321: } 322: 323: /* Prepare to find the next patch to do in the patch file. */ 324: 325: void 326: reinitialize_almost_everything() 327: { 328: re_patch(); 329: re_input(); 330: 331: input_lines = 0; 332: last_frozen_line = 0; 333: 334: filec = 0; 335: if (filearg[0] != Nullch && !out_of_mem) { 336: free(filearg[0]); 337: filearg[0] = Nullch; 338: } 339: 340: if (outname != Nullch) { 341: free(outname); 342: outname = Nullch; 343: } 344: 345: last_offset = 0; 346: 347: diff_type = 0; 348: 349: if (revision != Nullch) { 350: free(revision); 351: revision = Nullch; 352: } 353: 354: reverse = FALSE; 355: skip_rest_of_patch = FALSE; 356: 357: get_some_switches(); 358: 359: if (filec >= 2) 360: fatal1("You may not change to a different patch file.\n"); 361: } 362: 363: /* Process switches and filenames up to next '+' or end of list. */ 364: 365: void 366: get_some_switches() 367: { 368: Reg1 char *s; 369: 370: rejname[0] = '\0'; 371: Argc_last = Argc; 372: Argv_last = Argv; 373: if (!Argc) 374: return; 375: for (Argc--,Argv++; Argc; Argc--,Argv++) { 376: s = Argv[0]; 377: if (strEQ(s, "+")) { 378: return; /* + will be skipped by for loop */ 379: } 380: if (*s != '-' || !s[1]) { 381: if (filec == MAXFILEC) 382: fatal1("Too many file arguments.\n"); 383: filearg[filec++] = savestr(s); 384: } 385: else { 386: switch (*++s) { 387: case 'b': 388: origext = savestr(Argv[1]); 389: Argc--,Argv++; 390: break; 391: case 'B': 392: origprae = savestr(Argv[1]); 393: Argc--,Argv++; 394: break; 395: case 'c': 396: diff_type = CONTEXT_DIFF; 397: break; 398: case 'd': 399: if (!*++s) { 400: Argc--,Argv++; 401: s = Argv[0]; 402: } 403: if (chdir(s) < 0) 404: fatal2("Can't cd to %s.\n", s); 405: break; 406: case 'D': 407: do_defines = TRUE; 408: if (!*++s) { 409: Argc--,Argv++; 410: s = Argv[0]; 411: } 412: if (!isalpha(*s)) 413: fatal1("Argument to -D not an identifier.\n"); 414: Sprintf(if_defined, "#ifdef %s\n", s); 415: Sprintf(not_defined, "#ifndef %s\n", s); 416: Sprintf(end_defined, "#endif /* %s */\n", s); 417: break; 418: case 'e': 419: diff_type = ED_DIFF; 420: break; 421: case 'f': 422: force = TRUE; 423: break; 424: case 'F': 425: if (*++s == '=') 426: s++; 427: maxfuzz = atoi(s); 428: break; 429: case 'l': 430: canonicalize = TRUE; 431: break; 432: case 'n': 433: diff_type = NORMAL_DIFF; 434: break; 435: case 'N': 436: noreverse = TRUE; 437: break; 438: case 'o': 439: outname = savestr(Argv[1]); 440: Argc--,Argv++; 441: break; 442: case 'p': 443: if (*++s == '=') 444: s++; 445: strippath = atoi(s); 446: break; 447: case 'r': 448: Strcpy(rejname, Argv[1]); 449: Argc--,Argv++; 450: break; 451: case 'R': 452: reverse = TRUE; 453: break; 454: case 's': 455: verbose = FALSE; 456: break; 457: case 'S': 458: skip_rest_of_patch = TRUE; 459: break; 460: case 'v': 461: version(); 462: break; 463: #ifdef DEBUGGING 464: case 'x': 465: debug = atoi(s+1); 466: break; 467: #endif 468: default: 469: fatal2("Unrecognized switch: %s\n", Argv[0]); 470: } 471: } 472: } 473: } 474: 475: /* Attempt to find the right place to apply this hunk of patch. */ 476: 477: LINENUM 478: locate_hunk(fuzz) 479: LINENUM fuzz; 480: { 481: Reg1 LINENUM first_guess = pch_first() + last_offset; 482: Reg2 LINENUM offset; 483: LINENUM pat_lines = pch_ptrn_lines(); 484: Reg3 LINENUM max_pos_offset = input_lines - first_guess 485: - pat_lines + 1; 486: Reg4 LINENUM max_neg_offset = first_guess - last_frozen_line - 1 487: + pch_context(); 488: 489: if (!pat_lines) /* null range matches always */ 490: return first_guess; 491: if (max_neg_offset >= first_guess) /* do not try lines < 0 */ 492: max_neg_offset = first_guess - 1; 493: if (first_guess <= input_lines && patch_match(first_guess, Nulline, fuzz)) 494: return first_guess; 495: for (offset = 1; ; offset++) { 496: Reg5 bool check_after = (offset <= max_pos_offset); 497: Reg6 bool check_before = (offset <= max_neg_offset); 498: 499: if (check_after && patch_match(first_guess, offset, fuzz)) { 500: #ifdef DEBUGGING 501: if (debug & 1) 502: say3("Offset changing from %ld to %ld\n", last_offset, offset); 503: #endif 504: last_offset = offset; 505: return first_guess+offset; 506: } 507: else if (check_before && patch_match(first_guess, -offset, fuzz)) { 508: #ifdef DEBUGGING 509: if (debug & 1) 510: say3("Offset changing from %ld to %ld\n", last_offset, -offset); 511: #endif 512: last_offset = -offset; 513: return first_guess-offset; 514: } 515: else if (!check_before && !check_after) 516: return Nulline; 517: } 518: } 519: 520: /* We did not find the pattern, dump out the hunk so they can handle it. */ 521: 522: void 523: abort_hunk() 524: { 525: Reg1 LINENUM i; 526: Reg2 LINENUM pat_end = pch_end(); 527: /* add in last_offset to guess the same as the previous successful hunk */ 528: LINENUM oldfirst = pch_first() + last_offset; 529: LINENUM newfirst = pch_newfirst() + last_offset; 530: LINENUM oldlast = oldfirst + pch_ptrn_lines() - 1; 531: LINENUM newlast = newfirst + pch_repl_lines() - 1; 532: char *stars = (diff_type == NEW_CONTEXT_DIFF ? " ****" : ""); 533: char *minuses = (diff_type == NEW_CONTEXT_DIFF ? " ----" : " -----"); 534: 535: fprintf(rejfp, "***************\n"); 536: for (i=0; i<=pat_end; i++) { 537: switch (pch_char(i)) { 538: case '*': 539: if (oldlast < oldfirst) 540: fprintf(rejfp, "*** 0%s\n", stars); 541: else if (oldlast == oldfirst) 542: fprintf(rejfp, "*** %ld%s\n", oldfirst, stars); 543: else 544: fprintf(rejfp, "*** %ld,%ld%s\n", oldfirst, oldlast, stars); 545: break; 546: case '=': 547: if (newlast < newfirst) 548: fprintf(rejfp, "--- 0%s\n", minuses); 549: else if (newlast == newfirst) 550: fprintf(rejfp, "--- %ld%s\n", newfirst, minuses); 551: else 552: fprintf(rejfp, "--- %ld,%ld%s\n", newfirst, newlast, minuses); 553: break; 554: case '\n': 555: fprintf(rejfp, "%s", pfetch(i)); 556: break; 557: case ' ': case '-': case '+': case '!': 558: fprintf(rejfp, "%c %s", pch_char(i), pfetch(i)); 559: break; 560: default: 561: say1("Fatal internal error in abort_hunk().\n"); 562: abort(); 563: } 564: } 565: } 566: 567: /* We found where to apply it (we hope), so do it. */ 568: 569: void 570: apply_hunk(where) 571: LINENUM where; 572: { 573: Reg1 LINENUM old = 1; 574: Reg2 LINENUM lastline = pch_ptrn_lines(); 575: Reg3 LINENUM new = lastline+1; 576: #define OUTSIDE 0 577: #define IN_IFNDEF 1 578: #define IN_IFDEF 2 579: #define IN_ELSE 3 580: Reg4 int def_state = OUTSIDE; 581: Reg5 bool R_do_defines = do_defines; 582: Reg6 LINENUM pat_end = pch_end(); 583: 584: where--; 585: while (pch_char(new) == '=' || pch_char(new) == '\n') 586: new++; 587: 588: while (old <= lastline) { 589: if (pch_char(old) == '-') { 590: copy_till(where + old - 1); 591: if (R_do_defines) { 592: if (def_state == OUTSIDE) { 593: fputs(not_defined, ofp); 594: def_state = IN_IFNDEF; 595: } 596: else if (def_state == IN_IFDEF) { 597: fputs(else_defined, ofp); 598: def_state = IN_ELSE; 599: } 600: fputs(pfetch(old), ofp); 601: } 602: last_frozen_line++; 603: old++; 604: } 605: else if (new > pat_end) 606: break; 607: else if (pch_char(new) == '+') { 608: copy_till(where + old - 1); 609: if (R_do_defines) { 610: if (def_state == IN_IFNDEF) { 611: fputs(else_defined, ofp); 612: def_state = IN_ELSE; 613: } 614: else if (def_state == OUTSIDE) { 615: fputs(if_defined, ofp); 616: def_state = IN_IFDEF; 617: } 618: } 619: fputs(pfetch(new), ofp); 620: new++; 621: } 622: else { 623: if (pch_char(new) != pch_char(old)) { 624: say3("Out-of-sync patch, lines %ld,%ld--mangled text or line numbers, maybe?\n", 625: pch_hunk_beg() + old, 626: pch_hunk_beg() + new); 627: #ifdef DEBUGGING 628: say3("oldchar = '%c', newchar = '%c'\n", 629: pch_char(old), pch_char(new)); 630: #endif 631: my_exit(1); 632: } 633: if (pch_char(new) == '!') { 634: copy_till(where + old - 1); 635: if (R_do_defines) { 636: fputs(not_defined, ofp); 637: def_state = IN_IFNDEF; 638: } 639: while (pch_char(old) == '!') { 640: if (R_do_defines) { 641: fputs(pfetch(old), ofp); 642: } 643: last_frozen_line++; 644: old++; 645: } 646: if (R_do_defines) { 647: fputs(else_defined, ofp); 648: def_state = IN_ELSE; 649: } 650: while (pch_char(new) == '!') { 651: fputs(pfetch(new), ofp); 652: new++; 653: } 654: if (R_do_defines) { 655: fputs(end_defined, ofp); 656: def_state = OUTSIDE; 657: } 658: } 659: else { 660: assert(pch_char(new) == ' '); 661: old++; 662: new++; 663: } 664: } 665: } 666: if (new <= pat_end && pch_char(new) == '+') { 667: copy_till(where + old - 1); 668: if (R_do_defines) { 669: if (def_state == OUTSIDE) { 670: fputs(if_defined, ofp); 671: def_state = IN_IFDEF; 672: } 673: else if (def_state == IN_IFNDEF) { 674: fputs(else_defined, ofp); 675: def_state = IN_ELSE; 676: } 677: } 678: while (new <= pat_end && pch_char(new) == '+') { 679: fputs(pfetch(new), ofp); 680: new++; 681: } 682: } 683: if (R_do_defines && def_state != OUTSIDE) { 684: fputs(end_defined, ofp); 685: } 686: } 687: 688: /* Open the new file. */ 689: 690: void 691: init_output(name) 692: char *name; 693: { 694: ofp = fopen(name, "w"); 695: if (ofp == Nullfp) 696: fatal2("patch: can't create %s.\n", name); 697: } 698: 699: /* Open a file to put hunks we can't locate. */ 700: 701: void 702: init_reject(name) 703: char *name; 704: { 705: rejfp = fopen(name, "w"); 706: if (rejfp == Nullfp) 707: fatal2("patch: can't create %s.\n", name); 708: } 709: 710: /* Copy input file to output, up to wherever hunk is to be applied. */ 711: 712: void 713: copy_till(lastline) 714: Reg1 LINENUM lastline; 715: { 716: Reg2 LINENUM R_last_frozen_line = last_frozen_line; 717: 718: if (R_last_frozen_line > lastline) 719: say1("patch: misordered hunks! output will be garbled.\n"); 720: while (R_last_frozen_line < lastline) { 721: dump_line(++R_last_frozen_line); 722: } 723: last_frozen_line = R_last_frozen_line; 724: } 725: 726: /* Finish copying the input file to the output file. */ 727: 728: void 729: spew_output() 730: { 731: #ifdef DEBUGGING 732: if (debug & 256) 733: say3("il=%ld lfl=%ld\n",input_lines,last_frozen_line); 734: #endif 735: if (input_lines) 736: copy_till(input_lines); /* dump remainder of file */ 737: Fclose(ofp); 738: ofp = Nullfp; 739: } 740: 741: /* Copy one line from input to output. */ 742: 743: void 744: dump_line(line) 745: LINENUM line; 746: { 747: Reg1 char *s; 748: Reg2 char R_newline = '\n'; 749: 750: /* Note: string is not null terminated. */ 751: for (s=ifetch(line, 0); putc(*s, ofp) != R_newline; s++) ; 752: } 753: 754: /* Does the patch pattern match at line base+offset? */ 755: 756: bool 757: patch_match(base, offset, fuzz) 758: LINENUM base; 759: LINENUM offset; 760: LINENUM fuzz; 761: { 762: Reg1 LINENUM pline = 1 + fuzz; 763: Reg2 LINENUM iline; 764: Reg3 LINENUM pat_lines = pch_ptrn_lines() - fuzz; 765: 766: for (iline=base+offset+fuzz; pline <= pat_lines; pline++,iline++) { 767: if (canonicalize) { 768: if (!similar(ifetch(iline, (offset >= 0)), 769: pfetch(pline), 770: pch_line_len(pline) )) 771: return FALSE; 772: } 773: else if (strnNE(ifetch(iline, (offset >= 0)), 774: pfetch(pline), 775: pch_line_len(pline) )) 776: return FALSE; 777: } 778: return TRUE; 779: } 780: 781: /* Do two lines match with canonicalized white space? */ 782: 783: bool 784: similar(a,b,len) 785: Reg1 char *a; 786: Reg2 char *b; 787: Reg3 int len; 788: { 789: while (len) { 790: if (isspace(*b)) { /* whitespace (or \n) to match? */ 791: if (!isspace(*a)) /* no corresponding whitespace? */ 792: return FALSE; 793: while (len && isspace(*b) && *b != '\n') 794: b++,len--; /* skip pattern whitespace */ 795: while (isspace(*a) && *a != '\n') 796: a++; /* skip target whitespace */ 797: if (*a == '\n' || *b == '\n') 798: return (*a == *b); /* should end in sync */ 799: } 800: else if (*a++ != *b++) /* match non-whitespace chars */ 801: return FALSE; 802: else 803: len--; /* probably not necessary */ 804: } 805: return TRUE; /* actually, this is not reached */ 806: /* since there is always a \n */ 807: } 808: 809: /* Exit with cleanup. */ 810: 811: void 812: my_exit(status) 813: int status; 814: { 815: Unlink(TMPINNAME); 816: if (!toutkeep) { 817: Unlink(TMPOUTNAME); 818: } 819: if (!trejkeep) { 820: Unlink(TMPREJNAME); 821: } 822: Unlink(TMPPATNAME); 823: exit(status); 824: }