patch.c revision 1.1.1.1 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: /tank/opengrok/rsync2/NetBSD/src/usr.bin/patch/patch.c,v 1.1.1.1 1997/01/09 14:47:39 tls 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 1.1.1.1 1997/01/09 14:47:39 tls
17 * Import from 4.4BSD-Lite2
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 i;
128
129 setbuf(stderr, serrbuf);
130 for (i = 0; i<MAXFILEC; i++)
131 filearg[i] = Nullch;
132 Mktemp(TMPOUTNAME);
133 Mktemp(TMPINNAME);
134 Mktemp(TMPREJNAME);
135 Mktemp(TMPPATNAME);
136
137 /* parse switches */
138 Argc = argc;
139 Argv = argv;
140 get_some_switches();
141
142 /* make sure we clean up /tmp in case of disaster */
143 set_signals();
144
145 for (
146 open_patch_file(filearg[1]);
147 there_is_another_patch();
148 reinitialize_almost_everything()
149 ) { /* for each patch in patch file */
150
151 if (outname == Nullch)
152 outname = savestr(filearg[0]);
153
154 /* initialize the patched file */
155 if (!skip_rest_of_patch)
156 init_output(TMPOUTNAME);
157
158 /* for ed script just up and do it and exit */
159 if (diff_type == ED_DIFF) {
160 do_ed_script();
161 continue;
162 }
163
164 /* initialize reject file */
165 init_reject(TMPREJNAME);
166
167 /* find out where all the lines are */
168 if (!skip_rest_of_patch)
169 scan_input(filearg[0]);
170
171 /* from here on, open no standard i/o files, because malloc */
172 /* might misfire and we can't catch it easily */
173
174 /* apply each hunk of patch */
175 hunk = 0;
176 failed = 0;
177 out_of_mem = FALSE;
178 while (another_hunk()) {
179 hunk++;
180 fuzz = Nulline;
181 mymaxfuzz = pch_context();
182 if (maxfuzz < mymaxfuzz)
183 mymaxfuzz = maxfuzz;
184 if (!skip_rest_of_patch) {
185 do {
186 where = locate_hunk(fuzz);
187 if (hunk == 1 && where == Nulline && !force) {
188 /* dwim for reversed patch? */
189 if (!pch_swap()) {
190 if (fuzz == Nulline)
191 say1("\
192 Not enough memory to try swapped hunk! Assuming unswapped.\n");
193 continue;
194 }
195 reverse = !reverse;
196 where = locate_hunk(fuzz); /* try again */
197 if (where == Nulline) { /* didn't find it swapped */
198 if (!pch_swap()) /* put it back to normal */
199 fatal1("Lost hunk on alloc error!\n");
200 reverse = !reverse;
201 }
202 else if (noreverse) {
203 if (!pch_swap()) /* put it back to normal */
204 fatal1("Lost hunk on alloc error!\n");
205 reverse = !reverse;
206 say1("\
207 Ignoring previously applied (or reversed) patch.\n");
208 skip_rest_of_patch = TRUE;
209 }
210 else {
211 ask3("\
212 %seversed (or previously applied) patch detected! %s -R? [y] ",
213 reverse ? "R" : "Unr",
214 reverse ? "Assume" : "Ignore");
215 if (*buf == 'n') {
216 ask1("Apply anyway? [n] ");
217 if (*buf != 'y')
218 skip_rest_of_patch = TRUE;
219 where = Nulline;
220 reverse = !reverse;
221 if (!pch_swap()) /* put it back to normal */
222 fatal1("Lost hunk on alloc error!\n");
223 }
224 }
225 }
226 } while (!skip_rest_of_patch && where == Nulline &&
227 ++fuzz <= mymaxfuzz);
228
229 if (skip_rest_of_patch) { /* just got decided */
230 Fclose(ofp);
231 ofp = Nullfp;
232 }
233 }
234
235 newwhere = pch_newfirst() + last_offset;
236 if (skip_rest_of_patch) {
237 abort_hunk();
238 failed++;
239 if (verbose)
240 say3("Hunk #%d ignored at %ld.\n", hunk, newwhere);
241 }
242 else if (where == Nulline) {
243 abort_hunk();
244 failed++;
245 if (verbose)
246 say3("Hunk #%d failed at %ld.\n", hunk, newwhere);
247 }
248 else {
249 apply_hunk(where);
250 if (verbose) {
251 say3("Hunk #%d succeeded at %ld", hunk, newwhere);
252 if (fuzz)
253 say2(" with fuzz %ld", fuzz);
254 if (last_offset)
255 say3(" (offset %ld line%s)",
256 last_offset, last_offset==1L?"":"s");
257 say1(".\n");
258 }
259 }
260 }
261
262 if (out_of_mem && using_plan_a) {
263 Argc = Argc_last;
264 Argv = Argv_last;
265 say1("\n\nRan out of memory using Plan A--trying again...\n\n");
266 continue;
267 }
268
269 assert(hunk);
270
271 /* finish spewing out the new file */
272 if (!skip_rest_of_patch)
273 spew_output();
274
275 /* and put the output where desired */
276 ignore_signals();
277 if (!skip_rest_of_patch) {
278 if (move_file(TMPOUTNAME, outname) < 0) {
279 toutkeep = TRUE;
280 chmod(TMPOUTNAME, filemode);
281 }
282 else
283 chmod(outname, filemode);
284 }
285 Fclose(rejfp);
286 rejfp = Nullfp;
287 if (failed) {
288 if (!*rejname) {
289 Strcpy(rejname, outname);
290 Strcat(rejname, ".rej");
291 }
292 if (skip_rest_of_patch) {
293 say4("%d out of %d hunks ignored--saving rejects to %s\n",
294 failed, hunk, rejname);
295 }
296 else {
297 say4("%d out of %d hunks failed--saving rejects to %s\n",
298 failed, hunk, rejname);
299 }
300 if (move_file(TMPREJNAME, rejname) < 0)
301 trejkeep = TRUE;
302 }
303 set_signals();
304 }
305 my_exit(0);
306 }
307
308 /* Prepare to find the next patch to do in the patch file. */
309
310 void
311 reinitialize_almost_everything()
312 {
313 re_patch();
314 re_input();
315
316 input_lines = 0;
317 last_frozen_line = 0;
318
319 filec = 0;
320 if (filearg[0] != Nullch && !out_of_mem) {
321 free(filearg[0]);
322 filearg[0] = Nullch;
323 }
324
325 if (outname != Nullch) {
326 free(outname);
327 outname = Nullch;
328 }
329
330 last_offset = 0;
331
332 diff_type = 0;
333
334 if (revision != Nullch) {
335 free(revision);
336 revision = Nullch;
337 }
338
339 reverse = FALSE;
340 skip_rest_of_patch = FALSE;
341
342 get_some_switches();
343
344 if (filec >= 2)
345 fatal1("You may not change to a different patch file.\n");
346 }
347
348 /* Process switches and filenames up to next '+' or end of list. */
349
350 void
351 get_some_switches()
352 {
353 Reg1 char *s;
354
355 rejname[0] = '\0';
356 Argc_last = Argc;
357 Argv_last = Argv;
358 if (!Argc)
359 return;
360 for (Argc--,Argv++; Argc; Argc--,Argv++) {
361 s = Argv[0];
362 if (strEQ(s, "+")) {
363 return; /* + will be skipped by for loop */
364 }
365 if (*s != '-' || !s[1]) {
366 if (filec == MAXFILEC)
367 fatal1("Too many file arguments.\n");
368 filearg[filec++] = savestr(s);
369 }
370 else {
371 switch (*++s) {
372 case 'b':
373 origext = savestr(Argv[1]);
374 Argc--,Argv++;
375 break;
376 case 'c':
377 diff_type = CONTEXT_DIFF;
378 break;
379 case 'd':
380 if (!*++s) {
381 Argc--,Argv++;
382 s = Argv[0];
383 }
384 if (chdir(s) < 0)
385 fatal2("Can't cd to %s.\n", s);
386 break;
387 case 'D':
388 do_defines = TRUE;
389 if (!*++s) {
390 Argc--,Argv++;
391 s = Argv[0];
392 }
393 Sprintf(if_defined, "#ifdef %s\n", s);
394 Sprintf(not_defined, "#ifndef %s\n", s);
395 Sprintf(end_defined, "#endif /* %s */\n", s);
396 break;
397 case 'e':
398 diff_type = ED_DIFF;
399 break;
400 case 'f':
401 force = TRUE;
402 break;
403 case 'F':
404 if (*++s == '=')
405 s++;
406 maxfuzz = atoi(s);
407 break;
408 case 'l':
409 canonicalize = TRUE;
410 break;
411 case 'n':
412 diff_type = NORMAL_DIFF;
413 break;
414 case 'N':
415 noreverse = TRUE;
416 break;
417 case 'o':
418 outname = savestr(Argv[1]);
419 Argc--,Argv++;
420 break;
421 case 'p':
422 if (*++s == '=')
423 s++;
424 strippath = atoi(s);
425 break;
426 case 'r':
427 Strcpy(rejname, Argv[1]);
428 Argc--,Argv++;
429 break;
430 case 'R':
431 reverse = TRUE;
432 break;
433 case 's':
434 verbose = FALSE;
435 break;
436 case 'S':
437 skip_rest_of_patch = TRUE;
438 break;
439 case 'v':
440 version();
441 break;
442 #ifdef DEBUGGING
443 case 'x':
444 debug = atoi(s+1);
445 break;
446 #endif
447 default:
448 fatal2("Unrecognized switch: %s\n", Argv[0]);
449 }
450 }
451 }
452 }
453
454 /* Attempt to find the right place to apply this hunk of patch. */
455
456 LINENUM
457 locate_hunk(fuzz)
458 LINENUM fuzz;
459 {
460 Reg1 LINENUM first_guess = pch_first() + last_offset;
461 Reg2 LINENUM offset;
462 LINENUM pat_lines = pch_ptrn_lines();
463 Reg3 LINENUM max_pos_offset = input_lines - first_guess
464 - pat_lines + 1;
465 Reg4 LINENUM max_neg_offset = first_guess - last_frozen_line - 1
466 + pch_context();
467
468 if (!pat_lines) /* null range matches always */
469 return first_guess;
470 if (max_neg_offset >= first_guess) /* do not try lines < 0 */
471 max_neg_offset = first_guess - 1;
472 if (first_guess <= input_lines && patch_match(first_guess, Nulline, fuzz))
473 return first_guess;
474 for (offset = 1; ; offset++) {
475 Reg5 bool check_after = (offset <= max_pos_offset);
476 Reg6 bool check_before = (offset <= max_neg_offset);
477
478 if (check_after && patch_match(first_guess, offset, fuzz)) {
479 #ifdef DEBUGGING
480 if (debug & 1)
481 say3("Offset changing from %ld to %ld\n", last_offset, offset);
482 #endif
483 last_offset = offset;
484 return first_guess+offset;
485 }
486 else if (check_before && patch_match(first_guess, -offset, fuzz)) {
487 #ifdef DEBUGGING
488 if (debug & 1)
489 say3("Offset changing from %ld to %ld\n", last_offset, -offset);
490 #endif
491 last_offset = -offset;
492 return first_guess-offset;
493 }
494 else if (!check_before && !check_after)
495 return Nulline;
496 }
497 }
498
499 /* We did not find the pattern, dump out the hunk so they can handle it. */
500
501 void
502 abort_hunk()
503 {
504 Reg1 LINENUM i;
505 Reg2 LINENUM pat_end = pch_end();
506 /* add in last_offset to guess the same as the previous successful hunk */
507 LINENUM oldfirst = pch_first() + last_offset;
508 LINENUM newfirst = pch_newfirst() + last_offset;
509 LINENUM oldlast = oldfirst + pch_ptrn_lines() - 1;
510 LINENUM newlast = newfirst + pch_repl_lines() - 1;
511 char *stars = (diff_type == NEW_CONTEXT_DIFF ? " ****" : "");
512 char *minuses = (diff_type == NEW_CONTEXT_DIFF ? " ----" : " -----");
513
514 fprintf(rejfp, "***************\n");
515 for (i=0; i<=pat_end; i++) {
516 switch (pch_char(i)) {
517 case '*':
518 if (oldlast < oldfirst)
519 fprintf(rejfp, "*** 0%s\n", stars);
520 else if (oldlast == oldfirst)
521 fprintf(rejfp, "*** %ld%s\n", oldfirst, stars);
522 else
523 fprintf(rejfp, "*** %ld,%ld%s\n", oldfirst, oldlast, stars);
524 break;
525 case '=':
526 if (newlast < newfirst)
527 fprintf(rejfp, "--- 0%s\n", minuses);
528 else if (newlast == newfirst)
529 fprintf(rejfp, "--- %ld%s\n", newfirst, minuses);
530 else
531 fprintf(rejfp, "--- %ld,%ld%s\n", newfirst, newlast, minuses);
532 break;
533 case '\n':
534 fprintf(rejfp, "%s", pfetch(i));
535 break;
536 case ' ': case '-': case '+': case '!':
537 fprintf(rejfp, "%c %s", pch_char(i), pfetch(i));
538 break;
539 default:
540 say1("Fatal internal error in abort_hunk().\n");
541 abort();
542 }
543 }
544 }
545
546 /* We found where to apply it (we hope), so do it. */
547
548 void
549 apply_hunk(where)
550 LINENUM where;
551 {
552 Reg1 LINENUM old = 1;
553 Reg2 LINENUM lastline = pch_ptrn_lines();
554 Reg3 LINENUM new = lastline+1;
555 #define OUTSIDE 0
556 #define IN_IFNDEF 1
557 #define IN_IFDEF 2
558 #define IN_ELSE 3
559 Reg4 int def_state = OUTSIDE;
560 Reg5 bool R_do_defines = do_defines;
561 Reg6 LINENUM pat_end = pch_end();
562
563 where--;
564 while (pch_char(new) == '=' || pch_char(new) == '\n')
565 new++;
566
567 while (old <= lastline) {
568 if (pch_char(old) == '-') {
569 copy_till(where + old - 1);
570 if (R_do_defines) {
571 if (def_state == OUTSIDE) {
572 fputs(not_defined, ofp);
573 def_state = IN_IFNDEF;
574 }
575 else if (def_state == IN_IFDEF) {
576 fputs(else_defined, ofp);
577 def_state = IN_ELSE;
578 }
579 fputs(pfetch(old), ofp);
580 }
581 last_frozen_line++;
582 old++;
583 }
584 else if (new > pat_end)
585 break;
586 else if (pch_char(new) == '+') {
587 copy_till(where + old - 1);
588 if (R_do_defines) {
589 if (def_state == IN_IFNDEF) {
590 fputs(else_defined, ofp);
591 def_state = IN_ELSE;
592 }
593 else if (def_state == OUTSIDE) {
594 fputs(if_defined, ofp);
595 def_state = IN_IFDEF;
596 }
597 }
598 fputs(pfetch(new), ofp);
599 new++;
600 }
601 else {
602 if (pch_char(new) != pch_char(old)) {
603 say3("Out-of-sync patch, lines %ld,%ld--mangled text or line numbers, maybe?\n",
604 pch_hunk_beg() + old,
605 pch_hunk_beg() + new);
606 #ifdef DEBUGGING
607 say3("oldchar = '%c', newchar = '%c'\n",
608 pch_char(old), pch_char(new));
609 #endif
610 my_exit(1);
611 }
612 if (pch_char(new) == '!') {
613 copy_till(where + old - 1);
614 if (R_do_defines) {
615 fputs(not_defined, ofp);
616 def_state = IN_IFNDEF;
617 }
618 while (pch_char(old) == '!') {
619 if (R_do_defines) {
620 fputs(pfetch(old), ofp);
621 }
622 last_frozen_line++;
623 old++;
624 }
625 if (R_do_defines) {
626 fputs(else_defined, ofp);
627 def_state = IN_ELSE;
628 }
629 while (pch_char(new) == '!') {
630 fputs(pfetch(new), ofp);
631 new++;
632 }
633 if (R_do_defines) {
634 fputs(end_defined, ofp);
635 def_state = OUTSIDE;
636 }
637 }
638 else {
639 assert(pch_char(new) == ' ');
640 old++;
641 new++;
642 }
643 }
644 }
645 if (new <= pat_end && pch_char(new) == '+') {
646 copy_till(where + old - 1);
647 if (R_do_defines) {
648 if (def_state == OUTSIDE) {
649 fputs(if_defined, ofp);
650 def_state = IN_IFDEF;
651 }
652 else if (def_state == IN_IFNDEF) {
653 fputs(else_defined, ofp);
654 def_state = IN_ELSE;
655 }
656 }
657 while (new <= pat_end && pch_char(new) == '+') {
658 fputs(pfetch(new), ofp);
659 new++;
660 }
661 }
662 if (R_do_defines && def_state != OUTSIDE) {
663 fputs(end_defined, ofp);
664 }
665 }
666
667 /* Open the new file. */
668
669 void
670 init_output(name)
671 char *name;
672 {
673 ofp = fopen(name, "w");
674 if (ofp == Nullfp)
675 fatal2("patch: can't create %s.\n", name);
676 }
677
678 /* Open a file to put hunks we can't locate. */
679
680 void
681 init_reject(name)
682 char *name;
683 {
684 rejfp = fopen(name, "w");
685 if (rejfp == Nullfp)
686 fatal2("patch: can't create %s.\n", name);
687 }
688
689 /* Copy input file to output, up to wherever hunk is to be applied. */
690
691 void
692 copy_till(lastline)
693 Reg1 LINENUM lastline;
694 {
695 Reg2 LINENUM R_last_frozen_line = last_frozen_line;
696
697 if (R_last_frozen_line > lastline)
698 say1("patch: misordered hunks! output will be garbled.\n");
699 while (R_last_frozen_line < lastline) {
700 dump_line(++R_last_frozen_line);
701 }
702 last_frozen_line = R_last_frozen_line;
703 }
704
705 /* Finish copying the input file to the output file. */
706
707 void
708 spew_output()
709 {
710 #ifdef DEBUGGING
711 if (debug & 256)
712 say3("il=%ld lfl=%ld\n",input_lines,last_frozen_line);
713 #endif
714 if (input_lines)
715 copy_till(input_lines); /* dump remainder of file */
716 Fclose(ofp);
717 ofp = Nullfp;
718 }
719
720 /* Copy one line from input to output. */
721
722 void
723 dump_line(line)
724 LINENUM line;
725 {
726 Reg1 char *s;
727 Reg2 char R_newline = '\n';
728
729 /* Note: string is not null terminated. */
730 for (s=ifetch(line, 0); putc(*s, ofp) != R_newline; s++) ;
731 }
732
733 /* Does the patch pattern match at line base+offset? */
734
735 bool
736 patch_match(base, offset, fuzz)
737 LINENUM base;
738 LINENUM offset;
739 LINENUM fuzz;
740 {
741 Reg1 LINENUM pline = 1 + fuzz;
742 Reg2 LINENUM iline;
743 Reg3 LINENUM pat_lines = pch_ptrn_lines() - fuzz;
744
745 for (iline=base+offset+fuzz; pline <= pat_lines; pline++,iline++) {
746 if (canonicalize) {
747 if (!similar(ifetch(iline, (offset >= 0)),
748 pfetch(pline),
749 pch_line_len(pline) ))
750 return FALSE;
751 }
752 else if (strnNE(ifetch(iline, (offset >= 0)),
753 pfetch(pline),
754 pch_line_len(pline) ))
755 return FALSE;
756 }
757 return TRUE;
758 }
759
760 /* Do two lines match with canonicalized white space? */
761
762 bool
763 similar(a,b,len)
764 Reg1 char *a;
765 Reg2 char *b;
766 Reg3 int len;
767 {
768 while (len) {
769 if (isspace(*b)) { /* whitespace (or \n) to match? */
770 if (!isspace(*a)) /* no corresponding whitespace? */
771 return FALSE;
772 while (len && isspace(*b) && *b != '\n')
773 b++,len--; /* skip pattern whitespace */
774 while (isspace(*a) && *a != '\n')
775 a++; /* skip target whitespace */
776 if (*a == '\n' || *b == '\n')
777 return (*a == *b); /* should end in sync */
778 }
779 else if (*a++ != *b++) /* match non-whitespace chars */
780 return FALSE;
781 else
782 len--; /* probably not necessary */
783 }
784 return TRUE; /* actually, this is not reached */
785 /* since there is always a \n */
786 }
787
788 /* Exit with cleanup. */
789
790 void
791 my_exit(status)
792 int status;
793 {
794 Unlink(TMPINNAME);
795 if (!toutkeep) {
796 Unlink(TMPOUTNAME);
797 }
798 if (!trejkeep) {
799 Unlink(TMPREJNAME);
800 }
801 Unlink(TMPPATNAME);
802 exit(status);
803 }
804