version 1.19, 2003/07/18 02:00:09 |
version 1.20, 2003/07/21 14:00:41 |
|
|
/* $OpenBSD$ */ |
/* $OpenBSD$ */ |
|
|
/* patch - a program to apply diffs to original files |
/* |
* |
* patch - a program to apply diffs to original files |
|
* |
* Copyright 1986, Larry Wall |
* Copyright 1986, Larry Wall |
* |
* |
* Redistribution and use in source and binary forms, with or without |
* Redistribution and use in source and binary forms, with or without |
* modification, are permitted provided that the following condition |
* modification, are permitted provided that the following condition is met: |
* is met: |
* 1. Redistributions of source code must retain the above copyright notice, |
* 1. Redistributions of source code must retain the above copyright |
* this condition and the following disclaimer. |
* notice, this condition and the following disclaimer. |
* |
* |
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY |
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND |
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED |
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE |
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
* DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR |
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE |
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL |
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL |
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR |
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS |
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER |
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) |
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT |
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT |
|
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY |
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY |
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF |
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF |
* SUCH DAMAGE. |
* SUCH DAMAGE. |
* |
* |
* -C option added in 1998, original code by Marc Espie, |
* -C option added in 1998, original code by Marc Espie, based on FreeBSD |
* based on FreeBSD behaviour |
* behaviour |
*/ |
*/ |
|
|
#ifndef lint |
#ifndef lint |
|
|
#include "inp.h" |
#include "inp.h" |
#include "backupfile.h" |
#include "backupfile.h" |
|
|
/* procedures */ |
void reinitialize_almost_everything(void); |
|
void get_some_switches(void); |
|
LINENUM locate_hunk(LINENUM); |
|
void abort_hunk(void); |
|
void apply_hunk(LINENUM); |
|
void init_output(char *); |
|
void init_reject(char *); |
|
void copy_till(LINENUM); |
|
void spew_output(void); |
|
void dump_line(LINENUM); |
|
bool patch_match(LINENUM, LINENUM, LINENUM); |
|
bool similar(char *, char *, int); |
|
void re_input(void); |
|
void my_exit(int) __attribute__((noreturn)); |
|
int optcmp(const void *, const void *); |
|
char decode_long_option(char *); |
|
|
void reinitialize_almost_everything(void); |
|
void get_some_switches(void); |
|
LINENUM locate_hunk(LINENUM); |
|
void abort_hunk(void); |
|
void apply_hunk(LINENUM); |
|
void init_output(char *); |
|
void init_reject(char *); |
|
void copy_till(LINENUM); |
|
void spew_output(void); |
|
void dump_line(LINENUM); |
|
bool patch_match(LINENUM, LINENUM, LINENUM); |
|
bool similar(char *, char *, int); |
|
void re_input(void); |
|
void my_exit(int) __attribute__((noreturn)); |
|
int optcmp(const void *, const void *); |
|
char decode_long_option(char *); |
|
|
|
/* TRUE if -E was specified on command line. */ |
/* TRUE if -E was specified on command line. */ |
static int remove_empty_files = FALSE; |
static int remove_empty_files = FALSE; |
|
|
/* TRUE if -R was specified on command line. */ |
/* TRUE if -R was specified on command line. */ |
static int reverse_flag_specified = FALSE; |
static int reverse_flag_specified = FALSE; |
|
|
/* TRUE if -C was specified on command line. */ |
/* TRUE if -C was specified on command line. */ |
bool check_only = FALSE; |
bool check_only = FALSE; |
|
|
/* Apply a set of diffs as appropriate. */ |
/* Apply a set of diffs as appropriate. */ |
|
|
int |
int |
main(int argc, char *argv[]) |
main(int argc, char *argv[]) |
{ |
{ |
LINENUM where; |
int hunk = 0, failed = 0, failtotal = 0, patch_seen = 0, i; |
LINENUM newwhere; |
LINENUM where, newwhere, fuzz, mymaxfuzz; |
LINENUM fuzz; |
char *tmpdir, *v; |
LINENUM mymaxfuzz; |
|
int hunk = 0; |
|
int failed = 0; |
|
int failtotal = 0; |
|
int patch_seen = 0; |
|
int i; |
|
|
|
setbuf(stderr, serrbuf); |
setbuf(stderr, serrbuf); |
for (i = 0; i<MAXFILEC; i++) |
for (i = 0; i < MAXFILEC; i++) |
filearg[i] = Nullch; |
filearg[i] = Nullch; |
|
|
myuid = getuid(); |
myuid = getuid(); |
|
|
/* Cons up the names of the temporary files. */ |
/* Cons up the names of the temporary files. */ |
{ |
tmpdir = getenv("TMPDIR"); |
/* Directory for temporary files. */ |
if (tmpdir == NULL) { |
char *tmpdir; |
tmpdir = "/tmp"; |
|
} |
|
if (asprintf(&TMPOUTNAME, "%s/patchoXXXXXXXXXX", tmpdir) == -1) |
|
fatal("cannot allocate memory"); |
|
if ((i = mkstemp(TMPOUTNAME)) < 0) |
|
pfatal("can't create %s", TMPOUTNAME); |
|
close(i); |
|
|
tmpdir = getenv ("TMPDIR"); |
if (asprintf(&TMPINNAME, "%s/patchiXXXXXXXXXX", tmpdir) == -1) |
if (tmpdir == NULL) { |
fatal("cannot allocate memory"); |
tmpdir = "/tmp"; |
if ((i = mkstemp(TMPINNAME)) < 0) |
} |
pfatal("can't create %s", TMPINNAME); |
|
close(i); |
|
|
if (asprintf(&TMPOUTNAME, "%s/patchoXXXXXXXXXX", tmpdir) == -1) |
if (asprintf(&TMPREJNAME, "%s/patchrXXXXXXXXXX", tmpdir) == -1) |
fatal("cannot allocate memory"); |
fatal("cannot allocate memory"); |
if ((i = mkstemp(TMPOUTNAME)) < 0) |
if ((i = mkstemp(TMPREJNAME)) < 0) |
pfatal("can't create %s", TMPOUTNAME); |
pfatal("can't create %s", TMPREJNAME); |
close(i); |
close(i); |
|
|
if (asprintf(&TMPINNAME, "%s/patchiXXXXXXXXXX", tmpdir) == -1) |
if (asprintf(&TMPPATNAME, "%s/patchpXXXXXXXXXX", tmpdir) == -1) |
fatal("cannot allocate memory"); |
fatal("cannot allocate memory"); |
if ((i = mkstemp(TMPINNAME)) < 0) |
if ((i = mkstemp(TMPPATNAME)) < 0) |
pfatal("can't create %s", TMPINNAME); |
pfatal("can't create %s", TMPPATNAME); |
close(i); |
close(i); |
|
|
if (asprintf(&TMPREJNAME, "%s/patchrXXXXXXXXXX", tmpdir) == -1) |
v = getenv("SIMPLE_BACKUP_SUFFIX"); |
fatal("cannot allocate memory"); |
if (v) |
if ((i = mkstemp(TMPREJNAME)) < 0) |
simple_backup_suffix = v; |
pfatal("can't create %s", TMPREJNAME); |
else |
close(i); |
simple_backup_suffix = ORIGEXT; |
|
|
if (asprintf(&TMPPATNAME, "%s/patchpXXXXXXXXXX", tmpdir) == -1) |
v = getenv("VERSION_CONTROL"); |
fatal("cannot allocate memory"); |
backup_type = get_version(v); /* OK to pass NULL. */ |
if ((i = mkstemp(TMPPATNAME)) < 0) |
|
pfatal("can't create %s", TMPPATNAME); |
|
close(i); |
|
} |
|
|
|
{ |
/* parse switches */ |
char *v; |
Argc = argc; |
|
Argv = argv; |
|
get_some_switches(); |
|
|
v = getenv ("SIMPLE_BACKUP_SUFFIX"); |
/* make sure we clean up /tmp in case of disaster */ |
if (v) |
set_signals(0); |
simple_backup_suffix = v; |
|
else |
|
simple_backup_suffix = ORIGEXT; |
|
#ifndef NODIR |
|
v = getenv ("VERSION_CONTROL"); |
|
backup_type = get_version (v); /* OK to pass NULL. */ |
|
#endif |
|
} |
|
|
|
/* parse switches */ |
for (open_patch_file(filearg[1]); there_is_another_patch(); |
Argc = argc; |
reinitialize_almost_everything()) { |
Argv = argv; |
/* for each patch in patch file */ |
get_some_switches(); |
|
|
|
/* make sure we clean up /tmp in case of disaster */ |
patch_seen = TRUE; |
set_signals(0); |
|
|
|
for ( |
if (outname == Nullch) |
open_patch_file(filearg[1]); |
outname = savestr(filearg[0]); |
there_is_another_patch(); |
|
reinitialize_almost_everything() |
|
) { /* for each patch in patch file */ |
|
patch_seen = TRUE; |
|
|
|
if (outname == Nullch) |
/* for ed script just up and do it and exit */ |
outname = savestr(filearg[0]); |
if (diff_type == ED_DIFF) { |
|
do_ed_script(); |
|
continue; |
|
} |
|
/* initialize the patched file */ |
|
if (!skip_rest_of_patch) |
|
init_output(TMPOUTNAME); |
|
|
/* for ed script just up and do it and exit */ |
/* initialize reject file */ |
if (diff_type == ED_DIFF) { |
init_reject(TMPREJNAME); |
do_ed_script(); |
|
continue; |
|
} |
|
|
|
/* initialize the patched file */ |
/* find out where all the lines are */ |
if (!skip_rest_of_patch) |
if (!skip_rest_of_patch) |
init_output(TMPOUTNAME); |
scan_input(filearg[0]); |
|
|
/* initialize reject file */ |
/* from here on, open no standard i/o files, because malloc */ |
init_reject(TMPREJNAME); |
/* might misfire and we can't catch it easily */ |
|
|
/* find out where all the lines are */ |
/* apply each hunk of patch */ |
if (!skip_rest_of_patch) |
hunk = 0; |
scan_input(filearg[0]); |
failed = 0; |
|
out_of_mem = FALSE; |
/* from here on, open no standard i/o files, because malloc */ |
while (another_hunk()) { |
/* might misfire and we can't catch it easily */ |
hunk++; |
|
fuzz = Nulline; |
/* apply each hunk of patch */ |
mymaxfuzz = pch_context(); |
hunk = 0; |
if (maxfuzz < mymaxfuzz) |
failed = 0; |
mymaxfuzz = maxfuzz; |
out_of_mem = FALSE; |
if (!skip_rest_of_patch) { |
while (another_hunk()) { |
do { |
hunk++; |
where = locate_hunk(fuzz); |
fuzz = Nulline; |
if (hunk == 1 && where == Nulline && !force) { |
mymaxfuzz = pch_context(); |
|
if (maxfuzz < mymaxfuzz) |
|
mymaxfuzz = maxfuzz; |
|
if (!skip_rest_of_patch) { |
|
do { |
|
where = locate_hunk(fuzz); |
|
if (hunk == 1 && where == Nulline && !force) { |
|
/* dwim for reversed patch? */ |
/* dwim for reversed patch? */ |
if (!pch_swap()) { |
if (!pch_swap()) { |
if (fuzz == Nulline) |
if (fuzz == Nulline) |
say( |
say("Not enough memory to try swapped hunk! Assuming unswapped.\n"); |
"Not enough memory to try swapped hunk! Assuming unswapped.\n"); |
continue; |
continue; |
} |
|
reverse = !reverse; |
|
/* try again */ |
|
where = locate_hunk(fuzz); |
|
if (where == Nulline) { |
|
/* didn't find it swapped */ |
|
if (!pch_swap()) |
|
/* put it back to normal */ |
|
fatal("lost hunk on alloc error!\n"); |
|
reverse = !reverse; |
|
} else if (noreverse) { |
|
if (!pch_swap()) |
|
/* put it back to normal */ |
|
fatal("lost hunk on alloc error!\n"); |
|
reverse = !reverse; |
|
say("Ignoring previously applied (or reversed) patch.\n"); |
|
skip_rest_of_patch = TRUE; |
|
} else if (batch) { |
|
if (verbose) |
|
say("%seversed (or previously applied) patch detected! %s -R.", |
|
reverse ? "R" : "Unr", |
|
reverse ? "Assuming" : "Ignoring"); |
|
} else { |
|
ask("%seversed (or previously applied) patch detected! %s -R? [y] ", |
|
reverse ? "R" : "Unr", |
|
reverse ? "Assume" : "Ignore"); |
|
if (*buf == 'n') { |
|
ask("Apply anyway? [n] "); |
|
if (*buf != 'y') |
|
skip_rest_of_patch = TRUE; |
|
where = Nulline; |
|
reverse = !reverse; |
|
if (!pch_swap()) |
|
/* put it back to normal */ |
|
fatal("lost hunk on alloc error!\n"); |
|
} |
|
} |
|
} |
|
} while (!skip_rest_of_patch && where == Nulline && |
|
++fuzz <= mymaxfuzz); |
|
|
|
if (skip_rest_of_patch) { /* just got decided */ |
|
fclose(ofp); |
|
ofp = Nullfp; |
|
} |
} |
} |
reverse = !reverse; |
newwhere = pch_newfirst() + last_offset; |
where = locate_hunk(fuzz); /* try again */ |
if (skip_rest_of_patch) { |
if (where == Nulline) { /* didn't find it swapped */ |
abort_hunk(); |
if (!pch_swap()) /* put it back to normal */ |
failed++; |
fatal("lost hunk on alloc error!\n"); |
if (verbose) |
reverse = !reverse; |
say("Hunk #%d ignored at %ld.\n", |
|
hunk, newwhere); |
|
} else if (where == Nulline) { |
|
abort_hunk(); |
|
failed++; |
|
if (verbose) |
|
say("Hunk #%d failed at %ld.\n", |
|
hunk, newwhere); |
|
} else { |
|
apply_hunk(where); |
|
if (verbose) { |
|
say("Hunk #%d succeeded at %ld", |
|
hunk, newwhere); |
|
if (fuzz) |
|
say(" with fuzz %ld", fuzz); |
|
if (last_offset) |
|
say(" (offset %ld line%s)", |
|
last_offset, |
|
last_offset == 1L ? "" : "s"); |
|
say(".\n"); |
|
} |
} |
} |
else if (noreverse) { |
|
if (!pch_swap()) /* put it back to normal */ |
|
fatal("lost hunk on alloc error!\n"); |
|
reverse = !reverse; |
|
say( |
|
"Ignoring previously applied (or reversed) patch.\n"); |
|
skip_rest_of_patch = TRUE; |
|
} |
|
else if (batch) { |
|
if (verbose) |
|
say( |
|
"%seversed (or previously applied) patch detected! %s -R.", |
|
reverse ? "R" : "Unr", |
|
reverse ? "Assuming" : "Ignoring"); |
|
} |
|
else { |
|
ask( |
|
"%seversed (or previously applied) patch detected! %s -R? [y] ", |
|
reverse ? "R" : "Unr", |
|
reverse ? "Assume" : "Ignore"); |
|
if (*buf == 'n') { |
|
ask("Apply anyway? [n] "); |
|
if (*buf != 'y') |
|
skip_rest_of_patch = TRUE; |
|
where = Nulline; |
|
reverse = !reverse; |
|
if (!pch_swap()) /* put it back to normal */ |
|
fatal("lost hunk on alloc error!\n"); |
|
} |
|
} |
|
} |
|
} while (!skip_rest_of_patch && where == Nulline && |
|
++fuzz <= mymaxfuzz); |
|
|
|
if (skip_rest_of_patch) { /* just got decided */ |
|
fclose(ofp); |
|
ofp = Nullfp; |
|
} |
} |
} |
|
|
|
newwhere = pch_newfirst() + last_offset; |
if (out_of_mem && using_plan_a) { |
if (skip_rest_of_patch) { |
Argc = Argc_last; |
abort_hunk(); |
Argv = Argv_last; |
failed++; |
say("\n\nRan out of memory using Plan A--trying again...\n\n"); |
if (verbose) |
if (ofp) |
say("Hunk #%d ignored at %ld.\n", hunk, newwhere); |
fclose(ofp); |
} |
ofp = Nullfp; |
else if (where == Nulline) { |
if (rejfp) |
abort_hunk(); |
fclose(rejfp); |
failed++; |
rejfp = Nullfp; |
if (verbose) |
continue; |
say("Hunk #%d failed at %ld.\n", hunk, newwhere); |
|
} |
|
else { |
|
apply_hunk(where); |
|
if (verbose) { |
|
say("Hunk #%d succeeded at %ld", hunk, newwhere); |
|
if (fuzz) |
|
say(" with fuzz %ld", fuzz); |
|
if (last_offset) |
|
say(" (offset %ld line%s)", |
|
last_offset, last_offset==1L?"":"s"); |
|
say(".\n"); |
|
} |
} |
} |
assert(hunk); |
} |
|
|
|
if (out_of_mem && using_plan_a) { |
/* finish spewing out the new file */ |
Argc = Argc_last; |
if (!skip_rest_of_patch) |
Argv = Argv_last; |
spew_output(); |
say("\n\nRan out of memory using Plan A--trying again...\n\n"); |
|
if (ofp) |
|
fclose(ofp); |
|
ofp = Nullfp; |
|
if (rejfp) |
|
fclose(rejfp); |
|
rejfp = Nullfp; |
|
continue; |
|
} |
|
|
|
assert(hunk); |
/* and put the output where desired */ |
|
ignore_signals(); |
|
if (!skip_rest_of_patch) { |
|
struct stat statbuf; |
|
char *realout = outname; |
|
|
/* finish spewing out the new file */ |
if (!check_only) { |
if (!skip_rest_of_patch) |
if (move_file(TMPOUTNAME, outname) < 0) { |
spew_output(); |
toutkeep = TRUE; |
|
realout = TMPOUTNAME; |
|
chmod(TMPOUTNAME, filemode); |
|
} else |
|
chmod(outname, filemode); |
|
|
/* and put the output where desired */ |
if (remove_empty_files && |
ignore_signals(); |
stat(realout, &statbuf) == 0 && |
if (!skip_rest_of_patch) { |
statbuf.st_size == 0) { |
struct stat statbuf; |
if (verbose) |
char *realout = outname; |
say("Removing %s (empty after patching).\n", |
|
realout); |
if (!check_only) { |
unlink(realout); |
if (move_file(TMPOUTNAME, outname) < 0) { |
} |
toutkeep = TRUE; |
} |
realout = TMPOUTNAME; |
|
chmod(TMPOUTNAME, filemode); |
|
} |
} |
else |
fclose(rejfp); |
chmod(outname, filemode); |
rejfp = Nullfp; |
|
if (failed) { |
if (remove_empty_files && stat(realout, &statbuf) == 0 |
failtotal += failed; |
&& statbuf.st_size == 0) { |
if (!*rejname) { |
if (verbose) |
if (strlcpy(rejname, outname, |
say("Removing %s (empty after patching).\n", realout); |
sizeof(rejname)) >= sizeof(rejname)) |
while (unlink(realout) >= 0) ; /* while is for Eunice. */ |
fatal("filename %s is too long\n", outname); |
|
if (strlcat(rejname, REJEXT, |
|
sizeof(rejname)) >= sizeof(rejname)) |
|
fatal("filename %s is too long\n", outname); |
|
} |
|
if (skip_rest_of_patch) { |
|
say("%d out of %d hunks ignored--saving rejects to %s\n", |
|
failed, hunk, rejname); |
|
} else { |
|
say("%d out of %d hunks failed--saving rejects to %s\n", |
|
failed, hunk, rejname); |
|
} |
|
if (!check_only && move_file(TMPREJNAME, rejname) < 0) |
|
trejkeep = TRUE; |
} |
} |
} |
set_signals(1); |
} |
} |
fclose(rejfp); |
if (!patch_seen) |
rejfp = Nullfp; |
failtotal++; |
if (failed) { |
my_exit(failtotal); |
failtotal += failed; |
/* NOTREACHED */ |
if (!*rejname) { |
|
if (strlcpy(rejname, outname, sizeof(rejname)) >= sizeof(rejname)) |
|
fatal("filename %s is too long\n", outname); |
|
if (strlcat(rejname, REJEXT, sizeof(rejname)) >= sizeof(rejname)) |
|
fatal("filename %s is too long\n", outname); |
|
} |
|
if (skip_rest_of_patch) { |
|
say("%d out of %d hunks ignored--saving rejects to %s\n", |
|
failed, hunk, rejname); |
|
} |
|
else { |
|
say("%d out of %d hunks failed--saving rejects to %s\n", |
|
failed, hunk, rejname); |
|
} |
|
if (!check_only && move_file(TMPREJNAME, rejname) < 0) |
|
trejkeep = TRUE; |
|
} |
|
set_signals(1); |
|
} |
|
if (!patch_seen) |
|
failtotal++; |
|
my_exit(failtotal); |
|
/* NOTREACHED */ |
|
} |
} |
|
|
/* Prepare to find the next patch to do in the patch file. */ |
/* Prepare to find the next patch to do in the patch file. */ |
|
|
void |
void |
reinitialize_almost_everything() |
reinitialize_almost_everything(void) |
{ |
{ |
re_patch(); |
re_patch(); |
re_input(); |
re_input(); |
|
|
input_lines = 0; |
input_lines = 0; |
last_frozen_line = 0; |
last_frozen_line = 0; |
|
|
filec = 0; |
filec = 0; |
if (filearg[0] != Nullch && !out_of_mem) { |
if (filearg[0] != Nullch && !out_of_mem) { |
free(filearg[0]); |
free(filearg[0]); |
filearg[0] = Nullch; |
filearg[0] = Nullch; |
} |
} |
|
if (outname != Nullch) { |
|
free(outname); |
|
outname = Nullch; |
|
} |
|
last_offset = 0; |
|
|
if (outname != Nullch) { |
diff_type = 0; |
free(outname); |
|
outname = Nullch; |
|
} |
|
|
|
last_offset = 0; |
if (revision != Nullch) { |
|
free(revision); |
|
revision = Nullch; |
|
} |
|
reverse = reverse_flag_specified; |
|
skip_rest_of_patch = FALSE; |
|
|
diff_type = 0; |
get_some_switches(); |
|
|
if (revision != Nullch) { |
if (filec >= 2) |
free(revision); |
fatal("you may not change to a different patch file\n"); |
revision = Nullch; |
|
} |
|
|
|
reverse = reverse_flag_specified; |
|
skip_rest_of_patch = FALSE; |
|
|
|
get_some_switches(); |
|
|
|
if (filec >= 2) |
|
fatal("you may not change to a different patch file\n"); |
|
} |
} |
|
|
static char * |
static char * |
nextarg(void) |
nextarg(void) |
{ |
{ |
if (!--Argc) |
if (!--Argc) |
fatal("missing argument after `%s'\n", *Argv); |
fatal("missing argument after `%s'\n", *Argv); |
return *++Argv; |
return *++Argv; |
} |
} |
|
|
/* Module for handling of long options. */ |
/* Module for handling of long options. */ |
|
|
struct option { |
struct option { |
char *long_opt; |
char *long_opt; |
char short_opt; |
char short_opt; |
}; |
}; |
|
|
int |
int |
optcmp(const void *v1, const void *v2) |
optcmp(const void *v1, const void *v2) |
{ |
{ |
const struct option *a = v1, *b = v2; |
const struct option *a = v1, *b = v2; |
|
|
return strcmp (a->long_opt, b->long_opt); |
return strcmp(a->long_opt, b->long_opt); |
} |
} |
|
|
/* Decode Long options beginning with "--" to their short equivalents. */ |
/* Decode Long options beginning with "--" to their short equivalents. */ |
|
|
char |
char |
decode_long_option(char *opt) |
decode_long_option(char *opt) |
{ |
{ |
/* This table must be sorted on the first field. We also decode |
/* |
unimplemented options as those will be handled later anyway. */ |
* This table must be sorted on the first field. We also decode |
static struct option options[] = { |
* unimplemented options as those will be handled later anyway. |
{ "batch", 't' }, |
*/ |
{ "check", 'C' }, |
static struct option options[] = { |
{ "context", 'c' }, |
{"batch", 't'}, |
{ "debug", 'x' }, |
{"check", 'C'}, |
{ "directory", 'd' }, |
{"context", 'c'}, |
{ "ed", 'e' }, |
{"debug", 'x'}, |
{ "force", 'f' }, |
{"directory", 'd'}, |
{ "forward", 'N' }, |
{"ed", 'e'}, |
{ "fuzz", 'F' }, |
{"force", 'f'}, |
{ "ifdef", 'D' }, |
{"forward", 'N'}, |
{ "ignore-whitespace", 'l' }, |
{"fuzz", 'F'}, |
{ "normal", 'n' }, |
{"ifdef", 'D'}, |
{ "output", 'o' }, |
{"ignore-whitespace", 'l'}, |
{ "prefix", 'B' }, |
{"normal", 'n'}, |
{ "quiet", 's' }, |
{"output", 'o'}, |
{ "reject-file", 'r' }, |
{"prefix", 'B'}, |
{ "remove-empty-files", 'E' }, |
{"quiet", 's'}, |
{ "reverse", 'R' }, |
{"reject-file", 'r'}, |
{ "silent", 's' }, |
{"remove-empty-files", 'E'}, |
{ "skip", 'S' }, |
{"reverse", 'R'}, |
{ "strip", 'p' }, |
{"silent", 's'}, |
{ "suffix", 'b' }, |
{"skip", 'S'}, |
{ "unified", 'u' }, |
{"strip", 'p'}, |
{ "version", 'v' }, |
{"suffix", 'b'}, |
{ "version-control", 'V' }, |
{"unified", 'u'}, |
}; |
{"version", 'v'}, |
struct option key, *found; |
{"version-control", 'V'}, |
|
}; |
|
struct option key, *found; |
|
|
key.long_opt = opt; |
key.long_opt = opt; |
found = (struct option *)bsearch(&key, options, |
found = (struct option *) bsearch(&key, options, |
sizeof(options) / sizeof(options[0]), |
sizeof(options) / sizeof(options[0]), |
sizeof(options[0]), optcmp); |
sizeof(options[0]), optcmp); |
return found ? found->short_opt : '\0'; |
return found ? found->short_opt : '\0'; |
} |
} |
|
|
/* Process switches and filenames up to next '+' or end of list. */ |
/* Process switches and filenames up to next '+' or end of list. */ |
|
|
void |
void |
get_some_switches() |
get_some_switches(void) |
{ |
{ |
char *s; |
char *s; |
|
|
rejname[0] = '\0'; |
rejname[0] = '\0'; |
Argc_last = Argc; |
Argc_last = Argc; |
Argv_last = Argv; |
Argv_last = Argv; |
if (!Argc) |
if (!Argc) |
return; |
return; |
for (Argc--,Argv++; Argc; Argc--,Argv++) { |
for (Argc--, Argv++; Argc; Argc--, Argv++) { |
s = Argv[0]; |
s = Argv[0]; |
if (strEQ(s, "+")) { |
if (strEQ(s, "+")) { |
return; /* + will be skipped by for loop */ |
return; /* + will be skipped by for loop */ |
} |
} |
if (*s != '-' || !s[1]) { |
if (*s != '-' || !s[1]) { |
if (filec == MAXFILEC) |
if (filec == MAXFILEC) |
fatal("too many file arguments\n"); |
fatal("too many file arguments\n"); |
filearg[filec++] = savestr(s); |
filearg[filec++] = savestr(s); |
} |
} else { |
else { |
char opt; |
char opt; |
|
|
|
if (*(s + 1) == '-') { |
if (*(s + 1) == '-') { |
opt = decode_long_option(s + 2); |
opt = decode_long_option(s + 2); |
s += strlen(s) - 1; |
s += strlen(s) - 1; |
} |
} else |
else |
opt = *++s; |
opt = *++s; |
switch (opt) { |
switch (opt) { |
case 'b': |
case 'b': |
simple_backup_suffix = savestr(nextarg()); |
simple_backup_suffix = savestr(nextarg()); |
break; |
break; |
case 'B': |
case 'B': |
origprae = savestr(nextarg()); |
origprae = savestr(nextarg()); |
break; |
break; |
case 'c': |
case 'c': |
diff_type = CONTEXT_DIFF; |
diff_type = CONTEXT_DIFF; |
break; |
break; |
case 'C': |
case 'C': |
check_only = TRUE; |
check_only = TRUE; |
break; |
break; |
case 'd': |
case 'd': |
if (!*++s) |
if (!*++s) |
s = nextarg(); |
s = nextarg(); |
if (chdir(s) < 0) |
if (chdir(s) < 0) |
pfatal("can't cd to %s", s); |
pfatal("can't cd to %s", s); |
break; |
break; |
case 'D': |
case 'D': |
do_defines = TRUE; |
do_defines = TRUE; |
if (!*++s) |
if (!*++s) |
s = nextarg(); |
s = nextarg(); |
if (!isalpha(*s) && '_' != *s) |
if (!isalpha(*s) && '_' != *s) |
fatal("argument to -D is not an identifier\n"); |
fatal("argument to -D is not an identifier\n"); |
snprintf(if_defined, sizeof if_defined, |
snprintf(if_defined, sizeof if_defined, "#ifdef %s\n", s); |
"#ifdef %s\n", s); |
snprintf(not_defined, sizeof not_defined, "#ifndef %s\n", s); |
snprintf(not_defined, sizeof not_defined, |
snprintf(end_defined, sizeof end_defined, "#endif /* %s */\n", s); |
"#ifndef %s\n", s); |
break; |
snprintf(end_defined, sizeof end_defined, |
case 'e': |
"#endif /* %s */\n", s); |
diff_type = ED_DIFF; |
break; |
break; |
case 'e': |
case 'E': |
diff_type = ED_DIFF; |
remove_empty_files = TRUE; |
break; |
break; |
case 'E': |
case 'f': |
remove_empty_files = TRUE; |
force = TRUE; |
break; |
break; |
case 'f': |
case 'F': |
force = TRUE; |
if (!*++s) |
break; |
s = nextarg(); |
case 'F': |
else if (*s == '=') |
if (!*++s) |
s++; |
s = nextarg(); |
maxfuzz = atoi(s); |
else if (*s == '=') |
break; |
s++; |
case 'l': |
maxfuzz = atoi(s); |
canonicalize = TRUE; |
break; |
break; |
case 'l': |
case 'n': |
canonicalize = TRUE; |
diff_type = NORMAL_DIFF; |
break; |
break; |
case 'n': |
case 'N': |
diff_type = NORMAL_DIFF; |
noreverse = TRUE; |
break; |
break; |
case 'N': |
case 'o': |
noreverse = TRUE; |
outname = savestr(nextarg()); |
break; |
break; |
case 'o': |
case 'p': |
outname = savestr(nextarg()); |
if (!*++s) |
break; |
s = nextarg(); |
case 'p': |
else if (*s == '=') |
if (!*++s) |
s++; |
s = nextarg(); |
strippath = atoi(s); |
else if (*s == '=') |
break; |
s++; |
case 'r': |
strippath = atoi(s); |
if (strlcpy(rejname, nextarg(), sizeof(rejname)) >= sizeof(rejname)) |
break; |
fatal("argument for -r is too long\n"); |
case 'r': |
break; |
if (strlcpy(rejname, nextarg(), |
case 'R': |
sizeof(rejname)) >= sizeof(rejname)) |
reverse = TRUE; |
fatal("argument for -r is too long\n"); |
reverse_flag_specified = TRUE; |
break; |
break; |
case 'R': |
case 's': |
reverse = TRUE; |
verbose = FALSE; |
reverse_flag_specified = TRUE; |
break; |
break; |
case 'S': |
case 's': |
skip_rest_of_patch = TRUE; |
verbose = FALSE; |
break; |
break; |
case 't': |
case 'S': |
batch = TRUE; |
skip_rest_of_patch = TRUE; |
break; |
break; |
case 'u': |
case 't': |
diff_type = UNI_DIFF; |
batch = TRUE; |
break; |
break; |
case 'v': |
case 'u': |
version(); |
diff_type = UNI_DIFF; |
break; |
break; |
case 'V': |
case 'v': |
#ifndef NODIR |
version(); |
backup_type = get_version (nextarg ()); |
break; |
#endif |
case 'V': |
break; |
backup_type = get_version(nextarg()); |
|
break; |
#ifdef DEBUGGING |
#ifdef DEBUGGING |
case 'x': |
case 'x': |
if (!*++s) |
if (!*++s) |
s = nextarg(); |
s = nextarg(); |
debug = atoi(s); |
debug = atoi(s); |
break; |
break; |
#endif |
#endif |
default: |
default: |
fprintf(stderr, "patch: unrecognized option `%s'\n", Argv[0]); |
fprintf(stderr, "patch: unrecognized option `%s'\n", |
fprintf(stderr, "\ |
Argv[0]); |
|
fprintf(stderr, "\ |
Usage: patch [options] [origfile [patchfile]] [+ [options] [origfile]]...\n\ |
Usage: patch [options] [origfile [patchfile]] [+ [options] [origfile]]...\n\ |
Options:\n\ |
Options:\n\ |
[-cCeEflnNRsStuv] [-b backup-ext] [-B backup-prefix] [-d directory]\n\ |
[-cCeEflnNRsStuv] [-b backup-ext] [-B backup-prefix] [-d directory]\n\ |
[-D symbol] [-Fmax-fuzz] [-o out-file] [-p[strip-count]]\n\ |
[-D symbol] [-Fmax-fuzz] [-o out-file] [-p[strip-count]]\n\ |
[-r rej-name] [-V {numbered,existing,simple}]\n"); |
[-r rej-name] [-V {numbered,existing,simple}]\n"); |
my_exit(1); |
my_exit(1); |
} |
} |
|
} |
} |
} |
} |
|
} |
} |
|
|
/* Attempt to find the right place to apply this hunk of patch. */ |
/* |
|
* Attempt to find the right place to apply this hunk of patch. |
|
*/ |
LINENUM |
LINENUM |
locate_hunk(fuzz) |
locate_hunk(LINENUM fuzz) |
LINENUM fuzz; |
|
{ |
{ |
LINENUM first_guess = pch_first() + last_offset; |
LINENUM first_guess = pch_first() + last_offset; |
LINENUM offset; |
LINENUM offset; |
LINENUM pat_lines = pch_ptrn_lines(); |
LINENUM pat_lines = pch_ptrn_lines(); |
LINENUM max_pos_offset = input_lines - first_guess |
LINENUM max_pos_offset = input_lines - first_guess - pat_lines + 1; |
- pat_lines + 1; |
LINENUM max_neg_offset = first_guess - last_frozen_line - 1 + pch_context(); |
LINENUM max_neg_offset = first_guess - last_frozen_line - 1 |
|
+ pch_context(); |
|
|
|
if (!pat_lines) /* null range matches always */ |
if (!pat_lines) /* null range matches always */ |
return first_guess; |
return first_guess; |
if (max_neg_offset >= first_guess) /* do not try lines < 0 */ |
if (max_neg_offset >= first_guess) /* do not try lines < 0 */ |
max_neg_offset = first_guess - 1; |
max_neg_offset = first_guess - 1; |
if (first_guess <= input_lines && patch_match(first_guess, Nulline, fuzz)) |
if (first_guess <= input_lines && patch_match(first_guess, Nulline, fuzz)) |
return first_guess; |
return first_guess; |
for (offset = 1; ; offset++) { |
for (offset = 1; ; offset++) { |
bool check_after = (offset <= max_pos_offset); |
bool check_after = (offset <= max_pos_offset); |
bool check_before = (offset <= max_neg_offset); |
bool check_before = (offset <= max_neg_offset); |
|
|
if (check_after && patch_match(first_guess, offset, fuzz)) { |
if (check_after && patch_match(first_guess, offset, fuzz)) { |
#ifdef DEBUGGING |
#ifdef DEBUGGING |
if (debug & 1) |
if (debug & 1) |
say("Offset changing from %ld to %ld\n", last_offset, offset); |
say("Offset changing from %ld to %ld\n", |
|
last_offset, offset); |
#endif |
#endif |
last_offset = offset; |
last_offset = offset; |
return first_guess+offset; |
return first_guess + offset; |
} |
} else if (check_before && patch_match(first_guess, -offset, fuzz)) { |
else if (check_before && patch_match(first_guess, -offset, fuzz)) { |
|
#ifdef DEBUGGING |
#ifdef DEBUGGING |
if (debug & 1) |
if (debug & 1) |
say("Offset changing from %ld to %ld\n", last_offset, -offset); |
say("Offset changing from %ld to %ld\n", |
|
last_offset, -offset); |
#endif |
#endif |
last_offset = -offset; |
last_offset = -offset; |
return first_guess-offset; |
return first_guess - offset; |
|
} else if (!check_before && !check_after) |
|
return Nulline; |
} |
} |
else if (!check_before && !check_after) |
|
return Nulline; |
|
} |
|
} |
} |
|
|
/* We did not find the pattern, dump out the hunk so they can handle it. */ |
/* We did not find the pattern, dump out the hunk so they can handle it. */ |
|
|
void |
void |
abort_hunk() |
abort_hunk(void) |
{ |
{ |
LINENUM i; |
LINENUM i; |
LINENUM pat_end = pch_end(); |
LINENUM pat_end = pch_end(); |
/* add in last_offset to guess the same as the previous successful hunk */ |
/* |
LINENUM oldfirst = pch_first() + last_offset; |
* add in last_offset to guess the same as the previous successful |
LINENUM newfirst = pch_newfirst() + last_offset; |
* hunk |
LINENUM oldlast = oldfirst + pch_ptrn_lines() - 1; |
*/ |
LINENUM newlast = newfirst + pch_repl_lines() - 1; |
LINENUM oldfirst = pch_first() + last_offset; |
char *stars = (diff_type >= NEW_CONTEXT_DIFF ? " ****" : ""); |
LINENUM newfirst = pch_newfirst() + last_offset; |
char *minuses = (diff_type >= NEW_CONTEXT_DIFF ? " ----" : " -----"); |
LINENUM oldlast = oldfirst + pch_ptrn_lines() - 1; |
|
LINENUM newlast = newfirst + pch_repl_lines() - 1; |
|
char *stars = (diff_type >= NEW_CONTEXT_DIFF ? " ****" : ""); |
|
char *minuses = (diff_type >= NEW_CONTEXT_DIFF ? " ----" : " -----"); |
|
|
fprintf(rejfp, "***************\n"); |
fprintf(rejfp, "***************\n"); |
for (i=0; i<=pat_end; i++) { |
for (i = 0; i <= pat_end; i++) { |
switch (pch_char(i)) { |
switch (pch_char(i)) { |
case '*': |
case '*': |
if (oldlast < oldfirst) |
if (oldlast < oldfirst) |
fprintf(rejfp, "*** 0%s\n", stars); |
fprintf(rejfp, "*** 0%s\n", stars); |
else if (oldlast == oldfirst) |
else if (oldlast == oldfirst) |
fprintf(rejfp, "*** %ld%s\n", oldfirst, stars); |
fprintf(rejfp, "*** %ld%s\n", oldfirst, stars); |
else |
else |
fprintf(rejfp, "*** %ld,%ld%s\n", oldfirst, oldlast, stars); |
fprintf(rejfp, "*** %ld,%ld%s\n", oldfirst, |
break; |
oldlast, stars); |
case '=': |
break; |
if (newlast < newfirst) |
case '=': |
fprintf(rejfp, "--- 0%s\n", minuses); |
if (newlast < newfirst) |
else if (newlast == newfirst) |
fprintf(rejfp, "--- 0%s\n", minuses); |
fprintf(rejfp, "--- %ld%s\n", newfirst, minuses); |
else if (newlast == newfirst) |
else |
fprintf(rejfp, "--- %ld%s\n", newfirst, minuses); |
fprintf(rejfp, "--- %ld,%ld%s\n", newfirst, newlast, minuses); |
else |
break; |
fprintf(rejfp, "--- %ld,%ld%s\n", newfirst, |
case '\n': |
newlast, minuses); |
fprintf(rejfp, "%s", pfetch(i)); |
break; |
break; |
case '\n': |
case ' ': case '-': case '+': case '!': |
fprintf(rejfp, "%s", pfetch(i)); |
fprintf(rejfp, "%c %s", pch_char(i), pfetch(i)); |
break; |
break; |
case ' ': |
default: |
case '-': |
fatal("fatal internal error in abort_hunk\n"); |
case '+': |
|
case '!': |
|
fprintf(rejfp, "%c %s", pch_char(i), pfetch(i)); |
|
break; |
|
default: |
|
fatal("fatal internal error in abort_hunk\n"); |
|
} |
} |
} |
} |
|
} |
} |
|
|
/* We found where to apply it (we hope), so do it. */ |
/* We found where to apply it (we hope), so do it. */ |
|
|
void |
void |
apply_hunk(where) |
apply_hunk(LINENUM where) |
LINENUM where; |
|
{ |
{ |
LINENUM old = 1; |
LINENUM old = 1; |
LINENUM lastline = pch_ptrn_lines(); |
LINENUM lastline = pch_ptrn_lines(); |
LINENUM new = lastline+1; |
LINENUM new = lastline + 1; |
#define OUTSIDE 0 |
#define OUTSIDE 0 |
#define IN_IFNDEF 1 |
#define IN_IFNDEF 1 |
#define IN_IFDEF 2 |
#define IN_IFDEF 2 |
#define IN_ELSE 3 |
#define IN_ELSE 3 |
int def_state = OUTSIDE; |
int def_state = OUTSIDE; |
bool R_do_defines = do_defines; |
bool R_do_defines = do_defines; |
LINENUM pat_end = pch_end(); |
LINENUM pat_end = pch_end(); |
|
|
where--; |
where--; |
while (pch_char(new) == '=' || pch_char(new) == '\n') |
while (pch_char(new) == '=' || pch_char(new) == '\n') |
new++; |
new++; |
|
|
while (old <= lastline) { |
while (old <= lastline) { |
if (pch_char(old) == '-') { |
if (pch_char(old) == '-') { |
copy_till(where + old - 1); |
copy_till(where + old - 1); |
if (R_do_defines) { |
if (R_do_defines) { |
if (def_state == OUTSIDE) { |
if (def_state == OUTSIDE) { |
fputs(not_defined, ofp); |
fputs(not_defined, ofp); |
def_state = IN_IFNDEF; |
def_state = IN_IFNDEF; |
} |
} else if (def_state == IN_IFDEF) { |
else if (def_state == IN_IFDEF) { |
fputs(else_defined, ofp); |
fputs(else_defined, ofp); |
def_state = IN_ELSE; |
def_state = IN_ELSE; |
} |
} |
fputs(pfetch(old), ofp); |
fputs(pfetch(old), ofp); |
} |
} |
last_frozen_line++; |
last_frozen_line++; |
old++; |
old++; |
} else if (new > pat_end) { |
} |
break; |
else if (new > pat_end) { |
} else if (pch_char(new) == '+') { |
break; |
copy_till(where + old - 1); |
} |
if (R_do_defines) { |
else if (pch_char(new) == '+') { |
if (def_state == IN_IFNDEF) { |
copy_till(where + old - 1); |
fputs(else_defined, ofp); |
if (R_do_defines) { |
def_state = IN_ELSE; |
if (def_state == IN_IFNDEF) { |
} else if (def_state == OUTSIDE) { |
fputs(else_defined, ofp); |
fputs(if_defined, ofp); |
def_state = IN_ELSE; |
def_state = IN_IFDEF; |
} |
} |
else if (def_state == OUTSIDE) { |
} |
fputs(if_defined, ofp); |
fputs(pfetch(new), ofp); |
def_state = IN_IFDEF; |
new++; |
} |
} else if (pch_char(new) != pch_char(old)) { |
} |
say("Out-of-sync patch, lines %ld,%ld--mangled text or line numbers, maybe?\n", |
fputs(pfetch(new), ofp); |
pch_hunk_beg() + old, |
new++; |
pch_hunk_beg() + new); |
} |
|
else if (pch_char(new) != pch_char(old)) { |
|
say("Out-of-sync patch, lines %ld,%ld--mangled text or line numbers, maybe?\n", |
|
pch_hunk_beg() + old, |
|
pch_hunk_beg() + new); |
|
#ifdef DEBUGGING |
#ifdef DEBUGGING |
say("oldchar = '%c', newchar = '%c'\n", |
say("oldchar = '%c', newchar = '%c'\n", |
pch_char(old), pch_char(new)); |
pch_char(old), pch_char(new)); |
#endif |
#endif |
my_exit(1); |
my_exit(1); |
|
} else if (pch_char(new) == '!') { |
|
copy_till(where + old - 1); |
|
if (R_do_defines) { |
|
fputs(not_defined, ofp); |
|
def_state = IN_IFNDEF; |
|
} |
|
while (pch_char(old) == '!') { |
|
if (R_do_defines) { |
|
fputs(pfetch(old), ofp); |
|
} |
|
last_frozen_line++; |
|
old++; |
|
} |
|
if (R_do_defines) { |
|
fputs(else_defined, ofp); |
|
def_state = IN_ELSE; |
|
} |
|
while (pch_char(new) == '!') { |
|
fputs(pfetch(new), ofp); |
|
new++; |
|
} |
|
} else { |
|
assert(pch_char(new) == ' '); |
|
old++; |
|
new++; |
|
if (R_do_defines && def_state != OUTSIDE) { |
|
fputs(end_defined, ofp); |
|
def_state = OUTSIDE; |
|
} |
|
} |
} |
} |
else if (pch_char(new) == '!') { |
if (new <= pat_end && pch_char(new) == '+') { |
copy_till(where + old - 1); |
copy_till(where + old - 1); |
if (R_do_defines) { |
|
fputs(not_defined, ofp); |
|
def_state = IN_IFNDEF; |
|
} |
|
while (pch_char(old) == '!') { |
|
if (R_do_defines) { |
if (R_do_defines) { |
fputs(pfetch(old), ofp); |
if (def_state == OUTSIDE) { |
|
fputs(if_defined, ofp); |
|
def_state = IN_IFDEF; |
|
} else if (def_state == IN_IFNDEF) { |
|
fputs(else_defined, ofp); |
|
def_state = IN_ELSE; |
|
} |
} |
} |
last_frozen_line++; |
while (new <= pat_end && pch_char(new) == '+') { |
old++; |
fputs(pfetch(new), ofp); |
} |
new++; |
if (R_do_defines) { |
} |
fputs(else_defined, ofp); |
|
def_state = IN_ELSE; |
|
} |
|
while (pch_char(new) == '!') { |
|
fputs(pfetch(new), ofp); |
|
new++; |
|
} |
|
} |
} |
else { |
if (R_do_defines && def_state != OUTSIDE) { |
assert(pch_char(new) == ' '); |
|
old++; |
|
new++; |
|
if (R_do_defines && def_state != OUTSIDE) { |
|
fputs(end_defined, ofp); |
fputs(end_defined, ofp); |
def_state = OUTSIDE; |
|
} |
|
} |
} |
} |
|
if (new <= pat_end && pch_char(new) == '+') { |
|
copy_till(where + old - 1); |
|
if (R_do_defines) { |
|
if (def_state == OUTSIDE) { |
|
fputs(if_defined, ofp); |
|
def_state = IN_IFDEF; |
|
} |
|
else if (def_state == IN_IFNDEF) { |
|
fputs(else_defined, ofp); |
|
def_state = IN_ELSE; |
|
} |
|
} |
|
while (new <= pat_end && pch_char(new) == '+') { |
|
fputs(pfetch(new), ofp); |
|
new++; |
|
} |
|
} |
|
if (R_do_defines && def_state != OUTSIDE) { |
|
fputs(end_defined, ofp); |
|
} |
|
} |
} |
|
|
/* Open the new file. */ |
/* |
|
* Open the new file. |
|
*/ |
void |
void |
init_output(name) |
init_output(char *name) |
char *name; |
|
{ |
{ |
ofp = fopen(name, "w"); |
ofp = fopen(name, "w"); |
if (ofp == Nullfp) |
if (ofp == Nullfp) |
pfatal("can't create %s", name); |
pfatal("can't create %s", name); |
} |
} |
|
|
/* Open a file to put hunks we can't locate. */ |
/* |
|
* Open a file to put hunks we can't locate. |
|
*/ |
void |
void |
init_reject(name) |
init_reject(char *name) |
char *name; |
|
{ |
{ |
rejfp = fopen(name, "w"); |
rejfp = fopen(name, "w"); |
if (rejfp == Nullfp) |
if (rejfp == Nullfp) |
pfatal("can't create %s", name); |
pfatal("can't create %s", name); |
} |
} |
|
|
/* Copy input file to output, up to wherever hunk is to be applied. */ |
/* |
|
* Copy input file to output, up to wherever hunk is to be applied. |
|
*/ |
void |
void |
copy_till(lastline) |
copy_till(LINENUM lastline) |
LINENUM lastline; |
|
{ |
{ |
LINENUM R_last_frozen_line = last_frozen_line; |
LINENUM R_last_frozen_line = last_frozen_line; |
|
|
if (R_last_frozen_line > lastline) |
if (R_last_frozen_line > lastline) |
fatal("misordered hunks! output would be garbled\n"); |
fatal("misordered hunks! output would be garbled\n"); |
while (R_last_frozen_line < lastline) { |
while (R_last_frozen_line < lastline) |
dump_line(++R_last_frozen_line); |
dump_line(++R_last_frozen_line); |
} |
last_frozen_line = R_last_frozen_line; |
last_frozen_line = R_last_frozen_line; |
|
} |
} |
|
|
/* Finish copying the input file to the output file. */ |
/* |
|
* Finish copying the input file to the output file. |
|
*/ |
void |
void |
spew_output() |
spew_output(void) |
{ |
{ |
#ifdef DEBUGGING |
#ifdef DEBUGGING |
if (debug & 256) |
if (debug & 256) |
say("il=%ld lfl=%ld\n",input_lines,last_frozen_line); |
say("il=%ld lfl=%ld\n", input_lines, last_frozen_line); |
#endif |
#endif |
if (input_lines) |
if (input_lines) |
copy_till(input_lines); /* dump remainder of file */ |
copy_till(input_lines); /* dump remainder of file */ |
fclose(ofp); |
fclose(ofp); |
ofp = Nullfp; |
ofp = Nullfp; |
} |
} |
|
|
/* Copy one line from input to output. */ |
/* |
|
* Copy one line from input to output. |
|
*/ |
void |
void |
dump_line(line) |
dump_line(LINENUM line) |
LINENUM line; |
|
{ |
{ |
char *s; |
char *s, R_newline = '\n'; |
char R_newline = '\n'; |
|
|
|
s = ifetch(line, 0); |
s = ifetch(line, 0); |
if (s == NULL) |
if (s == NULL) |
return; |
return; |
/* Note: string is not null terminated. */ |
/* Note: string is not null terminated. */ |
for (; putc(*s, ofp) != R_newline; s++) ; |
for (; putc(*s, ofp) != R_newline; s++) |
|
; |
} |
} |
|
|
/* Does the patch pattern match at line base+offset? */ |
/* |
|
* Does the patch pattern match at line base+offset? |
|
*/ |
bool |
bool |
patch_match(base, offset, fuzz) |
patch_match(LINENUM base, LINENUM offset, LINENUM fuzz) |
LINENUM base; |
|
LINENUM offset; |
|
LINENUM fuzz; |
|
{ |
{ |
LINENUM pline = 1 + fuzz; |
LINENUM pline = 1 + fuzz; |
LINENUM iline; |
LINENUM iline; |
LINENUM pat_lines = pch_ptrn_lines() - fuzz; |
LINENUM pat_lines = pch_ptrn_lines() - fuzz; |
|
|
for (iline=base+offset+fuzz; pline <= pat_lines; pline++,iline++) { |
for (iline = base + offset + fuzz; pline <= pat_lines; pline++, iline++) { |
if (canonicalize) { |
if (canonicalize) { |
if (!similar(ifetch(iline, (offset >= 0)), |
if (!similar(ifetch(iline, (offset >= 0)), |
pfetch(pline), |
pfetch(pline), pch_line_len(pline))) |
pch_line_len(pline) )) |
return FALSE; |
return FALSE; |
} else if (strnNE(ifetch(iline, (offset >= 0)), |
|
pfetch(pline), pch_line_len(pline))) |
|
return FALSE; |
} |
} |
else if (strnNE(ifetch(iline, (offset >= 0)), |
return TRUE; |
pfetch(pline), |
|
pch_line_len(pline) )) |
|
return FALSE; |
|
} |
|
return TRUE; |
|
} |
} |
|
|
/* Do two lines match with canonicalized white space? */ |
/* |
|
* Do two lines match with canonicalized white space? |
|
*/ |
bool |
bool |
similar(a,b,len) |
similar(char *a, char *b, int len) |
char *a; |
|
char *b; |
|
int len; |
|
{ |
{ |
if (a == NULL || b == NULL) |
if (a == NULL || b == NULL) |
return FALSE; |
|
while (len) { |
|
if (isspace(*b)) { /* whitespace (or \n) to match? */ |
|
if (!isspace(*a)) /* no corresponding whitespace? */ |
|
return FALSE; |
return FALSE; |
while (len && isspace(*b) && *b != '\n') |
while (len) { |
b++,len--; /* skip pattern whitespace */ |
if (isspace(*b)) { /* whitespace (or \n) to match? */ |
while (isspace(*a) && *a != '\n') |
if (!isspace(*a)) /* no corresponding whitespace? */ |
a++; /* skip target whitespace */ |
return FALSE; |
if (*a == '\n' || *b == '\n') |
while (len && isspace(*b) && *b != '\n') |
return (*a == *b); /* should end in sync */ |
b++, len--; /* skip pattern whitespace */ |
|
while (isspace(*a) && *a != '\n') |
|
a++; /* skip target whitespace */ |
|
if (*a == '\n' || *b == '\n') |
|
return (*a == *b); /* should end in sync */ |
|
} else if (*a++ != *b++) /* match non-whitespace chars */ |
|
return FALSE; |
|
else |
|
len--; /* probably not necessary */ |
} |
} |
else if (*a++ != *b++) /* match non-whitespace chars */ |
return TRUE; /* actually, this is not reached */ |
return FALSE; |
/* since there is always a \n */ |
else |
|
len--; /* probably not necessary */ |
|
} |
|
return TRUE; /* actually, this is not reached */ |
|
/* since there is always a \n */ |
|
} |
} |
|
|
/* Exit with cleanup. */ |
/* |
|
* Exit with cleanup. |
|
*/ |
void |
void |
my_exit(status) |
my_exit(int status) |
int status; |
|
{ |
{ |
unlink(TMPINNAME); |
unlink(TMPINNAME); |
if (!toutkeep) { |
if (!toutkeep) |
unlink(TMPOUTNAME); |
unlink(TMPOUTNAME); |
} |
if (!trejkeep) |
if (!trejkeep) { |
unlink(TMPREJNAME); |
unlink(TMPREJNAME); |
unlink(TMPPATNAME); |
} |
exit(status); |
unlink(TMPPATNAME); |
|
exit(status); |
|
} |
} |