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