version 1.20, 2003/07/21 14:32:21 |
version 1.21, 2003/07/22 17:18:49 |
|
|
/* $OpenBSD$ */ |
/* $OpenBSD$ */ |
|
|
#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 <assert.h> |
|
#include <ctype.h> |
|
#include <stdlib.h> |
|
#include <string.h> |
|
#include <unistd.h> |
|
|
#include "EXTERN.h" |
#include "EXTERN.h" |
#include "common.h" |
#include "common.h" |
#include "util.h" |
#include "util.h" |
#include "INTERN.h" |
#include "INTERN.h" |
#include "pch.h" |
#include "pch.h" |
|
|
extern bool check_only; |
|
/* Patch (diff listing) abstract type. */ |
/* Patch (diff listing) abstract type. */ |
|
|
static long p_filesize; /* size of the patch file */ |
static long p_filesize; /* size of the patch file */ |
|
|
static LINENUM p_max; /* max allowed value of p_end */ |
static LINENUM p_max; /* max allowed value of p_end */ |
static LINENUM p_context = 3; /* # of context lines */ |
static LINENUM p_context = 3; /* # of context lines */ |
static LINENUM p_input_line = 0; /* current line # from patch file */ |
static LINENUM p_input_line = 0; /* current line # from patch file */ |
static char **p_line = Null(char **); /* the text of the hunk */ |
static char **p_line = NULL; /* the text of the hunk */ |
static short *p_len = Null(short *); /* length of each line */ |
static short *p_len = NULL; /* length of each line */ |
static char *p_char = Nullch;/* +, -, and ! */ |
static char *p_char = NULL;/* +, -, and ! */ |
static int hunkmax = INITHUNKMAX; /* size of above arrays to begin with */ |
static int hunkmax = INITHUNKMAX; /* size of above arrays to begin with */ |
static int p_indent; /* indent to patch */ |
static int p_indent; /* indent to patch */ |
static LINENUM p_base; /* where to intuit this time */ |
static LINENUM p_base; /* where to intuit this time */ |
|
|
static LINENUM p_efake = -1; /* end of faked up lines--don't free */ |
static LINENUM p_efake = -1; /* end of faked up lines--don't free */ |
static LINENUM p_bfake = -1; /* beg of faked up lines */ |
static LINENUM p_bfake = -1; /* beg of faked up lines */ |
|
|
|
static void grow_hunkmax(void); |
|
static int intuit_diff_type(void); |
|
static void next_intuit_at(long, long); |
|
static void skip_to(long, long); |
|
static char *pgets(char *, int, FILE *); |
|
|
/* |
/* |
* Prepare to look for the next patch in the patch file. |
* Prepare to look for the next patch in the patch file. |
*/ |
*/ |
void |
void |
re_patch(void) |
re_patch(void) |
{ |
{ |
p_first = Nulline; |
p_first = NULL; |
p_newfirst = Nulline; |
p_newfirst = NULL; |
p_ptrn_lines = Nulline; |
p_ptrn_lines = NULL; |
p_repl_lines = Nulline; |
p_repl_lines = NULL; |
p_end = (LINENUM) - 1; |
p_end = (LINENUM) - 1; |
p_max = Nulline; |
p_max = NULL; |
p_indent = 0; |
p_indent = 0; |
} |
} |
|
|
|
|
void |
void |
open_patch_file(char *filename) |
open_patch_file(char *filename) |
{ |
{ |
if (filename == Nullch || !*filename || strEQ(filename, "-")) { |
if (filename == NULL || !*filename || strEQ(filename, "-")) { |
pfp = fopen(TMPPATNAME, "w"); |
pfp = fopen(TMPPATNAME, "w"); |
if (pfp == Nullfp) |
if (pfp == NULL) |
pfatal("can't create %s", TMPPATNAME); |
pfatal("can't create %s", TMPPATNAME); |
while (fgets(buf, sizeof buf, stdin) != Nullch) |
while (fgets(buf, sizeof buf, stdin) != NULL) |
fputs(buf, pfp); |
fputs(buf, pfp); |
fclose(pfp); |
fclose(pfp); |
filename = TMPPATNAME; |
filename = TMPPATNAME; |
} |
} |
pfp = fopen(filename, "r"); |
pfp = fopen(filename, "r"); |
if (pfp == Nullfp) |
if (pfp == NULL) |
pfatal("patch file %s not found", filename); |
pfatal("patch file %s not found", filename); |
fstat(fileno(pfp), &filestat); |
fstat(fileno(pfp), &filestat); |
p_filesize = filestat.st_size; |
p_filesize = filestat.st_size; |
|
|
void |
void |
set_hunkmax(void) |
set_hunkmax(void) |
{ |
{ |
#ifndef lint |
if (p_line == NULL) |
if (p_line == Null(char **)) |
p_line = malloc((size_t) hunkmax * sizeof(char *)); |
p_line = (char **) malloc((size_t) hunkmax * sizeof(char *)); |
if (p_len == NULL) |
if (p_len == Null(short *)) |
p_len = malloc((size_t) hunkmax * sizeof(short)); |
p_len = (short *) malloc((size_t) hunkmax * sizeof(short)); |
if (p_char == NULL) |
#endif |
p_char = malloc((size_t) hunkmax * sizeof(char)); |
if (p_char == Nullch) |
|
p_char = (char *) malloc((size_t) hunkmax * sizeof(char)); |
|
} |
} |
|
|
/* |
/* |
* Enlarge the arrays containing the current hunk of patch. |
* Enlarge the arrays containing the current hunk of patch. |
*/ |
*/ |
void |
static void |
grow_hunkmax(void) |
grow_hunkmax(void) |
{ |
{ |
hunkmax *= 2; |
hunkmax *= 2; |
|
|
* since p_len can move into p_line's old space, and p_char can move into |
* since p_len can move into p_line's old space, and p_char can move into |
* p_len's old space. Not on PDP-11's however. But it doesn't matter. |
* p_len's old space. Not on PDP-11's however. But it doesn't matter. |
*/ |
*/ |
assert(p_line != Null(char **) &&p_len != Null(short *) &&p_char != Nullch); |
assert(p_line != NULL &&p_len != NULL &&p_char != NULL); |
#ifndef lint |
|
p_line = (char **) realloc((char *) p_line, hunkmax * sizeof(char *)); |
p_line = realloc(p_line, hunkmax * sizeof(char *)); |
p_len = (short *) realloc((char *) p_len, hunkmax * sizeof(short)); |
p_len = realloc(p_len, hunkmax * sizeof(short)); |
p_char = (char *) realloc((char *) p_char, hunkmax * sizeof(char)); |
p_char = realloc(p_char, hunkmax * sizeof(char)); |
#endif |
|
if (p_line != Null(char **) &&p_len != Null(short *) &&p_char != Nullch) |
if (p_line != NULL &&p_len != NULL &&p_char != NULL) |
return; |
return; |
if (!using_plan_a) |
if (!using_plan_a) |
fatal("out of memory\n"); |
fatal("out of memory\n"); |
|
|
say("(Patch is indented %d space%s.)\n", p_indent, |
say("(Patch is indented %d space%s.)\n", p_indent, |
p_indent == 1 ? "" : "s"); |
p_indent == 1 ? "" : "s"); |
skip_to(p_start, p_sline); |
skip_to(p_start, p_sline); |
while (filearg[0] == Nullch) { |
while (filearg[0] == NULL) { |
if (force || batch) { |
if (force || batch) { |
say("No file to patch. Skipping...\n"); |
say("No file to patch. Skipping...\n"); |
filearg[0] = savestr(bestguess); |
filearg[0] = savestr(bestguess); |
|
|
bestguess = savestr(buf); |
bestguess = savestr(buf); |
filearg[0] = fetchname(buf, 0, FALSE); |
filearg[0] = fetchname(buf, 0, FALSE); |
} |
} |
if (filearg[0] == Nullch) { |
if (filearg[0] == NULL) { |
ask("No file found--skip this patch? [n] "); |
ask("No file found--skip this patch? [n] "); |
if (*buf != 'y') |
if (*buf != 'y') |
continue; |
continue; |
|
|
|
|
/* Determine what kind of diff is in the remaining part of the patch file. */ |
/* Determine what kind of diff is in the remaining part of the patch file. */ |
|
|
int |
static int |
intuit_diff_type(void) |
intuit_diff_type(void) |
{ |
{ |
long this_line = 0, previous_line; |
long this_line = 0, previous_line; |
|
|
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 = Nullch; |
char *indtmp = NULL; |
char *oldtmp = Nullch; |
char *oldtmp = NULL; |
char *newtmp = Nullch; |
char *newtmp = NULL; |
char *indname = Nullch; |
char *indname = NULL; |
char *oldname = Nullch; |
char *oldname = NULL; |
char *newname = Nullch; |
char *newname = NULL; |
int indent, retval; |
int indent, retval; |
bool no_filearg = (filearg[0] == Nullch); |
bool no_filearg = (filearg[0] == NULL); |
|
|
ok_to_create_file = FALSE; |
ok_to_create_file = FALSE; |
fseek(pfp, p_base, 0); |
fseek(pfp, p_base, SEEK_SET); |
p_input_line = p_bline - 1; |
p_input_line = p_bline - 1; |
for (;;) { |
for (;;) { |
previous_line = this_line; |
previous_line = this_line; |
|
|
this_line = ftell(pfp); |
this_line = ftell(pfp); |
indent = 0; |
indent = 0; |
p_input_line++; |
p_input_line++; |
if (fgets(buf, sizeof buf, pfp) == Nullch) { |
if (fgets(buf, sizeof buf, pfp) == NULL) { |
if (first_command_line >= 0L) { |
if (first_command_line >= 0L) { |
/* nothing but deletes!? */ |
/* nothing but deletes!? */ |
p_start = first_command_line; |
p_start = first_command_line; |
|
|
*t = '\0'; |
*t = '\0'; |
if (!*revision) { |
if (!*revision) { |
free(revision); |
free(revision); |
revision = Nullch; |
revision = NULL; |
} |
} |
} |
} |
if ((!diff_type || diff_type == ED_DIFF) && |
if ((!diff_type || diff_type == ED_DIFF) && |
|
|
} |
} |
scan_exit: |
scan_exit: |
if (no_filearg) { |
if (no_filearg) { |
if (indtmp != Nullch) |
if (indtmp != NULL) |
indname = fetchname(indtmp, strippath, ok_to_create_file); |
indname = fetchname(indtmp, strippath, ok_to_create_file); |
if (oldtmp != Nullch) |
if (oldtmp != NULL) |
oldname = fetchname(oldtmp, strippath, ok_to_create_file); |
oldname = fetchname(oldtmp, strippath, ok_to_create_file); |
if (newtmp != Nullch) |
if (newtmp != NULL) |
newname = fetchname(newtmp, strippath, ok_to_create_file); |
newname = fetchname(newtmp, strippath, ok_to_create_file); |
if (indname) |
if (indname) |
filearg[0] = savestr(indname); |
filearg[0] = savestr(indname); |
|
|
} |
} |
if (bestguess) { |
if (bestguess) { |
free(bestguess); |
free(bestguess); |
bestguess = Nullch; |
bestguess = NULL; |
} |
} |
if (filearg[0] != Nullch) |
if (filearg[0] != NULL) |
bestguess = savestr(filearg[0]); |
bestguess = savestr(filearg[0]); |
else if (indtmp != Nullch) |
else if (indtmp != NULL) |
bestguess = fetchname(indtmp, strippath, TRUE); |
bestguess = fetchname(indtmp, strippath, TRUE); |
else { |
else { |
if (oldtmp != Nullch) |
if (oldtmp != NULL) |
oldname = fetchname(oldtmp, strippath, TRUE); |
oldname = fetchname(oldtmp, strippath, TRUE); |
if (newtmp != Nullch) |
if (newtmp != NULL) |
newname = fetchname(newtmp, strippath, TRUE); |
newname = fetchname(newtmp, strippath, TRUE); |
if (oldname && newname) { |
if (oldname && newname) { |
if (strlen(oldname) < strlen(newname)) |
if (strlen(oldname) < strlen(newname)) |
|
|
else if (newname) |
else if (newname) |
bestguess = savestr(newname); |
bestguess = savestr(newname); |
} |
} |
if (indtmp != Nullch) |
free(indtmp); |
free(indtmp); |
free(oldtmp); |
if (oldtmp != Nullch) |
free(newtmp); |
free(oldtmp); |
free(indname); |
if (newtmp != Nullch) |
free(oldname); |
free(newtmp); |
free(newname); |
if (indname != Nullch) |
|
free(indname); |
|
if (oldname != Nullch) |
|
free(oldname); |
|
if (newname != Nullch) |
|
free(newname); |
|
return retval; |
return retval; |
} |
} |
|
|
/* |
/* |
* Remember where this patch ends so we know where to start up again. |
* Remember where this patch ends so we know where to start up again. |
*/ |
*/ |
void |
static void |
next_intuit_at(long file_pos, long file_line) |
next_intuit_at(long file_pos, long file_line) |
{ |
{ |
p_base = file_pos; |
p_base = file_pos; |
|
|
/* |
/* |
* Basically a verbose fseek() to the actual diff listing. |
* Basically a verbose fseek() to the actual diff listing. |
*/ |
*/ |
void |
static void |
skip_to(long file_pos, long file_line) |
skip_to(long file_pos, long file_line) |
{ |
{ |
char *ret; |
char *ret; |
|
|
assert(p_base <= file_pos); |
assert(p_base <= file_pos); |
if (verbose && p_base < file_pos) { |
if (verbose && p_base < file_pos) { |
fseek(pfp, p_base, 0); |
fseek(pfp, p_base, SEEK_SET); |
say("The text leading up to this was:\n--------------------------\n"); |
say("The text leading up to this was:\n--------------------------\n"); |
while (ftell(pfp) < file_pos) { |
while (ftell(pfp) < file_pos) { |
ret = fgets(buf, sizeof buf, pfp); |
ret = fgets(buf, sizeof buf, pfp); |
assert(ret != Nullch); |
assert(ret != NULL); |
say("|%s", buf); |
say("|%s", buf); |
} |
} |
say("--------------------------\n"); |
say("--------------------------\n"); |
} else |
} else |
fseek(pfp, file_pos, 0); |
fseek(pfp, file_pos, SEEK_SET); |
p_input_line = file_line - 1; |
p_input_line = file_line - 1; |
} |
} |
|
|
|
|
|
|
ret = pgets(buf, sizeof buf, pfp); |
ret = pgets(buf, sizeof buf, pfp); |
p_input_line++; |
p_input_line++; |
if (ret == Nullch || strnNE(buf, "********", 8)) { |
if (ret == NULL || strnNE(buf, "********", 8)) { |
next_intuit_at(line_beginning, p_input_line); |
next_intuit_at(line_beginning, p_input_line); |
return FALSE; |
return FALSE; |
} |
} |
|
|
line_beginning = ftell(pfp); |
line_beginning = ftell(pfp); |
ret = pgets(buf, sizeof buf, pfp); |
ret = pgets(buf, sizeof buf, pfp); |
p_input_line++; |
p_input_line++; |
if (ret == Nullch) { |
if (ret == NULL) { |
if (p_max - p_end < 4) { |
if (p_max - p_end < 4) { |
/* assume blank lines got chopped */ |
/* assume blank lines got chopped */ |
strlcpy(buf, " \n", sizeof buf); |
strlcpy(buf, " \n", sizeof buf); |
|
|
p_end++; |
p_end++; |
assert(p_end < hunkmax); |
assert(p_end < hunkmax); |
p_char[p_end] = *buf; |
p_char[p_end] = *buf; |
p_line[p_end] = Nullch; |
p_line[p_end] = NULL; |
switch (*buf) { |
switch (*buf) { |
case '*': |
case '*': |
if (strnEQ(buf, "********", 8)) { |
if (strnEQ(buf, "********", 8)) { |
|
|
p_input_line = repl_patch_line; |
p_input_line = repl_patch_line; |
for (p_end--; p_end > repl_beginning; p_end--) |
for (p_end--; p_end > repl_beginning; p_end--) |
free(p_line[p_end]); |
free(p_line[p_end]); |
fseek(pfp, repl_backtrack_position, 0); |
fseek(pfp, repl_backtrack_position, SEEK_SET); |
|
|
/* redundant 'new' context lines were omitted - set */ |
/* redundant 'new' context lines were omitted - set */ |
/* up to fill them in from the old file context */ |
/* up to fill them in from the old file context */ |
|
|
|
|
ret = pgets(buf, sizeof buf, pfp); |
ret = pgets(buf, sizeof buf, pfp); |
p_input_line++; |
p_input_line++; |
if (ret == Nullch || strnNE(buf, "@@ -", 4)) { |
if (ret == NULL || strnNE(buf, "@@ -", 4)) { |
next_intuit_at(line_beginning, p_input_line); |
next_intuit_at(line_beginning, p_input_line); |
return FALSE; |
return FALSE; |
} |
} |
|
|
line_beginning = ftell(pfp); |
line_beginning = ftell(pfp); |
ret = pgets(buf, sizeof buf, pfp); |
ret = pgets(buf, sizeof buf, pfp); |
p_input_line++; |
p_input_line++; |
if (ret == Nullch) { |
if (ret == NULL) { |
if (p_max - filldst < 3) { |
if (p_max - filldst < 3) { |
/* assume blank lines got chopped */ |
/* assume blank lines got chopped */ |
strlcpy(buf, " \n", sizeof buf); |
strlcpy(buf, " \n", sizeof buf); |
|
|
p_context = 0; |
p_context = 0; |
ret = pgets(buf, sizeof buf, pfp); |
ret = pgets(buf, sizeof buf, pfp); |
p_input_line++; |
p_input_line++; |
if (ret == Nullch || !isdigit(*buf)) { |
if (ret == NULL || !isdigit(*buf)) { |
next_intuit_at(line_beginning, p_input_line); |
next_intuit_at(line_beginning, p_input_line); |
return FALSE; |
return FALSE; |
} |
} |
|
|
for (i = 1; i <= p_ptrn_lines; i++) { |
for (i = 1; i <= p_ptrn_lines; i++) { |
ret = pgets(buf, sizeof buf, pfp); |
ret = pgets(buf, sizeof buf, pfp); |
p_input_line++; |
p_input_line++; |
if (ret == Nullch) |
if (ret == NULL) |
fatal("unexpected end of file in patch at line %ld\n", |
fatal("unexpected end of file in patch at line %ld\n", |
p_input_line); |
p_input_line); |
if (*buf != '<') |
if (*buf != '<') |
|
|
if (hunk_type == 'c') { |
if (hunk_type == 'c') { |
ret = pgets(buf, sizeof buf, pfp); |
ret = pgets(buf, sizeof buf, pfp); |
p_input_line++; |
p_input_line++; |
if (ret == Nullch) |
if (ret == NULL) |
fatal("unexpected end of file in patch at line %ld\n", |
fatal("unexpected end of file in patch at line %ld\n", |
p_input_line); |
p_input_line); |
if (*buf != '-') |
if (*buf != '-') |
|
|
for (i++; i <= p_end; i++) { |
for (i++; i <= p_end; i++) { |
ret = pgets(buf, sizeof buf, pfp); |
ret = pgets(buf, sizeof buf, pfp); |
p_input_line++; |
p_input_line++; |
if (ret == Nullch) |
if (ret == NULL) |
fatal("unexpected end of file in patch at line %ld\n", |
fatal("unexpected end of file in patch at line %ld\n", |
p_input_line); |
p_input_line); |
if (*buf != '>') |
if (*buf != '>') |
|
|
/* |
/* |
* Input a line from the patch file, worrying about indentation. |
* Input a line from the patch file, worrying about indentation. |
*/ |
*/ |
char * |
static char * |
pgets(char *bf, int sz, FILE *fp) |
pgets(char *bf, int sz, FILE *fp) |
{ |
{ |
char *s, *ret = fgets(bf, sz, fp); |
char *s, *ret = fgets(bf, sz, fp); |
int indent = 0; |
int indent = 0; |
|
|
if (p_indent && ret != Nullch) { |
if (p_indent && ret != NULL) { |
for (s = buf; |
for (s = buf; |
indent < p_indent && (*s == ' ' || *s == '\t' || *s == 'X'); |
indent < p_indent && (*s == ' ' || *s == '\t' || *s == 'X'); |
s++) { |
s++) { |
|
|
tp_line = p_line; |
tp_line = p_line; |
tp_len = p_len; |
tp_len = p_len; |
tp_char = p_char; |
tp_char = p_char; |
p_line = Null(char **); /* force set_hunkmax to allocate again */ |
p_line = NULL; /* force set_hunkmax to allocate again */ |
p_len = Null(short *); |
p_len = NULL; |
p_char = Nullch; |
p_char = NULL; |
set_hunkmax(); |
set_hunkmax(); |
if (p_line == Null(char **) ||p_len == Null(short *) ||p_char == Nullch) { |
if (p_line == NULL ||p_len == NULL ||p_char == NULL) { |
#ifndef lint |
|
if (p_line == Null(char **)) |
if (p_line == NULL) /* XXX */ |
free((char *) p_line); |
free(p_line); |
p_line = tp_line; |
p_line = tp_line; |
if (p_len == Null(short *)) |
if (p_len == NULL) /* XXX */ |
free((char *) p_len); |
free(p_len); |
p_len = tp_len; |
p_len = tp_len; |
#endif |
if (p_char == NULL) /* XXX */ |
if (p_char == Nullch) |
free(p_char); |
free((char *) p_char); |
|
p_char = tp_char; |
p_char = tp_char; |
return FALSE; /* not enough memory to swap hunk! */ |
return FALSE; /* not enough memory to swap hunk! */ |
} |
} |
|
|
i = p_ptrn_lines; |
i = p_ptrn_lines; |
p_ptrn_lines = p_repl_lines; |
p_ptrn_lines = p_repl_lines; |
p_repl_lines = i; |
p_repl_lines = i; |
#ifndef lint |
|
if (tp_line == Null(char **)) |
if (tp_line == NULL) /* XXX */ |
free((char *) tp_line); |
free(tp_line); |
if (tp_len == Null(short *)) |
if (tp_len == NULL) /* XXX */ |
free((char *) tp_len); |
free(tp_len); |
#endif |
if (tp_char == NULL) /* XXX */ |
if (tp_char == Nullch) |
free(tp_char); |
free((char *) tp_char); |
|
return TRUE; |
return TRUE; |
} |
} |
|
|
|
|
} |
} |
for (;;) { |
for (;;) { |
beginning_of_this_line = ftell(pfp); |
beginning_of_this_line = ftell(pfp); |
if (pgets(buf, sizeof buf, pfp) == Nullch) { |
if (pgets(buf, sizeof buf, pfp) == NULL) { |
next_intuit_at(beginning_of_this_line, p_input_line); |
next_intuit_at(beginning_of_this_line, p_input_line); |
break; |
break; |
} |
} |
|
|
if (!skip_rest_of_patch) |
if (!skip_rest_of_patch) |
fputs(buf, pipefp); |
fputs(buf, pipefp); |
if (*t != 'd') { |
if (*t != 'd') { |
while (pgets(buf, sizeof buf, pfp) != Nullch) { |
while (pgets(buf, sizeof buf, pfp) != NULL) { |
p_input_line++; |
p_input_line++; |
if (!skip_rest_of_patch) |
if (!skip_rest_of_patch) |
fputs(buf, pipefp); |
fputs(buf, pipefp); |