//
// aegis - project change supervisor
// Copyright (C) 2001-2006, 2008 Peter Miller
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see
// .
//
#include
#include
#include
#include
bool
patch_apply(patch_ty *pp, string_ty *ifn, string_ty *ofn)
{
trace(("patch_apply(pp = %08lX, ifn = \"%s\", ofn = \"%s\")\n{\n",
(long)pp, (ifn ? ifn->str_text : ""), (ofn ? ofn->str_text : "")));
bool ok = true;
output::pointer ofp = output_file::text_open(ofn);
if (!ifn)
{
//
// Write all the lines from all the hunks
// to the output file.
//
// (There will only be one hunk if the patch asks for
// a modification to a file which doesn't exist.)
//
for (size_t k = 0; k < pp->actions.length; ++k)
{
patch_hunk_ty *php = pp->actions.item[0];
patch_line_list_ty *pllp = &php->after;
for (size_t m = 0; m < pllp->length; ++m)
{
ofp->fputs(pllp->item[m].value);
ofp->fputc('\n');
}
}
}
else
{
//
// Read the file into an array.
//
string_list_ty buffer;
input ifp = input_file_text_open(ifn);
for (;;)
{
nstring s;
if (!ifp->one_line(s))
break;
buffer.push_back(s.get_ref());
}
ifp.close();
//
// Now work over the hunk list, looking for where they go.
//
for (size_t j = 0; j < pp->actions.length; ++j)
{
int found;
patch_hunk_ty *php;
size_t min_line;
int running_offset;
php = pp->actions.item[j];
trace(("looking for %d,%d\n",
php->before.start_line_number,
php->before.start_line_number + php->before.length - 1));
found = 0;
min_line = 0;
running_offset = 0;
for (size_t k = 1; k <= 2 * buffer.nstrings; ++k)
{
size_t m;
int idx;
int offset;
//
// 0, -1, 1, -2, 2, etc...
//
offset = k >> 1;
if (k & 1)
offset = -offset;
offset += running_offset;
//
// If it doesn't fit in the buffer,
// it can't be there.
//
idx = php->before.start_line_number - 1 + offset;
if (idx < (int)min_line)
continue;
if (idx + php->before.length > buffer.nstrings)
continue;
//
// See if the lines match.
//
for (m = 0; m < php->before.length; ++m)
{
if
(
!str_equal
(
buffer.string[idx + m],
php->before.item[m].value
)
)
break;
}
if (m >= php->before.length)
{
trace(("found, offset=%d\n", offset));
php->before.start_line_number += offset;
found = 1;
min_line =
php->before.start_line_number - 1 + php->before.length;
running_offset = offset;
break;
}
}
//
// Remember if we didn't find a place to apply
// the patch. We'll return it later.
//
if (!found)
{
php->before.start_line_number += running_offset;
ok = false;
}
}
//
// Go over each hunk, emitting lines as we go.
//
int curline = 1;
for (size_t j = 0; j < pp->actions.length; ++j)
{
//
// First, any prelude.
//
patch_hunk_ty *php = pp->actions.item[j];
while
(
curline < php->before.start_line_number
&&
curline <= (int)buffer.nstrings
)
{
ofp->fputs(buffer.string[curline - 1]);
ofp->fputc('\n');
++curline;
}
curline += php->before.length;
//
// Toss the "before" and emit the "after".
// We checked that it was there already.
//
for (size_t k = 0; k < php->after.length; ++k)
{
ofp->fputs(php->after.item[k].value);
ofp->fputc('\n');
}
}
//
// Emit anything left over.
//
while (curline <= (int)buffer.nstrings)
{
ofp->fputs(buffer.string[curline - 1]);
ofp->fputc('\n');
++curline;
}
}
ofp.reset();
trace(("return %d\n", ok));
trace(("}\n"));
return ok;
}