// // 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; }