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