1587 lines
33 KiB
C
Executable File
1587 lines
33 KiB
C
Executable File
#ident "@(#)pch.c 1.3 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: pch.c
|
|
* Date: Sun Feb 12 18:48:18 PST 1995
|
|
*
|
|
* Description:
|
|
*
|
|
* Routines for processing patch files.
|
|
*
|
|
* Modifications:
|
|
* $Log$
|
|
*/
|
|
|
|
/*
|
|
* Include files:
|
|
*/
|
|
#include "common.h"
|
|
|
|
/* Patch (diff listing) abstract type. */
|
|
|
|
|
|
static char *inputfile = NULL;
|
|
static char *reversefile = NULL;
|
|
|
|
static LINENUM p_input_line = 0; /* current line # from patch file */
|
|
static LINENUM p_base = 0; /* where to intuit this time */
|
|
|
|
|
|
|
|
/*
|
|
* Function: int open_patch_file(char *)
|
|
*
|
|
* Description:
|
|
*
|
|
* Open the patch file at the beginning of time, load into our file
|
|
* handling scheme and strip out common indentation right up front.
|
|
*
|
|
* Inputs:
|
|
* filename -> A pointer to the file name.
|
|
* We accept a NULL pointer or the name "-"
|
|
* to mean stdin.
|
|
*
|
|
* Returns:
|
|
* Pointer to patch file info.
|
|
*/
|
|
|
|
int
|
|
open_patch_file(char *filename)
|
|
{
|
|
wchar_t *ret, *sp;
|
|
int info, i, indent;
|
|
|
|
if (filename == NULL || !*filename ||
|
|
(strcmp(filename, "-") == 0)) {
|
|
/* Use stdin */
|
|
info = open_file("", 0);
|
|
} else {
|
|
/* Use given filename */
|
|
info = open_file(filename, 0);
|
|
}
|
|
|
|
/* scan for common indentation characters */
|
|
indent = INT_MAX;
|
|
for (i = 0; indent > 0 && i < opened_files[info]->line_count; i++) {
|
|
ret = fetch_line(opened_files[info], i);
|
|
if (i == 0) {
|
|
/* Find initial spaces */
|
|
for (sp = ret; iswspace(*sp); sp++)
|
|
;
|
|
|
|
/*
|
|
* Copy into our holding area for
|
|
* later comparison
|
|
*/
|
|
indent = sp - ret;
|
|
if (indent) {
|
|
wcsncpy(wbuf, ret, indent);
|
|
wbuf[indent] = 0;
|
|
}
|
|
} else {
|
|
/*
|
|
* Start searching for the maximum
|
|
* initial sequences of spaces
|
|
* common amoung all lines
|
|
*
|
|
* When indent is 0 then there
|
|
* is no common sequence.
|
|
*/
|
|
for (; indent > 0; indent--) {
|
|
if (wcswcs(ret, wbuf) == ret)
|
|
break;
|
|
wbuf[indent] = 0;
|
|
}
|
|
}
|
|
}
|
|
|
|
/*
|
|
* If there is an identifiable indent then
|
|
* go ahead and strip the leading characters
|
|
* from the patch lines.
|
|
*/
|
|
if (indent) {
|
|
for (i = 0; i < opened_files[info]->line_count; i++) {
|
|
opened_files[info]->lines[i].offset +=
|
|
indent * sizeof (wchar_t);
|
|
opened_files[info]->lines[i].length -=
|
|
indent * sizeof (wchar_t);
|
|
}
|
|
if (verbose && indent == 1)
|
|
say(gettext("(Patch is indented 1 space.)\n"));
|
|
else if (verbose)
|
|
say(gettext("(Patch is indented %d spaces.)\n"),
|
|
indent);
|
|
}
|
|
return (info);
|
|
}
|
|
|
|
|
|
/*
|
|
* Function: int intuit_diff_type(file_info *)
|
|
*
|
|
* Description:
|
|
*
|
|
* Determine what kind of diff is in the remaining part of the patch file.
|
|
*
|
|
* Inputs:
|
|
* pinfo -> A pointer to the patch file info.
|
|
*/
|
|
|
|
static int
|
|
intuit_diff_type(file_info *pinfo)
|
|
{
|
|
long fcl_line;
|
|
bool stars_last_line = FALSE;
|
|
int retval;
|
|
wchar_t *s, *t;
|
|
char *index_file = NULL;
|
|
char *star_file = NULL;
|
|
char *minus_file = NULL;
|
|
|
|
fcl_line = -1;
|
|
retval = NULL;
|
|
for (p_input_line = p_base; ; p_input_line++) {
|
|
if ((s = fetch_line(pinfo, p_input_line)) == NULL) {
|
|
retval = 0;
|
|
goto scan_exit;
|
|
}
|
|
|
|
for (t = s; iswdigit(*t) || *t == L','; t++)
|
|
;
|
|
|
|
/*
|
|
* Possible normal diff or ed command
|
|
*/
|
|
if (fcl_line < 0L && (iswdigit(*s) &&
|
|
(*t == L'd' || *t == L'c' || *t == L'a'))) {
|
|
fcl_line = p_input_line;
|
|
if (*(t + 1) == L'\n')
|
|
retval = ED_DIFF;
|
|
else
|
|
retval = NORMAL_DIFF;
|
|
goto scan_exit;
|
|
}
|
|
if (fcl_line < 0L && (iswdigit(*s) &&
|
|
(*t == L'i' || *t == L's'))) {
|
|
retval = ED_DIFF;
|
|
goto scan_exit;
|
|
}
|
|
|
|
/* Context diff has stars */
|
|
if (!stars_last_line && !wcsncmp(s, L"*** ", 4)) {
|
|
/* Get input file name */
|
|
for (s += 4; *s && iswspace(*s); s++)
|
|
;
|
|
for (t = s; *t && !iswspace(*t); t++)
|
|
;
|
|
wcsncpy(wbuf, s, t - s);
|
|
wbuf[t - s] = 0;
|
|
star_file = fetchname(wbuf, strippath, 0);
|
|
} else if (!wcsncmp(s, L"--- ", 4)) {
|
|
/* Get reverse file name */
|
|
for (s += 4; *s && iswspace(*s); s++)
|
|
;
|
|
for (t = s; *t && !iswspace(*t); t++)
|
|
;
|
|
wcsncpy(wbuf, s, t - s);
|
|
wbuf[t - s] = 0;
|
|
minus_file = fetchname(wbuf, strippath, 0);
|
|
} else if (!wcsncmp(s, L"+++ ", 4)) {
|
|
/* Get reverse file name */
|
|
for (s += 4; *s && iswspace(*s); s++)
|
|
;
|
|
for (t = s; *t && !iswspace(*t); t++)
|
|
;
|
|
wcsncpy(wbuf, s, t - s);
|
|
wbuf[t - s] = 0;
|
|
star_file = minus_file;
|
|
minus_file = fetchname(wbuf, strippath, 0);
|
|
fcl_line = p_input_line+1;
|
|
retval = UNIFIED_DIFF;
|
|
goto scan_exit;
|
|
} else if (!wcsncmp(s, L"Index:", 6)) {
|
|
/* Get input file name */
|
|
for (s += 6; *s && iswspace(*s); s++)
|
|
;
|
|
for (t = s; *t && !iswspace(*t); t++)
|
|
;
|
|
wcsncpy(wbuf, s, t - s);
|
|
wbuf[t - s] = 0;
|
|
index_file = fetchname(wbuf, strippath, 0);
|
|
} else if (stars_last_line && !wcsncmp(s, L"*** ", 4)) {
|
|
/*
|
|
* if this is a new context diff the character just
|
|
* before the newline is a '*'.
|
|
*/
|
|
while (*s != L'\n')
|
|
s++;
|
|
|
|
fcl_line = p_input_line;
|
|
if (*(s - 1) == L'*')
|
|
retval = NEW_CONTEXT_DIFF;
|
|
else
|
|
retval = CONTEXT_DIFF;
|
|
goto scan_exit;
|
|
}
|
|
stars_last_line = !wcsncmp(s, L"********", 8);
|
|
}
|
|
scan_exit:
|
|
if (star_file && minus_file)
|
|
inputfile = index_file;
|
|
else if (star_file)
|
|
inputfile = star_file;
|
|
else if (minus_file)
|
|
inputfile = minus_file;
|
|
else
|
|
inputfile = index_file;
|
|
|
|
p_base = fcl_line;
|
|
return (retval);
|
|
}
|
|
|
|
|
|
/* constructing messages is a no-no for i18n */
|
|
static struct {
|
|
int mesno;
|
|
const char *dflt;
|
|
} messages[] = {
|
|
{ 0, 0 }, { 0, 0 },
|
|
{ 1, " Looks like a context diff to me...\n" },
|
|
{ 2, " The next patch looks like a context diff.\n" },
|
|
{ 3, " Looks like a normal diff.\n" },
|
|
{ 4, " The next patch looks like a normal diff.\n" },
|
|
{ 5, " Looks like an ed script.\n" },
|
|
{ 6, " The next patch looks like an ed script.\n" },
|
|
{ 7, " Looks like a new-style context diff.\n" },
|
|
{ 8, " The next patch looks like a new-style context diff.\n" },
|
|
{ 9, " Looks like a unified context diff.\n" },
|
|
{ 10, " The next patch looks like a unified context diff.\n" },
|
|
{ 11, " Looks like a modified ed diff.\n" },
|
|
{ 12, " The next patch looks like a modified ed diff.\n" },
|
|
};
|
|
|
|
|
|
/*
|
|
* Function: void there_is_another_patch(file_info *, char **)
|
|
*
|
|
* Description:
|
|
*
|
|
* True if the remainder of the patch file contains a diff of some sort.
|
|
*
|
|
* Inputs:
|
|
* pinfo -> A pointer to the file info.
|
|
* data -> A address to return the file name to patch.
|
|
*
|
|
* Returns:
|
|
* True if there is another patch otherwise false.
|
|
* If true then the name of file to patch is plased in *name.
|
|
*/
|
|
|
|
|
|
bool
|
|
there_is_another_patch(file_info *pinfo, char **name)
|
|
{
|
|
int start = p_base;
|
|
|
|
/*
|
|
* start out not knowing what the file name is...
|
|
*/
|
|
|
|
if (inputfile) {
|
|
free(inputfile);
|
|
}
|
|
inputfile = NULL;
|
|
|
|
if (reversefile) {
|
|
free(reversefile);
|
|
}
|
|
reversefile = NULL;
|
|
|
|
if (p_base != 0L && p_base >= pinfo->line_count) {
|
|
if (verbose)
|
|
say(gettext("done\n"));
|
|
return (NULL);
|
|
}
|
|
|
|
/* The -c, -e and -n overrule any kind of diff listing */
|
|
if (!cdiff_type) {
|
|
diff_type = intuit_diff_type(pinfo);
|
|
if (!diff_type) {
|
|
if (p_base > 0L) {
|
|
if (verbose)
|
|
say(gettext(" Ignoring the "
|
|
"trailing garbage.\ndone\n"));
|
|
} else {
|
|
say(gettext(" I can't seem to find a "
|
|
"patch in there anywhere.\n"));
|
|
}
|
|
return (FALSE);
|
|
}
|
|
} else {
|
|
diff_type = cdiff_type;
|
|
if (diff_type == CONTEXT_DIFF) {
|
|
int temp = intuit_diff_type(pinfo);
|
|
|
|
/* New context diffs are acceptable for -c flag */
|
|
if (temp == NEW_CONTEXT_DIFF)
|
|
diff_type = temp;
|
|
}
|
|
}
|
|
|
|
|
|
if (verbose)
|
|
say(gettext(
|
|
messages[diff_type*2 + (start != 0L)].dflt));
|
|
|
|
/* Reverse the patch now if requested */
|
|
if (reverse && reversefile && inputfile) {
|
|
char *temp;
|
|
|
|
temp = reversefile;
|
|
reversefile = inputfile;
|
|
inputfile = temp;
|
|
}
|
|
*name = inputfile;
|
|
|
|
return (diff_type ? TRUE : FALSE);
|
|
}
|
|
|
|
|
|
/*
|
|
* Function: void malformed(char *)
|
|
*
|
|
* Description:
|
|
*
|
|
* Print an error message about a malformed patch and exit.
|
|
*
|
|
* Inputs:
|
|
*
|
|
* reason -> Message indicating specific reason
|
|
*/
|
|
|
|
|
|
static void
|
|
malformed(LINENUM line, char *reason)
|
|
{
|
|
/* Print out generic malformed message */
|
|
say(gettext("Malformed patch at line %ld:\n"), line);
|
|
|
|
/* Now print out the specific reason and die */
|
|
fatal(gettext(reason));
|
|
/* NOTREACHED */
|
|
}
|
|
|
|
|
|
/*
|
|
* Function: hunk_info *add_to_hunk(hunk_info *, wchar_t *)
|
|
*
|
|
* Description:
|
|
*
|
|
* Append a patch line to the hunk file. Reallocate hunk if
|
|
* necessary.
|
|
*
|
|
* Inputs:
|
|
* hunk -> A pointer to the hunk.
|
|
* line -> A pointer to the wide character string to add.
|
|
*
|
|
* Returns:
|
|
*
|
|
* a new pointer to new hunk.
|
|
*/
|
|
|
|
static hunk_info *
|
|
add_to_hunk(hunk_info *hunk, wchar_t *line)
|
|
{
|
|
if (hunk->line_count >= hunk->max_lines) {
|
|
hunk->max_lines += LINE_REALLOC_INCR;
|
|
hunk = reallocate(hunk, sizeof (hunk_info) +
|
|
(sizeof (wchar_t *) * hunk->max_lines));
|
|
}
|
|
hunk->lines[hunk->line_count++] = wsavestr(line);
|
|
return (hunk);
|
|
}
|
|
|
|
|
|
/*
|
|
* Function: hunk_info another_context_hunk(file_info *)
|
|
*
|
|
* Description:
|
|
*
|
|
* Build a hunk from the patch file which has the expected form:
|
|
*
|
|
* *** filename1 <Last modification date/time>
|
|
* --- filename2 <Last modification date/time>
|
|
* ***************
|
|
* *** %d,%d
|
|
* %s ; Unaffected lines
|
|
* - %s ; deleted lines
|
|
* ! %s ; changed lines
|
|
*
|
|
* --- %d,%d
|
|
* %s ; Unaffected lines>
|
|
* + %s ; New lines
|
|
* - %s ; deleted lines
|
|
* ! %s ; changed lines
|
|
*
|
|
*
|
|
* Inputs:
|
|
* pinfo -> A pointer to the patch file info.
|
|
*
|
|
* Returns:
|
|
* address of hunk.
|
|
*/
|
|
|
|
static hunk_info *
|
|
another_context_hunk(file_info *pinfo)
|
|
{
|
|
int replace_count, in_replace;
|
|
LINENUM line;
|
|
wchar_t *s, *ret;
|
|
hunk_info *hunk;
|
|
wchar_t **file1_context, **file2_context;
|
|
|
|
p_input_line = p_base;
|
|
|
|
/* Allocate hunk head */
|
|
hunk = (hunk_info *) allocate(sizeof (hunk_info) +
|
|
(sizeof (wchar_t *) * LINE_REALLOC_INCR));
|
|
(void) memset(hunk, 0, sizeof (hunk_info));
|
|
hunk->max_lines = LINE_REALLOC_INCR;
|
|
replace_count = 0;
|
|
in_replace = 0;
|
|
do {
|
|
if ((ret = fetch_line(pinfo, p_input_line++)) == NULL) {
|
|
/* No start of pattern found */
|
|
return (NULL);
|
|
}
|
|
if (wcsncmp(ret, L"Index:", 6) == 0) {
|
|
p_base = p_input_line - 1;
|
|
return (NULL);
|
|
}
|
|
|
|
if ((wcsncmp(ret, L"*** ", 4) == 0) &&
|
|
(ret[wcslen(ret) - 2] == '*')) {
|
|
p_base = p_input_line - 1;
|
|
return (NULL);
|
|
}
|
|
} while (*ret != L'*');
|
|
|
|
/* Validate file2 *** %d,%d line */
|
|
if (wcsncmp(ret, L"*** ", 4) != 0) {
|
|
malformed(p_input_line, "Expected line beginning with '*** '");
|
|
/* NOTREACHED */
|
|
}
|
|
|
|
s = ret + 4;
|
|
while (!iswdigit(*s))
|
|
s++;
|
|
if (!iswdigit(*s)) {
|
|
malformed(p_input_line, "No pattern lines found in "
|
|
"'*** ' line.\n");
|
|
/* NOTREACHED */
|
|
}
|
|
|
|
hunk->file1_start = watol(s);
|
|
|
|
while (iswdigit(*s))
|
|
s++;
|
|
if (*s == ',') {
|
|
while (!iswdigit(*s))
|
|
s++;
|
|
|
|
if (!*s) {
|
|
malformed(p_input_line, "No digits were found "
|
|
"following ','.\n");
|
|
/* NOTREACHED */
|
|
}
|
|
hunk->file1_lines = watol(s) - hunk->file1_start + 1;
|
|
} else
|
|
hunk->file1_lines = 1;
|
|
|
|
/* Process lines above "--- %d,%d */
|
|
line = p_input_line;
|
|
for (;;) {
|
|
if ((ret = fetch_line(pinfo, p_input_line++)) == NULL) {
|
|
/* Early end of file */
|
|
malformed(p_input_line, "Premature end of file.\n");
|
|
/* NOTREACHED */
|
|
}
|
|
|
|
/* empty lines should be ignored */
|
|
if (*ret == L'\n')
|
|
continue;
|
|
|
|
/* Beginning of file 2 loop */
|
|
if (wcsncmp(ret, L"--- ", 4) == 0) {
|
|
break;
|
|
}
|
|
|
|
hunk = add_to_hunk(hunk, ret);
|
|
line++;
|
|
|
|
switch (*ret) {
|
|
case L'-':
|
|
/* FALLSTHROUGH */
|
|
|
|
case L' ':
|
|
in_replace = FALSE;
|
|
if (*(ret + 1) != L' ') {
|
|
malformed(p_input_line, "Second character "
|
|
"must be a ' ' character.\n");
|
|
/* NOTREACHED */
|
|
}
|
|
break;
|
|
|
|
case L'!':
|
|
if (!in_replace) {
|
|
in_replace = TRUE;
|
|
replace_count++;
|
|
}
|
|
if (*(ret + 1) != L' ') {
|
|
malformed(p_input_line, "Second character of "
|
|
"change line must be a ' ' character.\n");
|
|
/* NOTREACHED */
|
|
}
|
|
break;
|
|
|
|
case L'+':
|
|
malformed(p_input_line, "File1 lines cannot contain "
|
|
"inserted lines.\n");
|
|
/* NOTREACHED */
|
|
break;
|
|
|
|
case L'*':
|
|
if (wcsncmp(ret, L"********", 8) == 0) {
|
|
malformed(p_input_line, "New hunk detected "
|
|
"before file2 lines were found.\n");
|
|
/* NOTREACHED */
|
|
}
|
|
if (wcsncmp(ret, L"*** ", 4) == 0) {
|
|
malformed(p_input_line, "Unexpected *** found "
|
|
"in file1 lines.\n");
|
|
/* NOTREACHED */
|
|
}
|
|
/* FALLSTHROUGH */
|
|
|
|
default :
|
|
malformed(p_input_line, "File 1 lines must begin with "
|
|
"'- ', ' ', or '! '.\n");
|
|
break;
|
|
}
|
|
}
|
|
|
|
hunk->file1_lines = hunk->line_count;
|
|
|
|
/* Validate file2 --- %d,%d line */
|
|
s = ret + 4;
|
|
while (!iswdigit(*s))
|
|
s++;
|
|
if (!iswdigit(*s)) {
|
|
malformed(p_input_line, "No pattern lines found in "
|
|
"'*** ' line.\n");
|
|
/* NOTREACHED */
|
|
}
|
|
|
|
hunk->file2_start = watol(s);
|
|
|
|
while (iswdigit(*s))
|
|
s++;
|
|
if (*s == ',') {
|
|
while (!iswdigit(*s))
|
|
s++;
|
|
|
|
if (!*s) {
|
|
malformed(p_input_line, "No digits were found "
|
|
"following ','.\n");
|
|
/* NOTREACHED */
|
|
}
|
|
hunk->file2_lines = watol(s) - hunk->file2_start + 1;
|
|
} else
|
|
hunk->file2_lines = 1;
|
|
|
|
/* Process file2 lines */
|
|
in_replace = FALSE;
|
|
line = 0;
|
|
for (;;) {
|
|
/* end of file */
|
|
if ((ret = fetch_line(pinfo, p_input_line++)) == NULL) {
|
|
break;
|
|
}
|
|
|
|
/* empty lines should be ignored */
|
|
if (*ret == L'\n')
|
|
continue;
|
|
|
|
/* Beginning of next hunk */
|
|
if (wcsncmp(ret, L"********", 8) == 0) {
|
|
break;
|
|
}
|
|
if ((wcsncmp(ret, L"Index:", 6) == 0) ||
|
|
(wcsncmp(ret, L"*** ", 4) == 0)) {
|
|
p_base = p_input_line--;
|
|
break;
|
|
}
|
|
|
|
hunk = add_to_hunk(hunk, ret);
|
|
line++;
|
|
|
|
switch (*ret) {
|
|
case L' ':
|
|
/* FALLSTHROUGH */
|
|
case L'+':
|
|
in_replace = FALSE;
|
|
if (*(ret + 1) != L' ') {
|
|
malformed(p_input_line, "Second character "
|
|
"must be a ' ' character.\n");
|
|
/* NOTREACHED */
|
|
}
|
|
break;
|
|
|
|
case L'!':
|
|
if (!in_replace) {
|
|
in_replace = TRUE;
|
|
replace_count--;
|
|
}
|
|
if (*(ret + 1) != L' ') {
|
|
malformed(p_input_line, "Second character of "
|
|
"change line must be a ' ' character.\n");
|
|
/* NOTREACHED */
|
|
}
|
|
break;
|
|
|
|
default :
|
|
malformed(p_input_line, "Line must begin with '+ ', "
|
|
"' ', or '! '.\n");
|
|
break;
|
|
}
|
|
}
|
|
|
|
/*
|
|
* End of file or ***** was found either way we start here next time
|
|
*/
|
|
p_base = p_input_line;
|
|
|
|
if (replace_count) {
|
|
malformed(p_input_line, "Premature end of hunk (Unbalanced "
|
|
"change lines).\n");
|
|
/* NOTREACHED */
|
|
}
|
|
hunk->file2_lines = hunk->line_count - hunk->file1_lines;
|
|
|
|
/*
|
|
* The original diff goofed up on context lines.
|
|
* If a patch is close enough to the provious patch to include
|
|
* a previously changed line as context then the context line
|
|
* for file 1 does not reflect the changes. If this is not
|
|
* worked around then the hunk will fail since the context lines
|
|
* will not exist in our current file.
|
|
*/
|
|
file1_context = hunk->lines;
|
|
file2_context = hunk->lines + hunk->file1_lines;
|
|
for (line = 0; line < hunk->file1_lines; line++) {
|
|
if ((**file1_context != L' ') || (**file2_context != L' '))
|
|
break;
|
|
|
|
if (wcscmp(*file1_context, *file2_context) != 0) {
|
|
free(*file1_context);
|
|
*file1_context = wsavestr(*file2_context);
|
|
}
|
|
file1_context++;
|
|
file2_context++;
|
|
}
|
|
|
|
return (hunk);
|
|
}
|
|
|
|
|
|
/*
|
|
* Function: hunk_info another_new_context_hunk(file_info *)
|
|
*
|
|
* Description:
|
|
*
|
|
* Build a hunk from the patch file which has the expected form:
|
|
*
|
|
* *** filename1 <Last modification date/time>
|
|
* --- filename2 <Last modification date/time>
|
|
* ***************
|
|
* *** %d,%d ****
|
|
* %s ; Unaffected lines
|
|
* - %s ; deleted lines
|
|
* ! %s ; changed lines
|
|
* --- %d,%d ----
|
|
* %s ; Unaffected lines>
|
|
* + %s ; New lines
|
|
* - %s ; deleted lines
|
|
* ! %s ; changed lines
|
|
*
|
|
* Inputs:
|
|
* pinfo -> A pointer to the patch file info.
|
|
*
|
|
* Returns:
|
|
* address of hunk.
|
|
*/
|
|
|
|
static hunk_info *
|
|
another_new_context_hunk(file_info *pinfo)
|
|
{
|
|
int replace_count, in_replace;
|
|
LINENUM line;
|
|
wchar_t *s, *ret;
|
|
hunk_info *hunk;
|
|
|
|
p_input_line = p_base;
|
|
|
|
/* Allocate hunk head */
|
|
hunk = (hunk_info *) allocate(sizeof (hunk_info) +
|
|
(sizeof (wchar_t *) * LINE_REALLOC_INCR));
|
|
(void) memset(hunk, 0, sizeof (hunk_info));
|
|
hunk->max_lines = LINE_REALLOC_INCR;
|
|
replace_count = 0;
|
|
in_replace = 0;
|
|
do {
|
|
if ((ret = fetch_line(pinfo, p_input_line++)) == NULL) {
|
|
/* No start of pattern found */
|
|
return (NULL);
|
|
}
|
|
if (wcsncmp(ret, L"Index:", 6) == 0) {
|
|
p_base = p_input_line - 1;
|
|
return (NULL);
|
|
}
|
|
if ((wcsncmp(ret, L"*** ", 4) == 0) &&
|
|
(ret[wcslen(ret) - 2] != L'*')) {
|
|
p_base = p_input_line - 1;
|
|
return (NULL);
|
|
}
|
|
} while (*ret != L'*');
|
|
|
|
/* Validate file2 *** %d,%d *** line */
|
|
if (wcsncmp(ret, L"*** ", 4) != 0) {
|
|
malformed(p_input_line, "Expected line beginning with '*** '");
|
|
/* NOTREACHED */
|
|
}
|
|
|
|
s = ret + 4;
|
|
while (!iswdigit(*s))
|
|
s++;
|
|
if (!iswdigit(*s)) {
|
|
malformed(p_input_line, "No pattern lines found in "
|
|
"'*** ' line.\n");
|
|
/* NOTREACHED */
|
|
}
|
|
|
|
hunk->file1_start = watol(s);
|
|
|
|
while (iswdigit(*s))
|
|
s++;
|
|
if (*s == ',') {
|
|
while (!iswdigit(*s))
|
|
s++;
|
|
|
|
if (!*s) {
|
|
malformed(p_input_line, "No digits were found "
|
|
"following ','.\n");
|
|
/* NOTREACHED */
|
|
}
|
|
hunk->file1_lines = watol(s) - hunk->file1_start + 1;
|
|
} else
|
|
hunk->file1_lines = 1;
|
|
|
|
/* Process lines above "--- %d,%d ----" */
|
|
line = p_input_line;
|
|
for (;;) {
|
|
if ((ret = fetch_line(pinfo, p_input_line++)) == NULL) {
|
|
/* Early end of file */
|
|
malformed(p_input_line, "Premature end of file.\n");
|
|
/* NOTREACHED */
|
|
}
|
|
|
|
/* Beginning of file 2 loop */
|
|
if (wcsncmp(ret, L"--- ", 4) == 0) {
|
|
break;
|
|
}
|
|
|
|
hunk = add_to_hunk(hunk, ret);
|
|
line++;
|
|
|
|
switch (*ret) {
|
|
case L'-':
|
|
/* FALLSTHROUGH */
|
|
|
|
case L' ':
|
|
in_replace = FALSE;
|
|
if (*(ret + 1) != L' ') {
|
|
malformed(p_input_line, "Second character "
|
|
"must be a ' ' character.\n");
|
|
/* NOTREACHED */
|
|
}
|
|
break;
|
|
|
|
case L'!':
|
|
if (!in_replace) {
|
|
in_replace = TRUE;
|
|
replace_count++;
|
|
}
|
|
if (*(ret + 1) != L' ') {
|
|
malformed(p_input_line, "Second character of "
|
|
"change line must be a ' ' character.\n");
|
|
/* NOTREACHED */
|
|
}
|
|
break;
|
|
|
|
case L'+':
|
|
malformed(p_input_line, "File1 lines cannot contain "
|
|
"inserted lines.\n");
|
|
/* NOTREACHED */
|
|
break;
|
|
|
|
case L'*':
|
|
if (wcsncmp(ret, L"********", 8) == 0) {
|
|
malformed(p_input_line, "New hunk detected "
|
|
"before file2 lines were found.\n");
|
|
/* NOTREACHED */
|
|
}
|
|
if (wcsncmp(ret, L"*** ", 4) == 0) {
|
|
malformed(p_input_line, "Unexpected *** found "
|
|
"in file1 lines.\n");
|
|
/* NOTREACHED */
|
|
}
|
|
/* FALLSTHROUGH */
|
|
|
|
case L'\n':
|
|
break;
|
|
|
|
default :
|
|
malformed(p_input_line, "File 1 lines must begin with "
|
|
"'- ', ' ', or '! '.\n");
|
|
break;
|
|
}
|
|
}
|
|
|
|
hunk->file1_lines = hunk->line_count;
|
|
|
|
/* Validate file2 --- %d,%d --- line */
|
|
s = ret + 4;
|
|
while (!iswdigit(*s))
|
|
s++;
|
|
if (!iswdigit(*s)) {
|
|
malformed(p_input_line, "No pattern lines found in "
|
|
"'*** ' line.\n");
|
|
/* NOTREACHED */
|
|
}
|
|
|
|
hunk->file2_start = watol(s);
|
|
|
|
while (iswdigit(*s))
|
|
s++;
|
|
if (*s == ',') {
|
|
while (!iswdigit(*s))
|
|
s++;
|
|
|
|
if (!*s) {
|
|
malformed(p_input_line, "No digits were found "
|
|
"following ','.\n");
|
|
/* NOTREACHED */
|
|
}
|
|
hunk->file2_lines = watol(s) - hunk->file2_start + 1;
|
|
} else
|
|
hunk->file2_lines = 1;
|
|
|
|
|
|
/*
|
|
* 1st half of context diff is empty get
|
|
* context lines from second half
|
|
*/
|
|
if (hunk->line_count == 0) {
|
|
line = p_input_line;
|
|
for (;;) {
|
|
/* end of file */
|
|
if ((ret = fetch_line(pinfo, p_input_line++)) == NULL) {
|
|
break;
|
|
}
|
|
|
|
/* Beginning of next hunkp */
|
|
if (wcsncmp(ret, L"********", 8) == 0) {
|
|
break;
|
|
}
|
|
if (wcsncmp(ret, L"Index:", 6) == 0) {
|
|
p_base = p_input_line--;
|
|
break;
|
|
}
|
|
if (*ret == ' ') {
|
|
if (*(ret + 1) != L' ') {
|
|
malformed(p_input_line,
|
|
"Second character "
|
|
"must be a ' ' character.\n");
|
|
/* NOTREACHED */
|
|
}
|
|
hunk = add_to_hunk(hunk, ret);
|
|
}
|
|
}
|
|
p_input_line = line;
|
|
hunk->file1_lines = hunk->line_count;
|
|
}
|
|
|
|
/* Process file2 lines */
|
|
in_replace = FALSE;
|
|
line = 0;
|
|
for (;;) {
|
|
/* end of file */
|
|
if ((ret = fetch_line(pinfo, p_input_line++)) == NULL) {
|
|
break;
|
|
}
|
|
|
|
/* Beginning of next hunkp */
|
|
if (wcsncmp(ret, L"********", 8) == 0) {
|
|
break;
|
|
}
|
|
if ((wcsncmp(ret, L"Index:", 6) == 0) ||
|
|
(wcsncmp(ret, L"*** ", 4) == 0)) {
|
|
p_base = p_input_line--;
|
|
break;
|
|
}
|
|
|
|
hunk = add_to_hunk(hunk, ret);
|
|
line++;
|
|
|
|
switch (*ret) {
|
|
case L' ':
|
|
/* FALLSTHROUGH */
|
|
case L'+':
|
|
in_replace = FALSE;
|
|
if (*(ret + 1) != L' ') {
|
|
malformed(p_input_line, "Second character "
|
|
"must be a ' ' character.\n");
|
|
/* NOTREACHED */
|
|
}
|
|
break;
|
|
|
|
case L'!':
|
|
if (!in_replace) {
|
|
in_replace = TRUE;
|
|
replace_count--;
|
|
}
|
|
if (*(ret + 1) != L' ') {
|
|
malformed(p_input_line, "Second character of "
|
|
"change line must be a ' ' character.\n");
|
|
/* NOTREACHED */
|
|
}
|
|
break;
|
|
|
|
default :
|
|
malformed(p_input_line, "Line must begin with '+ ', "
|
|
"' ', or '! '.\n");
|
|
break;
|
|
}
|
|
}
|
|
|
|
/*
|
|
* End of file or ***** was found either way we start here next time
|
|
*/
|
|
p_base = p_input_line;
|
|
|
|
if (replace_count) {
|
|
malformed(p_input_line, "Premature end of hunk (Unbalanced "
|
|
"change lines).\n");
|
|
/* NOTREACHED */
|
|
}
|
|
if (line == 0) {
|
|
for (line = 0; line < hunk->file1_lines; line++) {
|
|
if (*(hunk->lines[line]) == L' ') {
|
|
hunk = add_to_hunk(hunk, hunk->lines[line]);
|
|
}
|
|
}
|
|
}
|
|
hunk->file2_lines = hunk->line_count - hunk->file1_lines;
|
|
return (hunk);
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
* Function: hunk_info another_normal_hunk(file_info *)
|
|
*
|
|
* Description:
|
|
*
|
|
* Compile a hunk from the patch file which has the expected form:
|
|
*
|
|
* Normal diffs have the form:
|
|
*
|
|
* %da%d\n
|
|
* %da%d,%d\n
|
|
* %dd%d\n
|
|
* %d,%dd%d\n
|
|
* %dc%d\n
|
|
* %d,%dc%d\n
|
|
* %dc%d,%d\n
|
|
* %d,%dc%d,%d\n
|
|
*
|
|
* Each command is followed by all the lines affected in file1 and file 2:
|
|
*
|
|
* < %s (file 1 lines)
|
|
* ---\n (seperator for change)
|
|
* > %s (file 2 lines)
|
|
*
|
|
* Inputs:
|
|
* pinfo -> A pointer to the patch file info.
|
|
*
|
|
* Returns:
|
|
* address of hunk.
|
|
*/
|
|
|
|
static hunk_info *
|
|
another_normal_diff_hunk(file_info *pinfo)
|
|
{
|
|
hunk_info *hunk;
|
|
wchar_t *ret, *s, hunk_type;
|
|
int i;
|
|
|
|
/* Allocate hunk head */
|
|
hunk = (hunk_info *)allocate(sizeof (hunk_info) +
|
|
(sizeof (wchar_t *) * LINE_REALLOC_INCR));
|
|
(void) memset(hunk, 0, sizeof (hunk_info));
|
|
hunk->max_lines = LINE_REALLOC_INCR;
|
|
|
|
/* Search for start of hunk */
|
|
do {
|
|
if ((ret = fetch_line(pinfo, p_input_line++)) == NULL) {
|
|
return (NULL);
|
|
}
|
|
if (wcsncmp(ret, L"Index:", 6) == 0) {
|
|
p_base = p_input_line - 1;
|
|
return (NULL);
|
|
}
|
|
} while (!iswdigit(*ret));
|
|
|
|
/* Now process hunk */
|
|
hunk->file1_start = (LINENUM)watol(ret);
|
|
for (s = ret; iswdigit(*s); s++)
|
|
;
|
|
|
|
if (*s == ',') {
|
|
hunk->file1_lines = watol(++s) - hunk->file1_start + 1;
|
|
while (iswdigit(*s))
|
|
s++;
|
|
} else {
|
|
hunk->file1_lines = 1;
|
|
}
|
|
|
|
hunk_type = *s;
|
|
|
|
hunk->file2_start = (LINENUM)watol(++s);
|
|
|
|
while (iswdigit(*s))
|
|
s++;
|
|
|
|
if (*s == L',')
|
|
hunk->file2_lines = (LINENUM)watol(++s) - hunk->file2_start + 1;
|
|
else
|
|
hunk->file2_lines = 1;
|
|
|
|
switch (hunk_type) {
|
|
case L'a' : /* Add lines */
|
|
/* Compile all lines starting with < */
|
|
for (i = 0; i < hunk->file2_lines; i++) {
|
|
if ((ret = fetch_line(pinfo, p_input_line++)) == NULL) {
|
|
malformed(p_input_line, "Unexpected end of "
|
|
"file.\n");
|
|
}
|
|
if (*ret != '>') {
|
|
malformed(p_input_line, "'> ' expected at "
|
|
"start of line.\n");
|
|
}
|
|
(void) sprintf(buf, "+ %S", ret + 2);
|
|
(void) mbstowcs(wbuf, buf, max_input);
|
|
hunk = add_to_hunk(hunk, wbuf);
|
|
}
|
|
hunk->file1_start++;
|
|
hunk->file1_lines = 0;
|
|
break;
|
|
|
|
case L'd' : /* Delete lines */
|
|
/* Compile all lines starting with < */
|
|
for (i = 0; i < hunk->file1_lines; i++) {
|
|
if ((ret = fetch_line(pinfo, p_input_line++)) == NULL) {
|
|
malformed(p_input_line, "Unexpected end of "
|
|
"file.\n");
|
|
}
|
|
if (*ret != '<') {
|
|
malformed(p_input_line, "'< ' expected at "
|
|
"start of line.\n");
|
|
}
|
|
(void) sprintf(buf, "- %S", ret + 2);
|
|
(void) mbstowcs(wbuf, buf, max_input);
|
|
hunk = add_to_hunk(hunk, wbuf);
|
|
}
|
|
hunk->file2_start++;
|
|
hunk->file2_lines = 0;
|
|
break;
|
|
|
|
case L'c' : /* Change lines */
|
|
/* Compile all lines starting with < */
|
|
for (i = 0; i < hunk->file1_lines; i++) {
|
|
if ((ret = fetch_line(pinfo, p_input_line++)) == NULL) {
|
|
malformed(p_input_line, "Unexpected end of "
|
|
"file.\n");
|
|
}
|
|
if (*ret != '<') {
|
|
malformed(p_input_line, "'< ' expected at "
|
|
"start of line.\n");
|
|
}
|
|
(void) sprintf(buf, "! %S", ret + 2);
|
|
(void) mbstowcs(wbuf, buf, max_input);
|
|
hunk = add_to_hunk(hunk, wbuf);
|
|
}
|
|
|
|
/* Make sure next line is a --- line */
|
|
if ((ret = fetch_line(pinfo, p_input_line++)) == NULL) {
|
|
malformed(p_input_line, "Unexpected end of file.\n");
|
|
/* NOTREACHED */
|
|
}
|
|
if (wcscmp(ret, L"---\n") != NULL) {
|
|
malformed(p_input_line, "'---\\n' expected.\n");
|
|
/* NOTREACHED */
|
|
}
|
|
|
|
/* Compile all lines starting with < */
|
|
for (i = 0; i < hunk->file2_lines; i++) {
|
|
if ((ret = fetch_line(pinfo, p_input_line++)) == NULL) {
|
|
malformed(p_input_line, "Unexpected end of "
|
|
"file.\n");
|
|
}
|
|
if (*ret != '>') {
|
|
malformed(p_input_line, "'>' expected at start "
|
|
"of line.\n");
|
|
}
|
|
(void) sprintf(buf, "! %S", ret + 2);
|
|
(void) mbstowcs(wbuf, buf, max_input);
|
|
hunk = add_to_hunk(hunk, wbuf);
|
|
}
|
|
break;
|
|
|
|
default :
|
|
malformed(p_input_line, "Unknown diff operator");
|
|
/* NOTREACHED */
|
|
}
|
|
/*
|
|
* End of file or ***** was found either way we start here next time
|
|
*/
|
|
p_base = p_input_line;
|
|
|
|
return (hunk);
|
|
}
|
|
|
|
|
|
/*
|
|
* Function: hunk_info another_unified_hunk(file_info *)
|
|
*
|
|
* Description:
|
|
*
|
|
* Build a hunk from the patch file which has the expected form:
|
|
*
|
|
* --- filename1 <Last modification date/time>
|
|
* +++ filename2 <Last modification date/time>
|
|
* @@ %d,%d %d,%d @@
|
|
* %s ; Unaffected lines
|
|
* -%s ; deleted lines
|
|
* +%s ; changed lines
|
|
*
|
|
* Inputs:
|
|
* pinfo -> A pointer to the patch file info.
|
|
*
|
|
* Returns:
|
|
* address of hunk.
|
|
*/
|
|
|
|
static hunk_info *
|
|
another_unified_hunk(file_info *pinfo)
|
|
{
|
|
LINENUM line;
|
|
wchar_t *s, *ret;
|
|
hunk_info *hunk;
|
|
|
|
p_input_line = p_base;
|
|
|
|
/* Allocate hunk head */
|
|
hunk = (hunk_info *) allocate(sizeof (hunk_info) +
|
|
(sizeof (wchar_t *) * LINE_REALLOC_INCR));
|
|
(void) memset(hunk, 0, sizeof (hunk_info));
|
|
hunk->max_lines = LINE_REALLOC_INCR;
|
|
|
|
do {
|
|
if ((ret = fetch_line(pinfo, p_input_line++)) == NULL) {
|
|
/* No start of pattern found */
|
|
return (NULL);
|
|
}
|
|
if (wcsncmp(ret, L"Index:", 6) == 0) {
|
|
p_base = p_input_line - 1;
|
|
return (NULL);
|
|
}
|
|
if (wcsncmp(ret, L"@@ ", 3) == 0 &&
|
|
*(ret + wcslen(ret) - 2) != L'@') {
|
|
p_base = p_input_line - 1;
|
|
return (NULL);
|
|
}
|
|
} while (*ret != L'@');
|
|
|
|
/* Validate file2 "@@ %d,%d %d,%d @@" line */
|
|
if (wcsncmp(ret, L"@@ ", 3) != 0) {
|
|
malformed(p_input_line, "Expected line beginning with '@@ '");
|
|
/* NOTREACHED */
|
|
}
|
|
|
|
s = ret + 3;
|
|
while (!iswdigit(*s))
|
|
s++;
|
|
if (!iswdigit(*s)) {
|
|
malformed(p_input_line, "No pattern lines found in "
|
|
"'@@ ' line.\n");
|
|
/* NOTREACHED */
|
|
}
|
|
|
|
hunk->file1_start = watol(s);
|
|
|
|
while (iswdigit(*s))
|
|
s++;
|
|
if (*s == ',') {
|
|
s++;
|
|
if (!iswdigit(*s)) {
|
|
malformed(p_input_line, "No digits were found "
|
|
"following ','.\n");
|
|
/* NOTREACHED */
|
|
}
|
|
hunk->file1_lines = watol(s) - hunk->file1_start + 1;
|
|
while (iswdigit(*s))
|
|
s++;
|
|
} else
|
|
hunk->file1_lines = 1;
|
|
|
|
while (!iswdigit(*s))
|
|
s++;
|
|
if (!iswdigit(*s)) {
|
|
malformed(p_input_line, "No pattern lines found in "
|
|
"to file range line.\n");
|
|
/* NOTREACHED */
|
|
}
|
|
|
|
hunk->file2_start = watol(s);
|
|
|
|
while (iswdigit(*s))
|
|
s++;
|
|
if (*s == ',') {
|
|
while (!iswdigit(*s))
|
|
s++;
|
|
|
|
if (!*s) {
|
|
malformed(p_input_line, "No digits were found "
|
|
"following ','.\n");
|
|
/* NOTREACHED */
|
|
}
|
|
hunk->file2_lines = watol(s) - hunk->file1_start + 1;
|
|
while (iswdigit(*s))
|
|
s++;
|
|
} else
|
|
hunk->file2_lines = 1;
|
|
|
|
|
|
/* Process lines in two passes */
|
|
line = p_input_line;
|
|
for (;;) {
|
|
if ((ret = fetch_line(pinfo, p_input_line++)) == NULL)
|
|
break;
|
|
|
|
if (*ret == L'+')
|
|
continue;
|
|
|
|
if (*ret == L'-' || *ret == L' ') {
|
|
wbuf[0] = *ret;
|
|
wbuf[1] = L' ';
|
|
(void) wcsncpy(&wbuf[2], ret+1, max_input-3);
|
|
wbuf[max_input-1] = L'\0';
|
|
hunk = add_to_hunk(hunk, wbuf);
|
|
continue;
|
|
}
|
|
break;
|
|
}
|
|
hunk->file1_lines = hunk->line_count;
|
|
p_input_line = line;
|
|
|
|
for (;;) {
|
|
if ((ret = fetch_line(pinfo, p_input_line++)) == NULL)
|
|
break;
|
|
|
|
if (*ret == L'-')
|
|
continue;
|
|
|
|
if (*ret == L'+' || *ret == L' ') {
|
|
wbuf[0] = *ret;
|
|
wbuf[1] = L' ';
|
|
(void) wcsncpy(&wbuf[2], ret+1, max_input-3);
|
|
wbuf[max_input-1] = L'\0';
|
|
hunk = add_to_hunk(hunk, wbuf);
|
|
continue;
|
|
}
|
|
break;
|
|
}
|
|
hunk->file2_lines = hunk->line_count - hunk->file1_lines;
|
|
|
|
/*
|
|
* End of file or @@ was found either way we start here next time
|
|
*/
|
|
p_base = p_input_line - 1;
|
|
|
|
return (hunk);
|
|
}
|
|
|
|
|
|
/*
|
|
* Function: void free_hunk(hunk_info *)
|
|
*
|
|
* Description:
|
|
*
|
|
* Free all memory allocated for hunk.
|
|
*
|
|
* Inputs:
|
|
* hunk -> address of hunk to free.
|
|
*/
|
|
|
|
void
|
|
free_hunk(hunk_info *hunk)
|
|
{
|
|
LINENUM i;
|
|
|
|
for (i = hunk->line_count-1; i >= 0; i--) {
|
|
free((void *)hunk->lines[i]);
|
|
}
|
|
free((void *)hunk);
|
|
}
|
|
|
|
|
|
/*
|
|
* Function: void pch_swap(hunk_info *)
|
|
*
|
|
* Description:
|
|
*
|
|
* Reverse the old and new portions of the current hunk in place.
|
|
*
|
|
* Inputs:
|
|
* hunk -> A pointer to the hunk to swap.
|
|
*
|
|
* Returns:
|
|
* nothing
|
|
*/
|
|
|
|
void
|
|
pch_swap(hunk_info *hunk)
|
|
{
|
|
hunk_info *temp;
|
|
LINENUM i;
|
|
int size;
|
|
|
|
/* Allocate temp hunk head and pointer space */
|
|
size = hunk->line_count * sizeof (wchar_t *);
|
|
size += sizeof (hunk_info);
|
|
temp = (hunk_info *)allocate(size);
|
|
(void) memcpy(temp, hunk, size);
|
|
|
|
hunk->max_lines = temp->max_lines;
|
|
hunk->line_count = temp->line_count;
|
|
|
|
hunk->file1_start = temp->file2_start;
|
|
hunk->file1_lines = temp->file2_lines;
|
|
|
|
hunk->file2_start = temp->file1_start;
|
|
hunk->file2_lines = temp->file1_lines;
|
|
|
|
/*
|
|
* Change all delete lines to add lines
|
|
* and swap with file 2 lines;
|
|
*/
|
|
for (i = 0; i < temp->file1_lines; i++) {
|
|
if (*(temp->lines[i]) == L'-')
|
|
*(temp->lines[i]) = L'+';
|
|
hunk->lines[hunk->file1_lines + i] = temp->lines[i];
|
|
}
|
|
|
|
/*
|
|
* Change all add lines to delete lines
|
|
* and swap with file 1 lines;
|
|
*/
|
|
for (i = 0; i < temp->file2_lines; i++) {
|
|
if (*(temp->lines[temp->file1_lines + i]) == L'+')
|
|
*(temp->lines[temp->file1_lines + i]) = L'-';
|
|
hunk->lines[i] = temp->lines[temp->file1_lines + i];
|
|
}
|
|
|
|
/* Free up the old unused header space */
|
|
(void) free(temp);
|
|
}
|
|
|
|
|
|
/*
|
|
* Function: hunk_info *another_hunk(file_info *)
|
|
*
|
|
* Description:
|
|
*
|
|
* Return next hunk to process if there is more of the current diff
|
|
* listing to process.
|
|
*
|
|
* Inputs:
|
|
* pinfo -> A pointer to the patch file descriptor.
|
|
*
|
|
* Returns:
|
|
*
|
|
* address of hunk or FALSE if nore more hunks are available.
|
|
*/
|
|
|
|
|
|
hunk_info *
|
|
another_hunk(file_info *pinfo)
|
|
{
|
|
hunk_info *hunk;
|
|
|
|
switch (diff_type) {
|
|
case CONTEXT_DIFF :
|
|
if ((hunk = another_context_hunk(pinfo)) == NULL)
|
|
return (FALSE);
|
|
break;
|
|
|
|
case NEW_CONTEXT_DIFF :
|
|
if ((hunk = another_new_context_hunk(pinfo)) == NULL)
|
|
return (FALSE);
|
|
break;
|
|
|
|
case NORMAL_DIFF :
|
|
if ((hunk = another_normal_diff_hunk(pinfo)) == NULL)
|
|
return (FALSE);
|
|
break;
|
|
|
|
case UNIFIED_DIFF :
|
|
if ((hunk = another_unified_hunk(pinfo)) == NULL)
|
|
return (FALSE);
|
|
break;
|
|
|
|
default :
|
|
fatal(gettext("patch: Unrecognized diff type"));
|
|
break;
|
|
}
|
|
|
|
if (reverse) /* backwards patch? */
|
|
pch_swap(hunk);
|
|
|
|
return (hunk);
|
|
}
|
|
|
|
|
|
/*
|
|
* Function: void do_ed_script(file_info *, file_info *)
|
|
*
|
|
* Description:
|
|
*
|
|
* Apply an ed script by feeding ed itself. Reintegrate results into
|
|
* our internal data structures.
|
|
*
|
|
* Inputs:
|
|
* winfo -> A pointer to the file info.
|
|
* pinfo -> A pointer to the patch file info.
|
|
*/
|
|
|
|
|
|
void
|
|
do_ed_script(file_info *winfo, file_info *pinfo)
|
|
{
|
|
FILE *pipefp;
|
|
wchar_t *start, *t;
|
|
char *temp, *tempname;
|
|
|
|
ignore_signals();
|
|
tempname = winfo->name;
|
|
winfo->name = temp = tmpnam(NULL);
|
|
sync_file(winfo, "");
|
|
winfo->name = tempname;
|
|
if (!skip_rest_of_patch) {
|
|
if (verbose)
|
|
(void) sprintf(buf, "%s %s", _PATH_ED, temp);
|
|
else
|
|
(void) sprintf(buf, "%s - %s", _PATH_ED, temp);
|
|
if ((pipefp = popen(buf, "w")) == (FILE *) -1) {
|
|
int save = errno;
|
|
|
|
(void) unlink(temp);
|
|
errno = save;
|
|
pfatal("ed");
|
|
/* NOTREACHED */
|
|
}
|
|
}
|
|
for (;;) {
|
|
if ((start = fetch_line(pinfo, p_base++)) == NULL) {
|
|
break;
|
|
}
|
|
if (wcsncmp(start, L"Index:", 6) == 0) {
|
|
p_base--;
|
|
break;
|
|
}
|
|
if (wcsncmp(start, L"***", 3) == 0) {
|
|
p_base--;
|
|
break;
|
|
}
|
|
|
|
/* search for possible second line in range */
|
|
|
|
for (t = start; iswdigit(*t) || *t == L','; t++)
|
|
;
|
|
|
|
if (iswdigit(*start) && (*t == L'd' || *t == L's')) {
|
|
if (!skip_rest_of_patch)
|
|
(void) fputws(start, pipefp);
|
|
} else if (*t == L'c' || *t == L'a' || *t == L'i') {
|
|
if (!skip_rest_of_patch)
|
|
(void) fputws(start, pipefp);
|
|
|
|
while (start = fetch_line(pinfo, p_base++)) {
|
|
if (!skip_rest_of_patch) {
|
|
(void) fputws(start, pipefp);
|
|
}
|
|
if (wcscmp(start, L".\n") == 0)
|
|
break;
|
|
}
|
|
} else {
|
|
break;
|
|
}
|
|
}
|
|
if (!skip_rest_of_patch) {
|
|
(void) fprintf(pipefp, "w\n");
|
|
(void) fprintf(pipefp, "q\n");
|
|
(void) fflush(pipefp);
|
|
(void) pclose(pipefp);
|
|
(void) wait(NULL);
|
|
update_with_file_contents(winfo, temp);
|
|
}
|
|
set_signals();
|
|
(void) unlink(temp);
|
|
}
|