version 1.22, 2003/07/21 21:01:45 |
version 1.23, 2003/07/22 17:18:49 |
|
|
*/ |
*/ |
|
|
#ifndef lint |
#ifndef lint |
static char rcsid[] = "$OpenBSD$"; |
static const char rcsid[] = "$OpenBSD$"; |
#endif /* not lint */ |
#endif /* not lint */ |
|
|
|
#include <sys/types.h> |
|
#include <sys/stat.h> |
|
#include <unistd.h> |
|
|
|
#include <assert.h> |
|
#include <ctype.h> |
|
#include <string.h> |
|
#include <stdlib.h> |
|
|
#include "INTERN.h" |
#include "INTERN.h" |
#include "common.h" |
#include "common.h" |
#include "EXTERN.h" |
#include "EXTERN.h" |
|
|
#include "inp.h" |
#include "inp.h" |
#include "backupfile.h" |
#include "backupfile.h" |
|
|
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 *); |
|
|
|
|
static void reinitialize_almost_everything(void); |
|
static void get_some_switches(void); |
|
static LINENUM locate_hunk(LINENUM); |
|
static void abort_hunk(void); |
|
static void apply_hunk(LINENUM); |
|
static void init_output(char *); |
|
static void init_reject(char *); |
|
static void copy_till(LINENUM); |
|
static void spew_output(void); |
|
static void dump_line(LINENUM); |
|
static bool patch_match(LINENUM, LINENUM, LINENUM); |
|
static bool similar(char *, char *, int); |
|
static int optcmp(const void *, const void *); |
|
static 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. */ |
/* buffer for stderr */ |
bool check_only = FALSE; |
static char serrbuf[BUFSIZ]; |
|
|
/* Apply a set of diffs as appropriate. */ |
/* Apply a set of diffs as appropriate. */ |
|
|
|
|
|
|
setbuf(stderr, serrbuf); |
setbuf(stderr, serrbuf); |
for (i = 0; i < MAXFILEC; i++) |
for (i = 0; i < MAXFILEC; i++) |
filearg[i] = Nullch; |
filearg[i] = NULL; |
|
|
myuid = getuid(); |
myuid = getuid(); |
|
|
|
|
|
|
patch_seen = TRUE; |
patch_seen = TRUE; |
|
|
if (outname == Nullch) |
if (outname == NULL) |
outname = savestr(filearg[0]); |
outname = savestr(filearg[0]); |
|
|
/* for ed script just up and do it and exit */ |
/* for ed script just up and do it and exit */ |
|
|
out_of_mem = FALSE; |
out_of_mem = FALSE; |
while (another_hunk()) { |
while (another_hunk()) { |
hunk++; |
hunk++; |
fuzz = Nulline; |
fuzz = NULL; |
mymaxfuzz = pch_context(); |
mymaxfuzz = pch_context(); |
if (maxfuzz < mymaxfuzz) |
if (maxfuzz < mymaxfuzz) |
mymaxfuzz = maxfuzz; |
mymaxfuzz = maxfuzz; |
if (!skip_rest_of_patch) { |
if (!skip_rest_of_patch) { |
do { |
do { |
where = locate_hunk(fuzz); |
where = locate_hunk(fuzz); |
if (hunk == 1 && where == Nulline && !force) { |
if (hunk == 1 && where == NULL && !force) { |
/* dwim for reversed patch? */ |
/* dwim for reversed patch? */ |
if (!pch_swap()) { |
if (!pch_swap()) { |
if (fuzz == Nulline) |
if (fuzz == NULL) |
say("Not enough memory to try swapped hunk! Assuming unswapped.\n"); |
say("Not enough memory to try swapped hunk! Assuming unswapped.\n"); |
continue; |
continue; |
} |
} |
reverse = !reverse; |
reverse = !reverse; |
/* try again */ |
/* try again */ |
where = locate_hunk(fuzz); |
where = locate_hunk(fuzz); |
if (where == Nulline) { |
if (where == NULL) { |
/* didn't find it swapped */ |
/* didn't find it swapped */ |
if (!pch_swap()) |
if (!pch_swap()) |
/* put it back to normal */ |
/* put it back to normal */ |
|
|
ask("Apply anyway? [n] "); |
ask("Apply anyway? [n] "); |
if (*buf != 'y') |
if (*buf != 'y') |
skip_rest_of_patch = TRUE; |
skip_rest_of_patch = TRUE; |
where = Nulline; |
where = NULL; |
reverse = !reverse; |
reverse = !reverse; |
if (!pch_swap()) |
if (!pch_swap()) |
/* put it back to normal */ |
/* put it back to normal */ |
|
|
} |
} |
} |
} |
} |
} |
} while (!skip_rest_of_patch && where == Nulline && |
} while (!skip_rest_of_patch && where == NULL && |
++fuzz <= mymaxfuzz); |
++fuzz <= mymaxfuzz); |
|
|
if (skip_rest_of_patch) { /* just got decided */ |
if (skip_rest_of_patch) { /* just got decided */ |
fclose(ofp); |
fclose(ofp); |
ofp = Nullfp; |
ofp = NULL; |
} |
} |
} |
} |
newwhere = pch_newfirst() + last_offset; |
newwhere = pch_newfirst() + last_offset; |
|
|
if (verbose) |
if (verbose) |
say("Hunk #%d ignored at %ld.\n", |
say("Hunk #%d ignored at %ld.\n", |
hunk, newwhere); |
hunk, newwhere); |
} else if (where == Nulline) { |
} else if (where == NULL) { |
abort_hunk(); |
abort_hunk(); |
failed++; |
failed++; |
if (verbose) |
if (verbose) |
|
|
say("\n\nRan out of memory using Plan A--trying again...\n\n"); |
say("\n\nRan out of memory using Plan A--trying again...\n\n"); |
if (ofp) |
if (ofp) |
fclose(ofp); |
fclose(ofp); |
ofp = Nullfp; |
ofp = NULL; |
if (rejfp) |
if (rejfp) |
fclose(rejfp); |
fclose(rejfp); |
rejfp = Nullfp; |
rejfp = NULL; |
continue; |
continue; |
} |
} |
assert(hunk); |
assert(hunk); |
|
|
} |
} |
} |
} |
fclose(rejfp); |
fclose(rejfp); |
rejfp = Nullfp; |
rejfp = NULL; |
if (failed) { |
if (failed) { |
failtotal += failed; |
failtotal += failed; |
if (!*rejname) { |
if (!*rejname) { |
|
|
|
|
/* 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 |
static void |
reinitialize_almost_everything(void) |
reinitialize_almost_everything(void) |
{ |
{ |
re_patch(); |
re_patch(); |
|
|
last_frozen_line = 0; |
last_frozen_line = 0; |
|
|
filec = 0; |
filec = 0; |
if (filearg[0] != Nullch && !out_of_mem) { |
if (filearg[0] != NULL && !out_of_mem) { |
free(filearg[0]); |
free(filearg[0]); |
filearg[0] = Nullch; |
filearg[0] = NULL; |
} |
} |
if (outname != Nullch) { |
if (outname != NULL) { |
free(outname); |
free(outname); |
outname = Nullch; |
outname = NULL; |
} |
} |
last_offset = 0; |
last_offset = 0; |
|
|
diff_type = 0; |
diff_type = 0; |
|
|
if (revision != Nullch) { |
if (revision != NULL) { |
free(revision); |
free(revision); |
revision = Nullch; |
revision = NULL; |
} |
} |
reverse = reverse_flag_specified; |
reverse = reverse_flag_specified; |
skip_rest_of_patch = FALSE; |
skip_rest_of_patch = FALSE; |
|
|
char short_opt; |
char short_opt; |
}; |
}; |
|
|
int |
static 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; |
|
|
|
|
/* Decode Long options beginning with "--" to their short equivalents. */ |
/* Decode Long options beginning with "--" to their short equivalents. */ |
|
|
char |
static char |
decode_long_option(char *opt) |
decode_long_option(char *opt) |
{ |
{ |
/* |
/* |
|
|
|
|
/* Process switches and filenames up to next '+' or end of list. */ |
/* Process switches and filenames up to next '+' or end of list. */ |
|
|
void |
static void |
get_some_switches(void) |
get_some_switches(void) |
{ |
{ |
char *s; |
char *s; |
|
|
/* |
/* |
* 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 |
static LINENUM |
locate_hunk(LINENUM fuzz) |
locate_hunk(LINENUM fuzz) |
{ |
{ |
LINENUM first_guess = pch_first() + last_offset; |
LINENUM first_guess = pch_first() + last_offset; |
|
|
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, NULL, 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); |
|
|
last_offset = -offset; |
last_offset = -offset; |
return first_guess - offset; |
return first_guess - offset; |
} else if (!check_before && !check_after) |
} else if (!check_before && !check_after) |
return Nulline; |
return NULL; |
} |
} |
} |
} |
|
|
/* 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 |
static void |
abort_hunk(void) |
abort_hunk(void) |
{ |
{ |
LINENUM i; |
LINENUM i; |
|
|
|
|
/* We found where to apply it (we hope), so do it. */ |
/* We found where to apply it (we hope), so do it. */ |
|
|
void |
static void |
apply_hunk(LINENUM where) |
apply_hunk(LINENUM where) |
{ |
{ |
LINENUM old = 1; |
LINENUM old = 1; |
|
|
/* |
/* |
* Open the new file. |
* Open the new file. |
*/ |
*/ |
void |
static void |
init_output(char *name) |
init_output(char *name) |
{ |
{ |
ofp = fopen(name, "w"); |
ofp = fopen(name, "w"); |
if (ofp == Nullfp) |
if (ofp == NULL) |
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 |
static void |
init_reject(char *name) |
init_reject(char *name) |
{ |
{ |
rejfp = fopen(name, "w"); |
rejfp = fopen(name, "w"); |
if (rejfp == Nullfp) |
if (rejfp == NULL) |
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 |
static void |
copy_till(LINENUM lastline) |
copy_till(LINENUM lastline) |
{ |
{ |
LINENUM R_last_frozen_line = last_frozen_line; |
LINENUM R_last_frozen_line = last_frozen_line; |
|
|
/* |
/* |
* Finish copying the input file to the output file. |
* Finish copying the input file to the output file. |
*/ |
*/ |
void |
static void |
spew_output(void) |
spew_output(void) |
{ |
{ |
#ifdef DEBUGGING |
#ifdef DEBUGGING |
|
|
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 = NULL; |
} |
} |
|
|
/* |
/* |
* Copy one line from input to output. |
* Copy one line from input to output. |
*/ |
*/ |
void |
static void |
dump_line(LINENUM line) |
dump_line(LINENUM line) |
{ |
{ |
char *s, R_newline = '\n'; |
char *s, R_newline = '\n'; |
|
|
/* |
/* |
* Does the patch pattern match at line base+offset? |
* Does the patch pattern match at line base+offset? |
*/ |
*/ |
bool |
static bool |
patch_match(LINENUM base, LINENUM offset, LINENUM fuzz) |
patch_match(LINENUM base, LINENUM offset, LINENUM fuzz) |
{ |
{ |
LINENUM pline = 1 + fuzz; |
LINENUM pline = 1 + fuzz; |
|
|
/* |
/* |
* Do two lines match with canonicalized white space? |
* Do two lines match with canonicalized white space? |
*/ |
*/ |
bool |
static bool |
similar(char *a, char *b, int len) |
similar(char *a, char *b, int len) |
{ |
{ |
while (len) { |
while (len) { |
|
|
} |
} |
return TRUE; /* actually, this is not reached */ |
return TRUE; /* actually, this is not reached */ |
/* since there is always a \n */ |
/* since there is always a \n */ |
} |
|
|
|
/* |
|
* Exit with cleanup. |
|
*/ |
|
void |
|
my_exit(int status) |
|
{ |
|
unlink(TMPINNAME); |
|
if (!toutkeep) |
|
unlink(TMPOUTNAME); |
|
if (!trejkeep) |
|
unlink(TMPREJNAME); |
|
unlink(TMPPATNAME); |
|
exit(status); |
|
} |
} |