install correct aliases file
[unix-history] / usr / src / usr.bin / patch / patch.c
CommitLineData
9c13eddc 1#ifndef lint
6f17a61a 2static char sccsid[] = "@(#)patch.c 5.9 (Berkeley) %G%";
9c13eddc
KM
3#endif not lint
4
6f17a61a
KB
5char rcsid[] =
6 "$Header: patch.c,v 2.0.1.4 87/02/16 14:00:04 lwall Exp $";
7
9c13eddc
KM
8/* patch - a program to apply diffs to original files
9 *
6f17a61a 10 * Copyright 1986, Larry Wall
9c13eddc
KM
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 $
6f17a61a
KB
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 *
56b0c556
KM
42 * 85/08/15 van%ucbmonet@berkeley
43 * Changes for 4.3bsd diff -c.
44 *
9c13eddc
KM
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
6f17a61a
KB
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"
9c13eddc
KM
94
95/* procedures */
96
6f17a61a
KB
97void reinitialize_almost_everything();
98void get_some_switches();
9c13eddc 99LINENUM locate_hunk();
6f17a61a
KB
100void abort_hunk();
101void apply_hunk();
102void init_output();
103void init_reject();
104void copy_till();
105void spew_output();
106void dump_line();
9c13eddc
KM
107bool patch_match();
108bool similar();
6f17a61a
KB
109void re_input();
110void my_exit();
9c13eddc 111
6f17a61a 112/* Apply a set of diffs as appropriate. */
9c13eddc
KM
113
114main(argc,argv)
115int argc;
116char **argv;
117{
118 LINENUM where;
6f17a61a
KB
119 LINENUM newwhere;
120 LINENUM fuzz;
121 LINENUM mymaxfuzz;
9c13eddc
KM
122 int hunk = 0;
123 int failed = 0;
124 int i;
125
6f17a61a 126 setbuf(stderr, serrbuf);
9c13eddc
KM
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 */
6f17a61a
KB
152 if (!skip_rest_of_patch)
153 init_output(TMPOUTNAME);
9c13eddc
KM
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 */
6f17a61a
KB
165 if (!skip_rest_of_patch)
166 scan_input(filearg[0]);
9c13eddc
KM
167
168 /* from here on, open no standard i/o files, because malloc */
6f17a61a 169 /* might misfire and we can't catch it easily */
9c13eddc
KM
170
171 /* apply each hunk of patch */
172 hunk = 0;
173 failed = 0;
6f17a61a 174 out_of_mem = FALSE;
9c13eddc
KM
175 while (another_hunk()) {
176 hunk++;
6f17a61a
KB
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("\
189Not 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("\
204Ignoring 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;
9c13eddc
KM
229 }
230 }
6f17a61a
KB
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) {
9c13eddc
KM
240 abort_hunk();
241 failed++;
242 if (verbose)
6f17a61a 243 say3("Hunk #%d failed at %ld.\n", hunk, newwhere);
9c13eddc
KM
244 }
245 else {
246 apply_hunk(where);
6f17a61a
KB
247 if (verbose) {
248 say3("Hunk #%d succeeded at %ld", hunk, newwhere);
249 if (fuzz)
250 say2(" with fuzz %ld", fuzz);
9c13eddc 251 if (last_offset)
6f17a61a
KB
252 say3(" (offset %ld line%s)",
253 last_offset, last_offset==1L?"":"s");
254 say1(".\n");
255 }
9c13eddc
KM
256 }
257 }
6f17a61a
KB
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 }
9c13eddc
KM
265
266 assert(hunk);
267
268 /* finish spewing out the new file */
6f17a61a
KB
269 if (!skip_rest_of_patch)
270 spew_output();
9c13eddc
KM
271
272 /* and put the output where desired */
273 ignore_signals();
6f17a61a
KB
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 }
9c13eddc
KM
282 Fclose(rejfp);
283 rejfp = Nullfp;
284 if (failed) {
285 if (!*rejname) {
286 Strcpy(rejname, outname);
287 Strcat(rejname, ".rej");
288 }
6f17a61a
KB
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;
9c13eddc
KM
299 }
300 set_signals();
301 }
302 my_exit(0);
303}
304
6f17a61a
KB
305/* Prepare to find the next patch to do in the patch file. */
306
307void
9c13eddc
KM
308reinitialize_almost_everything()
309{
310 re_patch();
311 re_input();
312
313 input_lines = 0;
314 last_frozen_line = 0;
315
316 filec = 0;
6f17a61a 317 if (filearg[0] != Nullch && !out_of_mem) {
9c13eddc
KM
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;
6f17a61a 337 skip_rest_of_patch = FALSE;
9c13eddc
KM
338
339 get_some_switches();
340
341 if (filec >= 2)
6f17a61a 342 fatal1("You may not change to a different patch file.\n");
9c13eddc
KM
343}
344
6f17a61a
KB
345/* Process switches and filenames up to next '+' or end of list. */
346
347void
9c13eddc
KM
348get_some_switches()
349{
6f17a61a 350 Reg1 char *s;
9c13eddc
KM
351
352 rejname[0] = '\0';
6f17a61a
KB
353 Argc_last = Argc;
354 Argv_last = Argv;
9c13eddc
KM
355 if (!Argc)
356 return;
357 for (Argc--,Argv++; Argc; Argc--,Argv++) {
358 s = Argv[0];
6f17a61a 359 if (strEQ(s, "+")) {
9c13eddc
KM
360 return; /* + will be skipped by for loop */
361 }
362 if (*s != '-' || !s[1]) {
363 if (filec == MAXFILEC)
6f17a61a 364 fatal1("Too many file arguments.\n");
9c13eddc
KM
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':
6f17a61a
KB
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);
9c13eddc
KM
383 break;
384 case 'D':
6f17a61a
KB
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);
9c13eddc
KM
393 break;
394 case 'e':
395 diff_type = ED_DIFF;
396 break;
6f17a61a
KB
397 case 'f':
398 force = TRUE;
399 break;
400 case 'F':
401 if (*++s == '=')
402 s++;
403 maxfuzz = atoi(s);
404 break;
9c13eddc
KM
405 case 'l':
406 canonicalize = TRUE;
407 break;
408 case 'n':
409 diff_type = NORMAL_DIFF;
410 break;
6f17a61a
KB
411 case 'N':
412 noreverse = TRUE;
413 break;
9c13eddc
KM
414 case 'o':
415 outname = savestr(Argv[1]);
416 Argc--,Argv++;
417 break;
418 case 'p':
6f17a61a
KB
419 if (*++s == '=')
420 s++;
421 strippath = atoi(s);
9c13eddc
KM
422 break;
423 case 'r':
6f17a61a 424 Strcpy(rejname, Argv[1]);
9c13eddc
KM
425 Argc--,Argv++;
426 break;
427 case 'R':
428 reverse = TRUE;
429 break;
430 case 's':
431 verbose = FALSE;
432 break;
6f17a61a
KB
433 case 'S':
434 skip_rest_of_patch = TRUE;
435 break;
436 case 'v':
437 version();
438 break;
9c13eddc
KM
439#ifdef DEBUGGING
440 case 'x':
441 debug = atoi(s+1);
442 break;
443#endif
444 default:
6f17a61a 445 fatal2("Unrecognized switch: %s\n", Argv[0]);
9c13eddc
KM
446 }
447 }
448 }
449}
450
6f17a61a
KB
451/* Attempt to find the right place to apply this hunk of patch. */
452
9c13eddc 453LINENUM
6f17a61a
KB
454locate_hunk(fuzz)
455LINENUM fuzz;
9c13eddc 456{
6f17a61a
KB
457 Reg1 LINENUM first_guess = pch_first() + last_offset;
458 Reg2 LINENUM offset;
9c13eddc 459 LINENUM pat_lines = pch_ptrn_lines();
6f17a61a 460 Reg3 LINENUM max_pos_offset = input_lines - first_guess
9c13eddc 461 - pat_lines + 1;
6f17a61a
KB
462 Reg4 LINENUM max_neg_offset = first_guess - last_frozen_line - 1
463 + pch_context();
9c13eddc
KM
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;
6f17a61a 469 if (first_guess <= input_lines && patch_match(first_guess, Nulline, fuzz))
9c13eddc
KM
470 return first_guess;
471 for (offset = 1; ; offset++) {
6f17a61a
KB
472 Reg5 bool check_after = (offset <= max_pos_offset);
473 Reg6 bool check_before = (offset <= max_neg_offset);
9c13eddc 474
6f17a61a 475 if (check_after && patch_match(first_guess, offset, fuzz)) {
9c13eddc
KM
476#ifdef DEBUGGING
477 if (debug & 1)
6f17a61a 478 say3("Offset changing from %ld to %ld\n", last_offset, offset);
9c13eddc
KM
479#endif
480 last_offset = offset;
481 return first_guess+offset;
482 }
6f17a61a 483 else if (check_before && patch_match(first_guess, -offset, fuzz)) {
9c13eddc
KM
484#ifdef DEBUGGING
485 if (debug & 1)
6f17a61a 486 say3("Offset changing from %ld to %ld\n", last_offset, -offset);
9c13eddc
KM
487#endif
488 last_offset = -offset;
489 return first_guess-offset;
490 }
491 else if (!check_before && !check_after)
6f17a61a 492 return Nulline;
9c13eddc
KM
493 }
494}
495
6f17a61a 496/* We did not find the pattern, dump out the hunk so they can handle it. */
9c13eddc 497
6f17a61a 498void
9c13eddc
KM
499abort_hunk()
500{
6f17a61a
KB
501 Reg1 LINENUM i;
502 Reg2 LINENUM pat_end = pch_end();
9c13eddc 503 /* add in last_offset to guess the same as the previous successful hunk */
6f17a61a
KB
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");
9c13eddc
KM
512 for (i=0; i<=pat_end; i++) {
513 switch (pch_char(i)) {
514 case '*':
6f17a61a
KB
515 if (oldlast < oldfirst)
516 fprintf(rejfp, "*** 0%s\n", stars);
517 else if (oldlast == oldfirst)
518 fprintf(rejfp, "*** %ld%s\n", oldfirst, stars);
756fee39 519 else
6f17a61a 520 fprintf(rejfp, "*** %ld,%ld%s\n", oldfirst, oldlast, stars);
9c13eddc
KM
521 break;
522 case '=':
6f17a61a
KB
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);
9c13eddc
KM
529 break;
530 case '\n':
6f17a61a 531 fprintf(rejfp, "%s", pfetch(i));
9c13eddc
KM
532 break;
533 case ' ': case '-': case '+': case '!':
6f17a61a 534 fprintf(rejfp, "%c %s", pch_char(i), pfetch(i));
9c13eddc
KM
535 break;
536 default:
6f17a61a 537 say1("Fatal internal error in abort_hunk().\n");
9c13eddc
KM
538 abort();
539 }
540 }
541}
542
6f17a61a 543/* We found where to apply it (we hope), so do it. */
9c13eddc 544
6f17a61a 545void
9c13eddc
KM
546apply_hunk(where)
547LINENUM where;
548{
6f17a61a
KB
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();
9c13eddc
KM
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);
6f17a61a
KB
567 if (R_do_defines) {
568 if (def_state == OUTSIDE) {
9c13eddc 569 fputs(not_defined, ofp);
6f17a61a
KB
570 def_state = IN_IFNDEF;
571 }
572 else if (def_state == IN_IFDEF) {
9c13eddc 573 fputs(else_defined, ofp);
6f17a61a 574 def_state = IN_ELSE;
9c13eddc
KM
575 }
576 fputs(pfetch(old), ofp);
577 }
578 last_frozen_line++;
579 old++;
580 }
6f17a61a
KB
581 else if (new > pat_end)
582 break;
9c13eddc
KM
583 else if (pch_char(new) == '+') {
584 copy_till(where + old - 1);
6f17a61a
KB
585 if (R_do_defines) {
586 if (def_state == IN_IFNDEF) {
9c13eddc 587 fputs(else_defined, ofp);
6f17a61a
KB
588 def_state = IN_ELSE;
589 }
590 else if (def_state == OUTSIDE) {
9c13eddc 591 fputs(if_defined, ofp);
6f17a61a 592 def_state = IN_IFDEF;
9c13eddc
KM
593 }
594 }
6f17a61a 595 fputs(pfetch(new), ofp);
9c13eddc
KM
596 new++;
597 }
598 else {
599 if (pch_char(new) != pch_char(old)) {
6f17a61a
KB
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);
9c13eddc 603#ifdef DEBUGGING
6f17a61a 604 say3("oldchar = '%c', newchar = '%c'\n",
9c13eddc
KM
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);
6f17a61a
KB
611 if (R_do_defines) {
612 fputs(not_defined, ofp);
613 def_state = IN_IFNDEF;
9c13eddc
KM
614 }
615 while (pch_char(old) == '!') {
6f17a61a
KB
616 if (R_do_defines) {
617 fputs(pfetch(old), ofp);
9c13eddc
KM
618 }
619 last_frozen_line++;
620 old++;
621 }
6f17a61a 622 if (R_do_defines) {
9c13eddc 623 fputs(else_defined, ofp);
6f17a61a 624 def_state = IN_ELSE;
9c13eddc
KM
625 }
626 while (pch_char(new) == '!') {
6f17a61a 627 fputs(pfetch(new), ofp);
9c13eddc
KM
628 new++;
629 }
6f17a61a 630 if (R_do_defines) {
9c13eddc 631 fputs(end_defined, ofp);
6f17a61a 632 def_state = OUTSIDE;
9c13eddc
KM
633 }
634 }
635 else {
636 assert(pch_char(new) == ' ');
637 old++;
638 new++;
639 }
640 }
641 }
6f17a61a 642 if (new <= pat_end && pch_char(new) == '+') {
9c13eddc 643 copy_till(where + old - 1);
6f17a61a
KB
644 if (R_do_defines) {
645 if (def_state == OUTSIDE) {
9c13eddc 646 fputs(if_defined, ofp);
6f17a61a
KB
647 def_state = IN_IFDEF;
648 }
649 else if (def_state == IN_IFNDEF) {
9c13eddc 650 fputs(else_defined, ofp);
6f17a61a 651 def_state = IN_ELSE;
9c13eddc
KM
652 }
653 }
6f17a61a
KB
654 while (new <= pat_end && pch_char(new) == '+') {
655 fputs(pfetch(new), ofp);
9c13eddc
KM
656 new++;
657 }
658 }
6f17a61a 659 if (R_do_defines && def_state != OUTSIDE) {
9c13eddc
KM
660 fputs(end_defined, ofp);
661 }
662}
663
6f17a61a 664/* Open the new file. */
9c13eddc 665
6f17a61a 666void
9c13eddc
KM
667init_output(name)
668char *name;
669{
6f17a61a 670 ofp = fopen(name, "w");
9c13eddc 671 if (ofp == Nullfp)
6f17a61a 672 fatal2("patch: can't create %s.\n", name);
9c13eddc
KM
673}
674
6f17a61a
KB
675/* Open a file to put hunks we can't locate. */
676
677void
9c13eddc
KM
678init_reject(name)
679char *name;
680{
6f17a61a 681 rejfp = fopen(name, "w");
9c13eddc 682 if (rejfp == Nullfp)
6f17a61a 683 fatal2("patch: can't create %s.\n", name);
9c13eddc
KM
684}
685
6f17a61a 686/* Copy input file to output, up to wherever hunk is to be applied. */
9c13eddc 687
6f17a61a 688void
9c13eddc 689copy_till(lastline)
6f17a61a 690Reg1 LINENUM lastline;
9c13eddc 691{
6f17a61a
KB
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);
9c13eddc 698 }
6f17a61a 699 last_frozen_line = R_last_frozen_line;
9c13eddc
KM
700}
701
6f17a61a
KB
702/* Finish copying the input file to the output file. */
703
704void
9c13eddc
KM
705spew_output()
706{
6f17a61a
KB
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 */
9c13eddc
KM
713 Fclose(ofp);
714 ofp = Nullfp;
715}
716
6f17a61a
KB
717/* Copy one line from input to output. */
718
719void
9c13eddc
KM
720dump_line(line)
721LINENUM line;
722{
6f17a61a
KB
723 Reg1 char *s;
724 Reg2 char R_newline = '\n';
9c13eddc 725
6f17a61a
KB
726 /* Note: string is not null terminated. */
727 for (s=ifetch(line, 0); putc(*s, ofp) != R_newline; s++) ;
9c13eddc
KM
728}
729
6f17a61a 730/* Does the patch pattern match at line base+offset? */
9c13eddc
KM
731
732bool
6f17a61a 733patch_match(base, offset, fuzz)
9c13eddc
KM
734LINENUM base;
735LINENUM offset;
6f17a61a 736LINENUM fuzz;
9c13eddc 737{
6f17a61a
KB
738 Reg1 LINENUM pline = 1 + fuzz;
739 Reg2 LINENUM iline;
740 Reg3 LINENUM pat_lines = pch_ptrn_lines() - fuzz;
9c13eddc 741
6f17a61a 742 for (iline=base+offset+fuzz; pline <= pat_lines; pline++,iline++) {
9c13eddc 743 if (canonicalize) {
6f17a61a 744 if (!similar(ifetch(iline, (offset >= 0)),
9c13eddc
KM
745 pfetch(pline),
746 pch_line_len(pline) ))
747 return FALSE;
748 }
6f17a61a 749 else if (strnNE(ifetch(iline, (offset >= 0)),
9c13eddc
KM
750 pfetch(pline),
751 pch_line_len(pline) ))
752 return FALSE;
753 }
754 return TRUE;
755}
756
6f17a61a 757/* Do two lines match with canonicalized white space? */
9c13eddc
KM
758
759bool
760similar(a,b,len)
6f17a61a
KB
761Reg1 char *a;
762Reg2 char *b;
763Reg3 int len;
9c13eddc
KM
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
6f17a61a 785/* Exit with cleanup. */
9c13eddc 786
6f17a61a 787void
9c13eddc
KM
788my_exit(status)
789int status;
790{
791 Unlink(TMPINNAME);
6f17a61a
KB
792 if (!toutkeep) {
793 Unlink(TMPOUTNAME);
9c13eddc 794 }
6f17a61a
KB
795 if (!trejkeep) {
796 Unlink(TMPREJNAME);
9c13eddc 797 }
6f17a61a
KB
798 Unlink(TMPPATNAME);
799 exit(status);
9c13eddc 800}