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 3450dacbf6SKyle 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); 10750dacbf6SKyle 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 1502dd076b8SGabor Kovesdan main(int argc, char *argv[]) 1512dd076b8SGabor Kovesdan { 15250dacbf6SKyle Evans struct stat statbuf; 1532dd076b8SGabor Kovesdan int error = 0, hunk, failed, i, fd; 15450dacbf6SKyle Evans bool out_creating, out_existed, patch_seen, remove_file; 15550dacbf6SKyle 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 22650dacbf6SKyle Evans if (source_file != NULL && (diff_type == CONTEXT_DIFF || 22750dacbf6SKyle Evans diff_type == NEW_CONTEXT_DIFF || 22850dacbf6SKyle Evans diff_type == UNI_DIFF)) 22950dacbf6SKyle Evans out_creating = strcmp(source_file, _PATH_DEVNULL) == 0; 23050dacbf6SKyle Evans else 23150dacbf6SKyle 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 23950dacbf6SKyle Evans /* 24050dacbf6SKyle Evans * At this point, we know if we're supposed to be creating the 24150dacbf6SKyle Evans * file and we know if we should be trying to handle a conflict 24250dacbf6SKyle Evans * between the patch and the file already existing. We defer 24350dacbf6SKyle Evans * handling it until hunk processing because we want to swap 24450dacbf6SKyle Evans * the hunk if they opt to reverse it, but we want to make sure 24550dacbf6SKyle Evans * we *can* swap the hunk without running into memory issues 24650dacbf6SKyle Evans * before we offer it. We also want to be verbose if flags or 24750dacbf6SKyle Evans * user decision cause us to skip -- this is explained a little 24850dacbf6SKyle Evans * more later. 24950dacbf6SKyle Evans */ 25050dacbf6SKyle Evans out_existed = stat(outname, &statbuf) == 0; 25150dacbf6SKyle 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; 27850dacbf6SKyle Evans remove_file = false; 2792dd076b8SGabor Kovesdan while (another_hunk()) { 28050dacbf6SKyle Evans assert(!out_creating || hunk == 0); 2812dd076b8SGabor Kovesdan hunk++; 2822dd076b8SGabor Kovesdan fuzz = 0; 28350dacbf6SKyle Evans 28450dacbf6SKyle Evans /* 28550dacbf6SKyle Evans * There are only three cases in handle_creation() that 28650dacbf6SKyle Evans * results in us skipping hunk location, in order: 28750dacbf6SKyle Evans * 28850dacbf6SKyle Evans * 1.) Potentially reversed but -f/--force'd, 28950dacbf6SKyle Evans * 2.) Potentially reversed but -N/--forward'd 29050dacbf6SKyle Evans * 3.) Reversed and the user's opted to not apply it. 29150dacbf6SKyle Evans * 29250dacbf6SKyle Evans * In all three cases, we still want to inform the user 29350dacbf6SKyle Evans * that we're ignoring it in the standard way, which is 29450dacbf6SKyle Evans * also tied to this hunk processing loop. 29550dacbf6SKyle Evans */ 29650dacbf6SKyle Evans if (out_creating) 29750dacbf6SKyle Evans reverse_seen = handle_creation(out_existed, 29850dacbf6SKyle Evans &remove_file); 29950dacbf6SKyle 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 42750dacbf6SKyle Evans /* 42850dacbf6SKyle Evans * remove_file is a per-patch flag indicating 42950dacbf6SKyle Evans * whether it's OK to remove the empty file. 43050dacbf6SKyle Evans * This is specifically set when we're reversing 43150dacbf6SKyle Evans * the creation of a file and it ends up empty. 43250dacbf6SKyle Evans * This is an exception to the global policy 43350dacbf6SKyle Evans * (remove_empty_files) because the user would 43450dacbf6SKyle Evans * likely not expect the reverse of file 43550dacbf6SKyle Evans * creation to leave an empty file laying 43650dacbf6SKyle Evans * around. 43750dacbf6SKyle Evans */ 43850dacbf6SKyle 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); 466*7e688ed4SKyle Evans else if (filearg[0] != NULL) 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]); 469*7e688ed4SKyle Evans else 470*7e688ed4SKyle Evans /* File prompt ignored, just note # hunks. */ 471*7e688ed4SKyle Evans say("%d out of %d hunks %s\n", 472*7e688ed4SKyle Evans failed, hunk, skip_rest_of_patch ? "ignored" : "failed"); 4732dd076b8SGabor Kovesdan if (!check_only && move_file(TMPREJNAME, rejname) < 0) 4742dd076b8SGabor Kovesdan trejkeep = true; 4752dd076b8SGabor Kovesdan } 4762dd076b8SGabor Kovesdan set_signals(1); 4772dd076b8SGabor Kovesdan } 478e56ef7d3SXin LI 479ef30b5a8SKyle Evans if (!patch_seen && nonempty_patchf_seen) 480e56ef7d3SXin LI error = 2; 481e56ef7d3SXin LI 4822dd076b8SGabor Kovesdan my_exit(error); 4832dd076b8SGabor Kovesdan /* NOTREACHED */ 4842dd076b8SGabor Kovesdan } 4852dd076b8SGabor Kovesdan 4862dd076b8SGabor Kovesdan /* Prepare to find the next patch to do in the patch file. */ 4872dd076b8SGabor Kovesdan 4882dd076b8SGabor Kovesdan static void 4892dd076b8SGabor Kovesdan reinitialize_almost_everything(void) 4902dd076b8SGabor Kovesdan { 4912dd076b8SGabor Kovesdan re_patch(); 4922dd076b8SGabor Kovesdan re_input(); 4932dd076b8SGabor Kovesdan 4942dd076b8SGabor Kovesdan input_lines = 0; 4952dd076b8SGabor Kovesdan last_frozen_line = 0; 4962dd076b8SGabor Kovesdan 4972dd076b8SGabor Kovesdan filec = 0; 4982dd076b8SGabor Kovesdan if (!out_of_mem) { 4992dd076b8SGabor Kovesdan free(filearg[0]); 5002dd076b8SGabor Kovesdan filearg[0] = NULL; 5012dd076b8SGabor Kovesdan } 5022dd076b8SGabor Kovesdan 50350dacbf6SKyle Evans free(source_file); 50450dacbf6SKyle Evans source_file = NULL; 50550dacbf6SKyle Evans 5062dd076b8SGabor Kovesdan free(outname); 5072dd076b8SGabor Kovesdan outname = NULL; 5082dd076b8SGabor Kovesdan 5092dd076b8SGabor Kovesdan last_offset = 0; 5102dd076b8SGabor Kovesdan diff_type = 0; 5112dd076b8SGabor Kovesdan 5122dd076b8SGabor Kovesdan free(revision); 5132dd076b8SGabor Kovesdan revision = NULL; 5142dd076b8SGabor Kovesdan 5152dd076b8SGabor Kovesdan reverse = reverse_flag_specified; 5162dd076b8SGabor Kovesdan skip_rest_of_patch = false; 5172dd076b8SGabor Kovesdan 5182dd076b8SGabor Kovesdan get_some_switches(); 5192dd076b8SGabor Kovesdan } 5202dd076b8SGabor Kovesdan 5212dd076b8SGabor Kovesdan /* Process switches and filenames. */ 5222dd076b8SGabor Kovesdan 5232dd076b8SGabor Kovesdan static void 5242dd076b8SGabor Kovesdan get_some_switches(void) 5252dd076b8SGabor Kovesdan { 5262dd076b8SGabor Kovesdan const char *options = "b::B:cCd:D:eEfF:i:lnNo:p:r:RstuvV:x:z:"; 5272dd076b8SGabor Kovesdan static struct option longopts[] = { 5282dd076b8SGabor Kovesdan {"backup", no_argument, 0, 'b'}, 5292dd076b8SGabor Kovesdan {"batch", no_argument, 0, 't'}, 5302dd076b8SGabor Kovesdan {"check", no_argument, 0, 'C'}, 5312dd076b8SGabor Kovesdan {"context", no_argument, 0, 'c'}, 5322dd076b8SGabor Kovesdan {"debug", required_argument, 0, 'x'}, 5332dd076b8SGabor Kovesdan {"directory", required_argument, 0, 'd'}, 5345e64d66cSPedro F. Giffuni {"dry-run", no_argument, 0, 'C'}, 5352dd076b8SGabor Kovesdan {"ed", no_argument, 0, 'e'}, 5362dd076b8SGabor Kovesdan {"force", no_argument, 0, 'f'}, 5372dd076b8SGabor Kovesdan {"forward", no_argument, 0, 'N'}, 5382dd076b8SGabor Kovesdan {"fuzz", required_argument, 0, 'F'}, 5392dd076b8SGabor Kovesdan {"ifdef", required_argument, 0, 'D'}, 5402dd076b8SGabor Kovesdan {"input", required_argument, 0, 'i'}, 5412dd076b8SGabor Kovesdan {"ignore-whitespace", no_argument, 0, 'l'}, 5422dd076b8SGabor Kovesdan {"normal", no_argument, 0, 'n'}, 5432dd076b8SGabor Kovesdan {"output", required_argument, 0, 'o'}, 5442dd076b8SGabor Kovesdan {"prefix", required_argument, 0, 'B'}, 5452dd076b8SGabor Kovesdan {"quiet", no_argument, 0, 's'}, 5462dd076b8SGabor Kovesdan {"reject-file", required_argument, 0, 'r'}, 5472dd076b8SGabor Kovesdan {"remove-empty-files", no_argument, 0, 'E'}, 5482dd076b8SGabor Kovesdan {"reverse", no_argument, 0, 'R'}, 5492dd076b8SGabor Kovesdan {"silent", no_argument, 0, 's'}, 5502dd076b8SGabor Kovesdan {"strip", required_argument, 0, 'p'}, 5512dd076b8SGabor Kovesdan {"suffix", required_argument, 0, 'z'}, 5522dd076b8SGabor Kovesdan {"unified", no_argument, 0, 'u'}, 5532dd076b8SGabor Kovesdan {"version", no_argument, 0, 'v'}, 5542dd076b8SGabor Kovesdan {"version-control", required_argument, 0, 'V'}, 5552dd076b8SGabor Kovesdan {"posix", no_argument, &posix, 1}, 5562dd076b8SGabor Kovesdan {NULL, 0, 0, 0} 5572dd076b8SGabor Kovesdan }; 5582dd076b8SGabor Kovesdan int ch; 5592dd076b8SGabor Kovesdan 5602dd076b8SGabor Kovesdan rejname[0] = '\0'; 5612dd076b8SGabor Kovesdan Argc_last = Argc; 5622dd076b8SGabor Kovesdan Argv_last = Argv; 5632dd076b8SGabor Kovesdan if (!Argc) 5642dd076b8SGabor Kovesdan return; 5652dd076b8SGabor Kovesdan optreset = optind = 1; 5662dd076b8SGabor Kovesdan while ((ch = getopt_long(Argc, Argv, options, longopts, NULL)) != -1) { 5672dd076b8SGabor Kovesdan switch (ch) { 5682dd076b8SGabor Kovesdan case 'b': 5692dd076b8SGabor Kovesdan if (backup_type == none) 5702dd076b8SGabor Kovesdan backup_type = numbered_existing; 5712dd076b8SGabor Kovesdan if (optarg == NULL) 5722dd076b8SGabor Kovesdan break; 5732dd076b8SGabor Kovesdan if (verbose) 5742dd076b8SGabor Kovesdan say("Warning, the ``-b suffix'' option has been" 5752dd076b8SGabor Kovesdan " obsoleted by the -z option.\n"); 5762dd076b8SGabor Kovesdan /* FALLTHROUGH */ 5772dd076b8SGabor Kovesdan case 'z': 5782dd076b8SGabor Kovesdan /* must directly follow 'b' case for backwards compat */ 579547e0acbSPedro F. Giffuni simple_backup_suffix = xstrdup(optarg); 5802dd076b8SGabor Kovesdan break; 5812dd076b8SGabor Kovesdan case 'B': 582547e0acbSPedro F. Giffuni origprae = xstrdup(optarg); 5832dd076b8SGabor Kovesdan break; 5842dd076b8SGabor Kovesdan case 'c': 5852dd076b8SGabor Kovesdan diff_type = CONTEXT_DIFF; 5862dd076b8SGabor Kovesdan break; 5872dd076b8SGabor Kovesdan case 'C': 5882dd076b8SGabor Kovesdan check_only = true; 5892dd076b8SGabor Kovesdan break; 5902dd076b8SGabor Kovesdan case 'd': 5912dd076b8SGabor Kovesdan if (chdir(optarg) < 0) 5922dd076b8SGabor Kovesdan pfatal("can't cd to %s", optarg); 5932dd076b8SGabor Kovesdan break; 5942dd076b8SGabor Kovesdan case 'D': 5952dd076b8SGabor Kovesdan do_defines = true; 5962dd076b8SGabor Kovesdan if (!isalpha((unsigned char)*optarg) && *optarg != '_') 5972dd076b8SGabor Kovesdan fatal("argument to -D is not an identifier\n"); 5982dd076b8SGabor Kovesdan snprintf(if_defined, sizeof if_defined, 5992dd076b8SGabor Kovesdan "#ifdef %s\n", optarg); 6002dd076b8SGabor Kovesdan snprintf(not_defined, sizeof not_defined, 6012dd076b8SGabor Kovesdan "#ifndef %s\n", optarg); 6022dd076b8SGabor Kovesdan snprintf(end_defined, sizeof end_defined, 6032dd076b8SGabor Kovesdan "#endif /* %s */\n", optarg); 6042dd076b8SGabor Kovesdan break; 6052dd076b8SGabor Kovesdan case 'e': 6062dd076b8SGabor Kovesdan diff_type = ED_DIFF; 6072dd076b8SGabor Kovesdan break; 6082dd076b8SGabor Kovesdan case 'E': 6092dd076b8SGabor Kovesdan remove_empty_files = true; 6102dd076b8SGabor Kovesdan break; 6112dd076b8SGabor Kovesdan case 'f': 6122dd076b8SGabor Kovesdan force = true; 6132dd076b8SGabor Kovesdan break; 6142dd076b8SGabor Kovesdan case 'F': 6152dd076b8SGabor Kovesdan maxfuzz = atoi(optarg); 6162dd076b8SGabor Kovesdan break; 6172dd076b8SGabor Kovesdan case 'i': 6182dd076b8SGabor Kovesdan if (++filec == MAXFILEC) 6192dd076b8SGabor Kovesdan fatal("too many file arguments\n"); 620547e0acbSPedro F. Giffuni filearg[filec] = xstrdup(optarg); 6212dd076b8SGabor Kovesdan break; 6222dd076b8SGabor Kovesdan case 'l': 6232dd076b8SGabor Kovesdan canonicalize = true; 6242dd076b8SGabor Kovesdan break; 6252dd076b8SGabor Kovesdan case 'n': 6262dd076b8SGabor Kovesdan diff_type = NORMAL_DIFF; 6272dd076b8SGabor Kovesdan break; 6282dd076b8SGabor Kovesdan case 'N': 6292dd076b8SGabor Kovesdan noreverse = true; 6302dd076b8SGabor Kovesdan break; 6312dd076b8SGabor Kovesdan case 'o': 632547e0acbSPedro F. Giffuni outname = xstrdup(optarg); 6332dd076b8SGabor Kovesdan break; 6342dd076b8SGabor Kovesdan case 'p': 6352dd076b8SGabor Kovesdan strippath = atoi(optarg); 6362dd076b8SGabor Kovesdan break; 6372dd076b8SGabor Kovesdan case 'r': 6382dd076b8SGabor Kovesdan if (strlcpy(rejname, optarg, 6392dd076b8SGabor Kovesdan sizeof(rejname)) >= sizeof(rejname)) 6402dd076b8SGabor Kovesdan fatal("argument for -r is too long\n"); 6412dd076b8SGabor Kovesdan break; 6422dd076b8SGabor Kovesdan case 'R': 6432dd076b8SGabor Kovesdan reverse = true; 6442dd076b8SGabor Kovesdan reverse_flag_specified = true; 6452dd076b8SGabor Kovesdan break; 6462dd076b8SGabor Kovesdan case 's': 6472dd076b8SGabor Kovesdan verbose = false; 6482dd076b8SGabor Kovesdan break; 6492dd076b8SGabor Kovesdan case 't': 6502dd076b8SGabor Kovesdan batch = true; 6512dd076b8SGabor Kovesdan break; 6522dd076b8SGabor Kovesdan case 'u': 6532dd076b8SGabor Kovesdan diff_type = UNI_DIFF; 6542dd076b8SGabor Kovesdan break; 6552dd076b8SGabor Kovesdan case 'v': 6562dd076b8SGabor Kovesdan version(); 6572dd076b8SGabor Kovesdan break; 6582dd076b8SGabor Kovesdan case 'V': 6592dd076b8SGabor Kovesdan backup_type = get_version(optarg); 660300ca9a8SConrad Meyer Vflag = true; 6612dd076b8SGabor Kovesdan break; 6622dd076b8SGabor Kovesdan #ifdef DEBUGGING 6632dd076b8SGabor Kovesdan case 'x': 6642dd076b8SGabor Kovesdan debug = atoi(optarg); 6652dd076b8SGabor Kovesdan break; 6662dd076b8SGabor Kovesdan #endif 6672dd076b8SGabor Kovesdan default: 6682dd076b8SGabor Kovesdan if (ch != '\0') 6692dd076b8SGabor Kovesdan usage(); 6702dd076b8SGabor Kovesdan break; 6712dd076b8SGabor Kovesdan } 6722dd076b8SGabor Kovesdan } 6732dd076b8SGabor Kovesdan Argc -= optind; 6742dd076b8SGabor Kovesdan Argv += optind; 6752dd076b8SGabor Kovesdan 6762dd076b8SGabor Kovesdan if (Argc > 0) { 677547e0acbSPedro F. Giffuni filearg[0] = xstrdup(*Argv++); 6782dd076b8SGabor Kovesdan Argc--; 6792dd076b8SGabor Kovesdan while (Argc > 0) { 6802dd076b8SGabor Kovesdan if (++filec == MAXFILEC) 6812dd076b8SGabor Kovesdan fatal("too many file arguments\n"); 682547e0acbSPedro F. Giffuni filearg[filec] = xstrdup(*Argv++); 6832dd076b8SGabor Kovesdan Argc--; 6842dd076b8SGabor Kovesdan } 6852dd076b8SGabor Kovesdan } 6862dd076b8SGabor Kovesdan 6872dd076b8SGabor Kovesdan if (getenv("POSIXLY_CORRECT") != NULL) 6882dd076b8SGabor Kovesdan posix = 1; 6892dd076b8SGabor Kovesdan } 6902dd076b8SGabor Kovesdan 6912dd076b8SGabor Kovesdan static void 6922dd076b8SGabor Kovesdan usage(void) 6932dd076b8SGabor Kovesdan { 6942dd076b8SGabor Kovesdan fprintf(stderr, 6952dd076b8SGabor Kovesdan "usage: patch [-bCcEeflNnRstuv] [-B backup-prefix] [-D symbol] [-d directory]\n" 6962dd076b8SGabor Kovesdan " [-F max-fuzz] [-i patchfile] [-o out-file] [-p strip-count]\n" 697300ca9a8SConrad Meyer " [-r rej-name] [-V t | nil | never | none] [-x number]\n" 698300ca9a8SConrad Meyer " [-z backup-ext] [--posix] [origfile [patchfile]]\n" 6992dd076b8SGabor Kovesdan " patch <patchfile\n"); 700f718bedcSPedro F. Giffuni my_exit(EXIT_FAILURE); 7012dd076b8SGabor Kovesdan } 7022dd076b8SGabor Kovesdan 7032dd076b8SGabor Kovesdan /* 7042dd076b8SGabor Kovesdan * Attempt to find the right place to apply this hunk of patch. 7052dd076b8SGabor Kovesdan */ 7062dd076b8SGabor Kovesdan static LINENUM 7072dd076b8SGabor Kovesdan locate_hunk(LINENUM fuzz) 7082dd076b8SGabor Kovesdan { 7092dd076b8SGabor Kovesdan LINENUM first_guess = pch_first() + last_offset; 7102dd076b8SGabor Kovesdan LINENUM offset; 7112dd076b8SGabor Kovesdan LINENUM pat_lines = pch_ptrn_lines(); 7122dd076b8SGabor Kovesdan LINENUM max_pos_offset = input_lines - first_guess - pat_lines + 1; 7132dd076b8SGabor Kovesdan LINENUM max_neg_offset = first_guess - last_frozen_line - 1 + pch_context(); 7142dd076b8SGabor Kovesdan 7152dd076b8SGabor Kovesdan if (pat_lines == 0) { /* null range matches always */ 7162dd076b8SGabor Kovesdan if (verbose && fuzz == 0 && (diff_type == CONTEXT_DIFF 7172dd076b8SGabor Kovesdan || diff_type == NEW_CONTEXT_DIFF 7182dd076b8SGabor Kovesdan || diff_type == UNI_DIFF)) { 7192dd076b8SGabor Kovesdan say("Empty context always matches.\n"); 7202dd076b8SGabor Kovesdan } 7212dd076b8SGabor Kovesdan return (first_guess); 7222dd076b8SGabor Kovesdan } 7232dd076b8SGabor Kovesdan if (max_neg_offset >= first_guess) /* do not try lines < 0 */ 7242dd076b8SGabor Kovesdan max_neg_offset = first_guess - 1; 7252dd076b8SGabor Kovesdan if (first_guess <= input_lines && patch_match(first_guess, 0, fuzz)) 7262dd076b8SGabor Kovesdan return first_guess; 7272dd076b8SGabor Kovesdan for (offset = 1; ; offset++) { 7282dd076b8SGabor Kovesdan bool check_after = (offset <= max_pos_offset); 7292dd076b8SGabor Kovesdan bool check_before = (offset <= max_neg_offset); 7302dd076b8SGabor Kovesdan 7312dd076b8SGabor Kovesdan if (check_after && patch_match(first_guess, offset, fuzz)) { 7322dd076b8SGabor Kovesdan #ifdef DEBUGGING 7332dd076b8SGabor Kovesdan if (debug & 1) 7342dd076b8SGabor Kovesdan say("Offset changing from %ld to %ld\n", 7352dd076b8SGabor Kovesdan last_offset, offset); 7362dd076b8SGabor Kovesdan #endif 7372dd076b8SGabor Kovesdan last_offset = offset; 7382dd076b8SGabor Kovesdan return first_guess + offset; 7392dd076b8SGabor Kovesdan } else if (check_before && patch_match(first_guess, -offset, fuzz)) { 7402dd076b8SGabor Kovesdan #ifdef DEBUGGING 7412dd076b8SGabor Kovesdan if (debug & 1) 7422dd076b8SGabor Kovesdan say("Offset changing from %ld to %ld\n", 7432dd076b8SGabor Kovesdan last_offset, -offset); 7442dd076b8SGabor Kovesdan #endif 7452dd076b8SGabor Kovesdan last_offset = -offset; 7462dd076b8SGabor Kovesdan return first_guess - offset; 7472dd076b8SGabor Kovesdan } else if (!check_before && !check_after) 7482dd076b8SGabor Kovesdan return 0; 7492dd076b8SGabor Kovesdan } 7502dd076b8SGabor Kovesdan } 7512dd076b8SGabor Kovesdan 7522dd076b8SGabor Kovesdan /* We did not find the pattern, dump out the hunk so they can handle it. */ 7532dd076b8SGabor Kovesdan 7542dd076b8SGabor Kovesdan static void 7552dd076b8SGabor Kovesdan abort_context_hunk(void) 7562dd076b8SGabor Kovesdan { 7572dd076b8SGabor Kovesdan LINENUM i; 7582dd076b8SGabor Kovesdan const LINENUM pat_end = pch_end(); 7592dd076b8SGabor Kovesdan /* 7602dd076b8SGabor Kovesdan * add in last_offset to guess the same as the previous successful 7612dd076b8SGabor Kovesdan * hunk 7622dd076b8SGabor Kovesdan */ 7632dd076b8SGabor Kovesdan const LINENUM oldfirst = pch_first() + last_offset; 7642dd076b8SGabor Kovesdan const LINENUM newfirst = pch_newfirst() + last_offset; 7652dd076b8SGabor Kovesdan const LINENUM oldlast = oldfirst + pch_ptrn_lines() - 1; 7662dd076b8SGabor Kovesdan const LINENUM newlast = newfirst + pch_repl_lines() - 1; 7672dd076b8SGabor Kovesdan const char *stars = (diff_type >= NEW_CONTEXT_DIFF ? " ****" : ""); 7682dd076b8SGabor Kovesdan const char *minuses = (diff_type >= NEW_CONTEXT_DIFF ? " ----" : " -----"); 7692dd076b8SGabor Kovesdan 7702dd076b8SGabor Kovesdan fprintf(rejfp, "***************\n"); 7712dd076b8SGabor Kovesdan for (i = 0; i <= pat_end; i++) { 7722dd076b8SGabor Kovesdan switch (pch_char(i)) { 7732dd076b8SGabor Kovesdan case '*': 7742dd076b8SGabor Kovesdan if (oldlast < oldfirst) 7752dd076b8SGabor Kovesdan fprintf(rejfp, "*** 0%s\n", stars); 7762dd076b8SGabor Kovesdan else if (oldlast == oldfirst) 7772dd076b8SGabor Kovesdan fprintf(rejfp, "*** %ld%s\n", oldfirst, stars); 7782dd076b8SGabor Kovesdan else 7792dd076b8SGabor Kovesdan fprintf(rejfp, "*** %ld,%ld%s\n", oldfirst, 7802dd076b8SGabor Kovesdan oldlast, stars); 7812dd076b8SGabor Kovesdan break; 7822dd076b8SGabor Kovesdan case '=': 7832dd076b8SGabor Kovesdan if (newlast < newfirst) 7842dd076b8SGabor Kovesdan fprintf(rejfp, "--- 0%s\n", minuses); 7852dd076b8SGabor Kovesdan else if (newlast == newfirst) 7862dd076b8SGabor Kovesdan fprintf(rejfp, "--- %ld%s\n", newfirst, minuses); 7872dd076b8SGabor Kovesdan else 7882dd076b8SGabor Kovesdan fprintf(rejfp, "--- %ld,%ld%s\n", newfirst, 7892dd076b8SGabor Kovesdan newlast, minuses); 7902dd076b8SGabor Kovesdan break; 7912dd076b8SGabor Kovesdan case '\n': 7922dd076b8SGabor Kovesdan fprintf(rejfp, "%s", pfetch(i)); 7932dd076b8SGabor Kovesdan break; 7942dd076b8SGabor Kovesdan case ' ': 7952dd076b8SGabor Kovesdan case '-': 7962dd076b8SGabor Kovesdan case '+': 7972dd076b8SGabor Kovesdan case '!': 7982dd076b8SGabor Kovesdan fprintf(rejfp, "%c %s", pch_char(i), pfetch(i)); 7992dd076b8SGabor Kovesdan break; 8002dd076b8SGabor Kovesdan default: 8012dd076b8SGabor Kovesdan fatal("fatal internal error in abort_context_hunk\n"); 8022dd076b8SGabor Kovesdan } 8032dd076b8SGabor Kovesdan } 8042dd076b8SGabor Kovesdan } 8052dd076b8SGabor Kovesdan 8062dd076b8SGabor Kovesdan static void 8072dd076b8SGabor Kovesdan rej_line(int ch, LINENUM i) 8082dd076b8SGabor Kovesdan { 8093548708cSPedro F. Giffuni size_t len; 8102dd076b8SGabor Kovesdan const char *line = pfetch(i); 8112dd076b8SGabor Kovesdan 812fa812237SPedro F. Giffuni len = strlen(line); 8132dd076b8SGabor Kovesdan 8142dd076b8SGabor Kovesdan fprintf(rejfp, "%c%s", ch, line); 8154f548c19SPedro F. Giffuni if (len == 0 || line[len - 1] != '\n') { 8164f548c19SPedro F. Giffuni if (len >= USHRT_MAX) 817ad8469feSPedro F. Giffuni fprintf(rejfp, "\n\\ Line too long\n"); 8184f548c19SPedro F. Giffuni else 8194f548c19SPedro F. Giffuni fprintf(rejfp, "\n\\ No newline at end of line\n"); 8204f548c19SPedro F. Giffuni } 8212dd076b8SGabor Kovesdan } 8222dd076b8SGabor Kovesdan 8232dd076b8SGabor Kovesdan static void 8242dd076b8SGabor Kovesdan abort_hunk(void) 8252dd076b8SGabor Kovesdan { 8262dd076b8SGabor Kovesdan LINENUM i, j, split; 8272dd076b8SGabor Kovesdan int ch1, ch2; 8282dd076b8SGabor Kovesdan const LINENUM pat_end = pch_end(); 8292dd076b8SGabor Kovesdan const LINENUM oldfirst = pch_first() + last_offset; 8302dd076b8SGabor Kovesdan const LINENUM newfirst = pch_newfirst() + last_offset; 8312dd076b8SGabor Kovesdan 8322dd076b8SGabor Kovesdan if (diff_type != UNI_DIFF) { 8332dd076b8SGabor Kovesdan abort_context_hunk(); 8342dd076b8SGabor Kovesdan return; 8352dd076b8SGabor Kovesdan } 8362dd076b8SGabor Kovesdan split = -1; 8372dd076b8SGabor Kovesdan for (i = 0; i <= pat_end; i++) { 8382dd076b8SGabor Kovesdan if (pch_char(i) == '=') { 8392dd076b8SGabor Kovesdan split = i; 8402dd076b8SGabor Kovesdan break; 8412dd076b8SGabor Kovesdan } 8422dd076b8SGabor Kovesdan } 8432dd076b8SGabor Kovesdan if (split == -1) { 8442dd076b8SGabor Kovesdan fprintf(rejfp, "malformed hunk: no split found\n"); 8452dd076b8SGabor Kovesdan return; 8462dd076b8SGabor Kovesdan } 8472dd076b8SGabor Kovesdan i = 0; 8482dd076b8SGabor Kovesdan j = split + 1; 8492dd076b8SGabor Kovesdan fprintf(rejfp, "@@ -%ld,%ld +%ld,%ld @@\n", 8502dd076b8SGabor Kovesdan pch_ptrn_lines() ? oldfirst : 0, 8512dd076b8SGabor Kovesdan pch_ptrn_lines(), newfirst, pch_repl_lines()); 8522dd076b8SGabor Kovesdan while (i < split || j <= pat_end) { 8532dd076b8SGabor Kovesdan ch1 = i < split ? pch_char(i) : -1; 8542dd076b8SGabor Kovesdan ch2 = j <= pat_end ? pch_char(j) : -1; 8552dd076b8SGabor Kovesdan if (ch1 == '-') { 8562dd076b8SGabor Kovesdan rej_line('-', i); 8572dd076b8SGabor Kovesdan i++; 8582dd076b8SGabor Kovesdan } else if (ch1 == ' ' && ch2 == ' ') { 8592dd076b8SGabor Kovesdan rej_line(' ', i); 8602dd076b8SGabor Kovesdan i++; 8612dd076b8SGabor Kovesdan j++; 8622dd076b8SGabor Kovesdan } else if (ch1 == '!' && ch2 == '!') { 8632dd076b8SGabor Kovesdan while (i < split && ch1 == '!') { 8642dd076b8SGabor Kovesdan rej_line('-', i); 8652dd076b8SGabor Kovesdan i++; 8662dd076b8SGabor Kovesdan ch1 = i < split ? pch_char(i) : -1; 8672dd076b8SGabor Kovesdan } 8682dd076b8SGabor Kovesdan while (j <= pat_end && ch2 == '!') { 8692dd076b8SGabor Kovesdan rej_line('+', j); 8702dd076b8SGabor Kovesdan j++; 8712dd076b8SGabor Kovesdan ch2 = j <= pat_end ? pch_char(j) : -1; 8722dd076b8SGabor Kovesdan } 8732dd076b8SGabor Kovesdan } else if (ch1 == '*') { 8742dd076b8SGabor Kovesdan i++; 8752dd076b8SGabor Kovesdan } else if (ch2 == '+' || ch2 == ' ') { 8762dd076b8SGabor Kovesdan rej_line(ch2, j); 8772dd076b8SGabor Kovesdan j++; 8782dd076b8SGabor Kovesdan } else { 8792dd076b8SGabor Kovesdan fprintf(rejfp, "internal error on (%ld %ld %ld)\n", 8802dd076b8SGabor Kovesdan i, split, j); 8812dd076b8SGabor Kovesdan rej_line(ch1, i); 8822dd076b8SGabor Kovesdan rej_line(ch2, j); 8832dd076b8SGabor Kovesdan return; 8842dd076b8SGabor Kovesdan } 8852dd076b8SGabor Kovesdan } 8862dd076b8SGabor Kovesdan } 8872dd076b8SGabor Kovesdan 8882dd076b8SGabor Kovesdan /* We found where to apply it (we hope), so do it. */ 8892dd076b8SGabor Kovesdan 8902dd076b8SGabor Kovesdan static void 8912dd076b8SGabor Kovesdan apply_hunk(LINENUM where) 8922dd076b8SGabor Kovesdan { 8932dd076b8SGabor Kovesdan LINENUM old = 1; 8942dd076b8SGabor Kovesdan const LINENUM lastline = pch_ptrn_lines(); 8952dd076b8SGabor Kovesdan LINENUM new = lastline + 1; 8962dd076b8SGabor Kovesdan #define OUTSIDE 0 8972dd076b8SGabor Kovesdan #define IN_IFNDEF 1 8982dd076b8SGabor Kovesdan #define IN_IFDEF 2 8992dd076b8SGabor Kovesdan #define IN_ELSE 3 9002dd076b8SGabor Kovesdan int def_state = OUTSIDE; 9012dd076b8SGabor Kovesdan const LINENUM pat_end = pch_end(); 9022dd076b8SGabor Kovesdan 9032dd076b8SGabor Kovesdan where--; 9042dd076b8SGabor Kovesdan while (pch_char(new) == '=' || pch_char(new) == '\n') 9052dd076b8SGabor Kovesdan new++; 9062dd076b8SGabor Kovesdan 9072dd076b8SGabor Kovesdan while (old <= lastline) { 9082dd076b8SGabor Kovesdan if (pch_char(old) == '-') { 9092dd076b8SGabor Kovesdan copy_till(where + old - 1, false); 9102dd076b8SGabor Kovesdan if (do_defines) { 9112dd076b8SGabor Kovesdan if (def_state == OUTSIDE) { 9122dd076b8SGabor Kovesdan fputs(not_defined, ofp); 9132dd076b8SGabor Kovesdan def_state = IN_IFNDEF; 9142dd076b8SGabor Kovesdan } else if (def_state == IN_IFDEF) { 9152dd076b8SGabor Kovesdan fputs(else_defined, ofp); 9162dd076b8SGabor Kovesdan def_state = IN_ELSE; 9172dd076b8SGabor Kovesdan } 9182dd076b8SGabor Kovesdan fputs(pfetch(old), ofp); 9192dd076b8SGabor Kovesdan } 9202dd076b8SGabor Kovesdan last_frozen_line++; 9212dd076b8SGabor Kovesdan old++; 9222dd076b8SGabor Kovesdan } else if (new > pat_end) { 9232dd076b8SGabor Kovesdan break; 9242dd076b8SGabor Kovesdan } else if (pch_char(new) == '+') { 9252dd076b8SGabor Kovesdan copy_till(where + old - 1, false); 9262dd076b8SGabor Kovesdan if (do_defines) { 9272dd076b8SGabor Kovesdan if (def_state == IN_IFNDEF) { 9282dd076b8SGabor Kovesdan fputs(else_defined, ofp); 9292dd076b8SGabor Kovesdan def_state = IN_ELSE; 9302dd076b8SGabor Kovesdan } else if (def_state == OUTSIDE) { 9312dd076b8SGabor Kovesdan fputs(if_defined, ofp); 9322dd076b8SGabor Kovesdan def_state = IN_IFDEF; 9332dd076b8SGabor Kovesdan } 9342dd076b8SGabor Kovesdan } 9352dd076b8SGabor Kovesdan fputs(pfetch(new), ofp); 9362dd076b8SGabor Kovesdan new++; 9372dd076b8SGabor Kovesdan } else if (pch_char(new) != pch_char(old)) { 9382dd076b8SGabor Kovesdan say("Out-of-sync patch, lines %ld,%ld--mangled text or line numbers, maybe?\n", 9392dd076b8SGabor Kovesdan pch_hunk_beg() + old, 9402dd076b8SGabor Kovesdan pch_hunk_beg() + new); 9412dd076b8SGabor Kovesdan #ifdef DEBUGGING 9422dd076b8SGabor Kovesdan say("oldchar = '%c', newchar = '%c'\n", 9432dd076b8SGabor Kovesdan pch_char(old), pch_char(new)); 9442dd076b8SGabor Kovesdan #endif 9452dd076b8SGabor Kovesdan my_exit(2); 9462dd076b8SGabor Kovesdan } else if (pch_char(new) == '!') { 9472dd076b8SGabor Kovesdan copy_till(where + old - 1, false); 9482dd076b8SGabor Kovesdan if (do_defines) { 9492dd076b8SGabor Kovesdan fputs(not_defined, ofp); 9502dd076b8SGabor Kovesdan def_state = IN_IFNDEF; 9512dd076b8SGabor Kovesdan } 9522dd076b8SGabor Kovesdan while (pch_char(old) == '!') { 9532dd076b8SGabor Kovesdan if (do_defines) { 9542dd076b8SGabor Kovesdan fputs(pfetch(old), ofp); 9552dd076b8SGabor Kovesdan } 9562dd076b8SGabor Kovesdan last_frozen_line++; 9572dd076b8SGabor Kovesdan old++; 9582dd076b8SGabor Kovesdan } 9592dd076b8SGabor Kovesdan if (do_defines) { 9602dd076b8SGabor Kovesdan fputs(else_defined, ofp); 9612dd076b8SGabor Kovesdan def_state = IN_ELSE; 9622dd076b8SGabor Kovesdan } 9632dd076b8SGabor Kovesdan while (pch_char(new) == '!') { 9642dd076b8SGabor Kovesdan fputs(pfetch(new), ofp); 9652dd076b8SGabor Kovesdan new++; 9662dd076b8SGabor Kovesdan } 9672dd076b8SGabor Kovesdan } else { 9682dd076b8SGabor Kovesdan if (pch_char(new) != ' ') 9692dd076b8SGabor Kovesdan fatal("Internal error: expected ' '\n"); 9702dd076b8SGabor Kovesdan old++; 9712dd076b8SGabor Kovesdan new++; 9722dd076b8SGabor Kovesdan if (do_defines && def_state != OUTSIDE) { 9732dd076b8SGabor Kovesdan fputs(end_defined, ofp); 9742dd076b8SGabor Kovesdan def_state = OUTSIDE; 9752dd076b8SGabor Kovesdan } 9762dd076b8SGabor Kovesdan } 9772dd076b8SGabor Kovesdan } 9782dd076b8SGabor Kovesdan if (new <= pat_end && pch_char(new) == '+') { 9792dd076b8SGabor Kovesdan copy_till(where + old - 1, false); 9802dd076b8SGabor Kovesdan if (do_defines) { 9812dd076b8SGabor Kovesdan if (def_state == OUTSIDE) { 9822dd076b8SGabor Kovesdan fputs(if_defined, ofp); 9832dd076b8SGabor Kovesdan def_state = IN_IFDEF; 9842dd076b8SGabor Kovesdan } else if (def_state == IN_IFNDEF) { 9852dd076b8SGabor Kovesdan fputs(else_defined, ofp); 9862dd076b8SGabor Kovesdan def_state = IN_ELSE; 9872dd076b8SGabor Kovesdan } 9882dd076b8SGabor Kovesdan } 9892dd076b8SGabor Kovesdan while (new <= pat_end && pch_char(new) == '+') { 9902dd076b8SGabor Kovesdan fputs(pfetch(new), ofp); 9912dd076b8SGabor Kovesdan new++; 9922dd076b8SGabor Kovesdan } 9932dd076b8SGabor Kovesdan } 9942dd076b8SGabor Kovesdan if (do_defines && def_state != OUTSIDE) { 9952dd076b8SGabor Kovesdan fputs(end_defined, ofp); 9962dd076b8SGabor Kovesdan } 9972dd076b8SGabor Kovesdan } 9982dd076b8SGabor Kovesdan 9992dd076b8SGabor Kovesdan /* 10002dd076b8SGabor Kovesdan * Open the new file. 10012dd076b8SGabor Kovesdan */ 10022dd076b8SGabor Kovesdan static void 10032dd076b8SGabor Kovesdan init_output(const char *name) 10042dd076b8SGabor Kovesdan { 10052dd076b8SGabor Kovesdan ofp = fopen(name, "w"); 10062dd076b8SGabor Kovesdan if (ofp == NULL) 10072dd076b8SGabor Kovesdan pfatal("can't create %s", name); 10082dd076b8SGabor Kovesdan } 10092dd076b8SGabor Kovesdan 10102dd076b8SGabor Kovesdan /* 10112dd076b8SGabor Kovesdan * Open a file to put hunks we can't locate. 10122dd076b8SGabor Kovesdan */ 10132dd076b8SGabor Kovesdan static void 10142dd076b8SGabor Kovesdan init_reject(const char *name) 10152dd076b8SGabor Kovesdan { 10162dd076b8SGabor Kovesdan rejfp = fopen(name, "w"); 10172dd076b8SGabor Kovesdan if (rejfp == NULL) 10182dd076b8SGabor Kovesdan pfatal("can't create %s", name); 10192dd076b8SGabor Kovesdan } 10202dd076b8SGabor Kovesdan 10212dd076b8SGabor Kovesdan /* 10222dd076b8SGabor Kovesdan * Copy input file to output, up to wherever hunk is to be applied. 10232dd076b8SGabor Kovesdan * If endoffile is true, treat the last line specially since it may 10242dd076b8SGabor Kovesdan * lack a newline. 10252dd076b8SGabor Kovesdan */ 10262dd076b8SGabor Kovesdan static void 10272dd076b8SGabor Kovesdan copy_till(LINENUM lastline, bool endoffile) 10282dd076b8SGabor Kovesdan { 10292dd076b8SGabor Kovesdan if (last_frozen_line > lastline) 10302dd076b8SGabor Kovesdan fatal("misordered hunks! output would be garbled\n"); 10312dd076b8SGabor Kovesdan while (last_frozen_line < lastline) { 10322dd076b8SGabor Kovesdan if (++last_frozen_line == lastline && endoffile) 10332dd076b8SGabor Kovesdan dump_line(last_frozen_line, !last_line_missing_eol); 10342dd076b8SGabor Kovesdan else 10352dd076b8SGabor Kovesdan dump_line(last_frozen_line, true); 10362dd076b8SGabor Kovesdan } 10372dd076b8SGabor Kovesdan } 10382dd076b8SGabor Kovesdan 10392dd076b8SGabor Kovesdan /* 10402dd076b8SGabor Kovesdan * Finish copying the input file to the output file. 10412dd076b8SGabor Kovesdan */ 10422dd076b8SGabor Kovesdan static bool 10432dd076b8SGabor Kovesdan spew_output(void) 10442dd076b8SGabor Kovesdan { 10452dd076b8SGabor Kovesdan int rv; 10462dd076b8SGabor Kovesdan 10472dd076b8SGabor Kovesdan #ifdef DEBUGGING 10482dd076b8SGabor Kovesdan if (debug & 256) 10492dd076b8SGabor Kovesdan say("il=%ld lfl=%ld\n", input_lines, last_frozen_line); 10502dd076b8SGabor Kovesdan #endif 10512dd076b8SGabor Kovesdan if (input_lines) 10522dd076b8SGabor Kovesdan copy_till(input_lines, true); /* dump remainder of file */ 1053ffca5883SGlen Barber rv = ferror(ofp) == 0 && fclose(ofp) == 0; 10542dd076b8SGabor Kovesdan ofp = NULL; 10552dd076b8SGabor Kovesdan return rv; 10562dd076b8SGabor Kovesdan } 10572dd076b8SGabor Kovesdan 10582dd076b8SGabor Kovesdan /* 10592dd076b8SGabor Kovesdan * Copy one line from input to output. 10602dd076b8SGabor Kovesdan */ 10612dd076b8SGabor Kovesdan static void 10622dd076b8SGabor Kovesdan dump_line(LINENUM line, bool write_newline) 10632dd076b8SGabor Kovesdan { 10642dd076b8SGabor Kovesdan char *s; 10652dd076b8SGabor Kovesdan 10662dd076b8SGabor Kovesdan s = ifetch(line, 0); 10672dd076b8SGabor Kovesdan if (s == NULL) 10682dd076b8SGabor Kovesdan return; 10692dd076b8SGabor Kovesdan /* Note: string is not NUL terminated. */ 10702dd076b8SGabor Kovesdan for (; *s != '\n'; s++) 10712dd076b8SGabor Kovesdan putc(*s, ofp); 10722dd076b8SGabor Kovesdan if (write_newline) 10732dd076b8SGabor Kovesdan putc('\n', ofp); 10742dd076b8SGabor Kovesdan } 10752dd076b8SGabor Kovesdan 10762dd076b8SGabor Kovesdan /* 10772dd076b8SGabor Kovesdan * Does the patch pattern match at line base+offset? 10782dd076b8SGabor Kovesdan */ 10792dd076b8SGabor Kovesdan static bool 10802dd076b8SGabor Kovesdan patch_match(LINENUM base, LINENUM offset, LINENUM fuzz) 10812dd076b8SGabor Kovesdan { 10822dd076b8SGabor Kovesdan LINENUM pline = 1 + fuzz; 10832dd076b8SGabor Kovesdan LINENUM iline; 10842dd076b8SGabor Kovesdan LINENUM pat_lines = pch_ptrn_lines() - fuzz; 10852dd076b8SGabor Kovesdan const char *ilineptr; 10862dd076b8SGabor Kovesdan const char *plineptr; 10874f548c19SPedro F. Giffuni unsigned short plinelen; 10882dd076b8SGabor Kovesdan 1089bc4f0fe3SKyle Evans /* Patch does not match if we don't have any more context to use */ 1090bc4f0fe3SKyle Evans if (pline > pat_lines) 1091bc4f0fe3SKyle Evans return false; 10922dd076b8SGabor Kovesdan for (iline = base + offset + fuzz; pline <= pat_lines; pline++, iline++) { 10932dd076b8SGabor Kovesdan ilineptr = ifetch(iline, offset >= 0); 10942dd076b8SGabor Kovesdan if (ilineptr == NULL) 10952dd076b8SGabor Kovesdan return false; 10962dd076b8SGabor Kovesdan plineptr = pfetch(pline); 10972dd076b8SGabor Kovesdan plinelen = pch_line_len(pline); 10982dd076b8SGabor Kovesdan if (canonicalize) { 10992dd076b8SGabor Kovesdan if (!similar(ilineptr, plineptr, plinelen)) 11002dd076b8SGabor Kovesdan return false; 11012dd076b8SGabor Kovesdan } else if (strnNE(ilineptr, plineptr, plinelen)) 11022dd076b8SGabor Kovesdan return false; 11032dd076b8SGabor Kovesdan if (iline == input_lines) { 11042dd076b8SGabor Kovesdan /* 11052dd076b8SGabor Kovesdan * We are looking at the last line of the file. 11062dd076b8SGabor Kovesdan * If the file has no eol, the patch line should 11072dd076b8SGabor Kovesdan * not have one either and vice-versa. Note that 11082dd076b8SGabor Kovesdan * plinelen > 0. 11092dd076b8SGabor Kovesdan */ 11102dd076b8SGabor Kovesdan if (last_line_missing_eol) { 11112dd076b8SGabor Kovesdan if (plineptr[plinelen - 1] == '\n') 11122dd076b8SGabor Kovesdan return false; 11132dd076b8SGabor Kovesdan } else { 11142dd076b8SGabor Kovesdan if (plineptr[plinelen - 1] != '\n') 11152dd076b8SGabor Kovesdan return false; 11162dd076b8SGabor Kovesdan } 11172dd076b8SGabor Kovesdan } 11182dd076b8SGabor Kovesdan } 11192dd076b8SGabor Kovesdan return true; 11202dd076b8SGabor Kovesdan } 11212dd076b8SGabor Kovesdan 11222dd076b8SGabor Kovesdan /* 11232dd076b8SGabor Kovesdan * Do two lines match with canonicalized white space? 11242dd076b8SGabor Kovesdan */ 11252dd076b8SGabor Kovesdan static bool 11262dd076b8SGabor Kovesdan similar(const char *a, const char *b, int len) 11272dd076b8SGabor Kovesdan { 11282dd076b8SGabor Kovesdan while (len) { 11292dd076b8SGabor Kovesdan if (isspace((unsigned char)*b)) { /* whitespace (or \n) to match? */ 11302dd076b8SGabor Kovesdan if (!isspace((unsigned char)*a)) /* no corresponding whitespace? */ 11312dd076b8SGabor Kovesdan return false; 11322dd076b8SGabor Kovesdan while (len && isspace((unsigned char)*b) && *b != '\n') 11332dd076b8SGabor Kovesdan b++, len--; /* skip pattern whitespace */ 11342dd076b8SGabor Kovesdan while (isspace((unsigned char)*a) && *a != '\n') 11352dd076b8SGabor Kovesdan a++; /* skip target whitespace */ 11362dd076b8SGabor Kovesdan if (*a == '\n' || *b == '\n') 11372dd076b8SGabor Kovesdan return (*a == *b); /* should end in sync */ 11382dd076b8SGabor Kovesdan } else if (*a++ != *b++) /* match non-whitespace chars */ 11392dd076b8SGabor Kovesdan return false; 11402dd076b8SGabor Kovesdan else 11412dd076b8SGabor Kovesdan len--; /* probably not necessary */ 11422dd076b8SGabor Kovesdan } 11432dd076b8SGabor Kovesdan return true; /* actually, this is not reached */ 11442dd076b8SGabor Kovesdan /* since there is always a \n */ 11452dd076b8SGabor Kovesdan } 114650dacbf6SKyle Evans 114750dacbf6SKyle Evans static bool 114850dacbf6SKyle Evans handle_creation(bool out_existed, bool *remove) 114950dacbf6SKyle Evans { 115050dacbf6SKyle Evans bool reverse_seen; 115150dacbf6SKyle Evans 115250dacbf6SKyle Evans reverse_seen = false; 115350dacbf6SKyle Evans if (reverse && out_existed) { 115450dacbf6SKyle Evans /* 115550dacbf6SKyle Evans * If the patch creates the file and we're reversing the patch, 115650dacbf6SKyle Evans * then we need to indicate to the patch processor that it's OK 115750dacbf6SKyle Evans * to remove this file. 115850dacbf6SKyle Evans */ 115950dacbf6SKyle Evans *remove = true; 116050dacbf6SKyle Evans } else if (!reverse && out_existed) { 116150dacbf6SKyle Evans /* 116250dacbf6SKyle Evans * Otherwise, we need to blow the horn because the patch appears 116350dacbf6SKyle Evans * to be reversed/already applied. For non-batch jobs, we'll 116450dacbf6SKyle Evans * prompt to figure out what we should be trying to do to raise 116550dacbf6SKyle Evans * awareness of the issue. batch (-t) processing suppresses the 116650dacbf6SKyle Evans * questions and just assumes that we're reversed if it looks 116750dacbf6SKyle Evans * like we are, which is always the case if we've reached this 116850dacbf6SKyle Evans * branch. 116950dacbf6SKyle Evans */ 117050dacbf6SKyle Evans if (force) { 117150dacbf6SKyle Evans skip_rest_of_patch = true; 117250dacbf6SKyle Evans return (false); 117350dacbf6SKyle Evans } 117450dacbf6SKyle Evans if (noreverse) { 117550dacbf6SKyle Evans /* If -N is supplied, however, we bail out/ignore. */ 117650dacbf6SKyle Evans say("Ignoring previously applied (or reversed) patch.\n"); 117750dacbf6SKyle Evans skip_rest_of_patch = true; 117850dacbf6SKyle Evans return (false); 117950dacbf6SKyle Evans } 118050dacbf6SKyle Evans 118150dacbf6SKyle Evans /* Unreversed... suspicious if the file existed. */ 118250dacbf6SKyle Evans if (!pch_swap()) 118350dacbf6SKyle Evans fatal("lost hunk on alloc error!\n"); 118450dacbf6SKyle Evans 118550dacbf6SKyle Evans reverse = !reverse; 118650dacbf6SKyle Evans 118750dacbf6SKyle Evans if (batch) { 118850dacbf6SKyle Evans if (verbose) 118950dacbf6SKyle Evans say("Patch creates file that already exists, %s %seversed", 119050dacbf6SKyle Evans reverse ? "Assuming" : "Ignoring", 119150dacbf6SKyle Evans reverse ? "R" : "Unr"); 119250dacbf6SKyle Evans } else { 119350dacbf6SKyle Evans ask("Patch creates file that already exists! %s -R? [y] ", 119450dacbf6SKyle Evans reverse ? "Assume" : "Ignore"); 119550dacbf6SKyle Evans 119650dacbf6SKyle Evans if (*buf == 'n') { 119750dacbf6SKyle Evans ask("Apply anyway? [n]"); 119850dacbf6SKyle Evans if (*buf != 'y') 119950dacbf6SKyle Evans /* Don't apply; error out. */ 120050dacbf6SKyle Evans skip_rest_of_patch = true; 120150dacbf6SKyle Evans else 120250dacbf6SKyle Evans /* Attempt to apply. */ 120350dacbf6SKyle Evans reverse_seen = true; 120450dacbf6SKyle Evans reverse = !reverse; 120550dacbf6SKyle Evans if (!pch_swap()) 120650dacbf6SKyle Evans fatal("lost hunk on alloc error!\n"); 120750dacbf6SKyle Evans } else { 120850dacbf6SKyle Evans /* 120950dacbf6SKyle Evans * They've opted to assume -R; effectively the 121050dacbf6SKyle Evans * same as the first branch in this function, 121150dacbf6SKyle Evans * but the decision is here rather than in a 121250dacbf6SKyle Evans * prior patch/hunk as in that branch. 121350dacbf6SKyle Evans */ 121450dacbf6SKyle Evans *remove = true; 121550dacbf6SKyle Evans } 121650dacbf6SKyle Evans } 121750dacbf6SKyle Evans } 121850dacbf6SKyle Evans 121950dacbf6SKyle Evans /* 122050dacbf6SKyle Evans * The return value indicates if we offered a chance to reverse but the 122150dacbf6SKyle Evans * user declined. This keeps the main patch processor in the loop since 122250dacbf6SKyle Evans * we've taken this out of the normal flow of hunk processing to 122350dacbf6SKyle Evans * simplify logic a little bit. 122450dacbf6SKyle Evans */ 122550dacbf6SKyle Evans return (reverse_seen); 122650dacbf6SKyle Evans } 1227