/* patch-parser.c: * * vim:smartindent ts=8:sts=2:sta:et:ai:shiftwidth=2 **************************************************************** * Copyright (C) 2005 Canonical Limited * Authors: Robert Collins * * See the file "COPYING" for further information about * the copyright and warranty status of this work. * * Portions Copyright (C) 2001, 2002, 2003, 2004 Tim Waugh */ #include "hackerlab/bugs/panic.h" #include "hackerlab/char/str.h" #include "hackerlab/vu/safe-printfmt.h" #include "libawk/relational.h" #include "libarch/patch-parser.h" /* FROM PatchUtils */ static int read_atatline (const char *atatline, unsigned long *orig_offset, unsigned long *orig_count, unsigned long *new_offset, unsigned long *new_count); /** * \@brief parse patch_contents and return a list of the * dels and adds in the patch, adjusted for use with the * file_offset_mapper api * * we parse in the 'be generous in what you accept style: * we will parse invalid patches and do our best. */ patch_line_changes_list patch_parser_parse(t_uchar const * patch_content) { rel_table lines = rel_nl_split (patch_content); int line; patch_line_changes_list result = NULL; int current_state = 0; /* 0 = want --, 1 = want ++, 2 = want @@, 3= want @@ or hunks */ int current_adjusted_line = 0; int hunk_adjustment = 0; for (line = 0; line < rel_n_records (lines); ++line) { switch (current_state) { case 0: if (!str_cmp_prefix ("---", lines[line][0])) { ++current_state; continue; } case 1: if (!str_cmp_prefix ("+++", lines[line][0])) { ++current_state; continue; } case 2: if (!str_cmp_prefix ("@@", lines[line][0])) { unsigned long curr_offset; read_atatline(lines[line][0], &curr_offset, NULL, NULL, NULL); current_adjusted_line = (int) curr_offset; // + hunk_adjustment; ++current_state; hunk_adjustment = 0; continue; } case 3: if (!str_cmp_prefix ("@@", lines[line][0])) { unsigned long curr_offset; read_atatline(lines[line][0], &curr_offset, NULL, NULL, NULL); current_adjusted_line = (int) curr_offset; // + hunk_adjustment; hunk_adjustment = 0; continue; } else if (lines[line][0][0] == '-') { patch_line_change_t * change = ar_ref_patch_line_change(&result, ar_size_patch_line_change(result)); change->offset = current_adjusted_line++ - 1; change->operation = PATCH_DEL_LINE; ++hunk_adjustment; /* carry out adjustment to the next hunk */ invariant (change->offset > -1); } else if (lines[line][0][0] == '+') { patch_line_change_t * change = ar_ref_patch_line_change(&result, ar_size_patch_line_change(result)); change->offset = current_adjusted_line - 1; change->operation = PATCH_ADD_LINE; if (change->offset == -1) { /* special case BOGON: new files are -0,0 +1,length */ change->offset = 0; } } else if (lines[line][0][0] == ' ') { ++current_adjusted_line; } } } rel_free_table (lines); return result; } void ar_print_patch_line_change (int fd, patch_line_changes_list changes) { int line; for (line = 0; line < ar_size_patch_line_change (changes); ++line) safe_printfmt (2, "%d %d\n", changes[line].offset, changes[line].operation); } /* librarising is too hard right now: * so we use one function from patchutils */ /* * diff.c - diff specific util functions * Copyright (C) 2001, 2002, 2003, 2004 Tim Waugh * * 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 2 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, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #include #include static unsigned long calculate_num_lines (const char *atatline, char which) { char *p = strchr (atatline, which); if (!p) return 1; while (*p && *p != ',' && *p != ' ') p++; if (!*p || *p == ' ') return 1; return strtoul (p + 1, NULL, 10); } static unsigned long orig_num_lines (const char *atatline) { return calculate_num_lines (atatline, '-'); } static unsigned long new_num_lines (const char *atatline) { return calculate_num_lines (atatline, '+'); } /* Parse an @@ line. */ int read_atatline (const char *atatline, unsigned long *orig_offset, unsigned long *orig_count, unsigned long *new_offset, unsigned long *new_count) { char *endptr; unsigned long res; char *p; if (orig_offset) { p = strchr (atatline, '-'); if (!p) return 1; p++; res = strtoul (p, &endptr, 0); if (p == endptr) return 1; *orig_offset = res; } if (orig_count) *orig_count = orig_num_lines (atatline); if (new_offset) { p = strchr (atatline, '+'); if (!p) return 1; p++; res = strtoul (p, &endptr, 0); if (p == endptr) return 1; *new_offset = res; } if (new_count) *new_count = new_num_lines (atatline); return 0; }