12dd076b8SGabor Kovesdan /*-
22dd076b8SGabor Kovesdan * Copyright 1986, Larry Wall
32dd076b8SGabor Kovesdan *
42dd076b8SGabor Kovesdan * Redistribution and use in source and binary forms, with or without
52dd076b8SGabor Kovesdan * modification, are permitted provided that the following condition is met:
62dd076b8SGabor Kovesdan * 1. Redistributions of source code must retain the above copyright notice,
72dd076b8SGabor Kovesdan * this condition and the following disclaimer.
82dd076b8SGabor Kovesdan *
92dd076b8SGabor Kovesdan * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY
102dd076b8SGabor Kovesdan * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
112dd076b8SGabor Kovesdan * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
122dd076b8SGabor Kovesdan * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
132dd076b8SGabor Kovesdan * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
142dd076b8SGabor Kovesdan * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
152dd076b8SGabor Kovesdan * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
162dd076b8SGabor Kovesdan * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
172dd076b8SGabor Kovesdan * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
182dd076b8SGabor Kovesdan * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
192dd076b8SGabor Kovesdan * SUCH DAMAGE.
202dd076b8SGabor Kovesdan *
212dd076b8SGabor Kovesdan * patch - a program to apply diffs to original files
222dd076b8SGabor Kovesdan *
232dd076b8SGabor Kovesdan * -C option added in 1998, original code by Marc Espie, based on FreeBSD
242dd076b8SGabor Kovesdan * behaviour
252dd076b8SGabor Kovesdan *
26547e0acbSPedro F. Giffuni * $OpenBSD: patch.c,v 1.54 2014/12/13 10:31:07 tobias Exp $
27e56ef7d3SXin LI * $FreeBSD$
282dd076b8SGabor Kovesdan *
292dd076b8SGabor Kovesdan */
302dd076b8SGabor Kovesdan
312dd076b8SGabor Kovesdan #include <sys/types.h>
322dd076b8SGabor Kovesdan #include <sys/stat.h>
332dd076b8SGabor Kovesdan
34*50dacbf6SKyle Evans #include <assert.h>
352dd076b8SGabor Kovesdan #include <ctype.h>
362dd076b8SGabor Kovesdan #include <getopt.h>
372dd076b8SGabor Kovesdan #include <limits.h>
382dd076b8SGabor Kovesdan #include <stdio.h>
392dd076b8SGabor Kovesdan #include <string.h>
402dd076b8SGabor Kovesdan #include <stdlib.h>
412dd076b8SGabor Kovesdan #include <unistd.h>
422dd076b8SGabor Kovesdan
432dd076b8SGabor Kovesdan #include "common.h"
442dd076b8SGabor Kovesdan #include "util.h"
452dd076b8SGabor Kovesdan #include "pch.h"
462dd076b8SGabor Kovesdan #include "inp.h"
472dd076b8SGabor Kovesdan #include "backupfile.h"
482dd076b8SGabor Kovesdan #include "pathnames.h"
492dd076b8SGabor Kovesdan
502dd076b8SGabor Kovesdan mode_t filemode = 0644;
512dd076b8SGabor Kovesdan
522dd076b8SGabor Kovesdan char *buf; /* general purpose buffer */
532dd076b8SGabor Kovesdan size_t buf_size; /* size of the general purpose buffer */
542dd076b8SGabor Kovesdan
552dd076b8SGabor Kovesdan bool using_plan_a = true; /* try to keep everything in memory */
562dd076b8SGabor Kovesdan bool out_of_mem = false; /* ran out of memory in plan a */
57ef30b5a8SKyle Evans bool nonempty_patchf_seen = false; /* seen nonempty patch file? */
582dd076b8SGabor Kovesdan
592dd076b8SGabor Kovesdan #define MAXFILEC 2
602dd076b8SGabor Kovesdan
612dd076b8SGabor Kovesdan char *filearg[MAXFILEC];
622dd076b8SGabor Kovesdan bool ok_to_create_file = false;
632dd076b8SGabor Kovesdan char *outname = NULL;
642dd076b8SGabor Kovesdan char *origprae = NULL;
652dd076b8SGabor Kovesdan char *TMPOUTNAME;
662dd076b8SGabor Kovesdan char *TMPINNAME;
672dd076b8SGabor Kovesdan char *TMPREJNAME;
682dd076b8SGabor Kovesdan char *TMPPATNAME;
692dd076b8SGabor Kovesdan bool toutkeep = false;
702dd076b8SGabor Kovesdan bool trejkeep = false;
712dd076b8SGabor Kovesdan bool warn_on_invalid_line;
722dd076b8SGabor Kovesdan bool last_line_missing_eol;
732dd076b8SGabor Kovesdan
742dd076b8SGabor Kovesdan #ifdef DEBUGGING
752dd076b8SGabor Kovesdan int debug = 0;
762dd076b8SGabor Kovesdan #endif
772dd076b8SGabor Kovesdan
782dd076b8SGabor Kovesdan bool force = false;
792dd076b8SGabor Kovesdan bool batch = false;
802dd076b8SGabor Kovesdan bool verbose = true;
812dd076b8SGabor Kovesdan bool reverse = false;
822dd076b8SGabor Kovesdan bool noreverse = false;
832dd076b8SGabor Kovesdan bool skip_rest_of_patch = false;
842dd076b8SGabor Kovesdan int strippath = 957;
852dd076b8SGabor Kovesdan bool canonicalize = false;
862dd076b8SGabor Kovesdan bool check_only = false;
872dd076b8SGabor Kovesdan int diff_type = 0;
882dd076b8SGabor Kovesdan char *revision = NULL; /* prerequisite revision, if any */
892dd076b8SGabor Kovesdan LINENUM input_lines = 0; /* how long is input file in lines */
902dd076b8SGabor Kovesdan int posix = 0; /* strict POSIX mode? */
912dd076b8SGabor Kovesdan
922dd076b8SGabor Kovesdan static void reinitialize_almost_everything(void);
932dd076b8SGabor Kovesdan static void get_some_switches(void);
942dd076b8SGabor Kovesdan static LINENUM locate_hunk(LINENUM);
952dd076b8SGabor Kovesdan static void abort_context_hunk(void);
962dd076b8SGabor Kovesdan static void rej_line(int, LINENUM);
972dd076b8SGabor Kovesdan static void abort_hunk(void);
982dd076b8SGabor Kovesdan static void apply_hunk(LINENUM);
992dd076b8SGabor Kovesdan static void init_output(const char *);
1002dd076b8SGabor Kovesdan static void init_reject(const char *);
1012dd076b8SGabor Kovesdan static void copy_till(LINENUM, bool);
1022dd076b8SGabor Kovesdan static bool spew_output(void);
1032dd076b8SGabor Kovesdan static void dump_line(LINENUM, bool);
1042dd076b8SGabor Kovesdan static bool patch_match(LINENUM, LINENUM, LINENUM);
1052dd076b8SGabor Kovesdan static bool similar(const char *, const char *, int);
1062dd076b8SGabor Kovesdan static void usage(void);
107*50dacbf6SKyle Evans static bool handle_creation(bool, bool *);
1082dd076b8SGabor Kovesdan
1092dd076b8SGabor Kovesdan /* true if -E was specified on command line. */
1102dd076b8SGabor Kovesdan static bool remove_empty_files = false;
1112dd076b8SGabor Kovesdan
1122dd076b8SGabor Kovesdan /* true if -R was specified on command line. */
1132dd076b8SGabor Kovesdan static bool reverse_flag_specified = false;
1142dd076b8SGabor Kovesdan
115300ca9a8SConrad Meyer static bool Vflag = false;
116300ca9a8SConrad Meyer
1172dd076b8SGabor Kovesdan /* buffer holding the name of the rejected patch file. */
118c844f14eSPedro F. Giffuni static char rejname[PATH_MAX];
1192dd076b8SGabor Kovesdan
1202dd076b8SGabor Kovesdan /* how many input lines have been irretractibly output */
1212dd076b8SGabor Kovesdan static LINENUM last_frozen_line = 0;
1222dd076b8SGabor Kovesdan
1232dd076b8SGabor Kovesdan static int Argc; /* guess */
1242dd076b8SGabor Kovesdan static char **Argv;
1252dd076b8SGabor Kovesdan static int Argc_last; /* for restarting plan_b */
1262dd076b8SGabor Kovesdan static char **Argv_last;
1272dd076b8SGabor Kovesdan
1282dd076b8SGabor Kovesdan static FILE *ofp = NULL; /* output file pointer */
1292dd076b8SGabor Kovesdan static FILE *rejfp = NULL; /* reject file pointer */
1302dd076b8SGabor Kovesdan
1312dd076b8SGabor Kovesdan static int filec = 0; /* how many file arguments? */
1322dd076b8SGabor Kovesdan static LINENUM last_offset = 0;
1332dd076b8SGabor Kovesdan static LINENUM maxfuzz = 2;
1342dd076b8SGabor Kovesdan
1352dd076b8SGabor Kovesdan /* patch using ifdef, ifndef, etc. */
1362dd076b8SGabor Kovesdan static bool do_defines = false;
1372dd076b8SGabor Kovesdan /* #ifdef xyzzy */
1382dd076b8SGabor Kovesdan static char if_defined[128];
1392dd076b8SGabor Kovesdan /* #ifndef xyzzy */
1402dd076b8SGabor Kovesdan static char not_defined[128];
1412dd076b8SGabor Kovesdan /* #else */
1422dd076b8SGabor Kovesdan static const char else_defined[] = "#else\n";
1432dd076b8SGabor Kovesdan /* #endif xyzzy */
1442dd076b8SGabor Kovesdan static char end_defined[128];
1452dd076b8SGabor Kovesdan
1462dd076b8SGabor Kovesdan
1472dd076b8SGabor Kovesdan /* Apply a set of diffs as appropriate. */
1482dd076b8SGabor Kovesdan
1492dd076b8SGabor Kovesdan int
main(int argc,char * argv[])1502dd076b8SGabor Kovesdan main(int argc, char *argv[])
1512dd076b8SGabor Kovesdan {
152*50dacbf6SKyle Evans struct stat statbuf;
1532dd076b8SGabor Kovesdan int error = 0, hunk, failed, i, fd;
154*50dacbf6SKyle Evans bool out_creating, out_existed, patch_seen, remove_file;
155*50dacbf6SKyle Evans bool reverse_seen;
1562dd076b8SGabor Kovesdan LINENUM where = 0, newwhere, fuzz, mymaxfuzz;
1572dd076b8SGabor Kovesdan const char *tmpdir;
1582dd076b8SGabor Kovesdan char *v;
1592dd076b8SGabor Kovesdan
160ab761cdbSPedro F. Giffuni setvbuf(stdout, NULL, _IOLBF, 0);
161ab761cdbSPedro F. Giffuni setvbuf(stderr, NULL, _IOLBF, 0);
1622dd076b8SGabor Kovesdan for (i = 0; i < MAXFILEC; i++)
1632dd076b8SGabor Kovesdan filearg[i] = NULL;
1642dd076b8SGabor Kovesdan
1652dd076b8SGabor Kovesdan buf_size = INITLINELEN;
1662dd076b8SGabor Kovesdan buf = malloc((unsigned)(buf_size));
1672dd076b8SGabor Kovesdan if (buf == NULL)
1682dd076b8SGabor Kovesdan fatal("out of memory\n");
1692dd076b8SGabor Kovesdan
1702dd076b8SGabor Kovesdan /* Cons up the names of the temporary files. */
1712dd076b8SGabor Kovesdan if ((tmpdir = getenv("TMPDIR")) == NULL || *tmpdir == '\0')
1722dd076b8SGabor Kovesdan tmpdir = _PATH_TMP;
1732dd076b8SGabor Kovesdan for (i = strlen(tmpdir) - 1; i > 0 && tmpdir[i] == '/'; i--)
1742dd076b8SGabor Kovesdan ;
1752dd076b8SGabor Kovesdan i++;
1762dd076b8SGabor Kovesdan if (asprintf(&TMPOUTNAME, "%.*s/patchoXXXXXXXXXX", i, tmpdir) == -1)
1772dd076b8SGabor Kovesdan fatal("cannot allocate memory");
1782dd076b8SGabor Kovesdan if ((fd = mkstemp(TMPOUTNAME)) < 0)
1792dd076b8SGabor Kovesdan pfatal("can't create %s", TMPOUTNAME);
1802dd076b8SGabor Kovesdan close(fd);
1812dd076b8SGabor Kovesdan
1822dd076b8SGabor Kovesdan if (asprintf(&TMPINNAME, "%.*s/patchiXXXXXXXXXX", i, tmpdir) == -1)
1832dd076b8SGabor Kovesdan fatal("cannot allocate memory");
1842dd076b8SGabor Kovesdan if ((fd = mkstemp(TMPINNAME)) < 0)
1852dd076b8SGabor Kovesdan pfatal("can't create %s", TMPINNAME);
1862dd076b8SGabor Kovesdan close(fd);
1872dd076b8SGabor Kovesdan
1882dd076b8SGabor Kovesdan if (asprintf(&TMPREJNAME, "%.*s/patchrXXXXXXXXXX", i, tmpdir) == -1)
1892dd076b8SGabor Kovesdan fatal("cannot allocate memory");
1902dd076b8SGabor Kovesdan if ((fd = mkstemp(TMPREJNAME)) < 0)
1912dd076b8SGabor Kovesdan pfatal("can't create %s", TMPREJNAME);
1922dd076b8SGabor Kovesdan close(fd);
1932dd076b8SGabor Kovesdan
1942dd076b8SGabor Kovesdan if (asprintf(&TMPPATNAME, "%.*s/patchpXXXXXXXXXX", i, tmpdir) == -1)
1952dd076b8SGabor Kovesdan fatal("cannot allocate memory");
1962dd076b8SGabor Kovesdan if ((fd = mkstemp(TMPPATNAME)) < 0)
1972dd076b8SGabor Kovesdan pfatal("can't create %s", TMPPATNAME);
1982dd076b8SGabor Kovesdan close(fd);
1992dd076b8SGabor Kovesdan
2002dd076b8SGabor Kovesdan v = getenv("SIMPLE_BACKUP_SUFFIX");
2012dd076b8SGabor Kovesdan if (v)
2022dd076b8SGabor Kovesdan simple_backup_suffix = v;
2032dd076b8SGabor Kovesdan else
2042dd076b8SGabor Kovesdan simple_backup_suffix = ORIGEXT;
2052dd076b8SGabor Kovesdan
2062dd076b8SGabor Kovesdan /* parse switches */
2072dd076b8SGabor Kovesdan Argc = argc;
2082dd076b8SGabor Kovesdan Argv = argv;
2092dd076b8SGabor Kovesdan get_some_switches();
2102dd076b8SGabor Kovesdan
211300ca9a8SConrad Meyer if (!Vflag) {
2122dd076b8SGabor Kovesdan if ((v = getenv("PATCH_VERSION_CONTROL")) == NULL)
2132dd076b8SGabor Kovesdan v = getenv("VERSION_CONTROL");
2142dd076b8SGabor Kovesdan if (v != NULL || !posix)
2152dd076b8SGabor Kovesdan backup_type = get_version(v); /* OK to pass NULL. */
2162dd076b8SGabor Kovesdan }
2172dd076b8SGabor Kovesdan
2182dd076b8SGabor Kovesdan /* make sure we clean up /tmp in case of disaster */
2192dd076b8SGabor Kovesdan set_signals(0);
2202dd076b8SGabor Kovesdan
221e56ef7d3SXin LI patch_seen = false;
2222dd076b8SGabor Kovesdan for (open_patch_file(filearg[1]); there_is_another_patch();
2232dd076b8SGabor Kovesdan reinitialize_almost_everything()) {
2242dd076b8SGabor Kovesdan /* for each patch in patch file */
2252dd076b8SGabor Kovesdan
226*50dacbf6SKyle Evans if (source_file != NULL && (diff_type == CONTEXT_DIFF ||
227*50dacbf6SKyle Evans diff_type == NEW_CONTEXT_DIFF ||
228*50dacbf6SKyle Evans diff_type == UNI_DIFF))
229*50dacbf6SKyle Evans out_creating = strcmp(source_file, _PATH_DEVNULL) == 0;
230*50dacbf6SKyle Evans else
231*50dacbf6SKyle Evans out_creating = false;
232e56ef7d3SXin LI patch_seen = true;
233e56ef7d3SXin LI
2342dd076b8SGabor Kovesdan warn_on_invalid_line = true;
2352dd076b8SGabor Kovesdan
2362dd076b8SGabor Kovesdan if (outname == NULL)
237547e0acbSPedro F. Giffuni outname = xstrdup(filearg[0]);
2382dd076b8SGabor Kovesdan
239*50dacbf6SKyle Evans /*
240*50dacbf6SKyle Evans * At this point, we know if we're supposed to be creating the
241*50dacbf6SKyle Evans * file and we know if we should be trying to handle a conflict
242*50dacbf6SKyle Evans * between the patch and the file already existing. We defer
243*50dacbf6SKyle Evans * handling it until hunk processing because we want to swap
244*50dacbf6SKyle Evans * the hunk if they opt to reverse it, but we want to make sure
245*50dacbf6SKyle Evans * we *can* swap the hunk without running into memory issues
246*50dacbf6SKyle Evans * before we offer it. We also want to be verbose if flags or
247*50dacbf6SKyle Evans * user decision cause us to skip -- this is explained a little
248*50dacbf6SKyle Evans * more later.
249*50dacbf6SKyle Evans */
250*50dacbf6SKyle Evans out_existed = stat(outname, &statbuf) == 0;
251*50dacbf6SKyle Evans
2522dd076b8SGabor Kovesdan /* for ed script just up and do it and exit */
2532dd076b8SGabor Kovesdan if (diff_type == ED_DIFF) {
2542dd076b8SGabor Kovesdan do_ed_script();
2552dd076b8SGabor Kovesdan continue;
2562dd076b8SGabor Kovesdan }
2572dd076b8SGabor Kovesdan /* initialize the patched file */
2582dd076b8SGabor Kovesdan if (!skip_rest_of_patch)
2592dd076b8SGabor Kovesdan init_output(TMPOUTNAME);
2602dd076b8SGabor Kovesdan
2612dd076b8SGabor Kovesdan /* initialize reject file */
2622dd076b8SGabor Kovesdan init_reject(TMPREJNAME);
2632dd076b8SGabor Kovesdan
2642dd076b8SGabor Kovesdan /* find out where all the lines are */
2652dd076b8SGabor Kovesdan if (!skip_rest_of_patch)
2662dd076b8SGabor Kovesdan scan_input(filearg[0]);
2672dd076b8SGabor Kovesdan
268b9740ba1SPedro F. Giffuni /*
269b9740ba1SPedro F. Giffuni * from here on, open no standard i/o files, because
270b9740ba1SPedro F. Giffuni * malloc might misfire and we can't catch it easily
271b9740ba1SPedro F. Giffuni */
2722dd076b8SGabor Kovesdan
2732dd076b8SGabor Kovesdan /* apply each hunk of patch */
2742dd076b8SGabor Kovesdan hunk = 0;
2752dd076b8SGabor Kovesdan failed = 0;
276e11cd3bcSXin LI reverse_seen = false;
2772dd076b8SGabor Kovesdan out_of_mem = false;
278*50dacbf6SKyle Evans remove_file = false;
2792dd076b8SGabor Kovesdan while (another_hunk()) {
280*50dacbf6SKyle Evans assert(!out_creating || hunk == 0);
2812dd076b8SGabor Kovesdan hunk++;
2822dd076b8SGabor Kovesdan fuzz = 0;
283*50dacbf6SKyle Evans
284*50dacbf6SKyle Evans /*
285*50dacbf6SKyle Evans * There are only three cases in handle_creation() that
286*50dacbf6SKyle Evans * results in us skipping hunk location, in order:
287*50dacbf6SKyle Evans *
288*50dacbf6SKyle Evans * 1.) Potentially reversed but -f/--force'd,
289*50dacbf6SKyle Evans * 2.) Potentially reversed but -N/--forward'd
290*50dacbf6SKyle Evans * 3.) Reversed and the user's opted to not apply it.
291*50dacbf6SKyle Evans *
292*50dacbf6SKyle Evans * In all three cases, we still want to inform the user
293*50dacbf6SKyle Evans * that we're ignoring it in the standard way, which is
294*50dacbf6SKyle Evans * also tied to this hunk processing loop.
295*50dacbf6SKyle Evans */
296*50dacbf6SKyle Evans if (out_creating)
297*50dacbf6SKyle Evans reverse_seen = handle_creation(out_existed,
298*50dacbf6SKyle Evans &remove_file);
299*50dacbf6SKyle Evans
3002dd076b8SGabor Kovesdan mymaxfuzz = pch_context();
3012dd076b8SGabor Kovesdan if (maxfuzz < mymaxfuzz)
3022dd076b8SGabor Kovesdan mymaxfuzz = maxfuzz;
3032dd076b8SGabor Kovesdan if (!skip_rest_of_patch) {
3042dd076b8SGabor Kovesdan do {
3052dd076b8SGabor Kovesdan where = locate_hunk(fuzz);
306e11cd3bcSXin LI if (hunk == 1 && where == 0 && !force && !reverse_seen) {
3072dd076b8SGabor Kovesdan /* dwim for reversed patch? */
3082dd076b8SGabor Kovesdan if (!pch_swap()) {
3092dd076b8SGabor Kovesdan if (fuzz == 0)
3102dd076b8SGabor Kovesdan say("Not enough memory to try swapped hunk! Assuming unswapped.\n");
3112dd076b8SGabor Kovesdan continue;
3122dd076b8SGabor Kovesdan }
3132dd076b8SGabor Kovesdan reverse = !reverse;
3142dd076b8SGabor Kovesdan /* try again */
3152dd076b8SGabor Kovesdan where = locate_hunk(fuzz);
3162dd076b8SGabor Kovesdan if (where == 0) {
3172dd076b8SGabor Kovesdan /* didn't find it swapped */
3182dd076b8SGabor Kovesdan if (!pch_swap())
3192dd076b8SGabor Kovesdan /* put it back to normal */
3202dd076b8SGabor Kovesdan fatal("lost hunk on alloc error!\n");
3212dd076b8SGabor Kovesdan reverse = !reverse;
3222dd076b8SGabor Kovesdan } else if (noreverse) {
3232dd076b8SGabor Kovesdan if (!pch_swap())
3242dd076b8SGabor Kovesdan /* put it back to normal */
3252dd076b8SGabor Kovesdan fatal("lost hunk on alloc error!\n");
3262dd076b8SGabor Kovesdan reverse = !reverse;
3272dd076b8SGabor Kovesdan say("Ignoring previously applied (or reversed) patch.\n");
3282dd076b8SGabor Kovesdan skip_rest_of_patch = true;
3292dd076b8SGabor Kovesdan } else if (batch) {
3302dd076b8SGabor Kovesdan if (verbose)
3312dd076b8SGabor Kovesdan say("%seversed (or previously applied) patch detected! %s -R.",
3322dd076b8SGabor Kovesdan reverse ? "R" : "Unr",
3332dd076b8SGabor Kovesdan reverse ? "Assuming" : "Ignoring");
3342dd076b8SGabor Kovesdan } else {
3352dd076b8SGabor Kovesdan ask("%seversed (or previously applied) patch detected! %s -R? [y] ",
3362dd076b8SGabor Kovesdan reverse ? "R" : "Unr",
3372dd076b8SGabor Kovesdan reverse ? "Assume" : "Ignore");
3382dd076b8SGabor Kovesdan if (*buf == 'n') {
3392dd076b8SGabor Kovesdan ask("Apply anyway? [n] ");
3402dd076b8SGabor Kovesdan if (*buf != 'y')
3412dd076b8SGabor Kovesdan skip_rest_of_patch = true;
342e11cd3bcSXin LI else
343e11cd3bcSXin LI reverse_seen = true;
3442dd076b8SGabor Kovesdan where = 0;
3452dd076b8SGabor Kovesdan reverse = !reverse;
3462dd076b8SGabor Kovesdan if (!pch_swap())
3472dd076b8SGabor Kovesdan /* put it back to normal */
3482dd076b8SGabor Kovesdan fatal("lost hunk on alloc error!\n");
3492dd076b8SGabor Kovesdan }
3502dd076b8SGabor Kovesdan }
3512dd076b8SGabor Kovesdan }
3522dd076b8SGabor Kovesdan } while (!skip_rest_of_patch && where == 0 &&
3532dd076b8SGabor Kovesdan ++fuzz <= mymaxfuzz);
3542dd076b8SGabor Kovesdan
3552dd076b8SGabor Kovesdan if (skip_rest_of_patch) { /* just got decided */
356ffca5883SGlen Barber if (ferror(ofp) || fclose(ofp)) {
3572dd076b8SGabor Kovesdan say("Error writing %s\n",
3582dd076b8SGabor Kovesdan TMPOUTNAME);
3592dd076b8SGabor Kovesdan error = 1;
3602dd076b8SGabor Kovesdan }
3612dd076b8SGabor Kovesdan ofp = NULL;
3622dd076b8SGabor Kovesdan }
3632dd076b8SGabor Kovesdan }
3642dd076b8SGabor Kovesdan newwhere = pch_newfirst() + last_offset;
3652dd076b8SGabor Kovesdan if (skip_rest_of_patch) {
3662dd076b8SGabor Kovesdan abort_hunk();
3672dd076b8SGabor Kovesdan failed++;
3682dd076b8SGabor Kovesdan if (verbose)
3692dd076b8SGabor Kovesdan say("Hunk #%d ignored at %ld.\n",
3702dd076b8SGabor Kovesdan hunk, newwhere);
3712dd076b8SGabor Kovesdan } else if (where == 0) {
3722dd076b8SGabor Kovesdan abort_hunk();
3732dd076b8SGabor Kovesdan failed++;
3742dd076b8SGabor Kovesdan if (verbose)
3752dd076b8SGabor Kovesdan say("Hunk #%d failed at %ld.\n",
3762dd076b8SGabor Kovesdan hunk, newwhere);
3772dd076b8SGabor Kovesdan } else {
3782dd076b8SGabor Kovesdan apply_hunk(where);
3792dd076b8SGabor Kovesdan if (verbose) {
3802dd076b8SGabor Kovesdan say("Hunk #%d succeeded at %ld",
3812dd076b8SGabor Kovesdan hunk, newwhere);
3822dd076b8SGabor Kovesdan if (fuzz != 0)
3832dd076b8SGabor Kovesdan say(" with fuzz %ld", fuzz);
3842dd076b8SGabor Kovesdan if (last_offset)
3852dd076b8SGabor Kovesdan say(" (offset %ld line%s)",
3862dd076b8SGabor Kovesdan last_offset,
3872dd076b8SGabor Kovesdan last_offset == 1L ? "" : "s");
3882dd076b8SGabor Kovesdan say(".\n");
3892dd076b8SGabor Kovesdan }
3902dd076b8SGabor Kovesdan }
3912dd076b8SGabor Kovesdan }
3922dd076b8SGabor Kovesdan
3932dd076b8SGabor Kovesdan if (out_of_mem && using_plan_a) {
3942dd076b8SGabor Kovesdan Argc = Argc_last;
3952dd076b8SGabor Kovesdan Argv = Argv_last;
3962dd076b8SGabor Kovesdan say("\n\nRan out of memory using Plan A--trying again...\n\n");
3972dd076b8SGabor Kovesdan if (ofp)
3982dd076b8SGabor Kovesdan fclose(ofp);
3992dd076b8SGabor Kovesdan ofp = NULL;
4002dd076b8SGabor Kovesdan if (rejfp)
4012dd076b8SGabor Kovesdan fclose(rejfp);
4022dd076b8SGabor Kovesdan rejfp = NULL;
4032dd076b8SGabor Kovesdan continue;
4042dd076b8SGabor Kovesdan }
4052dd076b8SGabor Kovesdan if (hunk == 0)
4062dd076b8SGabor Kovesdan fatal("Internal error: hunk should not be 0\n");
4072dd076b8SGabor Kovesdan
4082dd076b8SGabor Kovesdan /* finish spewing out the new file */
4092dd076b8SGabor Kovesdan if (!skip_rest_of_patch && !spew_output()) {
4102dd076b8SGabor Kovesdan say("Can't write %s\n", TMPOUTNAME);
4112dd076b8SGabor Kovesdan error = 1;
4122dd076b8SGabor Kovesdan }
4132dd076b8SGabor Kovesdan
4142dd076b8SGabor Kovesdan /* and put the output where desired */
4152dd076b8SGabor Kovesdan ignore_signals();
4162dd076b8SGabor Kovesdan if (!skip_rest_of_patch) {
4172dd076b8SGabor Kovesdan char *realout = outname;
4182dd076b8SGabor Kovesdan
4192dd076b8SGabor Kovesdan if (!check_only) {
4202dd076b8SGabor Kovesdan if (move_file(TMPOUTNAME, outname) < 0) {
4212dd076b8SGabor Kovesdan toutkeep = true;
4222dd076b8SGabor Kovesdan realout = TMPOUTNAME;
4232dd076b8SGabor Kovesdan chmod(TMPOUTNAME, filemode);
4242dd076b8SGabor Kovesdan } else
4252dd076b8SGabor Kovesdan chmod(outname, filemode);
4262dd076b8SGabor Kovesdan
427*50dacbf6SKyle Evans /*
428*50dacbf6SKyle Evans * remove_file is a per-patch flag indicating
429*50dacbf6SKyle Evans * whether it's OK to remove the empty file.
430*50dacbf6SKyle Evans * This is specifically set when we're reversing
431*50dacbf6SKyle Evans * the creation of a file and it ends up empty.
432*50dacbf6SKyle Evans * This is an exception to the global policy
433*50dacbf6SKyle Evans * (remove_empty_files) because the user would
434*50dacbf6SKyle Evans * likely not expect the reverse of file
435*50dacbf6SKyle Evans * creation to leave an empty file laying
436*50dacbf6SKyle Evans * around.
437*50dacbf6SKyle Evans */
438*50dacbf6SKyle Evans if ((remove_empty_files || remove_file) &&
4392dd076b8SGabor Kovesdan stat(realout, &statbuf) == 0 &&
4402dd076b8SGabor Kovesdan statbuf.st_size == 0) {
4412dd076b8SGabor Kovesdan if (verbose)
4422dd076b8SGabor Kovesdan say("Removing %s (empty after patching).\n",
4432dd076b8SGabor Kovesdan realout);
4442dd076b8SGabor Kovesdan unlink(realout);
4452dd076b8SGabor Kovesdan }
4462dd076b8SGabor Kovesdan }
4472dd076b8SGabor Kovesdan }
448ffca5883SGlen Barber if (ferror(rejfp) || fclose(rejfp)) {
4492dd076b8SGabor Kovesdan say("Error writing %s\n", rejname);
4502dd076b8SGabor Kovesdan error = 1;
4512dd076b8SGabor Kovesdan }
4522dd076b8SGabor Kovesdan rejfp = NULL;
4532dd076b8SGabor Kovesdan if (failed) {
4542dd076b8SGabor Kovesdan error = 1;
4552dd076b8SGabor Kovesdan if (*rejname == '\0') {
4562dd076b8SGabor Kovesdan if (strlcpy(rejname, outname,
4572dd076b8SGabor Kovesdan sizeof(rejname)) >= sizeof(rejname))
4582dd076b8SGabor Kovesdan fatal("filename %s is too long\n", outname);
4592dd076b8SGabor Kovesdan if (strlcat(rejname, REJEXT,
4602dd076b8SGabor Kovesdan sizeof(rejname)) >= sizeof(rejname))
4612dd076b8SGabor Kovesdan fatal("filename %s is too long\n", outname);
4622dd076b8SGabor Kovesdan }
463e56ef7d3SXin LI if (!check_only)
464e56ef7d3SXin LI say("%d out of %d hunks %s--saving rejects to %s\n",
465e56ef7d3SXin LI failed, hunk, skip_rest_of_patch ? "ignored" : "failed", rejname);
466e56ef7d3SXin LI else
467e11cd3bcSXin LI say("%d out of %d hunks %s while patching %s\n",
468e11cd3bcSXin LI failed, hunk, skip_rest_of_patch ? "ignored" : "failed", filearg[0]);
4692dd076b8SGabor Kovesdan if (!check_only && move_file(TMPREJNAME, rejname) < 0)
4702dd076b8SGabor Kovesdan trejkeep = true;
4712dd076b8SGabor Kovesdan }
4722dd076b8SGabor Kovesdan set_signals(1);
4732dd076b8SGabor Kovesdan }
474e56ef7d3SXin LI
475ef30b5a8SKyle Evans if (!patch_seen && nonempty_patchf_seen)
476e56ef7d3SXin LI error = 2;
477e56ef7d3SXin LI
4782dd076b8SGabor Kovesdan my_exit(error);
4792dd076b8SGabor Kovesdan /* NOTREACHED */
4802dd076b8SGabor Kovesdan }
4812dd076b8SGabor Kovesdan
4822dd076b8SGabor Kovesdan /* Prepare to find the next patch to do in the patch file. */
4832dd076b8SGabor Kovesdan
4842dd076b8SGabor Kovesdan static void
reinitialize_almost_everything(void)4852dd076b8SGabor Kovesdan reinitialize_almost_everything(void)
4862dd076b8SGabor Kovesdan {
4872dd076b8SGabor Kovesdan re_patch();
4882dd076b8SGabor Kovesdan re_input();
4892dd076b8SGabor Kovesdan
4902dd076b8SGabor Kovesdan input_lines = 0;
4912dd076b8SGabor Kovesdan last_frozen_line = 0;
4922dd076b8SGabor Kovesdan
4932dd076b8SGabor Kovesdan filec = 0;
4942dd076b8SGabor Kovesdan if (!out_of_mem) {
4952dd076b8SGabor Kovesdan free(filearg[0]);
4962dd076b8SGabor Kovesdan filearg[0] = NULL;
4972dd076b8SGabor Kovesdan }
4982dd076b8SGabor Kovesdan
499*50dacbf6SKyle Evans free(source_file);
500*50dacbf6SKyle Evans source_file = NULL;
501*50dacbf6SKyle Evans
5022dd076b8SGabor Kovesdan free(outname);
5032dd076b8SGabor Kovesdan outname = NULL;
5042dd076b8SGabor Kovesdan
5052dd076b8SGabor Kovesdan last_offset = 0;
5062dd076b8SGabor Kovesdan diff_type = 0;
5072dd076b8SGabor Kovesdan
5082dd076b8SGabor Kovesdan free(revision);
5092dd076b8SGabor Kovesdan revision = NULL;
5102dd076b8SGabor Kovesdan
5112dd076b8SGabor Kovesdan reverse = reverse_flag_specified;
5122dd076b8SGabor Kovesdan skip_rest_of_patch = false;
5132dd076b8SGabor Kovesdan
5142dd076b8SGabor Kovesdan get_some_switches();
5152dd076b8SGabor Kovesdan }
5162dd076b8SGabor Kovesdan
5172dd076b8SGabor Kovesdan /* Process switches and filenames. */
5182dd076b8SGabor Kovesdan
5192dd076b8SGabor Kovesdan static void
get_some_switches(void)5202dd076b8SGabor Kovesdan get_some_switches(void)
5212dd076b8SGabor Kovesdan {
5222dd076b8SGabor Kovesdan const char *options = "b::B:cCd:D:eEfF:i:lnNo:p:r:RstuvV:x:z:";
5232dd076b8SGabor Kovesdan static struct option longopts[] = {
5242dd076b8SGabor Kovesdan {"backup", no_argument, 0, 'b'},
5252dd076b8SGabor Kovesdan {"batch", no_argument, 0, 't'},
5262dd076b8SGabor Kovesdan {"check", no_argument, 0, 'C'},
5272dd076b8SGabor Kovesdan {"context", no_argument, 0, 'c'},
5282dd076b8SGabor Kovesdan {"debug", required_argument, 0, 'x'},
5292dd076b8SGabor Kovesdan {"directory", required_argument, 0, 'd'},
5305e64d66cSPedro F. Giffuni {"dry-run", no_argument, 0, 'C'},
5312dd076b8SGabor Kovesdan {"ed", no_argument, 0, 'e'},
5322dd076b8SGabor Kovesdan {"force", no_argument, 0, 'f'},
5332dd076b8SGabor Kovesdan {"forward", no_argument, 0, 'N'},
5342dd076b8SGabor Kovesdan {"fuzz", required_argument, 0, 'F'},
5352dd076b8SGabor Kovesdan {"ifdef", required_argument, 0, 'D'},
5362dd076b8SGabor Kovesdan {"input", required_argument, 0, 'i'},
5372dd076b8SGabor Kovesdan {"ignore-whitespace", no_argument, 0, 'l'},
5382dd076b8SGabor Kovesdan {"normal", no_argument, 0, 'n'},
5392dd076b8SGabor Kovesdan {"output", required_argument, 0, 'o'},
5402dd076b8SGabor Kovesdan {"prefix", required_argument, 0, 'B'},
5412dd076b8SGabor Kovesdan {"quiet", no_argument, 0, 's'},
5422dd076b8SGabor Kovesdan {"reject-file", required_argument, 0, 'r'},
5432dd076b8SGabor Kovesdan {"remove-empty-files", no_argument, 0, 'E'},
5442dd076b8SGabor Kovesdan {"reverse", no_argument, 0, 'R'},
5452dd076b8SGabor Kovesdan {"silent", no_argument, 0, 's'},
5462dd076b8SGabor Kovesdan {"strip", required_argument, 0, 'p'},
5472dd076b8SGabor Kovesdan {"suffix", required_argument, 0, 'z'},
5482dd076b8SGabor Kovesdan {"unified", no_argument, 0, 'u'},
5492dd076b8SGabor Kovesdan {"version", no_argument, 0, 'v'},
5502dd076b8SGabor Kovesdan {"version-control", required_argument, 0, 'V'},
5512dd076b8SGabor Kovesdan {"posix", no_argument, &posix, 1},
5522dd076b8SGabor Kovesdan {NULL, 0, 0, 0}
5532dd076b8SGabor Kovesdan };
5542dd076b8SGabor Kovesdan int ch;
5552dd076b8SGabor Kovesdan
5562dd076b8SGabor Kovesdan rejname[0] = '\0';
5572dd076b8SGabor Kovesdan Argc_last = Argc;
5582dd076b8SGabor Kovesdan Argv_last = Argv;
5592dd076b8SGabor Kovesdan if (!Argc)
5602dd076b8SGabor Kovesdan return;
5612dd076b8SGabor Kovesdan optreset = optind = 1;
5622dd076b8SGabor Kovesdan while ((ch = getopt_long(Argc, Argv, options, longopts, NULL)) != -1) {
5632dd076b8SGabor Kovesdan switch (ch) {
5642dd076b8SGabor Kovesdan case 'b':
5652dd076b8SGabor Kovesdan if (backup_type == none)
5662dd076b8SGabor Kovesdan backup_type = numbered_existing;
5672dd076b8SGabor Kovesdan if (optarg == NULL)
5682dd076b8SGabor Kovesdan break;
5692dd076b8SGabor Kovesdan if (verbose)
5702dd076b8SGabor Kovesdan say("Warning, the ``-b suffix'' option has been"
5712dd076b8SGabor Kovesdan " obsoleted by the -z option.\n");
5722dd076b8SGabor Kovesdan /* FALLTHROUGH */
5732dd076b8SGabor Kovesdan case 'z':
5742dd076b8SGabor Kovesdan /* must directly follow 'b' case for backwards compat */
575547e0acbSPedro F. Giffuni simple_backup_suffix = xstrdup(optarg);
5762dd076b8SGabor Kovesdan break;
5772dd076b8SGabor Kovesdan case 'B':
578547e0acbSPedro F. Giffuni origprae = xstrdup(optarg);
5792dd076b8SGabor Kovesdan break;
5802dd076b8SGabor Kovesdan case 'c':
5812dd076b8SGabor Kovesdan diff_type = CONTEXT_DIFF;
5822dd076b8SGabor Kovesdan break;
5832dd076b8SGabor Kovesdan case 'C':
5842dd076b8SGabor Kovesdan check_only = true;
5852dd076b8SGabor Kovesdan break;
5862dd076b8SGabor Kovesdan case 'd':
5872dd076b8SGabor Kovesdan if (chdir(optarg) < 0)
5882dd076b8SGabor Kovesdan pfatal("can't cd to %s", optarg);
5892dd076b8SGabor Kovesdan break;
5902dd076b8SGabor Kovesdan case 'D':
5912dd076b8SGabor Kovesdan do_defines = true;
5922dd076b8SGabor Kovesdan if (!isalpha((unsigned char)*optarg) && *optarg != '_')
5932dd076b8SGabor Kovesdan fatal("argument to -D is not an identifier\n");
5942dd076b8SGabor Kovesdan snprintf(if_defined, sizeof if_defined,
5952dd076b8SGabor Kovesdan "#ifdef %s\n", optarg);
5962dd076b8SGabor Kovesdan snprintf(not_defined, sizeof not_defined,
5972dd076b8SGabor Kovesdan "#ifndef %s\n", optarg);
5982dd076b8SGabor Kovesdan snprintf(end_defined, sizeof end_defined,
5992dd076b8SGabor Kovesdan "#endif /* %s */\n", optarg);
6002dd076b8SGabor Kovesdan break;
6012dd076b8SGabor Kovesdan case 'e':
6022dd076b8SGabor Kovesdan diff_type = ED_DIFF;
6032dd076b8SGabor Kovesdan break;
6042dd076b8SGabor Kovesdan case 'E':
6052dd076b8SGabor Kovesdan remove_empty_files = true;
6062dd076b8SGabor Kovesdan break;
6072dd076b8SGabor Kovesdan case 'f':
6082dd076b8SGabor Kovesdan force = true;
6092dd076b8SGabor Kovesdan break;
6102dd076b8SGabor Kovesdan case 'F':
6112dd076b8SGabor Kovesdan maxfuzz = atoi(optarg);
6122dd076b8SGabor Kovesdan break;
6132dd076b8SGabor Kovesdan case 'i':
6142dd076b8SGabor Kovesdan if (++filec == MAXFILEC)
6152dd076b8SGabor Kovesdan fatal("too many file arguments\n");
616547e0acbSPedro F. Giffuni filearg[filec] = xstrdup(optarg);
6172dd076b8SGabor Kovesdan break;
6182dd076b8SGabor Kovesdan case 'l':
6192dd076b8SGabor Kovesdan canonicalize = true;
6202dd076b8SGabor Kovesdan break;
6212dd076b8SGabor Kovesdan case 'n':
6222dd076b8SGabor Kovesdan diff_type = NORMAL_DIFF;
6232dd076b8SGabor Kovesdan break;
6242dd076b8SGabor Kovesdan case 'N':
6252dd076b8SGabor Kovesdan noreverse = true;
6262dd076b8SGabor Kovesdan break;
6272dd076b8SGabor Kovesdan case 'o':
628547e0acbSPedro F. Giffuni outname = xstrdup(optarg);
6292dd076b8SGabor Kovesdan break;
6302dd076b8SGabor Kovesdan case 'p':
6312dd076b8SGabor Kovesdan strippath = atoi(optarg);
6322dd076b8SGabor Kovesdan break;
6332dd076b8SGabor Kovesdan case 'r':
6342dd076b8SGabor Kovesdan if (strlcpy(rejname, optarg,
6352dd076b8SGabor Kovesdan sizeof(rejname)) >= sizeof(rejname))
6362dd076b8SGabor Kovesdan fatal("argument for -r is too long\n");
6372dd076b8SGabor Kovesdan break;
6382dd076b8SGabor Kovesdan case 'R':
6392dd076b8SGabor Kovesdan reverse = true;
6402dd076b8SGabor Kovesdan reverse_flag_specified = true;
6412dd076b8SGabor Kovesdan break;
6422dd076b8SGabor Kovesdan case 's':
6432dd076b8SGabor Kovesdan verbose = false;
6442dd076b8SGabor Kovesdan break;
6452dd076b8SGabor Kovesdan case 't':
6462dd076b8SGabor Kovesdan batch = true;
6472dd076b8SGabor Kovesdan break;
6482dd076b8SGabor Kovesdan case 'u':
6492dd076b8SGabor Kovesdan diff_type = UNI_DIFF;
6502dd076b8SGabor Kovesdan break;
6512dd076b8SGabor Kovesdan case 'v':
6522dd076b8SGabor Kovesdan version();
6532dd076b8SGabor Kovesdan break;
6542dd076b8SGabor Kovesdan case 'V':
6552dd076b8SGabor Kovesdan backup_type = get_version(optarg);
656300ca9a8SConrad Meyer Vflag = true;
6572dd076b8SGabor Kovesdan break;
6582dd076b8SGabor Kovesdan #ifdef DEBUGGING
6592dd076b8SGabor Kovesdan case 'x':
6602dd076b8SGabor Kovesdan debug = atoi(optarg);
6612dd076b8SGabor Kovesdan break;
6622dd076b8SGabor Kovesdan #endif
6632dd076b8SGabor Kovesdan default:
6642dd076b8SGabor Kovesdan if (ch != '\0')
6652dd076b8SGabor Kovesdan usage();
6662dd076b8SGabor Kovesdan break;
6672dd076b8SGabor Kovesdan }
6682dd076b8SGabor Kovesdan }
6692dd076b8SGabor Kovesdan Argc -= optind;
6702dd076b8SGabor Kovesdan Argv += optind;
6712dd076b8SGabor Kovesdan
6722dd076b8SGabor Kovesdan if (Argc > 0) {
673547e0acbSPedro F. Giffuni filearg[0] = xstrdup(*Argv++);
6742dd076b8SGabor Kovesdan Argc--;
6752dd076b8SGabor Kovesdan while (Argc > 0) {
6762dd076b8SGabor Kovesdan if (++filec == MAXFILEC)
6772dd076b8SGabor Kovesdan fatal("too many file arguments\n");
678547e0acbSPedro F. Giffuni filearg[filec] = xstrdup(*Argv++);
6792dd076b8SGabor Kovesdan Argc--;
6802dd076b8SGabor Kovesdan }
6812dd076b8SGabor Kovesdan }
6822dd076b8SGabor Kovesdan
6832dd076b8SGabor Kovesdan if (getenv("POSIXLY_CORRECT") != NULL)
6842dd076b8SGabor Kovesdan posix = 1;
6852dd076b8SGabor Kovesdan }
6862dd076b8SGabor Kovesdan
6872dd076b8SGabor Kovesdan static void
usage(void)6882dd076b8SGabor Kovesdan usage(void)
6892dd076b8SGabor Kovesdan {
6902dd076b8SGabor Kovesdan fprintf(stderr,
6912dd076b8SGabor Kovesdan "usage: patch [-bCcEeflNnRstuv] [-B backup-prefix] [-D symbol] [-d directory]\n"
6922dd076b8SGabor Kovesdan " [-F max-fuzz] [-i patchfile] [-o out-file] [-p strip-count]\n"
693300ca9a8SConrad Meyer " [-r rej-name] [-V t | nil | never | none] [-x number]\n"
694300ca9a8SConrad Meyer " [-z backup-ext] [--posix] [origfile [patchfile]]\n"
6952dd076b8SGabor Kovesdan " patch <patchfile\n");
696f718bedcSPedro F. Giffuni my_exit(EXIT_FAILURE);
6972dd076b8SGabor Kovesdan }
6982dd076b8SGabor Kovesdan
6992dd076b8SGabor Kovesdan /*
7002dd076b8SGabor Kovesdan * Attempt to find the right place to apply this hunk of patch.
7012dd076b8SGabor Kovesdan */
7022dd076b8SGabor Kovesdan static LINENUM
locate_hunk(LINENUM fuzz)7032dd076b8SGabor Kovesdan locate_hunk(LINENUM fuzz)
7042dd076b8SGabor Kovesdan {
7052dd076b8SGabor Kovesdan LINENUM first_guess = pch_first() + last_offset;
7062dd076b8SGabor Kovesdan LINENUM offset;
7072dd076b8SGabor Kovesdan LINENUM pat_lines = pch_ptrn_lines();
7082dd076b8SGabor Kovesdan LINENUM max_pos_offset = input_lines - first_guess - pat_lines + 1;
7092dd076b8SGabor Kovesdan LINENUM max_neg_offset = first_guess - last_frozen_line - 1 + pch_context();
7102dd076b8SGabor Kovesdan
7112dd076b8SGabor Kovesdan if (pat_lines == 0) { /* null range matches always */
7122dd076b8SGabor Kovesdan if (verbose && fuzz == 0 && (diff_type == CONTEXT_DIFF
7132dd076b8SGabor Kovesdan || diff_type == NEW_CONTEXT_DIFF
7142dd076b8SGabor Kovesdan || diff_type == UNI_DIFF)) {
7152dd076b8SGabor Kovesdan say("Empty context always matches.\n");
7162dd076b8SGabor Kovesdan }
7172dd076b8SGabor Kovesdan return (first_guess);
7182dd076b8SGabor Kovesdan }
7192dd076b8SGabor Kovesdan if (max_neg_offset >= first_guess) /* do not try lines < 0 */
7202dd076b8SGabor Kovesdan max_neg_offset = first_guess - 1;
7212dd076b8SGabor Kovesdan if (first_guess <= input_lines && patch_match(first_guess, 0, fuzz))
7222dd076b8SGabor Kovesdan return first_guess;
7232dd076b8SGabor Kovesdan for (offset = 1; ; offset++) {
7242dd076b8SGabor Kovesdan bool check_after = (offset <= max_pos_offset);
7252dd076b8SGabor Kovesdan bool check_before = (offset <= max_neg_offset);
7262dd076b8SGabor Kovesdan
7272dd076b8SGabor Kovesdan if (check_after && patch_match(first_guess, offset, fuzz)) {
7282dd076b8SGabor Kovesdan #ifdef DEBUGGING
7292dd076b8SGabor Kovesdan if (debug & 1)
7302dd076b8SGabor Kovesdan say("Offset changing from %ld to %ld\n",
7312dd076b8SGabor Kovesdan last_offset, offset);
7322dd076b8SGabor Kovesdan #endif
7332dd076b8SGabor Kovesdan last_offset = offset;
7342dd076b8SGabor Kovesdan return first_guess + offset;
7352dd076b8SGabor Kovesdan } else if (check_before && patch_match(first_guess, -offset, fuzz)) {
7362dd076b8SGabor Kovesdan #ifdef DEBUGGING
7372dd076b8SGabor Kovesdan if (debug & 1)
7382dd076b8SGabor Kovesdan say("Offset changing from %ld to %ld\n",
7392dd076b8SGabor Kovesdan last_offset, -offset);
7402dd076b8SGabor Kovesdan #endif
7412dd076b8SGabor Kovesdan last_offset = -offset;
7422dd076b8SGabor Kovesdan return first_guess - offset;
7432dd076b8SGabor Kovesdan } else if (!check_before && !check_after)
7442dd076b8SGabor Kovesdan return 0;
7452dd076b8SGabor Kovesdan }
7462dd076b8SGabor Kovesdan }
7472dd076b8SGabor Kovesdan
7482dd076b8SGabor Kovesdan /* We did not find the pattern, dump out the hunk so they can handle it. */
7492dd076b8SGabor Kovesdan
7502dd076b8SGabor Kovesdan static void
abort_context_hunk(void)7512dd076b8SGabor Kovesdan abort_context_hunk(void)
7522dd076b8SGabor Kovesdan {
7532dd076b8SGabor Kovesdan LINENUM i;
7542dd076b8SGabor Kovesdan const LINENUM pat_end = pch_end();
7552dd076b8SGabor Kovesdan /*
7562dd076b8SGabor Kovesdan * add in last_offset to guess the same as the previous successful
7572dd076b8SGabor Kovesdan * hunk
7582dd076b8SGabor Kovesdan */
7592dd076b8SGabor Kovesdan const LINENUM oldfirst = pch_first() + last_offset;
7602dd076b8SGabor Kovesdan const LINENUM newfirst = pch_newfirst() + last_offset;
7612dd076b8SGabor Kovesdan const LINENUM oldlast = oldfirst + pch_ptrn_lines() - 1;
7622dd076b8SGabor Kovesdan const LINENUM newlast = newfirst + pch_repl_lines() - 1;
7632dd076b8SGabor Kovesdan const char *stars = (diff_type >= NEW_CONTEXT_DIFF ? " ****" : "");
7642dd076b8SGabor Kovesdan const char *minuses = (diff_type >= NEW_CONTEXT_DIFF ? " ----" : " -----");
7652dd076b8SGabor Kovesdan
7662dd076b8SGabor Kovesdan fprintf(rejfp, "***************\n");
7672dd076b8SGabor Kovesdan for (i = 0; i <= pat_end; i++) {
7682dd076b8SGabor Kovesdan switch (pch_char(i)) {
7692dd076b8SGabor Kovesdan case '*':
7702dd076b8SGabor Kovesdan if (oldlast < oldfirst)
7712dd076b8SGabor Kovesdan fprintf(rejfp, "*** 0%s\n", stars);
7722dd076b8SGabor Kovesdan else if (oldlast == oldfirst)
7732dd076b8SGabor Kovesdan fprintf(rejfp, "*** %ld%s\n", oldfirst, stars);
7742dd076b8SGabor Kovesdan else
7752dd076b8SGabor Kovesdan fprintf(rejfp, "*** %ld,%ld%s\n", oldfirst,
7762dd076b8SGabor Kovesdan oldlast, stars);
7772dd076b8SGabor Kovesdan break;
7782dd076b8SGabor Kovesdan case '=':
7792dd076b8SGabor Kovesdan if (newlast < newfirst)
7802dd076b8SGabor Kovesdan fprintf(rejfp, "--- 0%s\n", minuses);
7812dd076b8SGabor Kovesdan else if (newlast == newfirst)
7822dd076b8SGabor Kovesdan fprintf(rejfp, "--- %ld%s\n", newfirst, minuses);
7832dd076b8SGabor Kovesdan else
7842dd076b8SGabor Kovesdan fprintf(rejfp, "--- %ld,%ld%s\n", newfirst,
7852dd076b8SGabor Kovesdan newlast, minuses);
7862dd076b8SGabor Kovesdan break;
7872dd076b8SGabor Kovesdan case '\n':
7882dd076b8SGabor Kovesdan fprintf(rejfp, "%s", pfetch(i));
7892dd076b8SGabor Kovesdan break;
7902dd076b8SGabor Kovesdan case ' ':
7912dd076b8SGabor Kovesdan case '-':
7922dd076b8SGabor Kovesdan case '+':
7932dd076b8SGabor Kovesdan case '!':
7942dd076b8SGabor Kovesdan fprintf(rejfp, "%c %s", pch_char(i), pfetch(i));
7952dd076b8SGabor Kovesdan break;
7962dd076b8SGabor Kovesdan default:
7972dd076b8SGabor Kovesdan fatal("fatal internal error in abort_context_hunk\n");
7982dd076b8SGabor Kovesdan }
7992dd076b8SGabor Kovesdan }
8002dd076b8SGabor Kovesdan }
8012dd076b8SGabor Kovesdan
8022dd076b8SGabor Kovesdan static void
rej_line(int ch,LINENUM i)8032dd076b8SGabor Kovesdan rej_line(int ch, LINENUM i)
8042dd076b8SGabor Kovesdan {
8053548708cSPedro F. Giffuni size_t len;
8062dd076b8SGabor Kovesdan const char *line = pfetch(i);
8072dd076b8SGabor Kovesdan
808fa812237SPedro F. Giffuni len = strlen(line);
8092dd076b8SGabor Kovesdan
8102dd076b8SGabor Kovesdan fprintf(rejfp, "%c%s", ch, line);
8114f548c19SPedro F. Giffuni if (len == 0 || line[len - 1] != '\n') {
8124f548c19SPedro F. Giffuni if (len >= USHRT_MAX)
813ad8469feSPedro F. Giffuni fprintf(rejfp, "\n\\ Line too long\n");
8144f548c19SPedro F. Giffuni else
8154f548c19SPedro F. Giffuni fprintf(rejfp, "\n\\ No newline at end of line\n");
8164f548c19SPedro F. Giffuni }
8172dd076b8SGabor Kovesdan }
8182dd076b8SGabor Kovesdan
8192dd076b8SGabor Kovesdan static void
abort_hunk(void)8202dd076b8SGabor Kovesdan abort_hunk(void)
8212dd076b8SGabor Kovesdan {
8222dd076b8SGabor Kovesdan LINENUM i, j, split;
8232dd076b8SGabor Kovesdan int ch1, ch2;
8242dd076b8SGabor Kovesdan const LINENUM pat_end = pch_end();
8252dd076b8SGabor Kovesdan const LINENUM oldfirst = pch_first() + last_offset;
8262dd076b8SGabor Kovesdan const LINENUM newfirst = pch_newfirst() + last_offset;
8272dd076b8SGabor Kovesdan
8282dd076b8SGabor Kovesdan if (diff_type != UNI_DIFF) {
8292dd076b8SGabor Kovesdan abort_context_hunk();
8302dd076b8SGabor Kovesdan return;
8312dd076b8SGabor Kovesdan }
8322dd076b8SGabor Kovesdan split = -1;
8332dd076b8SGabor Kovesdan for (i = 0; i <= pat_end; i++) {
8342dd076b8SGabor Kovesdan if (pch_char(i) == '=') {
8352dd076b8SGabor Kovesdan split = i;
8362dd076b8SGabor Kovesdan break;
8372dd076b8SGabor Kovesdan }
8382dd076b8SGabor Kovesdan }
8392dd076b8SGabor Kovesdan if (split == -1) {
8402dd076b8SGabor Kovesdan fprintf(rejfp, "malformed hunk: no split found\n");
8412dd076b8SGabor Kovesdan return;
8422dd076b8SGabor Kovesdan }
8432dd076b8SGabor Kovesdan i = 0;
8442dd076b8SGabor Kovesdan j = split + 1;
8452dd076b8SGabor Kovesdan fprintf(rejfp, "@@ -%ld,%ld +%ld,%ld @@\n",
8462dd076b8SGabor Kovesdan pch_ptrn_lines() ? oldfirst : 0,
8472dd076b8SGabor Kovesdan pch_ptrn_lines(), newfirst, pch_repl_lines());
8482dd076b8SGabor Kovesdan while (i < split || j <= pat_end) {
8492dd076b8SGabor Kovesdan ch1 = i < split ? pch_char(i) : -1;
8502dd076b8SGabor Kovesdan ch2 = j <= pat_end ? pch_char(j) : -1;
8512dd076b8SGabor Kovesdan if (ch1 == '-') {
8522dd076b8SGabor Kovesdan rej_line('-', i);
8532dd076b8SGabor Kovesdan i++;
8542dd076b8SGabor Kovesdan } else if (ch1 == ' ' && ch2 == ' ') {
8552dd076b8SGabor Kovesdan rej_line(' ', i);
8562dd076b8SGabor Kovesdan i++;
8572dd076b8SGabor Kovesdan j++;
8582dd076b8SGabor Kovesdan } else if (ch1 == '!' && ch2 == '!') {
8592dd076b8SGabor Kovesdan while (i < split && ch1 == '!') {
8602dd076b8SGabor Kovesdan rej_line('-', i);
8612dd076b8SGabor Kovesdan i++;
8622dd076b8SGabor Kovesdan ch1 = i < split ? pch_char(i) : -1;
8632dd076b8SGabor Kovesdan }
8642dd076b8SGabor Kovesdan while (j <= pat_end && ch2 == '!') {
8652dd076b8SGabor Kovesdan rej_line('+', j);
8662dd076b8SGabor Kovesdan j++;
8672dd076b8SGabor Kovesdan ch2 = j <= pat_end ? pch_char(j) : -1;
8682dd076b8SGabor Kovesdan }
8692dd076b8SGabor Kovesdan } else if (ch1 == '*') {
8702dd076b8SGabor Kovesdan i++;
8712dd076b8SGabor Kovesdan } else if (ch2 == '+' || ch2 == ' ') {
8722dd076b8SGabor Kovesdan rej_line(ch2, j);
8732dd076b8SGabor Kovesdan j++;
8742dd076b8SGabor Kovesdan } else {
8752dd076b8SGabor Kovesdan fprintf(rejfp, "internal error on (%ld %ld %ld)\n",
8762dd076b8SGabor Kovesdan i, split, j);
8772dd076b8SGabor Kovesdan rej_line(ch1, i);
8782dd076b8SGabor Kovesdan rej_line(ch2, j);
8792dd076b8SGabor Kovesdan return;
8802dd076b8SGabor Kovesdan }
8812dd076b8SGabor Kovesdan }
8822dd076b8SGabor Kovesdan }
8832dd076b8SGabor Kovesdan
8842dd076b8SGabor Kovesdan /* We found where to apply it (we hope), so do it. */
8852dd076b8SGabor Kovesdan
8862dd076b8SGabor Kovesdan static void
apply_hunk(LINENUM where)8872dd076b8SGabor Kovesdan apply_hunk(LINENUM where)
8882dd076b8SGabor Kovesdan {
8892dd076b8SGabor Kovesdan LINENUM old = 1;
8902dd076b8SGabor Kovesdan const LINENUM lastline = pch_ptrn_lines();
8912dd076b8SGabor Kovesdan LINENUM new = lastline + 1;
8922dd076b8SGabor Kovesdan #define OUTSIDE 0
8932dd076b8SGabor Kovesdan #define IN_IFNDEF 1
8942dd076b8SGabor Kovesdan #define IN_IFDEF 2
8952dd076b8SGabor Kovesdan #define IN_ELSE 3
8962dd076b8SGabor Kovesdan int def_state = OUTSIDE;
8972dd076b8SGabor Kovesdan const LINENUM pat_end = pch_end();
8982dd076b8SGabor Kovesdan
8992dd076b8SGabor Kovesdan where--;
9002dd076b8SGabor Kovesdan while (pch_char(new) == '=' || pch_char(new) == '\n')
9012dd076b8SGabor Kovesdan new++;
9022dd076b8SGabor Kovesdan
9032dd076b8SGabor Kovesdan while (old <= lastline) {
9042dd076b8SGabor Kovesdan if (pch_char(old) == '-') {
9052dd076b8SGabor Kovesdan copy_till(where + old - 1, false);
9062dd076b8SGabor Kovesdan if (do_defines) {
9072dd076b8SGabor Kovesdan if (def_state == OUTSIDE) {
9082dd076b8SGabor Kovesdan fputs(not_defined, ofp);
9092dd076b8SGabor Kovesdan def_state = IN_IFNDEF;
9102dd076b8SGabor Kovesdan } else if (def_state == IN_IFDEF) {
9112dd076b8SGabor Kovesdan fputs(else_defined, ofp);
9122dd076b8SGabor Kovesdan def_state = IN_ELSE;
9132dd076b8SGabor Kovesdan }
9142dd076b8SGabor Kovesdan fputs(pfetch(old), ofp);
9152dd076b8SGabor Kovesdan }
9162dd076b8SGabor Kovesdan last_frozen_line++;
9172dd076b8SGabor Kovesdan old++;
9182dd076b8SGabor Kovesdan } else if (new > pat_end) {
9192dd076b8SGabor Kovesdan break;
9202dd076b8SGabor Kovesdan } else if (pch_char(new) == '+') {
9212dd076b8SGabor Kovesdan copy_till(where + old - 1, false);
9222dd076b8SGabor Kovesdan if (do_defines) {
9232dd076b8SGabor Kovesdan if (def_state == IN_IFNDEF) {
9242dd076b8SGabor Kovesdan fputs(else_defined, ofp);
9252dd076b8SGabor Kovesdan def_state = IN_ELSE;
9262dd076b8SGabor Kovesdan } else if (def_state == OUTSIDE) {
9272dd076b8SGabor Kovesdan fputs(if_defined, ofp);
9282dd076b8SGabor Kovesdan def_state = IN_IFDEF;
9292dd076b8SGabor Kovesdan }
9302dd076b8SGabor Kovesdan }
9312dd076b8SGabor Kovesdan fputs(pfetch(new), ofp);
9322dd076b8SGabor Kovesdan new++;
9332dd076b8SGabor Kovesdan } else if (pch_char(new) != pch_char(old)) {
9342dd076b8SGabor Kovesdan say("Out-of-sync patch, lines %ld,%ld--mangled text or line numbers, maybe?\n",
9352dd076b8SGabor Kovesdan pch_hunk_beg() + old,
9362dd076b8SGabor Kovesdan pch_hunk_beg() + new);
9372dd076b8SGabor Kovesdan #ifdef DEBUGGING
9382dd076b8SGabor Kovesdan say("oldchar = '%c', newchar = '%c'\n",
9392dd076b8SGabor Kovesdan pch_char(old), pch_char(new));
9402dd076b8SGabor Kovesdan #endif
9412dd076b8SGabor Kovesdan my_exit(2);
9422dd076b8SGabor Kovesdan } else if (pch_char(new) == '!') {
9432dd076b8SGabor Kovesdan copy_till(where + old - 1, false);
9442dd076b8SGabor Kovesdan if (do_defines) {
9452dd076b8SGabor Kovesdan fputs(not_defined, ofp);
9462dd076b8SGabor Kovesdan def_state = IN_IFNDEF;
9472dd076b8SGabor Kovesdan }
9482dd076b8SGabor Kovesdan while (pch_char(old) == '!') {
9492dd076b8SGabor Kovesdan if (do_defines) {
9502dd076b8SGabor Kovesdan fputs(pfetch(old), ofp);
9512dd076b8SGabor Kovesdan }
9522dd076b8SGabor Kovesdan last_frozen_line++;
9532dd076b8SGabor Kovesdan old++;
9542dd076b8SGabor Kovesdan }
9552dd076b8SGabor Kovesdan if (do_defines) {
9562dd076b8SGabor Kovesdan fputs(else_defined, ofp);
9572dd076b8SGabor Kovesdan def_state = IN_ELSE;
9582dd076b8SGabor Kovesdan }
9592dd076b8SGabor Kovesdan while (pch_char(new) == '!') {
9602dd076b8SGabor Kovesdan fputs(pfetch(new), ofp);
9612dd076b8SGabor Kovesdan new++;
9622dd076b8SGabor Kovesdan }
9632dd076b8SGabor Kovesdan } else {
9642dd076b8SGabor Kovesdan if (pch_char(new) != ' ')
9652dd076b8SGabor Kovesdan fatal("Internal error: expected ' '\n");
9662dd076b8SGabor Kovesdan old++;
9672dd076b8SGabor Kovesdan new++;
9682dd076b8SGabor Kovesdan if (do_defines && def_state != OUTSIDE) {
9692dd076b8SGabor Kovesdan fputs(end_defined, ofp);
9702dd076b8SGabor Kovesdan def_state = OUTSIDE;
9712dd076b8SGabor Kovesdan }
9722dd076b8SGabor Kovesdan }
9732dd076b8SGabor Kovesdan }
9742dd076b8SGabor Kovesdan if (new <= pat_end && pch_char(new) == '+') {
9752dd076b8SGabor Kovesdan copy_till(where + old - 1, false);
9762dd076b8SGabor Kovesdan if (do_defines) {
9772dd076b8SGabor Kovesdan if (def_state == OUTSIDE) {
9782dd076b8SGabor Kovesdan fputs(if_defined, ofp);
9792dd076b8SGabor Kovesdan def_state = IN_IFDEF;
9802dd076b8SGabor Kovesdan } else if (def_state == IN_IFNDEF) {
9812dd076b8SGabor Kovesdan fputs(else_defined, ofp);
9822dd076b8SGabor Kovesdan def_state = IN_ELSE;
9832dd076b8SGabor Kovesdan }
9842dd076b8SGabor Kovesdan }
9852dd076b8SGabor Kovesdan while (new <= pat_end && pch_char(new) == '+') {
9862dd076b8SGabor Kovesdan fputs(pfetch(new), ofp);
9872dd076b8SGabor Kovesdan new++;
9882dd076b8SGabor Kovesdan }
9892dd076b8SGabor Kovesdan }
9902dd076b8SGabor Kovesdan if (do_defines && def_state != OUTSIDE) {
9912dd076b8SGabor Kovesdan fputs(end_defined, ofp);
9922dd076b8SGabor Kovesdan }
9932dd076b8SGabor Kovesdan }
9942dd076b8SGabor Kovesdan
9952dd076b8SGabor Kovesdan /*
9962dd076b8SGabor Kovesdan * Open the new file.
9972dd076b8SGabor Kovesdan */
9982dd076b8SGabor Kovesdan static void
init_output(const char * name)9992dd076b8SGabor Kovesdan init_output(const char *name)
10002dd076b8SGabor Kovesdan {
10012dd076b8SGabor Kovesdan ofp = fopen(name, "w");
10022dd076b8SGabor Kovesdan if (ofp == NULL)
10032dd076b8SGabor Kovesdan pfatal("can't create %s", name);
10042dd076b8SGabor Kovesdan }
10052dd076b8SGabor Kovesdan
10062dd076b8SGabor Kovesdan /*
10072dd076b8SGabor Kovesdan * Open a file to put hunks we can't locate.
10082dd076b8SGabor Kovesdan */
10092dd076b8SGabor Kovesdan static void
init_reject(const char * name)10102dd076b8SGabor Kovesdan init_reject(const char *name)
10112dd076b8SGabor Kovesdan {
10122dd076b8SGabor Kovesdan rejfp = fopen(name, "w");
10132dd076b8SGabor Kovesdan if (rejfp == NULL)
10142dd076b8SGabor Kovesdan pfatal("can't create %s", name);
10152dd076b8SGabor Kovesdan }
10162dd076b8SGabor Kovesdan
10172dd076b8SGabor Kovesdan /*
10182dd076b8SGabor Kovesdan * Copy input file to output, up to wherever hunk is to be applied.
10192dd076b8SGabor Kovesdan * If endoffile is true, treat the last line specially since it may
10202dd076b8SGabor Kovesdan * lack a newline.
10212dd076b8SGabor Kovesdan */
10222dd076b8SGabor Kovesdan static void
copy_till(LINENUM lastline,bool endoffile)10232dd076b8SGabor Kovesdan copy_till(LINENUM lastline, bool endoffile)
10242dd076b8SGabor Kovesdan {
10252dd076b8SGabor Kovesdan if (last_frozen_line > lastline)
10262dd076b8SGabor Kovesdan fatal("misordered hunks! output would be garbled\n");
10272dd076b8SGabor Kovesdan while (last_frozen_line < lastline) {
10282dd076b8SGabor Kovesdan if (++last_frozen_line == lastline && endoffile)
10292dd076b8SGabor Kovesdan dump_line(last_frozen_line, !last_line_missing_eol);
10302dd076b8SGabor Kovesdan else
10312dd076b8SGabor Kovesdan dump_line(last_frozen_line, true);
10322dd076b8SGabor Kovesdan }
10332dd076b8SGabor Kovesdan }
10342dd076b8SGabor Kovesdan
10352dd076b8SGabor Kovesdan /*
10362dd076b8SGabor Kovesdan * Finish copying the input file to the output file.
10372dd076b8SGabor Kovesdan */
10382dd076b8SGabor Kovesdan static bool
spew_output(void)10392dd076b8SGabor Kovesdan spew_output(void)
10402dd076b8SGabor Kovesdan {
10412dd076b8SGabor Kovesdan int rv;
10422dd076b8SGabor Kovesdan
10432dd076b8SGabor Kovesdan #ifdef DEBUGGING
10442dd076b8SGabor Kovesdan if (debug & 256)
10452dd076b8SGabor Kovesdan say("il=%ld lfl=%ld\n", input_lines, last_frozen_line);
10462dd076b8SGabor Kovesdan #endif
10472dd076b8SGabor Kovesdan if (input_lines)
10482dd076b8SGabor Kovesdan copy_till(input_lines, true); /* dump remainder of file */
1049ffca5883SGlen Barber rv = ferror(ofp) == 0 && fclose(ofp) == 0;
10502dd076b8SGabor Kovesdan ofp = NULL;
10512dd076b8SGabor Kovesdan return rv;
10522dd076b8SGabor Kovesdan }
10532dd076b8SGabor Kovesdan
10542dd076b8SGabor Kovesdan /*
10552dd076b8SGabor Kovesdan * Copy one line from input to output.
10562dd076b8SGabor Kovesdan */
10572dd076b8SGabor Kovesdan static void
dump_line(LINENUM line,bool write_newline)10582dd076b8SGabor Kovesdan dump_line(LINENUM line, bool write_newline)
10592dd076b8SGabor Kovesdan {
10602dd076b8SGabor Kovesdan char *s;
10612dd076b8SGabor Kovesdan
10622dd076b8SGabor Kovesdan s = ifetch(line, 0);
10632dd076b8SGabor Kovesdan if (s == NULL)
10642dd076b8SGabor Kovesdan return;
10652dd076b8SGabor Kovesdan /* Note: string is not NUL terminated. */
10662dd076b8SGabor Kovesdan for (; *s != '\n'; s++)
10672dd076b8SGabor Kovesdan putc(*s, ofp);
10682dd076b8SGabor Kovesdan if (write_newline)
10692dd076b8SGabor Kovesdan putc('\n', ofp);
10702dd076b8SGabor Kovesdan }
10712dd076b8SGabor Kovesdan
10722dd076b8SGabor Kovesdan /*
10732dd076b8SGabor Kovesdan * Does the patch pattern match at line base+offset?
10742dd076b8SGabor Kovesdan */
10752dd076b8SGabor Kovesdan static bool
patch_match(LINENUM base,LINENUM offset,LINENUM fuzz)10762dd076b8SGabor Kovesdan patch_match(LINENUM base, LINENUM offset, LINENUM fuzz)
10772dd076b8SGabor Kovesdan {
10782dd076b8SGabor Kovesdan LINENUM pline = 1 + fuzz;
10792dd076b8SGabor Kovesdan LINENUM iline;
10802dd076b8SGabor Kovesdan LINENUM pat_lines = pch_ptrn_lines() - fuzz;
10812dd076b8SGabor Kovesdan const char *ilineptr;
10822dd076b8SGabor Kovesdan const char *plineptr;
10834f548c19SPedro F. Giffuni unsigned short plinelen;
10842dd076b8SGabor Kovesdan
1085bc4f0fe3SKyle Evans /* Patch does not match if we don't have any more context to use */
1086bc4f0fe3SKyle Evans if (pline > pat_lines)
1087bc4f0fe3SKyle Evans return false;
10882dd076b8SGabor Kovesdan for (iline = base + offset + fuzz; pline <= pat_lines; pline++, iline++) {
10892dd076b8SGabor Kovesdan ilineptr = ifetch(iline, offset >= 0);
10902dd076b8SGabor Kovesdan if (ilineptr == NULL)
10912dd076b8SGabor Kovesdan return false;
10922dd076b8SGabor Kovesdan plineptr = pfetch(pline);
10932dd076b8SGabor Kovesdan plinelen = pch_line_len(pline);
10942dd076b8SGabor Kovesdan if (canonicalize) {
10952dd076b8SGabor Kovesdan if (!similar(ilineptr, plineptr, plinelen))
10962dd076b8SGabor Kovesdan return false;
10972dd076b8SGabor Kovesdan } else if (strnNE(ilineptr, plineptr, plinelen))
10982dd076b8SGabor Kovesdan return false;
10992dd076b8SGabor Kovesdan if (iline == input_lines) {
11002dd076b8SGabor Kovesdan /*
11012dd076b8SGabor Kovesdan * We are looking at the last line of the file.
11022dd076b8SGabor Kovesdan * If the file has no eol, the patch line should
11032dd076b8SGabor Kovesdan * not have one either and vice-versa. Note that
11042dd076b8SGabor Kovesdan * plinelen > 0.
11052dd076b8SGabor Kovesdan */
11062dd076b8SGabor Kovesdan if (last_line_missing_eol) {
11072dd076b8SGabor Kovesdan if (plineptr[plinelen - 1] == '\n')
11082dd076b8SGabor Kovesdan return false;
11092dd076b8SGabor Kovesdan } else {
11102dd076b8SGabor Kovesdan if (plineptr[plinelen - 1] != '\n')
11112dd076b8SGabor Kovesdan return false;
11122dd076b8SGabor Kovesdan }
11132dd076b8SGabor Kovesdan }
11142dd076b8SGabor Kovesdan }
11152dd076b8SGabor Kovesdan return true;
11162dd076b8SGabor Kovesdan }
11172dd076b8SGabor Kovesdan
11182dd076b8SGabor Kovesdan /*
11192dd076b8SGabor Kovesdan * Do two lines match with canonicalized white space?
11202dd076b8SGabor Kovesdan */
11212dd076b8SGabor Kovesdan static bool
similar(const char * a,const char * b,int len)11222dd076b8SGabor Kovesdan similar(const char *a, const char *b, int len)
11232dd076b8SGabor Kovesdan {
11242dd076b8SGabor Kovesdan while (len) {
11252dd076b8SGabor Kovesdan if (isspace((unsigned char)*b)) { /* whitespace (or \n) to match? */
11262dd076b8SGabor Kovesdan if (!isspace((unsigned char)*a)) /* no corresponding whitespace? */
11272dd076b8SGabor Kovesdan return false;
11282dd076b8SGabor Kovesdan while (len && isspace((unsigned char)*b) && *b != '\n')
11292dd076b8SGabor Kovesdan b++, len--; /* skip pattern whitespace */
11302dd076b8SGabor Kovesdan while (isspace((unsigned char)*a) && *a != '\n')
11312dd076b8SGabor Kovesdan a++; /* skip target whitespace */
11322dd076b8SGabor Kovesdan if (*a == '\n' || *b == '\n')
11332dd076b8SGabor Kovesdan return (*a == *b); /* should end in sync */
11342dd076b8SGabor Kovesdan } else if (*a++ != *b++) /* match non-whitespace chars */
11352dd076b8SGabor Kovesdan return false;
11362dd076b8SGabor Kovesdan else
11372dd076b8SGabor Kovesdan len--; /* probably not necessary */
11382dd076b8SGabor Kovesdan }
11392dd076b8SGabor Kovesdan return true; /* actually, this is not reached */
11402dd076b8SGabor Kovesdan /* since there is always a \n */
11412dd076b8SGabor Kovesdan }
1142*50dacbf6SKyle Evans
1143*50dacbf6SKyle Evans static bool
handle_creation(bool out_existed,bool * remove)1144*50dacbf6SKyle Evans handle_creation(bool out_existed, bool *remove)
1145*50dacbf6SKyle Evans {
1146*50dacbf6SKyle Evans bool reverse_seen;
1147*50dacbf6SKyle Evans
1148*50dacbf6SKyle Evans reverse_seen = false;
1149*50dacbf6SKyle Evans if (reverse && out_existed) {
1150*50dacbf6SKyle Evans /*
1151*50dacbf6SKyle Evans * If the patch creates the file and we're reversing the patch,
1152*50dacbf6SKyle Evans * then we need to indicate to the patch processor that it's OK
1153*50dacbf6SKyle Evans * to remove this file.
1154*50dacbf6SKyle Evans */
1155*50dacbf6SKyle Evans *remove = true;
1156*50dacbf6SKyle Evans } else if (!reverse && out_existed) {
1157*50dacbf6SKyle Evans /*
1158*50dacbf6SKyle Evans * Otherwise, we need to blow the horn because the patch appears
1159*50dacbf6SKyle Evans * to be reversed/already applied. For non-batch jobs, we'll
1160*50dacbf6SKyle Evans * prompt to figure out what we should be trying to do to raise
1161*50dacbf6SKyle Evans * awareness of the issue. batch (-t) processing suppresses the
1162*50dacbf6SKyle Evans * questions and just assumes that we're reversed if it looks
1163*50dacbf6SKyle Evans * like we are, which is always the case if we've reached this
1164*50dacbf6SKyle Evans * branch.
1165*50dacbf6SKyle Evans */
1166*50dacbf6SKyle Evans if (force) {
1167*50dacbf6SKyle Evans skip_rest_of_patch = true;
1168*50dacbf6SKyle Evans return (false);
1169*50dacbf6SKyle Evans }
1170*50dacbf6SKyle Evans if (noreverse) {
1171*50dacbf6SKyle Evans /* If -N is supplied, however, we bail out/ignore. */
1172*50dacbf6SKyle Evans say("Ignoring previously applied (or reversed) patch.\n");
1173*50dacbf6SKyle Evans skip_rest_of_patch = true;
1174*50dacbf6SKyle Evans return (false);
1175*50dacbf6SKyle Evans }
1176*50dacbf6SKyle Evans
1177*50dacbf6SKyle Evans /* Unreversed... suspicious if the file existed. */
1178*50dacbf6SKyle Evans if (!pch_swap())
1179*50dacbf6SKyle Evans fatal("lost hunk on alloc error!\n");
1180*50dacbf6SKyle Evans
1181*50dacbf6SKyle Evans reverse = !reverse;
1182*50dacbf6SKyle Evans
1183*50dacbf6SKyle Evans if (batch) {
1184*50dacbf6SKyle Evans if (verbose)
1185*50dacbf6SKyle Evans say("Patch creates file that already exists, %s %seversed",
1186*50dacbf6SKyle Evans reverse ? "Assuming" : "Ignoring",
1187*50dacbf6SKyle Evans reverse ? "R" : "Unr");
1188*50dacbf6SKyle Evans } else {
1189*50dacbf6SKyle Evans ask("Patch creates file that already exists! %s -R? [y] ",
1190*50dacbf6SKyle Evans reverse ? "Assume" : "Ignore");
1191*50dacbf6SKyle Evans
1192*50dacbf6SKyle Evans if (*buf == 'n') {
1193*50dacbf6SKyle Evans ask("Apply anyway? [n]");
1194*50dacbf6SKyle Evans if (*buf != 'y')
1195*50dacbf6SKyle Evans /* Don't apply; error out. */
1196*50dacbf6SKyle Evans skip_rest_of_patch = true;
1197*50dacbf6SKyle Evans else
1198*50dacbf6SKyle Evans /* Attempt to apply. */
1199*50dacbf6SKyle Evans reverse_seen = true;
1200*50dacbf6SKyle Evans reverse = !reverse;
1201*50dacbf6SKyle Evans if (!pch_swap())
1202*50dacbf6SKyle Evans fatal("lost hunk on alloc error!\n");
1203*50dacbf6SKyle Evans } else {
1204*50dacbf6SKyle Evans /*
1205*50dacbf6SKyle Evans * They've opted to assume -R; effectively the
1206*50dacbf6SKyle Evans * same as the first branch in this function,
1207*50dacbf6SKyle Evans * but the decision is here rather than in a
1208*50dacbf6SKyle Evans * prior patch/hunk as in that branch.
1209*50dacbf6SKyle Evans */
1210*50dacbf6SKyle Evans *remove = true;
1211*50dacbf6SKyle Evans }
1212*50dacbf6SKyle Evans }
1213*50dacbf6SKyle Evans }
1214*50dacbf6SKyle Evans
1215*50dacbf6SKyle Evans /*
1216*50dacbf6SKyle Evans * The return value indicates if we offered a chance to reverse but the
1217*50dacbf6SKyle Evans * user declined. This keeps the main patch processor in the loop since
1218*50dacbf6SKyle Evans * we've taken this out of the normal flow of hunk processing to
1219*50dacbf6SKyle Evans * simplify logic a little bit.
1220*50dacbf6SKyle Evans */
1221*50dacbf6SKyle Evans return (reverse_seen);
1222*50dacbf6SKyle Evans }
1223