1 /* patch - a program to apply diffs to original files */
2
3 /* $Id: patch.c,v 1.23 1997/07/05 10:32:23 eggert Exp $ */
4
5 /*
6 Copyright 1984, 1985, 1986, 1987, 1988 Larry Wall
7 Copyright 1989, 1990, 1991, 1992, 1993, 1997 Free Software Foundation, Inc.
8
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; either version 2, or (at your option)
12 any later version.
13
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
18
19 You should have received a copy of the GNU General Public License
20 along with this program; see the file COPYING.
21 If not, write to the Free Software Foundation,
22 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
23 */
24
25 #define XTERN
26 #include <common.h>
27 #undef XTERN
28 #define XTERN extern
29 #include <argmatch.h>
30 #include <backupfile.h>
31 #include <getopt.h>
32 #include <inp.h>
33 #include <pch.h>
34 #include <util.h>
35 #include <version.h>
36
37 #if HAVE_UTIME_H
38 # include <utime.h>
39 #endif
40 /* Some nonstandard hosts don't declare this structure even in <utime.h>. */
41 #if ! HAVE_STRUCT_UTIMBUF
42 struct utimbuf
43 {
44 time_t actime;
45 time_t modtime;
46 };
47 #endif
48
49 /* Output stream state. */
50 struct outstate
51 {
52 FILE *ofp;
53 int after_newline;
54 int zero_output;
55 };
56
57 /* procedures */
58
59 static FILE *create_output_file PARAMS ((char const *));
60 static LINENUM locate_hunk PARAMS ((LINENUM));
61 static bool apply_hunk PARAMS ((struct outstate *, LINENUM));
62 static bool copy_till PARAMS ((struct outstate *, LINENUM));
63 static bool patch_match PARAMS ((LINENUM, LINENUM, LINENUM, LINENUM));
64 static bool similar PARAMS ((char const *, size_t, char const *, size_t));
65 static bool spew_output PARAMS ((struct outstate *));
66 static char const *make_temp PARAMS ((int));
67 static int numeric_string PARAMS ((char const *, int, char const *));
68 static void abort_hunk PARAMS ((void));
69 static void cleanup PARAMS ((void));
70 static void get_some_switches PARAMS ((void));
71 static void init_output PARAMS ((char const *, struct outstate *));
72 static void init_reject PARAMS ((char const *));
73 static void reinitialize_almost_everything PARAMS ((void));
74 static void usage PARAMS ((FILE *, int)) __attribute__((noreturn));
75
76 static int make_backups;
77 static int backup_if_mismatch;
78 static char const *version_control;
79 static int remove_empty_files;
80
81 /* TRUE if -R was specified on command line. */
82 static int reverse_flag_specified;
83
84 /* how many input lines have been irretractably output */
85 static LINENUM last_frozen_line;
86
87 static char const *do_defines; /* symbol to patch using ifdef, ifndef, etc. */
88 static char const if_defined[] = "\n#ifdef %s\n";
89 static char const not_defined[] = "#ifndef %s\n";
90 static char const else_defined[] = "\n#else\n";
91 static char const end_defined[] = "\n#endif /* %s */\n";
92
93 static int Argc;
94 static char * const *Argv;
95
96 static FILE *rejfp; /* reject file pointer */
97
98 static char const *patchname;
99 static char *rejname;
100 static char const * volatile TMPREJNAME;
101
102 static LINENUM last_offset;
103 static LINENUM maxfuzz = 2;
104
105 static char serrbuf[BUFSIZ];
106
107 char const program_name[] = "patch";
108
109 /* Apply a set of diffs as appropriate. */
110
111 int main PARAMS ((int, char **));
112
113 int
main(argc,argv)114 main(argc,argv)
115 int argc;
116 char **argv;
117 {
118 char const *val;
119 bool somefailed = FALSE;
120 struct outstate outstate;
121
122 init_time ();
123
124 setbuf(stderr, serrbuf);
125
126 bufsize = 8 * 1024;
127 buf = xmalloc (bufsize);
128
129 strippath = INT_MAX;
130
131 posixly_correct = getenv ("POSIXLY_CORRECT") != 0;
132 backup_if_mismatch = ! posixly_correct;
133 patch_get = ((val = getenv ("PATCH_GET"))
134 ? numeric_string (val, 1, "PATCH_GET value")
135 : posixly_correct - 1);
136
137 {
138 char const *v = getenv ("SIMPLE_BACKUP_SUFFIX");
139 if (v && *v)
140 simple_backup_suffix = v;
141 }
142
143 version_control = getenv ("PATCH_VERSION_CONTROL");
144 if (! version_control)
145 version_control = getenv ("VERSION_CONTROL");
146
147 /* Cons up the names of the global temporary files.
148 Do this before `cleanup' can possibly be called (e.g. by `pfatal'). */
149 TMPOUTNAME = make_temp ('o');
150 TMPINNAME = make_temp ('i');
151 TMPREJNAME = make_temp ('r');
152 TMPPATNAME = make_temp ('p');
153
154 /* parse switches */
155 Argc = argc;
156 Argv = argv;
157 get_some_switches();
158
159 if (make_backups | backup_if_mismatch)
160 backup_type = get_version (version_control);
161
162 init_output (outfile, &outstate);
163
164 /* Make sure we clean up in case of disaster. */
165 set_signals(0);
166
167 for (
168 open_patch_file (patchname);
169 there_is_another_patch();
170 reinitialize_almost_everything()
171 ) { /* for each patch in patch file */
172 int hunk = 0;
173 int failed = 0;
174 int mismatch = 0;
175 char *outname = outfile ? outfile : inname;
176
177 if (!skip_rest_of_patch)
178 get_input_file (inname, outname);
179
180 if (diff_type == ED_DIFF) {
181 outstate.zero_output = 0;
182 if (! dry_run)
183 {
184 do_ed_script (outstate.ofp);
185 if (! outfile)
186 {
187 struct stat statbuf;
188 if (stat (TMPOUTNAME, &statbuf) != 0)
189 pfatal ("%s", TMPOUTNAME);
190 outstate.zero_output = statbuf.st_size == 0;
191 }
192 }
193 } else {
194 int got_hunk;
195 int apply_anyway = 0;
196
197 /* initialize the patched file */
198 if (! skip_rest_of_patch && ! outfile)
199 init_output (TMPOUTNAME, &outstate);
200
201 /* initialize reject file */
202 init_reject(TMPREJNAME);
203
204 /* find out where all the lines are */
205 if (!skip_rest_of_patch)
206 scan_input (inname);
207
208 /* from here on, open no standard i/o files, because malloc */
209 /* might misfire and we can't catch it easily */
210
211 /* apply each hunk of patch */
212 while (0 < (got_hunk = another_hunk (diff_type, reverse))) {
213 LINENUM where = 0; /* Pacify `gcc -Wall'. */
214 LINENUM newwhere;
215 LINENUM fuzz = 0;
216 LINENUM prefix_context = pch_prefix_context ();
217 LINENUM suffix_context = pch_suffix_context ();
218 LINENUM context = (prefix_context < suffix_context
219 ? suffix_context : prefix_context);
220 LINENUM mymaxfuzz = (maxfuzz < context ? maxfuzz : context);
221 hunk++;
222 if (!skip_rest_of_patch) {
223 do {
224 where = locate_hunk(fuzz);
225 if (! where || fuzz || last_offset)
226 mismatch = 1;
227 if (hunk == 1 && ! where && ! (force | apply_anyway)
228 && reverse == reverse_flag_specified) {
229 /* dwim for reversed patch? */
230 if (!pch_swap()) {
231 say (
232 "Not enough memory to try swapped hunk! Assuming unswapped.\n");
233 continue;
234 }
235 /* Try again. */
236 where = locate_hunk (fuzz);
237 if (where
238 && (ok_to_reverse
239 ("%s patch detected!",
240 (reverse
241 ? "Unreversed"
242 : "Reversed (or previously applied)"))))
243 reverse ^= 1;
244 else
245 {
246 /* Put it back to normal. */
247 if (! pch_swap ())
248 fatal ("lost hunk on alloc error!");
249 if (where)
250 {
251 apply_anyway = 1;
252 fuzz--; /* Undo `++fuzz' below. */
253 where = 0;
254 }
255 }
256 }
257 } while (!skip_rest_of_patch && !where
258 && ++fuzz <= mymaxfuzz);
259
260 if (skip_rest_of_patch) { /* just got decided */
261 if (outstate.ofp && ! outfile)
262 {
263 fclose (outstate.ofp);
264 outstate.ofp = 0;
265 }
266 }
267 }
268
269 newwhere = pch_newfirst() + last_offset;
270 if (skip_rest_of_patch) {
271 abort_hunk();
272 failed++;
273 if (verbosity == VERBOSE)
274 say ("Hunk #%d ignored at %ld.\n", hunk, newwhere);
275 }
276 else if (!where
277 || (where == 1 && pch_says_nonexistent (reverse)
278 && instat.st_size)) {
279 if (where)
280 say ("Patch attempted to create file `%s', which already exists.\n", inname);
281 abort_hunk();
282 failed++;
283 if (verbosity != SILENT)
284 say ("Hunk #%d FAILED at %ld.\n", hunk, newwhere);
285 }
286 else if (! apply_hunk (&outstate, where)) {
287 abort_hunk ();
288 failed++;
289 if (verbosity != SILENT)
290 say ("Hunk #%d FAILED at %ld.\n", hunk, newwhere);
291 } else {
292 if (verbosity == VERBOSE
293 || (verbosity != SILENT && (fuzz || last_offset))) {
294 say ("Hunk #%d succeeded at %ld", hunk, newwhere);
295 if (fuzz)
296 say (" with fuzz %ld", fuzz);
297 if (last_offset)
298 say (" (offset %ld line%s)",
299 last_offset, last_offset==1?"":"s");
300 say (".\n");
301 }
302 }
303 }
304
305 if (got_hunk < 0 && using_plan_a) {
306 if (outfile)
307 fatal ("out of memory using Plan A");
308 say ("\n\nRan out of memory using Plan A -- trying again...\n\n");
309 if (outstate.ofp)
310 {
311 fclose (outstate.ofp);
312 outstate.ofp = 0;
313 }
314 fclose (rejfp);
315 continue;
316 }
317
318 /* finish spewing out the new file */
319 if (!skip_rest_of_patch)
320 {
321 assert (hunk);
322 if (! spew_output (&outstate))
323 {
324 say ("Skipping patch.\n");
325 skip_rest_of_patch = TRUE;
326 }
327 }
328 }
329
330 /* and put the output where desired */
331 ignore_signals ();
332 if (! skip_rest_of_patch && ! outfile) {
333 if (outstate.zero_output
334 && (remove_empty_files
335 || (pch_says_nonexistent (reverse ^ 1) == 2
336 && ! posixly_correct)))
337 {
338 if (verbosity == VERBOSE)
339 say ("Removing file `%s'%s.\n", outname,
340 dry_run ? " and any empty ancestor directories" : "");
341 if (! dry_run)
342 {
343 move_file ((char *) 0, outname, (mode_t) 0,
344 (make_backups
345 || (backup_if_mismatch && (mismatch | failed))));
346 removedirs (outname);
347 }
348 }
349 else
350 {
351 if (! outstate.zero_output
352 && pch_says_nonexistent (reverse ^ 1))
353 {
354 mismatch = 1;
355 if (verbosity != SILENT)
356 say ("File `%s' is not empty after patch, as expected.\n",
357 outname);
358 }
359
360 if (! dry_run)
361 {
362 time_t t;
363
364 move_file (TMPOUTNAME, outname, instat.st_mode,
365 (make_backups
366 || (backup_if_mismatch && (mismatch | failed))));
367
368 if ((set_time | set_utc)
369 && (t = pch_timestamp (reverse ^ 1)) != (time_t) -1)
370 {
371 struct utimbuf utimbuf;
372 utimbuf.actime = utimbuf.modtime = t;
373
374 if (! force && ! inerrno
375 && ! pch_says_nonexistent (reverse)
376 && (t = pch_timestamp (reverse)) != (time_t) -1
377 && t != instat.st_mtime)
378 say ("not setting time of file `%s' (time mismatch)\n",
379 outname);
380 else if (! force && (mismatch | failed))
381 say ("not setting time of file `%s' (contents mismatch)\n",
382 outname);
383 else if (utime (outname, &utimbuf) != 0)
384 pfatal ("can't set timestamp on file `%s'", outname);
385 }
386
387 if (! inerrno && chmod (outname, instat.st_mode) != 0)
388 pfatal ("can't set permissions on file `%s'", outname);
389 }
390 }
391 }
392 if (diff_type != ED_DIFF) {
393 if (fclose (rejfp) != 0)
394 write_fatal ();
395 if (failed) {
396 somefailed = TRUE;
397 say ("%d out of %d hunk%s %s", failed, hunk, "s" + (hunk == 1),
398 skip_rest_of_patch ? "ignored" : "FAILED");
399 if (outname) {
400 char *rej = rejname;
401 if (!rejname) {
402 rej = xmalloc (strlen (outname) + 5);
403 strcpy (rej, outname);
404 addext (rej, ".rej", '#');
405 }
406 say (" -- saving rejects to %s", rej);
407 if (! dry_run)
408 {
409 move_file (TMPREJNAME, rej, instat.st_mode, FALSE);
410 if (! inerrno
411 && (chmod (rej, (instat.st_mode
412 & ~(S_IXUSR|S_IXGRP|S_IXOTH)))
413 != 0))
414 pfatal ("can't set permissions on file `%s'", rej);
415 }
416 if (!rejname)
417 free (rej);
418 }
419 say ("\n");
420 }
421 }
422 set_signals (1);
423 }
424 if (outstate.ofp && (ferror (outstate.ofp) || fclose (outstate.ofp) != 0))
425 write_fatal ();
426 cleanup ();
427 if (somefailed)
428 exit (1);
429 return 0;
430 }
431
432 /* Prepare to find the next patch to do in the patch file. */
433
434 static void
reinitialize_almost_everything()435 reinitialize_almost_everything()
436 {
437 re_patch();
438 re_input();
439
440 input_lines = 0;
441 last_frozen_line = 0;
442
443 if (inname) {
444 free (inname);
445 inname = 0;
446 }
447
448 last_offset = 0;
449
450 diff_type = NO_DIFF;
451
452 if (revision) {
453 free(revision);
454 revision = 0;
455 }
456
457 reverse = reverse_flag_specified;
458 skip_rest_of_patch = FALSE;
459 }
460
461 static char const shortopts[] = "bB:cd:D:eEfF:g:i:lnNo:p:r:RstTuvV:x:Y:z:Z";
462 static struct option const longopts[] =
463 {
464 {"backup", no_argument, NULL, 'b'},
465 {"prefix", required_argument, NULL, 'B'},
466 {"context", no_argument, NULL, 'c'},
467 {"directory", required_argument, NULL, 'd'},
468 {"ifdef", required_argument, NULL, 'D'},
469 {"ed", no_argument, NULL, 'e'},
470 {"remove-empty-files", no_argument, NULL, 'E'},
471 {"force", no_argument, NULL, 'f'},
472 {"fuzz", required_argument, NULL, 'F'},
473 {"get", no_argument, NULL, 'g'},
474 {"input", required_argument, NULL, 'i'},
475 {"ignore-whitespace", no_argument, NULL, 'l'},
476 {"normal", no_argument, NULL, 'n'},
477 {"forward", no_argument, NULL, 'N'},
478 {"output", required_argument, NULL, 'o'},
479 {"strip", required_argument, NULL, 'p'},
480 {"reject-file", required_argument, NULL, 'r'},
481 {"reverse", no_argument, NULL, 'R'},
482 {"quiet", no_argument, NULL, 's'},
483 {"silent", no_argument, NULL, 's'},
484 {"batch", no_argument, NULL, 't'},
485 {"set-time", no_argument, NULL, 'T'},
486 {"unified", no_argument, NULL, 'u'},
487 {"version", no_argument, NULL, 'v'},
488 {"version-control", required_argument, NULL, 'V'},
489 {"debug", required_argument, NULL, 'x'},
490 {"basename-prefix", required_argument, NULL, 'Y'},
491 {"suffix", required_argument, NULL, 'z'},
492 {"set-utc", no_argument, NULL, 'Z'},
493 {"dry-run", no_argument, NULL, 129},
494 {"verbose", no_argument, NULL, 130},
495 {"binary", no_argument, NULL, 131},
496 {"help", no_argument, NULL, 132},
497 {"backup-if-mismatch", no_argument, NULL, 133},
498 {"no-backup-if-mismatch", no_argument, NULL, 134},
499 {NULL, no_argument, NULL, 0}
500 };
501
502 static char const *const option_help[] =
503 {
504 "Input options:",
505 "",
506 " -p NUM --strip=NUM Strip NUM leading components from file names.",
507 " -F LINES --fuzz LINES Set the fuzz factor to LINES for inexact matching.",
508 " -l --ignore-whitespace Ignore white space changes between patch and input.",
509 "",
510 " -c --context Interpret the patch as a context difference.",
511 " -e --ed Interpret the patch as an ed script.",
512 " -n --normal Interpret the patch as a normal difference.",
513 " -u --unified Interpret the patch as a unified difference.",
514 "",
515 " -N --forward Ignore patches that appear to be reversed or already applied.",
516 " -R --reverse Assume patches were created with old and new files swapped.",
517 "",
518 " -i PATCHFILE --input=PATCHFILE Read patch from PATCHFILE instead of stdin.",
519 "",
520 "Output options:",
521 "",
522 " -o FILE --output=FILE Output patched files to FILE.",
523 " -r FILE --reject-file=FILE Output rejects to FILE.",
524 "",
525 " -D NAME --ifdef=NAME Make merged if-then-else output using NAME.",
526 " -E --remove-empty-files Remove output files that are empty after patching.",
527 "",
528 " -Z --set-utc Set times of patched files, assuming diff uses UTC (GMT).",
529 " -T --set-time Likewise, assuming local time.",
530 "",
531 "Backup and version control options:",
532 "",
533 " -b --backup Back up the original contents of each file.",
534 " --backup-if-mismatch Back up if the patch does not match exactly.",
535 " --no-backup-if-mismatch Back up mismatches only if otherwise requested.",
536 "",
537 " -V STYLE --version-control=STYLE Use STYLE version control.",
538 " STYLE is either 'simple', 'numbered', or 'existing'.",
539 " -B PREFIX --prefix=PREFIX Prepend PREFIX to backup file names.",
540 " -Y PREFIX --basename-prefix=PREFIX Prepend PREFIX to backup file basenames.",
541 " -z SUFFIX --suffix=SUFFIX Append SUFFIX to backup file names.",
542 "",
543 " -g NUM --get=NUM Get files from RCS or SCCS if positive; ask if negative.",
544 "",
545 "Miscellaneous options:",
546 "",
547 " -t --batch Ask no questions; skip bad-Prereq patches; assume reversed.",
548 " -f --force Like -t, but ignore bad-Prereq patches, and assume unreversed.",
549 " -s --quiet --silent Work silently unless an error occurs.",
550 " --verbose Output extra information about the work being done.",
551 " --dry-run Do not actually change any files; just print what would happen.",
552 "",
553 " -d DIR --directory=DIR Change the working directory to DIR first.",
554 #if HAVE_SETMODE
555 " --binary Read and write data in binary mode.",
556 #else
557 " --binary Read and write data in binary mode (no effect on this platform).",
558 #endif
559 "",
560 " -v --version Output version info.",
561 " --help Output this help.",
562 "",
563 "Report bugs to <bug-gnu-utils@prep.ai.mit.edu>.",
564 0
565 };
566
567 static void
usage(stream,status)568 usage (stream, status)
569 FILE *stream;
570 int status;
571 {
572 char const * const *p;
573
574 if (status != 0)
575 {
576 fprintf (stream, "%s: Try `%s --help' for more information.\n",
577 program_name, Argv[0]);
578 }
579 else
580 {
581 fprintf (stream, "Usage: %s [OPTION]... [ORIGFILE [PATCHFILE]]\n\n",
582 Argv[0]);
583 for (p = option_help; *p; p++)
584 fprintf (stream, "%s\n", *p);
585 }
586
587 exit (status);
588 }
589
590 /* Process switches and filenames. */
591
592 static void
get_some_switches()593 get_some_switches()
594 {
595 register int optc;
596
597 if (rejname)
598 free (rejname);
599 rejname = 0;
600 if (optind == Argc)
601 return;
602 while ((optc = getopt_long (Argc, Argv, shortopts, longopts, (int *) 0))
603 != -1) {
604 switch (optc) {
605 case 'b':
606 make_backups = 1;
607 /* Special hack for backward compatibility with CVS 1.9.
608 If the last 4 args are `-b SUFFIX ORIGFILE PATCHFILE',
609 treat `-b' as if it were `-b -z'. */
610 if (Argc - optind == 3
611 && strcmp (Argv[optind - 1], "-b") == 0
612 && ! (Argv[optind + 0][0] == '-' && Argv[optind + 0][1])
613 && ! (Argv[optind + 1][0] == '-' && Argv[optind + 1][1])
614 && ! (Argv[optind + 2][0] == '-' && Argv[optind + 2][1]))
615 {
616 optarg = Argv[optind++];
617 if (verbosity != SILENT)
618 say ("warning: the `-b %s' option is obsolete; use `-b -z %s' instead\n",
619 optarg, optarg);
620 goto case_z;
621 }
622 break;
623 case 'B':
624 if (!*optarg)
625 fatal ("backup prefix is empty");
626 origprae = savestr (optarg);
627 break;
628 case 'c':
629 diff_type = CONTEXT_DIFF;
630 break;
631 case 'd':
632 if (chdir(optarg) < 0)
633 pfatal ("can't change directory to `%s'", optarg);
634 break;
635 case 'D':
636 do_defines = savestr (optarg);
637 break;
638 case 'e':
639 diff_type = ED_DIFF;
640 break;
641 case 'E':
642 remove_empty_files = TRUE;
643 break;
644 case 'f':
645 force = TRUE;
646 break;
647 case 'F':
648 maxfuzz = numeric_string (optarg, 0, "fuzz factor");
649 break;
650 case 'g':
651 patch_get = numeric_string (optarg, 1, "get option value");
652 break;
653 case 'i':
654 patchname = savestr (optarg);
655 break;
656 case 'l':
657 canonicalize = TRUE;
658 break;
659 case 'n':
660 diff_type = NORMAL_DIFF;
661 break;
662 case 'N':
663 noreverse = TRUE;
664 break;
665 case 'o':
666 if (strcmp (optarg, "-") == 0)
667 fatal ("can't output patches to standard output");
668 outfile = savestr (optarg);
669 break;
670 case 'p':
671 strippath = numeric_string (optarg, 0, "strip count");
672 break;
673 case 'r':
674 rejname = savestr (optarg);
675 break;
676 case 'R':
677 reverse = 1;
678 reverse_flag_specified = 1;
679 break;
680 case 's':
681 verbosity = SILENT;
682 break;
683 case 't':
684 batch = TRUE;
685 break;
686 case 'T':
687 set_time = 1;
688 break;
689 case 'u':
690 diff_type = UNI_DIFF;
691 break;
692 case 'v':
693 version();
694 exit (0);
695 break;
696 case 'V':
697 version_control = optarg;
698 break;
699 #if DEBUGGING
700 case 'x':
701 debug = numeric_string (optarg, 1, "debugging option");
702 break;
703 #endif
704 case 'Y':
705 if (!*optarg)
706 fatal ("backup basename prefix is empty");
707 origbase = savestr (optarg);
708 break;
709 case 'z':
710 case_z:
711 if (!*optarg)
712 fatal ("backup suffix is empty");
713 simple_backup_suffix = savestr (optarg);
714 break;
715 case 'Z':
716 set_utc = 1;
717 break;
718 case 129:
719 dry_run = TRUE;
720 break;
721 case 130:
722 verbosity = VERBOSE;
723 break;
724 case 131:
725 #if HAVE_SETMODE
726 binary_transput = O_BINARY;
727 #endif
728 break;
729 case 132:
730 usage (stdout, 0);
731 case 133:
732 backup_if_mismatch = 1;
733 break;
734 case 134:
735 backup_if_mismatch = 0;
736 break;
737 default:
738 usage (stderr, 2);
739 }
740 }
741
742 /* Process any filename args. */
743 if (optind < Argc)
744 {
745 inname = savestr (Argv[optind++]);
746 invc = -1;
747 if (optind < Argc)
748 {
749 patchname = savestr (Argv[optind++]);
750 if (optind < Argc)
751 {
752 fprintf (stderr, "%s: extra operand `%s'\n",
753 program_name, Argv[optind]);
754 usage (stderr, 2);
755 }
756 }
757 }
758 }
759
760 /* Handle STRING (possibly negative if NEGATIVE_ALLOWED is nonzero)
761 of type ARGTYPE_MSGID by converting it to an integer,
762 returning the result. */
763 static int
numeric_string(string,negative_allowed,argtype_msgid)764 numeric_string (string, negative_allowed, argtype_msgid)
765 char const *string;
766 int negative_allowed;
767 char const *argtype_msgid;
768 {
769 int value = 0;
770 char const *p = string;
771 int sign = *p == '-' ? -1 : 1;
772
773 p += *p == '-' || *p == '+';
774
775 do
776 {
777 int v10 = value * 10;
778 int digit = *p - '0';
779 int signed_digit = sign * digit;
780 int next_value = v10 + signed_digit;
781
782 if (9 < (unsigned) digit)
783 fatal ("%s `%s' is not a number", argtype_msgid, string);
784
785 if (v10 / 10 != value || (next_value < v10) != (signed_digit < 0))
786 fatal ("%s `%s' is too large", argtype_msgid, string);
787
788 value = next_value;
789 }
790 while (*++p);
791
792 if (value < 0 && ! negative_allowed)
793 fatal ("%s `%s' is negative", argtype_msgid, string);
794
795 return value;
796 }
797
798 /* Attempt to find the right place to apply this hunk of patch. */
799
800 static LINENUM
locate_hunk(fuzz)801 locate_hunk(fuzz)
802 LINENUM fuzz;
803 {
804 register LINENUM first_guess = pch_first () + last_offset;
805 register LINENUM offset;
806 LINENUM pat_lines = pch_ptrn_lines();
807 LINENUM prefix_context = pch_prefix_context ();
808 LINENUM suffix_context = pch_suffix_context ();
809 LINENUM context = (prefix_context < suffix_context
810 ? suffix_context : prefix_context);
811 LINENUM prefix_fuzz = fuzz + prefix_context - context;
812 LINENUM suffix_fuzz = fuzz + suffix_context - context;
813 LINENUM max_where = input_lines - (pat_lines - suffix_fuzz) + 1;
814 LINENUM min_where = last_frozen_line + 1 - (prefix_context - prefix_fuzz);
815 LINENUM max_pos_offset = max_where - first_guess;
816 LINENUM max_neg_offset = first_guess - min_where;
817 LINENUM max_offset = (max_pos_offset < max_neg_offset
818 ? max_neg_offset : max_pos_offset);
819
820 if (!pat_lines) /* null range matches always */
821 return first_guess;
822
823 /* Do not try lines <= 0. */
824 if (first_guess <= max_neg_offset)
825 max_neg_offset = first_guess - 1;
826
827 if (prefix_fuzz < 0)
828 {
829 /* Can only match start of file. */
830
831 if (suffix_fuzz < 0)
832 /* Can only match entire file. */
833 if (pat_lines != input_lines || prefix_context < last_frozen_line)
834 return 0;
835
836 offset = 1 - first_guess;
837 if (last_frozen_line <= prefix_context
838 && offset <= max_pos_offset
839 && patch_match (first_guess, offset, (LINENUM) 0, suffix_fuzz))
840 {
841 last_offset = offset;
842 return first_guess + offset;
843 }
844 else
845 return 0;
846 }
847
848 if (suffix_fuzz < 0)
849 {
850 /* Can only match end of file. */
851 offset = first_guess - (input_lines - pat_lines + 1);
852 if (offset <= max_neg_offset
853 && patch_match (first_guess, -offset, prefix_fuzz, (LINENUM) 0))
854 {
855 last_offset = - offset;
856 return first_guess - offset;
857 }
858 else
859 return 0;
860 }
861
862 for (offset = 0; offset <= max_offset; offset++) {
863 if (offset <= max_pos_offset
864 && patch_match (first_guess, offset, prefix_fuzz, suffix_fuzz)) {
865 if (debug & 1)
866 say ("Offset changing from %ld to %ld\n", last_offset, offset);
867 last_offset = offset;
868 return first_guess+offset;
869 }
870 if (0 < offset && offset <= max_neg_offset
871 && patch_match (first_guess, -offset, prefix_fuzz, suffix_fuzz)) {
872 if (debug & 1)
873 say ("Offset changing from %ld to %ld\n", last_offset, -offset);
874 last_offset = -offset;
875 return first_guess-offset;
876 }
877 }
878 return 0;
879 }
880
881 /* We did not find the pattern, dump out the hunk so they can handle it. */
882
883 static void
abort_hunk()884 abort_hunk()
885 {
886 register LINENUM i;
887 register LINENUM pat_end = pch_end ();
888 /* add in last_offset to guess the same as the previous successful hunk */
889 LINENUM oldfirst = pch_first() + last_offset;
890 LINENUM newfirst = pch_newfirst() + last_offset;
891 LINENUM oldlast = oldfirst + pch_ptrn_lines() - 1;
892 LINENUM newlast = newfirst + pch_repl_lines() - 1;
893 char const *stars =
894 (int) NEW_CONTEXT_DIFF <= (int) diff_type ? " ****" : "";
895 char const *minuses =
896 (int) NEW_CONTEXT_DIFF <= (int) diff_type ? " ----" : " -----";
897
898 fprintf(rejfp, "***************\n");
899 for (i=0; i<=pat_end; i++) {
900 switch (pch_char(i)) {
901 case '*':
902 if (oldlast < oldfirst)
903 fprintf(rejfp, "*** 0%s\n", stars);
904 else if (oldlast == oldfirst)
905 fprintf(rejfp, "*** %ld%s\n", oldfirst, stars);
906 else
907 fprintf(rejfp, "*** %ld,%ld%s\n", oldfirst, oldlast, stars);
908 break;
909 case '=':
910 if (newlast < newfirst)
911 fprintf(rejfp, "--- 0%s\n", minuses);
912 else if (newlast == newfirst)
913 fprintf(rejfp, "--- %ld%s\n", newfirst, minuses);
914 else
915 fprintf(rejfp, "--- %ld,%ld%s\n", newfirst, newlast, minuses);
916 break;
917 case ' ': case '-': case '+': case '!':
918 fprintf (rejfp, "%c ", pch_char (i));
919 /* fall into */
920 case '\n':
921 pch_write_line (i, rejfp);
922 break;
923 default:
924 fatal ("fatal internal error in abort_hunk");
925 }
926 if (ferror (rejfp))
927 write_fatal ();
928 }
929 }
930
931 /* We found where to apply it (we hope), so do it. */
932
933 static bool
apply_hunk(outstate,where)934 apply_hunk (outstate, where)
935 struct outstate *outstate;
936 LINENUM where;
937 {
938 register LINENUM old = 1;
939 register LINENUM lastline = pch_ptrn_lines ();
940 register LINENUM new = lastline+1;
941 register enum {OUTSIDE, IN_IFNDEF, IN_IFDEF, IN_ELSE} def_state = OUTSIDE;
942 register char const *R_do_defines = do_defines;
943 register LINENUM pat_end = pch_end ();
944 register FILE *fp = outstate->ofp;
945
946 where--;
947 while (pch_char(new) == '=' || pch_char(new) == '\n')
948 new++;
949
950 while (old <= lastline) {
951 if (pch_char(old) == '-') {
952 assert (outstate->after_newline);
953 if (! copy_till (outstate, where + old - 1))
954 return FALSE;
955 if (R_do_defines) {
956 if (def_state == OUTSIDE) {
957 fprintf (fp, outstate->after_newline + if_defined,
958 R_do_defines);
959 def_state = IN_IFNDEF;
960 }
961 else if (def_state == IN_IFDEF) {
962 fprintf (fp, outstate->after_newline + else_defined);
963 def_state = IN_ELSE;
964 }
965 if (ferror (fp))
966 write_fatal ();
967 outstate->after_newline = pch_write_line (old, fp);
968 outstate->zero_output = 0;
969 }
970 last_frozen_line++;
971 old++;
972 }
973 else if (new > pat_end) {
974 break;
975 }
976 else if (pch_char(new) == '+') {
977 if (! copy_till (outstate, where + old - 1))
978 return FALSE;
979 if (R_do_defines) {
980 if (def_state == IN_IFNDEF) {
981 fprintf (fp, outstate->after_newline + else_defined);
982 def_state = IN_ELSE;
983 }
984 else if (def_state == OUTSIDE) {
985 fprintf (fp, outstate->after_newline + if_defined,
986 R_do_defines);
987 def_state = IN_IFDEF;
988 }
989 if (ferror (fp))
990 write_fatal ();
991 }
992 outstate->after_newline = pch_write_line (new, fp);
993 outstate->zero_output = 0;
994 new++;
995 }
996 else if (pch_char(new) != pch_char(old)) {
997 if (debug & 1)
998 say ("oldchar = '%c', newchar = '%c'\n",
999 pch_char (old), pch_char (new));
1000 fatal ("Out-of-sync patch, lines %ld,%ld -- mangled text or line numbers, maybe?",
1001 pch_hunk_beg() + old,
1002 pch_hunk_beg() + new);
1003 }
1004 else if (pch_char(new) == '!') {
1005 assert (outstate->after_newline);
1006 if (! copy_till (outstate, where + old - 1))
1007 return FALSE;
1008 assert (outstate->after_newline);
1009 if (R_do_defines) {
1010 fprintf (fp, not_defined, R_do_defines);
1011 if (ferror (fp))
1012 write_fatal ();
1013 def_state = IN_IFNDEF;
1014 }
1015
1016 do
1017 {
1018 if (R_do_defines) {
1019 outstate->after_newline = pch_write_line (old, fp);
1020 }
1021 last_frozen_line++;
1022 old++;
1023 }
1024 while (pch_char (old) == '!');
1025
1026 if (R_do_defines) {
1027 fprintf (fp, outstate->after_newline + else_defined);
1028 if (ferror (fp))
1029 write_fatal ();
1030 def_state = IN_ELSE;
1031 }
1032
1033 do
1034 {
1035 outstate->after_newline = pch_write_line (new, fp);
1036 new++;
1037 }
1038 while (pch_char (new) == '!');
1039 outstate->zero_output = 0;
1040 }
1041 else {
1042 assert(pch_char(new) == ' ');
1043 old++;
1044 new++;
1045 if (R_do_defines && def_state != OUTSIDE) {
1046 fprintf (fp, outstate->after_newline + end_defined,
1047 R_do_defines);
1048 if (ferror (fp))
1049 write_fatal ();
1050 outstate->after_newline = 1;
1051 def_state = OUTSIDE;
1052 }
1053 }
1054 }
1055 if (new <= pat_end && pch_char(new) == '+') {
1056 if (! copy_till (outstate, where + old - 1))
1057 return FALSE;
1058 if (R_do_defines) {
1059 if (def_state == OUTSIDE) {
1060 fprintf (fp, outstate->after_newline + if_defined,
1061 R_do_defines);
1062 def_state = IN_IFDEF;
1063 }
1064 else if (def_state == IN_IFNDEF) {
1065 fprintf (fp, outstate->after_newline + else_defined);
1066 def_state = IN_ELSE;
1067 }
1068 if (ferror (fp))
1069 write_fatal ();
1070 outstate->zero_output = 0;
1071 }
1072
1073 do
1074 {
1075 if (! outstate->after_newline && putc ('\n', fp) == EOF)
1076 write_fatal ();
1077 outstate->after_newline = pch_write_line (new, fp);
1078 outstate->zero_output = 0;
1079 new++;
1080 }
1081 while (new <= pat_end && pch_char (new) == '+');
1082 }
1083 if (R_do_defines && def_state != OUTSIDE) {
1084 fprintf (fp, outstate->after_newline + end_defined, R_do_defines);
1085 if (ferror (fp))
1086 write_fatal ();
1087 outstate->after_newline = 1;
1088 }
1089 return TRUE;
1090 }
1091
1092 /* Create an output file. */
1093
1094 static FILE *
create_output_file(name)1095 create_output_file (name)
1096 char const *name;
1097 {
1098 int fd = create_file (name, O_WRONLY | binary_transput, instat.st_mode);
1099 FILE *f = fdopen (fd, binary_transput ? "wb" : "w");
1100 if (! f)
1101 pfatal ("can't create `%s'", name);
1102 return f;
1103 }
1104
1105 /* Open the new file. */
1106
1107 static void
init_output(name,outstate)1108 init_output (name, outstate)
1109 char const *name;
1110 struct outstate *outstate;
1111 {
1112 outstate->ofp = name ? create_output_file (name) : (FILE *) 0;
1113 outstate->after_newline = 1;
1114 outstate->zero_output = 1;
1115 }
1116
1117 /* Open a file to put hunks we can't locate. */
1118
1119 static void
init_reject(name)1120 init_reject(name)
1121 char const *name;
1122 {
1123 rejfp = create_output_file (name);
1124 }
1125
1126 /* Copy input file to output, up to wherever hunk is to be applied. */
1127
1128 static bool
copy_till(outstate,lastline)1129 copy_till (outstate, lastline)
1130 register struct outstate *outstate;
1131 register LINENUM lastline;
1132 {
1133 register LINENUM R_last_frozen_line = last_frozen_line;
1134 register FILE *fp = outstate->ofp;
1135 register char const *s;
1136 size_t size;
1137
1138 if (R_last_frozen_line > lastline)
1139 {
1140 say ("misordered hunks! output would be garbled\n");
1141 return FALSE;
1142 }
1143 while (R_last_frozen_line < lastline)
1144 {
1145 s = ifetch (++R_last_frozen_line, 0, &size);
1146 if (size)
1147 {
1148 if ((! outstate->after_newline && putc ('\n', fp) == EOF)
1149 || ! fwrite (s, sizeof *s, size, fp))
1150 write_fatal ();
1151 outstate->after_newline = s[size - 1] == '\n';
1152 outstate->zero_output = 0;
1153 }
1154 }
1155 last_frozen_line = R_last_frozen_line;
1156 return TRUE;
1157 }
1158
1159 /* Finish copying the input file to the output file. */
1160
1161 static bool
spew_output(outstate)1162 spew_output (outstate)
1163 struct outstate *outstate;
1164 {
1165 if (debug & 256)
1166 say ("il=%ld lfl=%ld\n", input_lines, last_frozen_line);
1167
1168 if (last_frozen_line < input_lines)
1169 if (! copy_till (outstate, input_lines))
1170 return FALSE;
1171
1172 if (outstate->ofp && ! outfile)
1173 {
1174 if (fclose (outstate->ofp) != 0)
1175 write_fatal ();
1176 outstate->ofp = 0;
1177 }
1178
1179 return TRUE;
1180 }
1181
1182 /* Does the patch pattern match at line base+offset? */
1183
1184 static bool
patch_match(base,offset,prefix_fuzz,suffix_fuzz)1185 patch_match (base, offset, prefix_fuzz, suffix_fuzz)
1186 LINENUM base;
1187 LINENUM offset;
1188 LINENUM prefix_fuzz;
1189 LINENUM suffix_fuzz;
1190 {
1191 register LINENUM pline = 1 + prefix_fuzz;
1192 register LINENUM iline;
1193 register LINENUM pat_lines = pch_ptrn_lines () - suffix_fuzz;
1194 size_t size;
1195 register char const *p;
1196
1197 for (iline=base+offset+prefix_fuzz; pline <= pat_lines; pline++,iline++) {
1198 p = ifetch (iline, offset >= 0, &size);
1199 if (canonicalize) {
1200 if (!similar(p, size,
1201 pfetch(pline),
1202 pch_line_len(pline) ))
1203 return FALSE;
1204 }
1205 else if (size != pch_line_len (pline)
1206 || memcmp (p, pfetch (pline), size) != 0)
1207 return FALSE;
1208 }
1209 return TRUE;
1210 }
1211
1212 /* Do two lines match with canonicalized white space? */
1213
1214 static bool
similar(a,alen,b,blen)1215 similar (a, alen, b, blen)
1216 register char const *a;
1217 register size_t alen;
1218 register char const *b;
1219 register size_t blen;
1220 {
1221 /* Ignore presence or absence of trailing newlines. */
1222 alen -= alen && a[alen - 1] == '\n';
1223 blen -= blen && b[blen - 1] == '\n';
1224
1225 for (;;)
1226 {
1227 if (!blen || (*b == ' ' || *b == '\t'))
1228 {
1229 while (blen && (*b == ' ' || *b == '\t'))
1230 b++, blen--;
1231 if (alen)
1232 {
1233 if (!(*a == ' ' || *a == '\t'))
1234 return FALSE;
1235 do a++, alen--;
1236 while (alen && (*a == ' ' || *a == '\t'));
1237 }
1238 if (!alen || !blen)
1239 return alen == blen;
1240 }
1241 else if (!alen || *a++ != *b++)
1242 return FALSE;
1243 else
1244 alen--, blen--;
1245 }
1246 }
1247
1248 /* Make a temporary file. */
1249
1250 #if HAVE_MKTEMP
1251 char *mktemp PARAMS ((char *));
1252 #endif
1253
1254 #ifndef TMPDIR
1255 #define TMPDIR "/tmp"
1256 #endif
1257
1258 static char const *
make_temp(letter)1259 make_temp (letter)
1260 int letter;
1261 {
1262 char *r;
1263 #if HAVE_MKTEMP
1264 char const *tmpdir = getenv ("TMPDIR"); /* Unix tradition */
1265 if (!tmpdir) tmpdir = getenv ("TMP"); /* DOS tradition */
1266 if (!tmpdir) tmpdir = getenv ("TEMP"); /* another DOS tradition */
1267 if (!tmpdir) tmpdir = TMPDIR;
1268 r = xmalloc (strlen (tmpdir) + 10);
1269 sprintf (r, "%s/p%cXXXXXX", tmpdir, letter);
1270 mktemp (r);
1271 if (!*r)
1272 pfatal ("mktemp");
1273 #else
1274 r = xmalloc (L_tmpnam);
1275 if (! (tmpnam (r) == r && *r))
1276 pfatal ("tmpnam");
1277 #endif
1278 return r;
1279 }
1280
1281 /* Fatal exit with cleanup. */
1282
1283 void
fatal_exit(sig)1284 fatal_exit (sig)
1285 int sig;
1286 {
1287 cleanup ();
1288
1289 if (sig)
1290 exit_with_signal (sig);
1291
1292 exit (2);
1293 }
1294
1295 static void
cleanup()1296 cleanup ()
1297 {
1298 unlink (TMPINNAME);
1299 unlink (TMPOUTNAME);
1300 unlink (TMPPATNAME);
1301 unlink (TMPREJNAME);
1302 }
1303