Merge from vendor branch GCC:
[dragonfly.git] / contrib / patch / patch.c
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
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
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
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
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
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
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
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
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 *
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
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
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
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
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
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
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 *
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
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
1296 cleanup ()
1297 {
1298   unlink (TMPINNAME);
1299   unlink (TMPOUTNAME);
1300   unlink (TMPPATNAME);
1301   unlink (TMPREJNAME);
1302 }