Changeset View
Changeset View
Standalone View
Standalone View
usr.bin/patch/patch.c
Show First 20 Lines • Show All 97 Lines • ▼ Show 20 Lines | |||||
static void init_output(const char *); | static void init_output(const char *); | ||||
static void init_reject(const char *); | static void init_reject(const char *); | ||||
static void copy_till(LINENUM, bool); | static void copy_till(LINENUM, bool); | ||||
static bool spew_output(void); | static bool spew_output(void); | ||||
static void dump_line(LINENUM, bool); | static void dump_line(LINENUM, bool); | ||||
static bool patch_match(LINENUM, LINENUM, LINENUM); | static bool patch_match(LINENUM, LINENUM, LINENUM); | ||||
static bool similar(const char *, const char *, int); | static bool similar(const char *, const char *, int); | ||||
static void usage(void); | static void usage(void); | ||||
static bool handle_creation(bool, bool *); | |||||
/* true if -E was specified on command line. */ | /* true if -E was specified on command line. */ | ||||
static bool remove_empty_files = false; | static bool remove_empty_files = false; | ||||
/* true if -R was specified on command line. */ | /* true if -R was specified on command line. */ | ||||
static bool reverse_flag_specified = false; | static bool reverse_flag_specified = false; | ||||
static bool Vflag = false; | static bool Vflag = false; | ||||
Show All 28 Lines | |||||
static char end_defined[128]; | static char end_defined[128]; | ||||
/* 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[]) | ||||
{ | { | ||||
struct stat statbuf; | |||||
int error = 0, hunk, failed, i, fd; | int error = 0, hunk, failed, i, fd; | ||||
bool patch_seen, reverse_seen; | bool out_creating, out_existed, patch_seen, remove_file; | ||||
bool reverse_seen; | |||||
LINENUM where = 0, newwhere, fuzz, mymaxfuzz; | LINENUM where = 0, newwhere, fuzz, mymaxfuzz; | ||||
const char *tmpdir; | const char *tmpdir; | ||||
char *v; | char *v; | ||||
setvbuf(stdout, NULL, _IOLBF, 0); | setvbuf(stdout, NULL, _IOLBF, 0); | ||||
setvbuf(stderr, NULL, _IOLBF, 0); | setvbuf(stderr, NULL, _IOLBF, 0); | ||||
for (i = 0; i < MAXFILEC; i++) | for (i = 0; i < MAXFILEC; i++) | ||||
filearg[i] = NULL; | filearg[i] = NULL; | ||||
▲ Show 20 Lines • Show All 54 Lines • ▼ Show 20 Lines | main(int argc, char *argv[]) | ||||
/* make sure we clean up /tmp in case of disaster */ | /* make sure we clean up /tmp in case of disaster */ | ||||
set_signals(0); | set_signals(0); | ||||
patch_seen = false; | patch_seen = false; | ||||
for (open_patch_file(filearg[1]); there_is_another_patch(); | for (open_patch_file(filearg[1]); there_is_another_patch(); | ||||
reinitialize_almost_everything()) { | reinitialize_almost_everything()) { | ||||
/* for each patch in patch file */ | /* for each patch in patch file */ | ||||
if (source_file != NULL && (diff_type == CONTEXT_DIFF || | |||||
diff_type == NEW_CONTEXT_DIFF || | |||||
diff_type == UNI_DIFF)) | |||||
out_creating = strcmp(source_file, _PATH_DEVNULL) == 0; | |||||
else | |||||
out_creating = false; | |||||
patch_seen = true; | patch_seen = true; | ||||
warn_on_invalid_line = true; | warn_on_invalid_line = true; | ||||
if (outname == NULL) | if (outname == NULL) | ||||
outname = xstrdup(filearg[0]); | outname = xstrdup(filearg[0]); | ||||
out_existed = stat(outname, &statbuf) == 0; | |||||
cem: On the /dev/null name-creation basis, it seems like we could just bail on this input patch at… | |||||
/* for ed script just up and do it and exit */ | /* for ed script just up and do it and exit */ | ||||
if (diff_type == ED_DIFF) { | if (diff_type == ED_DIFF) { | ||||
do_ed_script(); | do_ed_script(); | ||||
continue; | continue; | ||||
} | } | ||||
/* initialize the patched file */ | /* initialize the patched file */ | ||||
if (!skip_rest_of_patch) | if (!skip_rest_of_patch) | ||||
init_output(TMPOUTNAME); | init_output(TMPOUTNAME); | ||||
Show All 10 Lines | for (open_patch_file(filearg[1]); there_is_another_patch(); | ||||
* malloc might misfire and we can't catch it easily | * malloc might misfire and we can't catch it easily | ||||
*/ | */ | ||||
/* apply each hunk of patch */ | /* apply each hunk of patch */ | ||||
hunk = 0; | hunk = 0; | ||||
failed = 0; | failed = 0; | ||||
reverse_seen = false; | reverse_seen = false; | ||||
out_of_mem = false; | out_of_mem = false; | ||||
remove_file = false; | |||||
while (another_hunk()) { | while (another_hunk()) { | ||||
hunk++; | hunk++; | ||||
fuzz = 0; | fuzz = 0; | ||||
if (out_creating) | |||||
reverse_seen = handle_creation(out_existed, | |||||
&remove_file); | |||||
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 == 0 && !force && !reverse_seen) { | if (hunk == 1 && where == 0 && !force && !reverse_seen) { | ||||
/* dwim for reversed patch? */ | /* dwim for reversed patch? */ | ||||
▲ Show 20 Lines • Show All 101 Lines • ▼ Show 20 Lines | for (open_patch_file(filearg[1]); there_is_another_patch(); | ||||
if (!skip_rest_of_patch && !spew_output()) { | if (!skip_rest_of_patch && !spew_output()) { | ||||
say("Can't write %s\n", TMPOUTNAME); | say("Can't write %s\n", TMPOUTNAME); | ||||
error = 1; | error = 1; | ||||
} | } | ||||
/* and put the output where desired */ | /* and put the output where desired */ | ||||
ignore_signals(); | ignore_signals(); | ||||
if (!skip_rest_of_patch) { | if (!skip_rest_of_patch) { | ||||
struct stat statbuf; | |||||
char *realout = outname; | char *realout = outname; | ||||
if (!check_only) { | if (!check_only) { | ||||
if (move_file(TMPOUTNAME, outname) < 0) { | if (move_file(TMPOUTNAME, outname) < 0) { | ||||
toutkeep = true; | toutkeep = true; | ||||
realout = TMPOUTNAME; | realout = TMPOUTNAME; | ||||
chmod(TMPOUTNAME, filemode); | chmod(TMPOUTNAME, filemode); | ||||
} else | } else | ||||
chmod(outname, filemode); | chmod(outname, filemode); | ||||
if (remove_empty_files && | if ((remove_empty_files || remove_file) && | ||||
cemUnsubmitted Not Done Inline ActionsIf I understand correctly, remove_file will only work if we successfully (reverse-) applied a patch to totally empty the contents first. But unlike remove_empty_files, it's specific to the loop iteration and not global. ok. cem: If I understand correctly, `remove_file` will only work if we successfully (reverse-) applied a… | |||||
stat(realout, &statbuf) == 0 && | stat(realout, &statbuf) == 0 && | ||||
statbuf.st_size == 0) { | statbuf.st_size == 0) { | ||||
if (verbose) | if (verbose) | ||||
say("Removing %s (empty after patching).\n", | say("Removing %s (empty after patching).\n", | ||||
realout); | realout); | ||||
unlink(realout); | unlink(realout); | ||||
} | } | ||||
} | } | ||||
▲ Show 20 Lines • Show All 44 Lines • ▼ Show 20 Lines | reinitialize_almost_everything(void) | ||||
last_frozen_line = 0; | last_frozen_line = 0; | ||||
filec = 0; | filec = 0; | ||||
if (!out_of_mem) { | if (!out_of_mem) { | ||||
free(filearg[0]); | free(filearg[0]); | ||||
filearg[0] = NULL; | filearg[0] = NULL; | ||||
} | } | ||||
free(source_file); | |||||
source_file = NULL; | |||||
free(outname); | free(outname); | ||||
outname = NULL; | outname = NULL; | ||||
last_offset = 0; | last_offset = 0; | ||||
diff_type = 0; | diff_type = 0; | ||||
free(revision); | free(revision); | ||||
revision = NULL; | revision = NULL; | ||||
▲ Show 20 Lines • Show All 623 Lines • ▼ Show 20 Lines | if (isspace((unsigned char)*b)) { /* whitespace (or \n) to match? */ | ||||
return (*a == *b); /* should end in sync */ | return (*a == *b); /* should end in sync */ | ||||
} else if (*a++ != *b++) /* match non-whitespace chars */ | } else if (*a++ != *b++) /* match non-whitespace chars */ | ||||
return false; | return false; | ||||
else | else | ||||
len--; /* probably not necessary */ | len--; /* probably not necessary */ | ||||
} | } | ||||
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 */ | ||||
} | |||||
static bool | |||||
handle_creation(bool out_existed, bool *remove) | |||||
{ | |||||
bool reverse_seen; | |||||
reverse_seen = false; | |||||
if (reverse && out_existed) { | |||||
*remove = true; | |||||
} else if (!reverse && out_existed) { | |||||
cemUnsubmitted Not Done Inline ActionsI don't grok our patch well enough to understand what each of these cases (throughout the subroutine) does, so it's difficult for me to verify. Comments might help but they might make it too wordy. Up to you. cem: I don't grok our patch well enough to understand what each of these cases (throughout the… | |||||
if (force) { | |||||
skip_rest_of_patch = true; | |||||
return (false); | |||||
} | |||||
if (noreverse) { | |||||
say("Ignoring previously applied (or reversed) patch.\n"); | |||||
skip_rest_of_patch = true; | |||||
return (false); | |||||
} | |||||
/* Unreversed... suspicious if the file existed. */ | |||||
if (!pch_swap()) | |||||
fatal("lost hunk on alloc error!\n"); | |||||
reverse = !reverse; | |||||
if (batch) { | |||||
if (verbose) | |||||
say("Patch creates file that already exists, %s %seversed", | |||||
reverse ? "Assuming" : "Ignoring", | |||||
reverse ? "R" : "Unr"); | |||||
} else { | |||||
ask("Patch creates file that already exists! %s -R? [y] ", | |||||
reverse ? "Assume" : "Ignore"); | |||||
if (*buf == 'n') { | |||||
ask("Apply anyway? [n]"); | |||||
if (*buf != 'y') | |||||
/* Don't apply; error out */ | |||||
skip_rest_of_patch = true; | |||||
else | |||||
/* Attempt to apply */ | |||||
reverse_seen = true; | |||||
reverse = !reverse; | |||||
if (!pch_swap()) | |||||
fatal("lost hunk on alloc error!\n"); | |||||
} else { | |||||
/* They've opted to assume -R */ | |||||
*remove = true; | |||||
} | |||||
} | |||||
} | |||||
return (reverse_seen); | |||||
} | } |
On the /dev/null name-creation basis, it seems like we could just bail on this input patch at this point rather than wait until we get to hunk processing