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