version 1.31, 2003/09/28 07:55:19 |
version 1.32, 2003/10/31 20:20:45 |
|
|
#include <sys/stat.h> |
#include <sys/stat.h> |
|
|
#include <ctype.h> |
#include <ctype.h> |
|
#include <libgen.h> |
|
#include <limits.h> |
#include <stdio.h> |
#include <stdio.h> |
#include <stdlib.h> |
#include <stdlib.h> |
#include <string.h> |
#include <string.h> |
|
|
static void next_intuit_at(LINENUM, LINENUM); |
static void next_intuit_at(LINENUM, LINENUM); |
static void skip_to(LINENUM, LINENUM); |
static void skip_to(LINENUM, LINENUM); |
static char *pgets(char *, int, FILE *); |
static char *pgets(char *, int, FILE *); |
|
static char *best_name(const struct file_name *, bool); |
|
static char *posix_name(const struct file_name *, bool); |
|
static size_t num_components(const char *); |
|
|
|
|
/* |
/* |
* Prepare to look for the next patch in the patch file. |
* Prepare to look for the next patch in the patch file. |
*/ |
*/ |
|
|
bool |
bool |
there_is_another_patch(void) |
there_is_another_patch(void) |
{ |
{ |
|
bool exists = false; |
|
|
if (p_base != 0L && p_base >= p_filesize) { |
if (p_base != 0L && p_base >= p_filesize) { |
if (verbose) |
if (verbose) |
say("done\n"); |
say("done\n"); |
|
|
if (*buf != '\n') { |
if (*buf != '\n') { |
free(bestguess); |
free(bestguess); |
bestguess = savestr(buf); |
bestguess = savestr(buf); |
filearg[0] = fetchname(buf, 0, false); |
filearg[0] = fetchname(buf, &exists, 0); |
} |
} |
if (filearg[0] == NULL) { |
if (!exists) { |
|
free(filearg[0]); |
ask("No file found--skip this patch? [n] "); |
ask("No file found--skip this patch? [n] "); |
if (*buf != 'y') |
if (*buf != 'y') |
continue; |
continue; |
if (verbose) |
if (verbose) |
say("Skipping patch...\n"); |
say("Skipping patch...\n"); |
filearg[0] = fetchname(bestguess, 0, true); |
filearg[0] = fetchname(bestguess, &exists, 0); |
skip_rest_of_patch = true; |
skip_rest_of_patch = true; |
return true; |
return true; |
} |
} |
|
|
bool last_line_was_command = false, this_is_a_command = false; |
bool last_line_was_command = false, this_is_a_command = false; |
bool stars_last_line = false, stars_this_line = false; |
bool stars_last_line = false, stars_this_line = false; |
char *s, *t; |
char *s, *t; |
char *indtmp = NULL; |
|
char *oldtmp = NULL; |
|
char *newtmp = NULL; |
|
char *indname = NULL; |
|
char *oldname = NULL; |
|
char *newname = NULL; |
|
int indent, retval; |
int indent, retval; |
bool no_filearg = (filearg[0] == NULL); |
struct file_name names[MAX_FILE]; |
|
|
|
memset(names, 0, sizeof(names)); |
ok_to_create_file = false; |
ok_to_create_file = false; |
fseek(pfp, p_base, SEEK_SET); |
fseek(pfp, p_base, SEEK_SET); |
p_input_line = p_bline - 1; |
p_input_line = p_bline - 1; |
|
|
p_indent = indent; /* assume this for now */ |
p_indent = indent; /* assume this for now */ |
} |
} |
if (!stars_last_line && strnEQ(s, "*** ", 4)) |
if (!stars_last_line && strnEQ(s, "*** ", 4)) |
oldtmp = savestr(s + 4); |
names[OLD_FILE].path = fetchname(s + 4, |
|
&names[OLD_FILE].exists, strippath); |
else if (strnEQ(s, "--- ", 4)) |
else if (strnEQ(s, "--- ", 4)) |
newtmp = savestr(s + 4); |
names[NEW_FILE].path = fetchname(s + 4, |
|
&names[NEW_FILE].exists, strippath); |
else if (strnEQ(s, "+++ ", 4)) |
else if (strnEQ(s, "+++ ", 4)) |
oldtmp = savestr(s + 4); /* pretend it is the old name */ |
/* pretend it is the old name */ |
|
names[OLD_FILE].path = fetchname(s + 4, |
|
&names[OLD_FILE].exists, strippath); |
else if (strnEQ(s, "Index:", 6)) |
else if (strnEQ(s, "Index:", 6)) |
indtmp = savestr(s + 6); |
names[INDEX_FILE].path = fetchname(s + 6, |
|
&names[INDEX_FILE].exists, strippath); |
else if (strnEQ(s, "Prereq:", 7)) { |
else if (strnEQ(s, "Prereq:", 7)) { |
for (t = s + 7; isspace(*t); t++) |
for (t = s + 7; isspace(*t); t++) |
; |
; |
|
|
goto scan_exit; |
goto scan_exit; |
} |
} |
if ((!diff_type || diff_type == UNI_DIFF) && strnEQ(s, "@@ -", 4)) { |
if ((!diff_type || diff_type == UNI_DIFF) && strnEQ(s, "@@ -", 4)) { |
if (!atol(s + 3)) |
if (strnEQ(s + 4, "0,0", 3)) |
ok_to_create_file = true; |
ok_to_create_file = true; |
p_indent = indent; |
p_indent = indent; |
p_start = this_line; |
p_start = this_line; |
|
|
stars_this_line = strnEQ(s, "********", 8); |
stars_this_line = strnEQ(s, "********", 8); |
if ((!diff_type || diff_type == CONTEXT_DIFF) && stars_last_line && |
if ((!diff_type || diff_type == CONTEXT_DIFF) && stars_last_line && |
strnEQ(s, "*** ", 4)) { |
strnEQ(s, "*** ", 4)) { |
if (!atol(s + 4)) |
if (atol(s + 4) == 0) |
ok_to_create_file = true; |
ok_to_create_file = true; |
/* |
/* |
* if this is a new context diff the character just |
* If this is a new context diff the character just |
* before |
* before the newline is a '*'. |
*/ |
*/ |
/* the newline is a '*'. */ |
|
while (*s != '\n') |
while (*s != '\n') |
s++; |
s++; |
p_indent = indent; |
p_indent = indent; |
|
|
} |
} |
} |
} |
scan_exit: |
scan_exit: |
if (no_filearg) { |
if (retval == UNI_DIFF) { |
if (indtmp != NULL) |
/* unswap old and new */ |
indname = fetchname(indtmp, strippath, ok_to_create_file); |
struct file_name tmp = names[OLD_FILE]; |
if (oldtmp != NULL) |
names[OLD_FILE] = names[NEW_FILE]; |
oldname = fetchname(oldtmp, strippath, ok_to_create_file); |
names[NEW_FILE] = tmp; |
if (newtmp != NULL) |
|
newname = fetchname(newtmp, strippath, ok_to_create_file); |
|
if (indname) |
|
filearg[0] = savestr(indname); |
|
else if (oldname && newname) { |
|
if (strlen(oldname) < strlen(newname)) |
|
filearg[0] = savestr(oldname); |
|
else |
|
filearg[0] = savestr(newname); |
|
} else if (oldname) |
|
filearg[0] = savestr(oldname); |
|
else if (newname) |
|
filearg[0] = savestr(newname); |
|
} |
} |
|
if (filearg[0] == NULL) { |
|
if (posix) |
|
filearg[0] = posix_name(names, ok_to_create_file); |
|
else { |
|
/* Ignore the Index: name for context diffs, like GNU */ |
|
if (names[OLD_FILE].path != NULL || |
|
names[NEW_FILE].path != NULL) { |
|
free(names[INDEX_FILE].path); |
|
names[INDEX_FILE].path = NULL; |
|
} |
|
filearg[0] = best_name(names, ok_to_create_file); |
|
} |
|
} |
|
|
free(bestguess); |
free(bestguess); |
bestguess = NULL; |
bestguess = NULL; |
|
|
if (filearg[0] != NULL) |
if (filearg[0] != NULL) |
bestguess = savestr(filearg[0]); |
bestguess = savestr(filearg[0]); |
else if (indtmp != NULL) |
else if (!ok_to_create_file) { |
bestguess = fetchname(indtmp, strippath, true); |
/* |
else { |
* We don't want to create a new file but we need a |
if (oldtmp != NULL) |
* filename to set bestguess. Avoid setting filearg[0] |
oldname = fetchname(oldtmp, strippath, true); |
* so the file is not created automatically. |
if (newtmp != NULL) |
*/ |
newname = fetchname(newtmp, strippath, true); |
if (posix) |
if (oldname && newname) { |
bestguess = posix_name(names, true); |
if (strlen(oldname) < strlen(newname)) |
else |
bestguess = savestr(oldname); |
bestguess = best_name(names, true); |
else |
|
bestguess = savestr(newname); |
|
} else if (oldname) |
|
bestguess = savestr(oldname); |
|
else if (newname) |
|
bestguess = savestr(newname); |
|
} |
} |
free(indtmp); |
free(names[OLD_FILE].path); |
free(oldtmp); |
free(names[NEW_FILE].path); |
free(newtmp); |
free(names[INDEX_FILE].path); |
free(indname); |
|
free(oldname); |
|
free(newname); |
|
return retval; |
return retval; |
} |
} |
|
|
|
|
chmod(outname, filemode); |
chmod(outname, filemode); |
} |
} |
set_signals(1); |
set_signals(1); |
|
} |
|
|
|
/* |
|
* Choose the name of the file to be patched based on POSIX rules. |
|
* NOTE: the POSIX rules are amazingly stupid and we only follow them |
|
* if the user specified --posix or set POSIXLY_CORRECT. |
|
*/ |
|
static char * |
|
posix_name(const struct file_name *names, bool assume_exists) |
|
{ |
|
char *path = NULL; |
|
int i; |
|
|
|
/* |
|
* POSIX states that the filename will be chosen from one |
|
* of the old, new and index names (in that order) if |
|
* the file exists relative to CWD after -p stripping. |
|
*/ |
|
for (i = 0; i < MAX_FILE; i++) { |
|
if (names[i].path != NULL && names[i].exists) { |
|
path = names[i].path; |
|
break; |
|
} |
|
} |
|
if (path == NULL && !assume_exists) { |
|
/* |
|
* No files found, look for something we can checkout from |
|
* RCS/SCCS dirs. Same order as above. |
|
*/ |
|
for (i = 0; i < MAX_FILE; i++) { |
|
if (names[i].path != NULL && |
|
(path = checked_in(names[i].path)) != NULL) |
|
break; |
|
} |
|
/* |
|
* Still no match? Check to see if the diff could be creating |
|
* a new file. |
|
*/ |
|
if (path == NULL && ok_to_create_file && |
|
names[NEW_FILE].path != NULL) |
|
path = names[NEW_FILE].path; |
|
} |
|
|
|
return path ? savestr(path) : NULL; |
|
} |
|
|
|
/* |
|
* Choose the name of the file to be patched based the "best" one |
|
* available. |
|
*/ |
|
static char * |
|
best_name(const struct file_name *names, bool assume_exists) |
|
{ |
|
size_t min_components, min_baselen, min_len, tmp; |
|
char *best = NULL; |
|
int i; |
|
|
|
/* |
|
* The "best" name is the one with the fewest number of path |
|
* components, the shortest basename length, and the shortest |
|
* overall length (in that order). We only use the Index: file |
|
* if neither of the old or new files could be intuited from |
|
* the diff header. |
|
*/ |
|
min_components = min_baselen = min_len = SIZE_MAX; |
|
for (i = INDEX_FILE; i >= OLD_FILE; i--) { |
|
if (names[i].path == NULL || |
|
(!names[i].exists && !assume_exists)) |
|
continue; |
|
if ((tmp = num_components(names[i].path)) > min_components) |
|
continue; |
|
min_components = tmp; |
|
if ((tmp = strlen(basename(names[i].path))) > min_baselen) |
|
continue; |
|
min_baselen = tmp; |
|
if ((tmp = strlen(names[i].path)) > min_len) |
|
continue; |
|
min_len = tmp; |
|
best = names[i].path; |
|
} |
|
if (best == NULL) { |
|
/* |
|
* No files found, look for something we can checkout from |
|
* RCS/SCCS dirs. Logic is identical to that above... |
|
*/ |
|
min_components = min_baselen = min_len = SIZE_MAX; |
|
for (i = INDEX_FILE; i >= OLD_FILE; i--) { |
|
if (names[i].path == NULL || |
|
checked_in(names[i].path) == NULL) |
|
continue; |
|
if ((tmp = num_components(names[i].path)) > min_components) |
|
continue; |
|
min_components = tmp; |
|
if ((tmp = strlen(basename(names[i].path))) > min_baselen) |
|
continue; |
|
min_baselen = tmp; |
|
if ((tmp = strlen(names[i].path)) > min_len) |
|
continue; |
|
min_len = tmp; |
|
best = names[i].path; |
|
} |
|
/* |
|
* Still no match? Check to see if the diff could be creating |
|
* a new file. |
|
*/ |
|
if (best == NULL && ok_to_create_file && |
|
names[NEW_FILE].path != NULL) |
|
best = names[NEW_FILE].path; |
|
} |
|
|
|
return best ? savestr(best) : NULL; |
|
} |
|
|
|
static size_t |
|
num_components(const char *path) |
|
{ |
|
size_t n; |
|
const char *cp; |
|
|
|
for (n = 0, cp = path; (cp = strchr(cp, '/')) != NULL; n++, cp++) { |
|
while (*cp == '/') |
|
cp++; /* skip consecutive slashes */ |
|
} |
|
return n; |
} |
} |