Init
This commit is contained in:
987
cmd/patch/patch.c
Executable file
987
cmd/patch/patch.c
Executable file
@@ -0,0 +1,987 @@
|
||||
#ident "@(#)patch.c 1.2 95/09/07 SMI"
|
||||
/*
|
||||
* Copyright (c) 1995, Sun Microsystems, Inc.
|
||||
* All Rights Reserved.
|
||||
*
|
||||
* This module contains IBM CONFIDENTIAL code. -- (IBM
|
||||
* Confidential Restricted when combined with the aggregated
|
||||
* modules for this product)
|
||||
* OBJECT CODE ONLY SOURCE MATERIALS
|
||||
* (C) COPYRIGHT International Business Machines Corp. 1993
|
||||
* All Rights Reserved
|
||||
*
|
||||
* US Government Users Restricted Rights - Use, duplication or
|
||||
* disclosure restricted by GSA ADP Schedule Contract with IBM Corp.
|
||||
*
|
||||
* (c) Copyright 1990, 1991, 1992, 1993 OPEN SOFTWARE FOUNDATION, INC.
|
||||
* ALL RIGHTS RESERVED
|
||||
*
|
||||
* OSF/1 1.2
|
||||
*
|
||||
* Copyright 1986, Larry Wall
|
||||
*
|
||||
* This program may be copied as long as you don't try to make any
|
||||
* money off of it, or pretend that you wrote it.
|
||||
*/
|
||||
|
||||
/*
|
||||
* File: patch.c
|
||||
* Date: Sun Feb 12 18:48:18 PST 1995
|
||||
*
|
||||
* Description:
|
||||
*
|
||||
* patch - a program to apply diffs to original files
|
||||
*
|
||||
* Modifications:
|
||||
* $Log$
|
||||
*/
|
||||
|
||||
/*
|
||||
* Include files:
|
||||
*/
|
||||
|
||||
#include "common.h"
|
||||
|
||||
/*
|
||||
* Global variables
|
||||
*/
|
||||
|
||||
struct stat filestat; /* file statistics area */
|
||||
|
||||
/* Temp buffers for character conversion */
|
||||
char *buf; /* general purpose buffer */
|
||||
wchar_t *wbuf; /* general purpose buffer */
|
||||
|
||||
/* Flags */
|
||||
bool verbose = TRUE; /* Tell all */
|
||||
bool reverse = FALSE; /* Reverse patch files */
|
||||
bool skip_rest_of_patch = FALSE; /* Set on error */
|
||||
int strippath = INT_MAX; /* # path components to strip */
|
||||
int cdiff_type = 0; /* diff type from cmd line */
|
||||
int diff_type = 0; /* working diff type */
|
||||
int dont_sync = FALSE; /* Assume we sync files */
|
||||
long max_input;
|
||||
|
||||
/*
|
||||
* Local variables.
|
||||
*/
|
||||
|
||||
static LINENUM last_offset = 0;
|
||||
static bool force = FALSE;
|
||||
static bool noreverse = FALSE;
|
||||
static bool canonicalize = FALSE;
|
||||
static bool saveorig = FALSE;
|
||||
static wchar_t if_defined[128] = { 0 }; /* #ifdef xyzzy */
|
||||
static wchar_t if_ndefined[128] = { 0 }; /* #ifndef xyzzy */
|
||||
static wchar_t else_defined[] = { L"#else\n" }; /* #else */
|
||||
static wchar_t end_defined[128] = { 0 }; /* #endif xyzzy */
|
||||
|
||||
static char *patch_file = NULL;
|
||||
static char *output_file = NULL;
|
||||
static char *reject_file = NULL;
|
||||
static char *input_file = NULL;
|
||||
|
||||
static LINENUM delta;
|
||||
static int reject_written = 0;
|
||||
|
||||
/* To keep the compiler quiet... */
|
||||
void main(int, char **);
|
||||
|
||||
|
||||
/*
|
||||
* Function: void usage(char *)
|
||||
*
|
||||
* Description:
|
||||
*
|
||||
* Print problem and usage message on stderr and exit with error.
|
||||
*
|
||||
* Inputs:
|
||||
* problem -> Message to print.
|
||||
*/
|
||||
|
||||
static void
|
||||
usage(char *problem)
|
||||
{
|
||||
|
||||
say("patch: %s.\n", problem);
|
||||
fatal(gettext("Usage:\tpatch [-blNR] [-c|-e|-n] [-d dir]"
|
||||
" [-D define] [-i patchfile]\\\n"
|
||||
"\t [-o outfile] [-p num] [-r rejectfile] [file]\n"));
|
||||
exit(ABORT_EXIT_VALUE);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Function: void reinitialize(void)
|
||||
*
|
||||
* Description:
|
||||
*
|
||||
* Prepare to find the next patch to do in the patch file.
|
||||
*/
|
||||
|
||||
static void
|
||||
reinitialize(void)
|
||||
{
|
||||
last_offset = 0;
|
||||
delta = 0;
|
||||
|
||||
reverse = FALSE;
|
||||
skip_rest_of_patch = FALSE;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Function: void process_arguments(int, char **)
|
||||
*
|
||||
* Description:
|
||||
*
|
||||
* Process commmand line arguments.
|
||||
*/
|
||||
|
||||
static void
|
||||
process_arguments(int argc, char **argv)
|
||||
{
|
||||
int c;
|
||||
|
||||
while ((c = getopt(argc, argv, ":bcd:D:ei:lnNo:p:r:Rs")) != -1) {
|
||||
switch (c) {
|
||||
case 'b': /* Save copy of originals */
|
||||
saveorig = TRUE;
|
||||
break;
|
||||
|
||||
case 'c': /* Interpret patch as context diff */
|
||||
if (cdiff_type && cdiff_type != CONTEXT_DIFF) {
|
||||
usage(gettext("-c, -e, and -n are mutually"
|
||||
" exclusive options"));
|
||||
/* NOTREACHED */
|
||||
}
|
||||
cdiff_type = CONTEXT_DIFF;
|
||||
break;
|
||||
|
||||
case 'd': /* Chdir to optarg before processing */
|
||||
if (chdir(optarg) < 0) {
|
||||
fatal(gettext("cd to path %s failed.\n"),
|
||||
optarg);
|
||||
}
|
||||
break;
|
||||
|
||||
case 'D': /* #Ifdef changes */
|
||||
if (!isalpha(*optarg)) {
|
||||
fatal(gettext("Argument to -D"
|
||||
" is not an identifier.\n"));
|
||||
}
|
||||
(void) mbstowcs(wbuf, optarg,
|
||||
sizeof (wbuf) / sizeof (wchar_t));
|
||||
wcscpy(if_defined, L"#ifdef ");
|
||||
(void) mbstowcs(&if_defined[wcslen(if_defined)],
|
||||
optarg, 120);
|
||||
wcscat(if_defined, L"\n");
|
||||
|
||||
wcscpy(if_ndefined, L"#ifndef ");
|
||||
(void) mbstowcs(&if_ndefined[wcslen(if_ndefined)],
|
||||
optarg, 120);
|
||||
wcscat(if_ndefined, L"\n");
|
||||
|
||||
wcscpy(end_defined, L"#endif /* ");
|
||||
(void) mbstowcs(&end_defined[wcslen(end_defined)],
|
||||
optarg, 115);
|
||||
wcscat(end_defined, L" */\n");
|
||||
break;
|
||||
|
||||
case 'e': /* Interpret patch as ed script */
|
||||
if (cdiff_type && cdiff_type != ED_DIFF) {
|
||||
usage(gettext("-c, -e, and -n are mutually"
|
||||
" exclusive options"));
|
||||
/* NOTREACHED */
|
||||
}
|
||||
cdiff_type = ED_DIFF;
|
||||
break;
|
||||
|
||||
case 'i': /* Read patch from file rather than stdin */
|
||||
patch_file = optarg; /* patch input file */
|
||||
break;
|
||||
|
||||
case 'l': /* Cause any blank sequences to match */
|
||||
canonicalize = TRUE;
|
||||
break;
|
||||
|
||||
case 'n': /* Interpret patch as normal diff */
|
||||
if (cdiff_type && cdiff_type != NORMAL_DIFF) {
|
||||
usage(gettext("-c, -e, and -n are mutually"
|
||||
" exclusive options"));
|
||||
/* NOTREACHED */
|
||||
}
|
||||
cdiff_type = NORMAL_DIFF;
|
||||
break;
|
||||
|
||||
case 'N': /* Ignore previously applied patches */
|
||||
noreverse = TRUE;
|
||||
break;
|
||||
|
||||
case 'o': /* Output to named file */
|
||||
/*
|
||||
* If an empty string is passed I.E 'patch -o ""'
|
||||
* we accept this to mean stdout too.
|
||||
*/
|
||||
if (*optarg == NULL)
|
||||
output_file = "-";
|
||||
else
|
||||
output_file = optarg;
|
||||
break;
|
||||
|
||||
case 'p': /* delete specified # components from paths */
|
||||
if (!isdigit(*optarg)) {
|
||||
strippath = 0;
|
||||
optind--;
|
||||
} else {
|
||||
strippath = atoi(optarg);
|
||||
}
|
||||
break;
|
||||
|
||||
case 'r': /* Send rejects to named file */
|
||||
reject_file = optarg;
|
||||
break;
|
||||
|
||||
case 'R': /* reverse patch */
|
||||
reverse = TRUE;
|
||||
break;
|
||||
|
||||
case 's': /* Silent operation */
|
||||
verbose = FALSE;
|
||||
break;
|
||||
|
||||
case ':':
|
||||
if (optopt == 'p') {
|
||||
strippath = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
default: /* None of the above */
|
||||
usage(gettext("Invalid options"));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Get file name if specified. Otherwise name is derived from
|
||||
* patch file.
|
||||
*/
|
||||
if (argv[optind] != NULL) {
|
||||
(void) mbstowcs(wbuf, argv[optind], max_input);
|
||||
if (argv[optind + 1] != NULL) {
|
||||
usage(gettext("Too many file arguments"));
|
||||
}
|
||||
if ((input_file = fetchname(wbuf, 0, 0)) == NULL) {
|
||||
fatal(gettext("patch: Could not open \n"),
|
||||
argv[optind]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Function: void similar(wchar_t *, wchar_t *)
|
||||
*
|
||||
* Description:
|
||||
*
|
||||
* Do two lines match with canonicalized white space?
|
||||
*
|
||||
* Inputs:
|
||||
* a -> A pointer to the first wide character string.
|
||||
* b -> A pointer to the second wide character string.
|
||||
*
|
||||
* Returns:
|
||||
* TRUE -> Lines compare favorably.
|
||||
* FALSE -> Lines do not compare.
|
||||
*/
|
||||
|
||||
static bool
|
||||
similar(wchar_t *a, wchar_t *b)
|
||||
{
|
||||
int len = wcslen(b);
|
||||
|
||||
while (len) {
|
||||
if (iswspace(*b)) { /* whitespace (or \n) to match? */
|
||||
/* no corresponding whitespace? */
|
||||
if (!iswspace(*a))
|
||||
return (FALSE);
|
||||
|
||||
/* skip pattern whitespace */
|
||||
while (len && iswspace(*b) && *b != '\n') {
|
||||
b++;
|
||||
len--;
|
||||
}
|
||||
|
||||
/* skip target whitespace */
|
||||
while (iswspace(*a) && *a != '\n')
|
||||
a++;
|
||||
|
||||
/* should end in sync */
|
||||
if (*a == '\n' || *b == '\n')
|
||||
return (*a == *b);
|
||||
|
||||
/*
|
||||
* Othewise start matching non-whitespace
|
||||
* characters again (if any characters
|
||||
* are left.
|
||||
*/
|
||||
continue;
|
||||
} else if (*a++ != *b++) {
|
||||
/*
|
||||
* Non-whitespace chars did not match
|
||||
* so lines are not similar.
|
||||
*/
|
||||
return (FALSE);
|
||||
}
|
||||
/*
|
||||
* Non-whitespace chars matched
|
||||
* so lines are still similar.
|
||||
*/
|
||||
len--;
|
||||
}
|
||||
|
||||
/* Lines match */
|
||||
return (TRUE);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Function: bool patch_match(file_info *, hunk_info *, LINENUM)
|
||||
*
|
||||
* Description:
|
||||
*
|
||||
* Does the hunk patterns match starting at line offset?
|
||||
*
|
||||
* Inputs:
|
||||
* winfo -> A pointer to the file descriptor.
|
||||
* hunk -> A pointer to the patch descriptor.
|
||||
* offset -> Offset to start checking.
|
||||
*/
|
||||
|
||||
static bool
|
||||
patch_match(file_info *winfo, hunk_info *hunk, LINENUM offset)
|
||||
{
|
||||
wchar_t *patch_line, *input_line;
|
||||
LINENUM pline;
|
||||
|
||||
for (pline = 0; pline < hunk->file1_lines; pline++) {
|
||||
patch_line = hunk->lines[pline] + 2;
|
||||
if ((input_line = fetch_line(winfo, offset + pline)) == NULL)
|
||||
return (FALSE);
|
||||
if (canonicalize) {
|
||||
if (!similar(input_line, patch_line))
|
||||
return (FALSE);
|
||||
} else if (wcsncmp(input_line, patch_line, wcslen(patch_line)))
|
||||
return (FALSE);
|
||||
}
|
||||
return (TRUE);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Function: LINENUM locate_hunk(file_info *, hunk_info *, LINENUM)
|
||||
*
|
||||
* Description:
|
||||
*
|
||||
* Attempt to find the right place to apply this hunk of patch.
|
||||
* Fuzz is the current extent of the search. Most the time this
|
||||
* is 0, but for misplaced patches our caller keeps expanding the
|
||||
* search by one line. We take advantage of this and only check
|
||||
* the extremes since we know every position in the middle has already
|
||||
* failed.
|
||||
*
|
||||
* Inputs:
|
||||
* winfo -> A pointer to the file descriptor.
|
||||
* hunk -> A pointer to the patch descriptor.
|
||||
* fuzz -> +/- Offset to check at.
|
||||
*
|
||||
* Returns:
|
||||
* line number of match or -1 if no match was found yet.
|
||||
*/
|
||||
|
||||
static LINENUM
|
||||
locate_hunk(file_info *winfo, hunk_info *hunk, LINENUM fuzz)
|
||||
{
|
||||
LINENUM first_guess, max_pos_offset, max_neg_offset;
|
||||
|
||||
first_guess = hunk->file1_start + delta + last_offset - 1;
|
||||
|
||||
/* null range matches always */
|
||||
if (hunk->file1_lines == 0)
|
||||
return (first_guess);
|
||||
|
||||
max_pos_offset = first_guess + fuzz;
|
||||
max_neg_offset = first_guess - fuzz;
|
||||
|
||||
/* do not try lines < 0 */
|
||||
if (max_neg_offset < 0)
|
||||
max_neg_offset = 0;
|
||||
if (max_pos_offset < 0)
|
||||
max_pos_offset = 0;
|
||||
|
||||
/* do not try lines > number of lines in file */
|
||||
if ((max_neg_offset + hunk->file1_lines) > winfo->line_count)
|
||||
max_neg_offset = winfo->line_count - hunk->file1_lines;
|
||||
if ((max_pos_offset + hunk->file1_lines) > winfo->line_count)
|
||||
max_pos_offset = winfo->line_count - hunk->file1_lines;
|
||||
|
||||
/*
|
||||
* because of the way searches are expanded we only need
|
||||
* to check the extremes... If fuzz is 0 then we don't
|
||||
* even need to check both since they are identical.
|
||||
*/
|
||||
|
||||
if (fuzz && patch_match(winfo, hunk, max_neg_offset)) {
|
||||
last_offset = delta + hunk->file1_start - max_neg_offset - 1;
|
||||
return (max_neg_offset);
|
||||
}
|
||||
|
||||
if (patch_match(winfo, hunk, max_pos_offset)) {
|
||||
last_offset = delta + hunk->file1_start - max_pos_offset - 1;
|
||||
return (max_pos_offset);
|
||||
}
|
||||
return (-1);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Function: LINENUM check_hunk_location(file_info *, hunk_info *, int)
|
||||
*
|
||||
* Description:
|
||||
*
|
||||
*
|
||||
* Inputs:
|
||||
* winfo -> A pointer to the file descriptor.
|
||||
* hunk -> A pointer to the patch descriptor.
|
||||
* hunk_count -> Current hunk number.
|
||||
*
|
||||
* Returns:
|
||||
* line number of match or -1 if no match was found.
|
||||
*/
|
||||
|
||||
static LINENUM
|
||||
check_hunk_location(file_info *winfo, hunk_info *hunk, int hunk_count)
|
||||
{
|
||||
LINENUM where, fuzz;
|
||||
|
||||
fuzz = 0;
|
||||
do {
|
||||
where = locate_hunk(winfo, hunk, fuzz);
|
||||
if (hunk_count == 1 && where == -1 && !force) {
|
||||
/*
|
||||
* dwim for reversed patch?
|
||||
* for normal diffs swapping a pure delete will always
|
||||
* work and this is not what we want...
|
||||
*/
|
||||
if (diff_type == NORMAL_DIFF && hunk->file2_lines == 0)
|
||||
continue;
|
||||
|
||||
pch_swap(hunk);
|
||||
reverse = !reverse;
|
||||
|
||||
/* try again */
|
||||
where = locate_hunk(winfo, hunk, fuzz);
|
||||
|
||||
/* didn't find it swapped */
|
||||
if (where == -1) {
|
||||
pch_swap(hunk);
|
||||
reverse = !reverse;
|
||||
} else if (noreverse) {
|
||||
pch_swap(hunk);
|
||||
reverse = !reverse;
|
||||
say(gettext("Ignoring previously applied "
|
||||
"(or reversed) patch.\n"));
|
||||
skip_rest_of_patch = TRUE;
|
||||
} else {
|
||||
if (reverse) {
|
||||
ask(gettext("Reversed (or previously "
|
||||
"applied) patch detected! "
|
||||
"Assume -R [%s] "),
|
||||
nl_langinfo(YESSTR));
|
||||
} else {
|
||||
ask(gettext(
|
||||
"Unreversed (or previously "
|
||||
"applied) patch detected! "
|
||||
"Ignore -R? [%s] "),
|
||||
nl_langinfo(YESSTR));
|
||||
}
|
||||
if (rpmatch(buf) == 0) {
|
||||
/* no */
|
||||
ask(gettext("Apply anyway? [%s] "),
|
||||
nl_langinfo(NOSTR));
|
||||
if (rpmatch(buf) != 1) {
|
||||
skip_rest_of_patch = TRUE;
|
||||
}
|
||||
where = NULL;
|
||||
reverse = !reverse;
|
||||
pch_swap(hunk);
|
||||
}
|
||||
}
|
||||
}
|
||||
} while (!skip_rest_of_patch && where == -1 && ++fuzz <= MAXFUZZ);
|
||||
|
||||
return (where);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Function: void abort_hunk(hunk_info *, file_info *)
|
||||
*
|
||||
* Description:
|
||||
*
|
||||
* We did not find the pattern, dump out the hunk so the user
|
||||
* can handle it.
|
||||
*
|
||||
* Inputs:
|
||||
* hunk -> A pointer to the patch descriptor.
|
||||
* reject_info -> A pointer to the file descriptor.
|
||||
*/
|
||||
|
||||
static void
|
||||
abort_hunk(hunk_info *hunk, file_info *reject_info)
|
||||
{
|
||||
LINENUM i;
|
||||
|
||||
reject_written = 1;
|
||||
insert_line(reject_info, L"***************\n", reject_info->line_count);
|
||||
|
||||
(void) sprintf(buf, "*** %ld,%ld ****\n", hunk->file1_start,
|
||||
hunk->file1_start + hunk->file1_lines - 1);
|
||||
(void) mbstowcs(wbuf, buf, max_input);
|
||||
insert_line(reject_info, wbuf, reject_info->line_count);
|
||||
|
||||
for (i = 0; i < hunk->file1_lines; i++) {
|
||||
insert_line(reject_info, hunk->lines[i],
|
||||
reject_info->line_count);
|
||||
}
|
||||
|
||||
(void) sprintf(buf, "--- %ld,%ld ----\n", hunk->file2_start,
|
||||
hunk->file2_start + hunk->file2_lines - 1);
|
||||
(void) mbstowcs(wbuf, buf, max_input);
|
||||
insert_line(reject_info, wbuf, reject_info->line_count);
|
||||
|
||||
for (; i < hunk->line_count; i++) {
|
||||
insert_line(reject_info, hunk->lines[i],
|
||||
reject_info->line_count);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Function: void apply_hunk(file_info *, hunk_info *, LINENUM)
|
||||
*
|
||||
* Description:
|
||||
*
|
||||
* We found where to apply it (we hope), so do it.
|
||||
*
|
||||
* Hunk has already been error checked so we don't
|
||||
* check for malformed expressions here.
|
||||
*
|
||||
* The hunk is applied in 2 phases:
|
||||
* 1) Process the original lines (these include deletions, context lines,
|
||||
* and change lines) we simply delete deletions and change lines.
|
||||
* 2) Process the new lines (these include, additions, context lines,
|
||||
* and change lines) we simply add additions and change lines.
|
||||
*
|
||||
* The tricky part here is to properly account for #ifdef lines and
|
||||
* lines that would normally be deleted when ifdefs are required and
|
||||
* to not account so if they are not. The array deltas is used to
|
||||
* accomplish this. It tracks the number of additional lines that need
|
||||
* to be added to the line count at each sync point (context line) for
|
||||
* each context line in the second phase of application.
|
||||
*
|
||||
* Inputs:
|
||||
* winfo -> A pointer to the file descriptor.
|
||||
* hunk -> A pointer to the patch descriptor.
|
||||
* offset -> Offset to start checking.
|
||||
*/
|
||||
|
||||
static void
|
||||
apply_hunk(file_info *winfo, hunk_info *hunk, LINENUM where)
|
||||
{
|
||||
LINENUM i, wh;
|
||||
wchar_t *line;
|
||||
wchar_t in_define = 0;
|
||||
LINENUM *deltas;
|
||||
LINENUM context_line;
|
||||
|
||||
deltas = allocate(sizeof (LINENUM) * (hunk->line_count + 1));
|
||||
|
||||
/* file1 processing */
|
||||
wh = where;
|
||||
context_line = 0;
|
||||
for (i = 0; i < hunk->file1_lines; i++) {
|
||||
line = hunk->lines[i];
|
||||
switch (*line) {
|
||||
case L' ': /* Context line */
|
||||
if (*if_defined) {
|
||||
/* Put out #endif if needed */
|
||||
if (in_define) {
|
||||
insert_line(winfo, end_defined, wh++);
|
||||
deltas[context_line]++;
|
||||
delta++;
|
||||
in_define = 0;
|
||||
}
|
||||
context_line++;
|
||||
}
|
||||
wh++;
|
||||
break;
|
||||
|
||||
case L'-': /* Delete line */
|
||||
if (*if_defined) {
|
||||
/* Put out #ifndef if needed */
|
||||
if (!in_define) {
|
||||
in_define = *line;
|
||||
insert_line(winfo, if_ndefined, wh++);
|
||||
deltas[context_line]++;
|
||||
delta++;
|
||||
}
|
||||
wh++;
|
||||
} else {
|
||||
delete_line(winfo, wh);
|
||||
delta--;
|
||||
}
|
||||
break;
|
||||
|
||||
case L'!': /* Change line */
|
||||
if (*if_defined) {
|
||||
/* Put out #else if needed */
|
||||
if (!in_define) {
|
||||
in_define = *line;
|
||||
insert_line(winfo, else_defined, wh++);
|
||||
deltas[context_line]++;
|
||||
delta++;
|
||||
}
|
||||
/*
|
||||
* Deltas are accounted for at matching change
|
||||
*/
|
||||
wh++;
|
||||
} else {
|
||||
delete_line(winfo, wh);
|
||||
delta--;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* Put out #endif if needed */
|
||||
if (*if_defined && in_define) {
|
||||
insert_line(winfo, end_defined, wh++);
|
||||
deltas[context_line]++;
|
||||
delta++;
|
||||
in_define = 0;
|
||||
}
|
||||
|
||||
/* Finish adding lines */
|
||||
wh = where;
|
||||
context_line = 0;
|
||||
for (i = hunk->file1_lines; i < hunk->line_count; i++) {
|
||||
line = hunk->lines[i];
|
||||
switch (*line) {
|
||||
case L' ': /* Context line */
|
||||
wh += deltas[context_line++];
|
||||
if (*if_defined && in_define == L'+') {
|
||||
/* Put out #endif */
|
||||
insert_line(winfo, end_defined, wh++);
|
||||
delta++;
|
||||
in_define = 0;
|
||||
}
|
||||
wh++;
|
||||
break;
|
||||
|
||||
case L'+': /* Add line */
|
||||
if (*if_defined) {
|
||||
/* Put out #ifdef if needed */
|
||||
if (!in_define) {
|
||||
in_define = *line;
|
||||
insert_line(winfo, if_defined, wh++);
|
||||
delta++;
|
||||
}
|
||||
}
|
||||
insert_line(winfo, line + 2, wh++);
|
||||
delta++;
|
||||
break;
|
||||
|
||||
case L'!': /* Change line */
|
||||
if (*if_defined) {
|
||||
/* Put out #ifdef if needed */
|
||||
if (!in_define) {
|
||||
in_define = *line;
|
||||
insert_line(winfo, if_defined, wh++);
|
||||
delta++;
|
||||
}
|
||||
}
|
||||
insert_line(winfo, line + 2, wh++);
|
||||
delta++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* Put out final #endif if needed */
|
||||
if (*if_defined && in_define == L'+') {
|
||||
insert_line(winfo, end_defined, wh++);
|
||||
delta++;
|
||||
}
|
||||
in_define = 0;
|
||||
|
||||
/* Free up our temp space */
|
||||
free(deltas);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Function: void cleanup(void)
|
||||
*
|
||||
* Description:
|
||||
*
|
||||
* Called on exit. Writes out any files that have not already
|
||||
* been written to disk.
|
||||
*
|
||||
* Inputs:
|
||||
* info -> A pointer to the file descriptor.
|
||||
* data -> A pointer to the wide character string to add.
|
||||
*/
|
||||
|
||||
void
|
||||
cleanup(void)
|
||||
{
|
||||
unsigned long i;
|
||||
|
||||
if (dont_sync == FALSE) {
|
||||
for (i = 0; i < opened_file_descriptors; i++) {
|
||||
file_info *info;
|
||||
|
||||
if (opened_files[i]->flags & UPDATE_ON_EXIT) {
|
||||
(void) open_file(opened_files[i]->name, 0);
|
||||
sync_file(opened_files[i], NULL);
|
||||
close_file(opened_files[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
for (i = 0; i < opened_file_descriptors; i++) {
|
||||
unlink(opened_files[i]->temp_file);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Function: void ask_for_name(void)
|
||||
*
|
||||
* Description:
|
||||
*
|
||||
* Ask for a file to patch since none could be intuited.
|
||||
*
|
||||
* Returns:
|
||||
*
|
||||
* Name of a file that exists.
|
||||
*/
|
||||
|
||||
static char *
|
||||
ask_for_name(void)
|
||||
{
|
||||
struct stat statbuf;
|
||||
char *name = NULL;
|
||||
|
||||
while (name == NULL) {
|
||||
ask(gettext("File to patch: "));
|
||||
if (*buf != '\n') {
|
||||
(void) mbstowcs(wbuf, buf, max_input);
|
||||
/* Process potential file name */
|
||||
name = fetchname(wbuf, 0, FALSE);
|
||||
}
|
||||
if (name == NULL || lstat(name, &statbuf) == -1) {
|
||||
ask(gettext("No file found -- skip this patch? [%s] "),
|
||||
nl_langinfo(NOSTR));
|
||||
if (rpmatch(buf) != 1) { /* not yes */
|
||||
continue;
|
||||
}
|
||||
if (verbose)
|
||||
say(gettext("Skipping patch...\n"));
|
||||
|
||||
skip_rest_of_patch = TRUE;
|
||||
return (NULL);
|
||||
}
|
||||
}
|
||||
return (savestr(name));
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Function: void main(int, char **)
|
||||
*
|
||||
* Description:
|
||||
*
|
||||
* Process arguments and apply a set of diffs as appropriate.
|
||||
*/
|
||||
|
||||
|
||||
void
|
||||
main(int argc, char **argv)
|
||||
{
|
||||
int winfo, pinfo, reject_info;
|
||||
hunk_info *hunk;
|
||||
LINENUM where;
|
||||
struct stat statbuf;
|
||||
char *workname, *reject_name;
|
||||
int hunk_count;
|
||||
int failed = 0;
|
||||
int failtotal = 0;
|
||||
|
||||
/* Set locale environment variables local definitions */
|
||||
(void) setlocale(LC_ALL, "");
|
||||
#if !defined(TEXT_DOMAIN) /* Should be defined by cc -D */
|
||||
#define TEXT_DOMAIN "SYS_TEST" /* Use this only if it wasn't */
|
||||
#endif
|
||||
(void) textdomain(TEXT_DOMAIN);
|
||||
|
||||
/*
|
||||
* setup common buffers
|
||||
*/
|
||||
max_input = MAX_INPUT;
|
||||
buf = allocate((max_input + 1) * sizeof (char));
|
||||
wbuf = allocate((max_input + 1) * sizeof (wchar_t));
|
||||
|
||||
/* parse switches */
|
||||
process_arguments(argc, argv);
|
||||
|
||||
/* make sure we clean up /tmp and sync files in case of disaster */
|
||||
set_signals();
|
||||
(void) atexit(cleanup);
|
||||
|
||||
/* For each patch in file open file, apply patch */
|
||||
for (pinfo = open_patch_file(patch_file);
|
||||
there_is_another_patch(opened_files[pinfo], &workname);
|
||||
reinitialize()) {
|
||||
if (!skip_rest_of_patch) {
|
||||
if (input_file == NULL) {
|
||||
/*
|
||||
* No file was specified on command line so we
|
||||
* take the file name from patch file (if_any)
|
||||
*/
|
||||
if (workname == NULL) {
|
||||
/* No file name in patch file either! */
|
||||
input_file = ask_for_name();
|
||||
if (input_file == NULL)
|
||||
continue;
|
||||
workname = input_file;
|
||||
}
|
||||
} else {
|
||||
/*
|
||||
* file name was specified on command line or
|
||||
* user was prompted for it so the name never
|
||||
* changes
|
||||
*/
|
||||
workname = input_file;
|
||||
}
|
||||
winfo = open_file(workname, 0);
|
||||
opened_files[winfo]->flags |= UPDATE_ON_EXIT;
|
||||
if (saveorig && (output_file == 0))
|
||||
opened_files[winfo]->flags |= SAVE_ORIGINAL;
|
||||
}
|
||||
|
||||
/* for ed script just up and do it and exit */
|
||||
if (diff_type == ED_DIFF) {
|
||||
if (!skip_rest_of_patch)
|
||||
do_ed_script(opened_files[winfo],
|
||||
opened_files[pinfo]);
|
||||
goto next;
|
||||
}
|
||||
|
||||
/* Open up reject file */
|
||||
if (reject_file != NULL) {
|
||||
reject_name = reject_file;
|
||||
} else {
|
||||
(void) sprintf(buf, "%s.rej", workname);
|
||||
reject_name = savestr(buf);
|
||||
}
|
||||
|
||||
/* get an empty file */
|
||||
reject_info = open_file(reject_name, 1);
|
||||
|
||||
/* apply each hunk of patch to file */
|
||||
failed = hunk_count = 0;
|
||||
while ((hunk = another_hunk(opened_files[pinfo])) != NULL) {
|
||||
hunk_count++;
|
||||
where = check_hunk_location(opened_files[winfo], hunk, hunk_count);
|
||||
if (skip_rest_of_patch) {
|
||||
abort_hunk(hunk, opened_files[reject_info]);
|
||||
failed++;
|
||||
if (verbose) {
|
||||
say(gettext("Hunk #%d ignored at "
|
||||
"line %ld.\n"), hunk_count, where);
|
||||
}
|
||||
} else if (where == (LINENUM) -1) {
|
||||
abort_hunk(hunk, opened_files[reject_info]);
|
||||
failed++;
|
||||
if (verbose) {
|
||||
say(gettext("Hunk #%d failed at "
|
||||
"line %ld.\n"), hunk_count,
|
||||
hunk->file1_start);
|
||||
}
|
||||
} else {
|
||||
apply_hunk(opened_files[winfo], hunk, where);
|
||||
if (verbose) {
|
||||
if (last_offset == 1L) {
|
||||
say(gettext("Hunk #%d succeeded"
|
||||
" at line %ld (offset 1"
|
||||
" line)\n"), hunk_count,
|
||||
where - delta);
|
||||
} else if (last_offset > 1L) {
|
||||
say(gettext("Hunk #%d succeeded"
|
||||
" at %ld (offset %ld lines)"
|
||||
"\n"), hunk_count,
|
||||
where - delta,
|
||||
last_offset);
|
||||
}
|
||||
}
|
||||
}
|
||||
free_hunk(hunk);
|
||||
}
|
||||
|
||||
/* and put the output where desired */
|
||||
ignore_signals();
|
||||
|
||||
/* If patch failed write out stats */
|
||||
if (failed) {
|
||||
opened_files[reject_info]->flags |= UPDATE_ON_EXIT;
|
||||
failtotal = FAIL_EXIT_VALUE;
|
||||
if (skip_rest_of_patch) {
|
||||
say(gettext("%d out of %d hunks "
|
||||
"ignored: saving rejects to %s\n"),
|
||||
failed, hunk_count, reject_name);
|
||||
} else {
|
||||
say(gettext("%d out of %d hunks "
|
||||
"failed: saving rejects to %s\n"),
|
||||
failed, hunk_count, reject_name);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* If an output has been specified then all output goes to
|
||||
* that file and the original files are not touched. We also
|
||||
* Flush out the intermediate results after each patch in this
|
||||
* case since the spec says so...
|
||||
*/
|
||||
close_file(opened_files[reject_info]);
|
||||
next: if (output_file) {
|
||||
/*
|
||||
* We also need to create a .orig file if asked to
|
||||
* and file exists already...
|
||||
*/
|
||||
if (saveorig && (strcmp(output_file, "-") != 0)) {
|
||||
saveorig = 0;
|
||||
if (lstat(output_file, &statbuf) != -1) {
|
||||
(void) sprintf(buf, "%s.orig",
|
||||
output_file);
|
||||
(void) rename(output_file, buf);
|
||||
}
|
||||
}
|
||||
opened_files[winfo]->flags &= ~UPDATE_ON_EXIT;
|
||||
sync_file(opened_files[winfo], output_file);
|
||||
}
|
||||
close_file(opened_files[winfo]);
|
||||
}
|
||||
if (reject_written)
|
||||
exit(REJECT_EXIT_VALUE);
|
||||
exit(failtotal);
|
||||
}
|
||||
Reference in New Issue
Block a user