| 1 | /* reading patches */ | 
|---|
| 2 |  | 
|---|
| 3 | /* $Id: pch.c,v 1.44 2003/05/20 14:03:17 eggert Exp $ */ | 
|---|
| 4 |  | 
|---|
| 5 | /* Copyright (C) 1986, 1987, 1988 Larry Wall | 
|---|
| 6 |  | 
|---|
| 7 | Copyright (C) 1990, 1991, 1992, 1993, 1997, 1998, 1999, 2000, 2001, | 
|---|
| 8 | 2002, 2003 Free Software Foundation, Inc. | 
|---|
| 9 |  | 
|---|
| 10 | This program is free software; you can redistribute it and/or modify | 
|---|
| 11 | it under the terms of the GNU General Public License as published by | 
|---|
| 12 | the Free Software Foundation; either version 2, or (at your option) | 
|---|
| 13 | any later version. | 
|---|
| 14 |  | 
|---|
| 15 | This program is distributed in the hope that it will be useful, | 
|---|
| 16 | but WITHOUT ANY WARRANTY; without even the implied warranty of | 
|---|
| 17 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | 
|---|
| 18 | GNU General Public License for more details. | 
|---|
| 19 |  | 
|---|
| 20 | You should have received a copy of the GNU General Public License | 
|---|
| 21 | along with this program; see the file COPYING. | 
|---|
| 22 | If not, write to the Free Software Foundation, | 
|---|
| 23 | 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */ | 
|---|
| 24 |  | 
|---|
| 25 | #define XTERN extern | 
|---|
| 26 | #include <common.h> | 
|---|
| 27 | #include <backupfile.h> | 
|---|
| 28 | #include <dirname.h> | 
|---|
| 29 | #include <inp.h> | 
|---|
| 30 | #include <quotearg.h> | 
|---|
| 31 | #include <util.h> | 
|---|
| 32 | #undef XTERN | 
|---|
| 33 | #define XTERN | 
|---|
| 34 | #include <pch.h> | 
|---|
| 35 |  | 
|---|
| 36 | #define INITHUNKMAX 125                 /* initial dynamic allocation size */ | 
|---|
| 37 |  | 
|---|
| 38 | /* Patch (diff listing) abstract type. */ | 
|---|
| 39 |  | 
|---|
| 40 | static FILE *pfp;                       /* patch file pointer */ | 
|---|
| 41 | static int p_says_nonexistent[2];       /* [0] for old file, [1] for new: | 
|---|
| 42 | 0 for existent and nonempty, | 
|---|
| 43 | 1 for existent and probably (but not necessarily) empty, | 
|---|
| 44 | 2 for nonexistent */ | 
|---|
| 45 | static int p_rfc934_nesting;            /* RFC 934 nesting level */ | 
|---|
| 46 | static time_t p_timestamp[2];           /* timestamps in patch headers */ | 
|---|
| 47 | static off_t p_filesize;                /* size of the patch file */ | 
|---|
| 48 | static LINENUM p_first;                 /* 1st line number */ | 
|---|
| 49 | static LINENUM p_newfirst;              /* 1st line number of replacement */ | 
|---|
| 50 | static LINENUM p_ptrn_lines;            /* # lines in pattern */ | 
|---|
| 51 | static LINENUM p_repl_lines;            /* # lines in replacement text */ | 
|---|
| 52 | static LINENUM p_end = -1;              /* last line in hunk */ | 
|---|
| 53 | static LINENUM p_max;                   /* max allowed value of p_end */ | 
|---|
| 54 | static LINENUM p_prefix_context;        /* # of prefix context lines */ | 
|---|
| 55 | static LINENUM p_suffix_context;        /* # of suffix context lines */ | 
|---|
| 56 | static LINENUM p_input_line;            /* current line # from patch file */ | 
|---|
| 57 | static char **p_line;                   /* the text of the hunk */ | 
|---|
| 58 | static size_t *p_len;                   /* line length including \n if any */ | 
|---|
| 59 | static char *p_Char;                    /* +, -, and ! */ | 
|---|
| 60 | static LINENUM hunkmax = INITHUNKMAX;   /* size of above arrays */ | 
|---|
| 61 | static int p_indent;                    /* indent to patch */ | 
|---|
| 62 | static bool p_strip_trailing_cr;        /* true if stripping trailing \r */ | 
|---|
| 63 | static bool p_pass_comments_through;    /* true if not ignoring # lines */ | 
|---|
| 64 | static file_offset p_base;              /* where to intuit this time */ | 
|---|
| 65 | static LINENUM p_bline;                 /* line # of p_base */ | 
|---|
| 66 | static file_offset p_start;             /* where intuit found a patch */ | 
|---|
| 67 | static LINENUM p_sline;                 /* and the line number for it */ | 
|---|
| 68 | static LINENUM p_hunk_beg;              /* line number of current hunk */ | 
|---|
| 69 | static LINENUM p_efake = -1;            /* end of faked up lines--don't free */ | 
|---|
| 70 | static LINENUM p_bfake = -1;            /* beg of faked up lines */ | 
|---|
| 71 |  | 
|---|
| 72 | enum nametype { OLD, NEW, INDEX, NONE }; | 
|---|
| 73 |  | 
|---|
| 74 | static char *scan_linenum (char *, LINENUM *); | 
|---|
| 75 | static enum diff intuit_diff_type (void); | 
|---|
| 76 | static enum nametype best_name (char * const *, int const *); | 
|---|
| 77 | static int prefix_components (char *, bool); | 
|---|
| 78 | static size_t pget_line (int, int, bool, bool); | 
|---|
| 79 | static size_t get_line (void); | 
|---|
| 80 | static bool incomplete_line (void); | 
|---|
| 81 | static bool grow_hunkmax (void); | 
|---|
| 82 | static void malformed (void) __attribute__ ((noreturn)); | 
|---|
| 83 | static void next_intuit_at (file_offset, LINENUM); | 
|---|
| 84 | static void skip_to (file_offset, LINENUM); | 
|---|
| 85 | static char get_ed_command_letter (char const *); | 
|---|
| 86 |  | 
|---|
| 87 | /* Prepare to look for the next patch in the patch file. */ | 
|---|
| 88 |  | 
|---|
| 89 | void | 
|---|
| 90 | re_patch (void) | 
|---|
| 91 | { | 
|---|
| 92 | p_first = 0; | 
|---|
| 93 | p_newfirst = 0; | 
|---|
| 94 | p_ptrn_lines = 0; | 
|---|
| 95 | p_repl_lines = 0; | 
|---|
| 96 | p_end = -1; | 
|---|
| 97 | p_max = 0; | 
|---|
| 98 | p_indent = 0; | 
|---|
| 99 | p_strip_trailing_cr = false; | 
|---|
| 100 | } | 
|---|
| 101 |  | 
|---|
| 102 | /* Open the patch file at the beginning of time. */ | 
|---|
| 103 |  | 
|---|
| 104 | void | 
|---|
| 105 | open_patch_file (char const *filename) | 
|---|
| 106 | { | 
|---|
| 107 | file_offset file_pos = 0; | 
|---|
| 108 | struct stat st; | 
|---|
| 109 | if (!filename || !*filename || strEQ (filename, "-")) | 
|---|
| 110 | { | 
|---|
| 111 | file_offset stdin_pos; | 
|---|
| 112 | #if HAVE_SETMODE_DOS | 
|---|
| 113 | if (binary_transput) | 
|---|
| 114 | { | 
|---|
| 115 | if (isatty (STDIN_FILENO)) | 
|---|
| 116 | fatal ("cannot read binary data from tty on this platform"); | 
|---|
| 117 | setmode (STDIN_FILENO, O_BINARY); | 
|---|
| 118 | } | 
|---|
| 119 | #endif | 
|---|
| 120 | if (fstat (STDIN_FILENO, &st) != 0) | 
|---|
| 121 | pfatal ("fstat"); | 
|---|
| 122 | if (S_ISREG (st.st_mode) && (stdin_pos = file_tell (stdin)) != -1) | 
|---|
| 123 | { | 
|---|
| 124 | pfp = stdin; | 
|---|
| 125 | file_pos = stdin_pos; | 
|---|
| 126 | } | 
|---|
| 127 | else | 
|---|
| 128 | { | 
|---|
| 129 | size_t charsread; | 
|---|
| 130 | int exclusive = TMPPATNAME_needs_removal ? 0 : O_EXCL; | 
|---|
| 131 | TMPPATNAME_needs_removal = 1; | 
|---|
| 132 | pfp = fdopen (create_file (TMPPATNAME, | 
|---|
| 133 | O_RDWR | O_BINARY | exclusive, | 
|---|
| 134 | (mode_t) 0), | 
|---|
| 135 | "w+b"); | 
|---|
| 136 | if (!pfp) | 
|---|
| 137 | pfatal ("Can't open stream for file %s", quotearg (TMPPATNAME)); | 
|---|
| 138 | for (st.st_size = 0; | 
|---|
| 139 | (charsread = fread (buf, 1, bufsize, stdin)) != 0; | 
|---|
| 140 | st.st_size += charsread) | 
|---|
| 141 | if (fwrite (buf, 1, charsread, pfp) != charsread) | 
|---|
| 142 | write_fatal (); | 
|---|
| 143 | if (ferror (stdin) || fclose (stdin) != 0) | 
|---|
| 144 | read_fatal (); | 
|---|
| 145 | if (fflush (pfp) != 0 | 
|---|
| 146 | || file_seek (pfp, (file_offset) 0, SEEK_SET) != 0) | 
|---|
| 147 | write_fatal (); | 
|---|
| 148 | } | 
|---|
| 149 | } | 
|---|
| 150 | else | 
|---|
| 151 | { | 
|---|
| 152 | pfp = fopen (filename, binary_transput ? "rb" : "r"); | 
|---|
| 153 | if (!pfp) | 
|---|
| 154 | pfatal ("Can't open patch file %s", quotearg (filename)); | 
|---|
| 155 | if (fstat (fileno (pfp), &st) != 0) | 
|---|
| 156 | pfatal ("fstat"); | 
|---|
| 157 | } | 
|---|
| 158 | p_filesize = st.st_size; | 
|---|
| 159 | if (p_filesize != (file_offset) p_filesize) | 
|---|
| 160 | fatal ("patch file is too long"); | 
|---|
| 161 | next_intuit_at (file_pos, (LINENUM) 1); | 
|---|
| 162 | set_hunkmax(); | 
|---|
| 163 | } | 
|---|
| 164 |  | 
|---|
| 165 | /* Make sure our dynamically realloced tables are malloced to begin with. */ | 
|---|
| 166 |  | 
|---|
| 167 | void | 
|---|
| 168 | set_hunkmax (void) | 
|---|
| 169 | { | 
|---|
| 170 | if (!p_line) | 
|---|
| 171 | p_line = (char **) malloc (hunkmax * sizeof *p_line); | 
|---|
| 172 | if (!p_len) | 
|---|
| 173 | p_len = (size_t *) malloc (hunkmax * sizeof *p_len); | 
|---|
| 174 | if (!p_Char) | 
|---|
| 175 | p_Char = malloc (hunkmax * sizeof *p_Char); | 
|---|
| 176 | } | 
|---|
| 177 |  | 
|---|
| 178 | /* Enlarge the arrays containing the current hunk of patch. */ | 
|---|
| 179 |  | 
|---|
| 180 | static bool | 
|---|
| 181 | grow_hunkmax (void) | 
|---|
| 182 | { | 
|---|
| 183 | hunkmax *= 2; | 
|---|
| 184 | assert (p_line && p_len && p_Char); | 
|---|
| 185 | if ((p_line = (char **) realloc (p_line, hunkmax * sizeof (*p_line))) | 
|---|
| 186 | && (p_len = (size_t *) realloc (p_len, hunkmax * sizeof (*p_len))) | 
|---|
| 187 | && (p_Char = realloc (p_Char, hunkmax * sizeof (*p_Char)))) | 
|---|
| 188 | return true; | 
|---|
| 189 | if (!using_plan_a) | 
|---|
| 190 | memory_fatal (); | 
|---|
| 191 | /* Don't free previous values of p_line etc., | 
|---|
| 192 | since some broken implementations free them for us. | 
|---|
| 193 | Whatever is null will be allocated again from within plan_a (), | 
|---|
| 194 | of all places.  */ | 
|---|
| 195 | return false; | 
|---|
| 196 | } | 
|---|
| 197 |  | 
|---|
| 198 | /* True if the remainder of the patch file contains a diff of some sort. */ | 
|---|
| 199 |  | 
|---|
| 200 | bool | 
|---|
| 201 | there_is_another_patch (void) | 
|---|
| 202 | { | 
|---|
| 203 | if (p_base != 0 && p_base >= p_filesize) { | 
|---|
| 204 | if (verbosity == VERBOSE) | 
|---|
| 205 | say ("done\n"); | 
|---|
| 206 | return false; | 
|---|
| 207 | } | 
|---|
| 208 | if (verbosity == VERBOSE) | 
|---|
| 209 | say ("Hmm..."); | 
|---|
| 210 | diff_type = intuit_diff_type(); | 
|---|
| 211 | if (diff_type == NO_DIFF) { | 
|---|
| 212 | if (verbosity == VERBOSE) | 
|---|
| 213 | say (p_base | 
|---|
| 214 | ? "  Ignoring the trailing garbage.\ndone\n" | 
|---|
| 215 | : "  I can't seem to find a patch in there anywhere.\n"); | 
|---|
| 216 | if (! p_base && p_filesize) | 
|---|
| 217 | fatal ("Only garbage was found in the patch input."); | 
|---|
| 218 | return false; | 
|---|
| 219 | } | 
|---|
| 220 | if (skip_rest_of_patch) | 
|---|
| 221 | { | 
|---|
| 222 | Fseek (pfp, p_start, SEEK_SET); | 
|---|
| 223 | p_input_line = p_sline - 1; | 
|---|
| 224 | return true; | 
|---|
| 225 | } | 
|---|
| 226 | if (verbosity == VERBOSE) | 
|---|
| 227 | say ("  %sooks like %s to me...\n", | 
|---|
| 228 | (p_base == 0 ? "L" : "The next patch l"), | 
|---|
| 229 | diff_type == UNI_DIFF ? "a unified diff" : | 
|---|
| 230 | diff_type == CONTEXT_DIFF ? "a context diff" : | 
|---|
| 231 | diff_type == NEW_CONTEXT_DIFF ? "a new-style context diff" : | 
|---|
| 232 | diff_type == NORMAL_DIFF ? "a normal diff" : | 
|---|
| 233 | "an ed script" ); | 
|---|
| 234 |  | 
|---|
| 235 | if (verbosity != SILENT) | 
|---|
| 236 | { | 
|---|
| 237 | if (p_indent) | 
|---|
| 238 | say ("(Patch is indented %d space%s.)\n", p_indent, p_indent==1?"":"s"); | 
|---|
| 239 | if (p_strip_trailing_cr) | 
|---|
| 240 | say ("(Stripping trailing CRs from patch.)\n"); | 
|---|
| 241 | if (! inname) | 
|---|
| 242 | { | 
|---|
| 243 | char numbuf[LINENUM_LENGTH_BOUND + 1]; | 
|---|
| 244 | say ("can't find file to patch at input line %s\n", | 
|---|
| 245 | format_linenum (numbuf, p_sline)); | 
|---|
| 246 | if (diff_type != ED_DIFF) | 
|---|
| 247 | say (strippath == -1 | 
|---|
| 248 | ? "Perhaps you should have used the -p or --strip option?\n" | 
|---|
| 249 | : "Perhaps you used the wrong -p or --strip option?\n"); | 
|---|
| 250 | } | 
|---|
| 251 | } | 
|---|
| 252 |  | 
|---|
| 253 | skip_to(p_start,p_sline); | 
|---|
| 254 | while (!inname) { | 
|---|
| 255 | if (force | batch) { | 
|---|
| 256 | say ("No file to patch.  Skipping patch.\n"); | 
|---|
| 257 | skip_rest_of_patch = true; | 
|---|
| 258 | return true; | 
|---|
| 259 | } | 
|---|
| 260 | ask ("File to patch: "); | 
|---|
| 261 | inname = fetchname (buf, 0, (time_t *) 0); | 
|---|
| 262 | if (inname) | 
|---|
| 263 | { | 
|---|
| 264 | if (stat (inname, &instat) == 0) | 
|---|
| 265 | { | 
|---|
| 266 | inerrno = 0; | 
|---|
| 267 | invc = -1; | 
|---|
| 268 | } | 
|---|
| 269 | else | 
|---|
| 270 | { | 
|---|
| 271 | perror (inname); | 
|---|
| 272 | fflush (stderr); | 
|---|
| 273 | free (inname); | 
|---|
| 274 | inname = 0; | 
|---|
| 275 | } | 
|---|
| 276 | } | 
|---|
| 277 | if (!inname) { | 
|---|
| 278 | ask ("Skip this patch? [y] "); | 
|---|
| 279 | if (*buf != 'n') { | 
|---|
| 280 | if (verbosity != SILENT) | 
|---|
| 281 | say ("Skipping patch.\n"); | 
|---|
| 282 | skip_rest_of_patch = true; | 
|---|
| 283 | return true; | 
|---|
| 284 | } | 
|---|
| 285 | } | 
|---|
| 286 | } | 
|---|
| 287 | return true; | 
|---|
| 288 | } | 
|---|
| 289 |  | 
|---|
| 290 | /* Determine what kind of diff is in the remaining part of the patch file. */ | 
|---|
| 291 |  | 
|---|
| 292 | static enum diff | 
|---|
| 293 | intuit_diff_type (void) | 
|---|
| 294 | { | 
|---|
| 295 | register file_offset this_line = 0; | 
|---|
| 296 | register file_offset first_command_line = -1; | 
|---|
| 297 | char first_ed_command_letter = 0; | 
|---|
| 298 | LINENUM fcl_line = 0; /* Pacify `gcc -W'.  */ | 
|---|
| 299 | register bool this_is_a_command = false; | 
|---|
| 300 | register bool stars_this_line = false; | 
|---|
| 301 | enum nametype i; | 
|---|
| 302 | char *name[3]; | 
|---|
| 303 | struct stat st[3]; | 
|---|
| 304 | int stat_errno[3]; | 
|---|
| 305 | int version_controlled[3]; | 
|---|
| 306 | register enum diff retval; | 
|---|
| 307 |  | 
|---|
| 308 | name[OLD] = name[NEW] = name[INDEX] = 0; | 
|---|
| 309 | version_controlled[OLD] = -1; | 
|---|
| 310 | version_controlled[NEW] = -1; | 
|---|
| 311 | version_controlled[INDEX] = -1; | 
|---|
| 312 | p_rfc934_nesting = 0; | 
|---|
| 313 | p_timestamp[OLD] = p_timestamp[NEW] = (time_t) -1; | 
|---|
| 314 | p_says_nonexistent[OLD] = p_says_nonexistent[NEW] = 0; | 
|---|
| 315 | Fseek (pfp, p_base, SEEK_SET); | 
|---|
| 316 | p_input_line = p_bline - 1; | 
|---|
| 317 | for (;;) { | 
|---|
| 318 | register char *s; | 
|---|
| 319 | register char *t; | 
|---|
| 320 | register file_offset previous_line = this_line; | 
|---|
| 321 | register bool last_line_was_command = this_is_a_command; | 
|---|
| 322 | register bool stars_last_line = stars_this_line; | 
|---|
| 323 | register int indent = 0; | 
|---|
| 324 | char ed_command_letter; | 
|---|
| 325 | bool strip_trailing_cr; | 
|---|
| 326 | size_t chars_read; | 
|---|
| 327 |  | 
|---|
| 328 | this_line = file_tell (pfp); | 
|---|
| 329 | chars_read = pget_line (0, 0, false, false); | 
|---|
| 330 | if (chars_read == (size_t) -1) | 
|---|
| 331 | memory_fatal (); | 
|---|
| 332 | if (! chars_read) { | 
|---|
| 333 | if (first_ed_command_letter) { | 
|---|
| 334 | /* nothing but deletes!? */ | 
|---|
| 335 | p_start = first_command_line; | 
|---|
| 336 | p_sline = fcl_line; | 
|---|
| 337 | retval = ED_DIFF; | 
|---|
| 338 | goto scan_exit; | 
|---|
| 339 | } | 
|---|
| 340 | else { | 
|---|
| 341 | p_start = this_line; | 
|---|
| 342 | p_sline = p_input_line; | 
|---|
| 343 | return NO_DIFF; | 
|---|
| 344 | } | 
|---|
| 345 | } | 
|---|
| 346 | strip_trailing_cr = 2 <= chars_read && buf[chars_read - 2] == '\r'; | 
|---|
| 347 | for (s = buf; *s == ' ' || *s == '\t' || *s == 'X'; s++) { | 
|---|
| 348 | if (*s == '\t') | 
|---|
| 349 | indent = (indent + 8) & ~7; | 
|---|
| 350 | else | 
|---|
| 351 | indent++; | 
|---|
| 352 | } | 
|---|
| 353 | for (t = s;  ISDIGIT (*t) || *t == ',';  t++) | 
|---|
| 354 | continue; | 
|---|
| 355 | this_is_a_command = (ISDIGIT (*s) && | 
|---|
| 356 | (*t == 'd' || *t == 'c' || *t == 'a') ); | 
|---|
| 357 | if (first_command_line < 0 | 
|---|
| 358 | && ((ed_command_letter = get_ed_command_letter (s)) | 
|---|
| 359 | || this_is_a_command)) { | 
|---|
| 360 | first_command_line = this_line; | 
|---|
| 361 | first_ed_command_letter = ed_command_letter; | 
|---|
| 362 | fcl_line = p_input_line; | 
|---|
| 363 | p_indent = indent;          /* assume this for now */ | 
|---|
| 364 | p_strip_trailing_cr = strip_trailing_cr; | 
|---|
| 365 | } | 
|---|
| 366 | if (!stars_last_line && strnEQ(s, "*** ", 4)) | 
|---|
| 367 | name[OLD] = fetchname (s+4, strippath, &p_timestamp[OLD]); | 
|---|
| 368 | else if (strnEQ(s, "+++ ", 4)) | 
|---|
| 369 | /* Swap with NEW below.  */ | 
|---|
| 370 | name[OLD] = fetchname (s+4, strippath, &p_timestamp[OLD]); | 
|---|
| 371 | else if (strnEQ(s, "Index:", 6)) | 
|---|
| 372 | name[INDEX] = fetchname (s+6, strippath, (time_t *) 0); | 
|---|
| 373 | else if (strnEQ(s, "Prereq:", 7)) { | 
|---|
| 374 | for (t = s + 7;  ISSPACE ((unsigned char) *t);  t++) | 
|---|
| 375 | continue; | 
|---|
| 376 | revision = t; | 
|---|
| 377 | for (t = revision;  *t;  t++) | 
|---|
| 378 | if (ISSPACE ((unsigned char) *t)) | 
|---|
| 379 | { | 
|---|
| 380 | char const *u; | 
|---|
| 381 | for (u = t + 1;  ISSPACE ((unsigned char) *u);  u++) | 
|---|
| 382 | continue; | 
|---|
| 383 | if (*u) | 
|---|
| 384 | { | 
|---|
| 385 | char numbuf[LINENUM_LENGTH_BOUND + 1]; | 
|---|
| 386 | say ("Prereq: with multiple words at line %s of patch\n", | 
|---|
| 387 | format_linenum (numbuf, this_line)); | 
|---|
| 388 | } | 
|---|
| 389 | break; | 
|---|
| 390 | } | 
|---|
| 391 | if (t == revision) | 
|---|
| 392 | revision = 0; | 
|---|
| 393 | else { | 
|---|
| 394 | char oldc = *t; | 
|---|
| 395 | *t = '\0'; | 
|---|
| 396 | revision = savestr (revision); | 
|---|
| 397 | *t = oldc; | 
|---|
| 398 | } | 
|---|
| 399 | } else | 
|---|
| 400 | { | 
|---|
| 401 | for (t = s;  t[0] == '-' && t[1] == ' ';  t += 2) | 
|---|
| 402 | continue; | 
|---|
| 403 | if (strnEQ(t, "--- ", 4)) | 
|---|
| 404 | { | 
|---|
| 405 | time_t timestamp = (time_t) -1; | 
|---|
| 406 | name[NEW] = fetchname (t+4, strippath, ×tamp); | 
|---|
| 407 | if (timestamp != (time_t) -1) | 
|---|
| 408 | { | 
|---|
| 409 | p_timestamp[NEW] = timestamp; | 
|---|
| 410 | p_rfc934_nesting = (t - s) >> 1; | 
|---|
| 411 | } | 
|---|
| 412 | } | 
|---|
| 413 | } | 
|---|
| 414 | if ((diff_type == NO_DIFF || diff_type == ED_DIFF) && | 
|---|
| 415 | first_command_line >= 0 && | 
|---|
| 416 | strEQ(s, ".\n") ) { | 
|---|
| 417 | p_start = first_command_line; | 
|---|
| 418 | p_sline = fcl_line; | 
|---|
| 419 | retval = ED_DIFF; | 
|---|
| 420 | goto scan_exit; | 
|---|
| 421 | } | 
|---|
| 422 | if ((diff_type == NO_DIFF || diff_type == UNI_DIFF) | 
|---|
| 423 | && strnEQ(s, "@@ -", 4)) { | 
|---|
| 424 |  | 
|---|
| 425 | /* `name' and `p_timestamp' are backwards; swap them.  */ | 
|---|
| 426 | time_t ti = p_timestamp[OLD]; | 
|---|
| 427 | p_timestamp[OLD] = p_timestamp[NEW]; | 
|---|
| 428 | p_timestamp[NEW] = ti; | 
|---|
| 429 | t = name[OLD]; | 
|---|
| 430 | name[OLD] = name[NEW]; | 
|---|
| 431 | name[NEW] = t; | 
|---|
| 432 |  | 
|---|
| 433 | s += 4; | 
|---|
| 434 | if (s[0] == '0' && !ISDIGIT (s[1])) | 
|---|
| 435 | p_says_nonexistent[OLD] = 1 + ! p_timestamp[OLD]; | 
|---|
| 436 | while (*s != ' ' && *s != '\n') | 
|---|
| 437 | s++; | 
|---|
| 438 | while (*s == ' ') | 
|---|
| 439 | s++; | 
|---|
| 440 | if (s[0] == '+' && s[1] == '0' && !ISDIGIT (s[2])) | 
|---|
| 441 | p_says_nonexistent[NEW] = 1 + ! p_timestamp[NEW]; | 
|---|
| 442 | p_indent = indent; | 
|---|
| 443 | p_start = this_line; | 
|---|
| 444 | p_sline = p_input_line; | 
|---|
| 445 | retval = UNI_DIFF; | 
|---|
| 446 | if (! ((name[OLD] || ! p_timestamp[OLD]) | 
|---|
| 447 | && (name[NEW] || ! p_timestamp[NEW])) | 
|---|
| 448 | && ! name[INDEX]) | 
|---|
| 449 | { | 
|---|
| 450 | char numbuf[LINENUM_LENGTH_BOUND + 1]; | 
|---|
| 451 | say ("missing header for unified diff at line %s of patch\n", | 
|---|
| 452 | format_linenum (numbuf, p_sline)); | 
|---|
| 453 | } | 
|---|
| 454 | goto scan_exit; | 
|---|
| 455 | } | 
|---|
| 456 | stars_this_line = strnEQ(s, "********", 8); | 
|---|
| 457 | if ((diff_type == NO_DIFF | 
|---|
| 458 | || diff_type == CONTEXT_DIFF | 
|---|
| 459 | || diff_type == NEW_CONTEXT_DIFF) | 
|---|
| 460 | && stars_last_line && strnEQ (s, "*** ", 4)) { | 
|---|
| 461 | s += 4; | 
|---|
| 462 | if (s[0] == '0' && !ISDIGIT (s[1])) | 
|---|
| 463 | p_says_nonexistent[OLD] = 1 + ! p_timestamp[OLD]; | 
|---|
| 464 | /* if this is a new context diff the character just before */ | 
|---|
| 465 | /* the newline is a '*'. */ | 
|---|
| 466 | while (*s != '\n') | 
|---|
| 467 | s++; | 
|---|
| 468 | p_indent = indent; | 
|---|
| 469 | p_strip_trailing_cr = strip_trailing_cr; | 
|---|
| 470 | p_start = previous_line; | 
|---|
| 471 | p_sline = p_input_line - 1; | 
|---|
| 472 | retval = (*(s-1) == '*' ? NEW_CONTEXT_DIFF : CONTEXT_DIFF); | 
|---|
| 473 |  | 
|---|
| 474 | { | 
|---|
| 475 | /* Scan the first hunk to see whether the file contents | 
|---|
| 476 | appear to have been deleted.  */ | 
|---|
| 477 | file_offset saved_p_base = p_base; | 
|---|
| 478 | LINENUM saved_p_bline = p_bline; | 
|---|
| 479 | Fseek (pfp, previous_line, SEEK_SET); | 
|---|
| 480 | p_input_line -= 2; | 
|---|
| 481 | if (another_hunk (retval, false) | 
|---|
| 482 | && ! p_repl_lines && p_newfirst == 1) | 
|---|
| 483 | p_says_nonexistent[NEW] = 1 + ! p_timestamp[NEW]; | 
|---|
| 484 | next_intuit_at (saved_p_base, saved_p_bline); | 
|---|
| 485 | } | 
|---|
| 486 |  | 
|---|
| 487 | if (! ((name[OLD] || ! p_timestamp[OLD]) | 
|---|
| 488 | && (name[NEW] || ! p_timestamp[NEW])) | 
|---|
| 489 | && ! name[INDEX]) | 
|---|
| 490 | { | 
|---|
| 491 | char numbuf[LINENUM_LENGTH_BOUND + 1]; | 
|---|
| 492 | say ("missing header for context diff at line %s of patch\n", | 
|---|
| 493 | format_linenum (numbuf, p_sline)); | 
|---|
| 494 | } | 
|---|
| 495 | goto scan_exit; | 
|---|
| 496 | } | 
|---|
| 497 | if ((diff_type == NO_DIFF || diff_type == NORMAL_DIFF) && | 
|---|
| 498 | last_line_was_command && | 
|---|
| 499 | (strnEQ(s, "< ", 2) || strnEQ(s, "> ", 2)) ) { | 
|---|
| 500 | p_start = previous_line; | 
|---|
| 501 | p_sline = p_input_line - 1; | 
|---|
| 502 | p_indent = indent; | 
|---|
| 503 | p_strip_trailing_cr = strip_trailing_cr; | 
|---|
| 504 | retval = NORMAL_DIFF; | 
|---|
| 505 | goto scan_exit; | 
|---|
| 506 | } | 
|---|
| 507 | } | 
|---|
| 508 |  | 
|---|
| 509 | scan_exit: | 
|---|
| 510 |  | 
|---|
| 511 | /* To intuit `inname', the name of the file to patch, | 
|---|
| 512 | use the algorithm specified by POSIX 1003.1-2001 XCU lines 25680-26599 | 
|---|
| 513 | (with some modifications if posixly_correct is zero): | 
|---|
| 514 |  | 
|---|
| 515 | - Take the old and new names from the context header if present, | 
|---|
| 516 | and take the index name from the `Index:' line if present and | 
|---|
| 517 | if either the old and new names are both absent | 
|---|
| 518 | or posixly_correct is nonzero. | 
|---|
| 519 | Consider the file names to be in the order (old, new, index). | 
|---|
| 520 | - If some named files exist, use the first one if posixly_correct | 
|---|
| 521 | is nonzero, the best one otherwise. | 
|---|
| 522 | - If patch_get is nonzero, and no named files exist, | 
|---|
| 523 | but an RCS or SCCS master file exists, | 
|---|
| 524 | use the first named file with an RCS or SCCS master. | 
|---|
| 525 | - If no named files exist, no RCS or SCCS master was found, | 
|---|
| 526 | some names are given, posixly_correct is zero, | 
|---|
| 527 | and the patch appears to create a file, then use the best name | 
|---|
| 528 | requiring the creation of the fewest directories. | 
|---|
| 529 | - Otherwise, report failure by setting `inname' to 0; | 
|---|
| 530 | this causes our invoker to ask the user for a file name.  */ | 
|---|
| 531 |  | 
|---|
| 532 | i = NONE; | 
|---|
| 533 |  | 
|---|
| 534 | if (!inname) | 
|---|
| 535 | { | 
|---|
| 536 | enum nametype i0 = NONE; | 
|---|
| 537 |  | 
|---|
| 538 | if (! posixly_correct && (name[OLD] || name[NEW]) && name[INDEX]) | 
|---|
| 539 | { | 
|---|
| 540 | free (name[INDEX]); | 
|---|
| 541 | name[INDEX] = 0; | 
|---|
| 542 | } | 
|---|
| 543 |  | 
|---|
| 544 | for (i = OLD;  i <= INDEX;  i++) | 
|---|
| 545 | if (name[i]) | 
|---|
| 546 | { | 
|---|
| 547 | if (i0 != NONE && strcmp (name[i0], name[i]) == 0) | 
|---|
| 548 | { | 
|---|
| 549 | /* It's the same name as before; reuse stat results.  */ | 
|---|
| 550 | stat_errno[i] = stat_errno[i0]; | 
|---|
| 551 | if (! stat_errno[i]) | 
|---|
| 552 | st[i] = st[i0]; | 
|---|
| 553 | } | 
|---|
| 554 | else if (stat (name[i], &st[i]) != 0) | 
|---|
| 555 | stat_errno[i] = errno; | 
|---|
| 556 | else | 
|---|
| 557 | { | 
|---|
| 558 | stat_errno[i] = 0; | 
|---|
| 559 | if (posixly_correct) | 
|---|
| 560 | break; | 
|---|
| 561 | } | 
|---|
| 562 | i0 = i; | 
|---|
| 563 | } | 
|---|
| 564 |  | 
|---|
| 565 | if (! posixly_correct) | 
|---|
| 566 | { | 
|---|
| 567 | bool is_empty; | 
|---|
| 568 |  | 
|---|
| 569 | i = best_name (name, stat_errno); | 
|---|
| 570 |  | 
|---|
| 571 | if (i == NONE && patch_get) | 
|---|
| 572 | { | 
|---|
| 573 | enum nametype nope = NONE; | 
|---|
| 574 |  | 
|---|
| 575 | for (i = OLD;  i <= INDEX;  i++) | 
|---|
| 576 | if (name[i]) | 
|---|
| 577 | { | 
|---|
| 578 | char const *cs; | 
|---|
| 579 | char *getbuf; | 
|---|
| 580 | char *diffbuf; | 
|---|
| 581 | bool readonly = (outfile | 
|---|
| 582 | && strcmp (outfile, name[i]) != 0); | 
|---|
| 583 |  | 
|---|
| 584 | if (nope == NONE || strcmp (name[nope], name[i]) != 0) | 
|---|
| 585 | { | 
|---|
| 586 | cs = (version_controller | 
|---|
| 587 | (name[i], readonly, (struct stat *) 0, | 
|---|
| 588 | &getbuf, &diffbuf)); | 
|---|
| 589 | version_controlled[i] = !! cs; | 
|---|
| 590 | if (cs) | 
|---|
| 591 | { | 
|---|
| 592 | if (version_get (name[i], cs, false, readonly, | 
|---|
| 593 | getbuf, &st[i])) | 
|---|
| 594 | stat_errno[i] = 0; | 
|---|
| 595 | else | 
|---|
| 596 | version_controlled[i] = 0; | 
|---|
| 597 |  | 
|---|
| 598 | free (getbuf); | 
|---|
| 599 | if (diffbuf) | 
|---|
| 600 | free (diffbuf); | 
|---|
| 601 |  | 
|---|
| 602 | if (! stat_errno[i]) | 
|---|
| 603 | break; | 
|---|
| 604 | } | 
|---|
| 605 | } | 
|---|
| 606 |  | 
|---|
| 607 | nope = i; | 
|---|
| 608 | } | 
|---|
| 609 | } | 
|---|
| 610 |  | 
|---|
| 611 | is_empty = i == NONE || st[i].st_size == 0; | 
|---|
| 612 | if ((! is_empty) < p_says_nonexistent[reverse ^ is_empty]) | 
|---|
| 613 | { | 
|---|
| 614 | assert (i0 != NONE); | 
|---|
| 615 | reverse ^= | 
|---|
| 616 | ok_to_reverse | 
|---|
| 617 | ("The next patch%s would %s the file %s,\nwhich %s!", | 
|---|
| 618 | reverse ? ", when reversed," : "", | 
|---|
| 619 | (i == NONE ? "delete" | 
|---|
| 620 | : st[i].st_size == 0 ? "empty out" | 
|---|
| 621 | : "create"), | 
|---|
| 622 | quotearg (name[i == NONE || st[i].st_size == 0 ? i0 : i]), | 
|---|
| 623 | (i == NONE ? "does not exist" | 
|---|
| 624 | : st[i].st_size == 0 ? "is already empty" | 
|---|
| 625 | : "already exists")); | 
|---|
| 626 | } | 
|---|
| 627 |  | 
|---|
| 628 | if (i == NONE && p_says_nonexistent[reverse]) | 
|---|
| 629 | { | 
|---|
| 630 | int newdirs[3]; | 
|---|
| 631 | int newdirs_min = INT_MAX; | 
|---|
| 632 | int distance_from_minimum[3]; | 
|---|
| 633 |  | 
|---|
| 634 | for (i = OLD;  i <= INDEX;  i++) | 
|---|
| 635 | if (name[i]) | 
|---|
| 636 | { | 
|---|
| 637 | newdirs[i] = (prefix_components (name[i], false) | 
|---|
| 638 | - prefix_components (name[i], true)); | 
|---|
| 639 | if (newdirs[i] < newdirs_min) | 
|---|
| 640 | newdirs_min = newdirs[i]; | 
|---|
| 641 | } | 
|---|
| 642 |  | 
|---|
| 643 | for (i = OLD;  i <= INDEX;  i++) | 
|---|
| 644 | if (name[i]) | 
|---|
| 645 | distance_from_minimum[i] = newdirs[i] - newdirs_min; | 
|---|
| 646 |  | 
|---|
| 647 | i = best_name (name, distance_from_minimum); | 
|---|
| 648 | } | 
|---|
| 649 | } | 
|---|
| 650 | } | 
|---|
| 651 |  | 
|---|
| 652 | if (i == NONE) | 
|---|
| 653 | inerrno = -1; | 
|---|
| 654 | else | 
|---|
| 655 | { | 
|---|
| 656 | inname = name[i]; | 
|---|
| 657 | name[i] = 0; | 
|---|
| 658 | inerrno = stat_errno[i]; | 
|---|
| 659 | invc = version_controlled[i]; | 
|---|
| 660 | instat = st[i]; | 
|---|
| 661 | } | 
|---|
| 662 |  | 
|---|
| 663 | for (i = OLD;  i <= INDEX;  i++) | 
|---|
| 664 | if (name[i]) | 
|---|
| 665 | free (name[i]); | 
|---|
| 666 |  | 
|---|
| 667 | return retval; | 
|---|
| 668 | } | 
|---|
| 669 |  | 
|---|
| 670 | /* Count the path name components in FILENAME's prefix. | 
|---|
| 671 | If CHECKDIRS is true, count only existing directories.  */ | 
|---|
| 672 | static int | 
|---|
| 673 | prefix_components (char *filename, bool checkdirs) | 
|---|
| 674 | { | 
|---|
| 675 | int count = 0; | 
|---|
| 676 | struct stat stat_buf; | 
|---|
| 677 | int stat_result; | 
|---|
| 678 | char *f = filename + FILESYSTEM_PREFIX_LEN (filename); | 
|---|
| 679 |  | 
|---|
| 680 | if (*f) | 
|---|
| 681 | while (*++f) | 
|---|
| 682 | if (ISSLASH (f[0]) && ! ISSLASH (f[-1])) | 
|---|
| 683 | { | 
|---|
| 684 | if (checkdirs) | 
|---|
| 685 | { | 
|---|
| 686 | *f = '\0'; | 
|---|
| 687 | stat_result = stat (filename, &stat_buf); | 
|---|
| 688 | *f = '/'; | 
|---|
| 689 | if (! (stat_result == 0 && S_ISDIR (stat_buf.st_mode))) | 
|---|
| 690 | break; | 
|---|
| 691 | } | 
|---|
| 692 |  | 
|---|
| 693 | count++; | 
|---|
| 694 | } | 
|---|
| 695 |  | 
|---|
| 696 | return count; | 
|---|
| 697 | } | 
|---|
| 698 |  | 
|---|
| 699 | /* Return the index of the best of NAME[OLD], NAME[NEW], and NAME[INDEX]. | 
|---|
| 700 | Ignore null names, and ignore NAME[i] if IGNORE[i] is nonzero. | 
|---|
| 701 | Return NONE if all names are ignored.  */ | 
|---|
| 702 | static enum nametype | 
|---|
| 703 | best_name (char *const *name, int const *ignore) | 
|---|
| 704 | { | 
|---|
| 705 | enum nametype i; | 
|---|
| 706 | int components[3]; | 
|---|
| 707 | int components_min = INT_MAX; | 
|---|
| 708 | size_t basename_len[3]; | 
|---|
| 709 | size_t basename_len_min = SIZE_MAX; | 
|---|
| 710 | size_t len[3]; | 
|---|
| 711 | size_t len_min = SIZE_MAX; | 
|---|
| 712 |  | 
|---|
| 713 | for (i = OLD;  i <= INDEX;  i++) | 
|---|
| 714 | if (name[i] && !ignore[i]) | 
|---|
| 715 | { | 
|---|
| 716 | /* Take the names with the fewest prefix components.  */ | 
|---|
| 717 | components[i] = prefix_components (name[i], false); | 
|---|
| 718 | if (components_min < components[i]) | 
|---|
| 719 | continue; | 
|---|
| 720 | components_min = components[i]; | 
|---|
| 721 |  | 
|---|
| 722 | /* Of those, take the names with the shortest basename.  */ | 
|---|
| 723 | basename_len[i] = strlen (base_name (name[i])); | 
|---|
| 724 | if (basename_len_min < basename_len[i]) | 
|---|
| 725 | continue; | 
|---|
| 726 | basename_len_min = basename_len[i]; | 
|---|
| 727 |  | 
|---|
| 728 | /* Of those, take the shortest names.  */ | 
|---|
| 729 | len[i] = strlen (name[i]); | 
|---|
| 730 | if (len_min < len[i]) | 
|---|
| 731 | continue; | 
|---|
| 732 | len_min = len[i]; | 
|---|
| 733 | } | 
|---|
| 734 |  | 
|---|
| 735 | /* Of those, take the first name.  */ | 
|---|
| 736 | for (i = OLD;  i <= INDEX;  i++) | 
|---|
| 737 | if (name[i] && !ignore[i] | 
|---|
| 738 | && components[i] == components_min | 
|---|
| 739 | && basename_len[i] == basename_len_min | 
|---|
| 740 | && len[i] == len_min) | 
|---|
| 741 | break; | 
|---|
| 742 |  | 
|---|
| 743 | return i; | 
|---|
| 744 | } | 
|---|
| 745 |  | 
|---|
| 746 | /* Remember where this patch ends so we know where to start up again. */ | 
|---|
| 747 |  | 
|---|
| 748 | static void | 
|---|
| 749 | next_intuit_at (file_offset file_pos, LINENUM file_line) | 
|---|
| 750 | { | 
|---|
| 751 | p_base = file_pos; | 
|---|
| 752 | p_bline = file_line; | 
|---|
| 753 | } | 
|---|
| 754 |  | 
|---|
| 755 | /* Basically a verbose fseek() to the actual diff listing. */ | 
|---|
| 756 |  | 
|---|
| 757 | static void | 
|---|
| 758 | skip_to (file_offset file_pos, LINENUM file_line) | 
|---|
| 759 | { | 
|---|
| 760 | register FILE *i = pfp; | 
|---|
| 761 | register FILE *o = stdout; | 
|---|
| 762 | register int c; | 
|---|
| 763 |  | 
|---|
| 764 | assert(p_base <= file_pos); | 
|---|
| 765 | if ((verbosity == VERBOSE || !inname) && p_base < file_pos) { | 
|---|
| 766 | Fseek (i, p_base, SEEK_SET); | 
|---|
| 767 | say ("The text leading up to this was:\n--------------------------\n"); | 
|---|
| 768 |  | 
|---|
| 769 | while (file_tell (i) < file_pos) | 
|---|
| 770 | { | 
|---|
| 771 | putc ('|', o); | 
|---|
| 772 | do | 
|---|
| 773 | { | 
|---|
| 774 | if ((c = getc (i)) == EOF) | 
|---|
| 775 | read_fatal (); | 
|---|
| 776 | putc (c, o); | 
|---|
| 777 | } | 
|---|
| 778 | while (c != '\n'); | 
|---|
| 779 | } | 
|---|
| 780 |  | 
|---|
| 781 | say ("--------------------------\n"); | 
|---|
| 782 | } | 
|---|
| 783 | else | 
|---|
| 784 | Fseek (i, file_pos, SEEK_SET); | 
|---|
| 785 | p_input_line = file_line - 1; | 
|---|
| 786 | } | 
|---|
| 787 |  | 
|---|
| 788 | /* Make this a function for better debugging.  */ | 
|---|
| 789 | static void | 
|---|
| 790 | malformed (void) | 
|---|
| 791 | { | 
|---|
| 792 | char numbuf[LINENUM_LENGTH_BOUND + 1]; | 
|---|
| 793 | fatal ("malformed patch at line %s: %s", | 
|---|
| 794 | format_linenum (numbuf, p_input_line), buf); | 
|---|
| 795 | /* about as informative as "Syntax error" in C */ | 
|---|
| 796 | } | 
|---|
| 797 |  | 
|---|
| 798 | /* Parse a line number from a string. | 
|---|
| 799 | Return the address of the first char after the number.  */ | 
|---|
| 800 | static char * | 
|---|
| 801 | scan_linenum (char *s0, LINENUM *linenum) | 
|---|
| 802 | { | 
|---|
| 803 | char *s; | 
|---|
| 804 | LINENUM n = 0; | 
|---|
| 805 | bool overflow = false; | 
|---|
| 806 | char numbuf[LINENUM_LENGTH_BOUND + 1]; | 
|---|
| 807 |  | 
|---|
| 808 | for (s = s0;  ISDIGIT (*s);  s++) | 
|---|
| 809 | { | 
|---|
| 810 | LINENUM new_n = 10 * n + (*s - '0'); | 
|---|
| 811 | overflow |= new_n / 10 != n; | 
|---|
| 812 | n = new_n; | 
|---|
| 813 | } | 
|---|
| 814 |  | 
|---|
| 815 | if (s == s0) | 
|---|
| 816 | fatal ("missing line number at line %s: %s", | 
|---|
| 817 | format_linenum (numbuf, p_input_line), buf); | 
|---|
| 818 |  | 
|---|
| 819 | if (overflow) | 
|---|
| 820 | fatal ("line number %.*s is too large at line %s: %s", | 
|---|
| 821 | (int) (s - s0), s0, format_linenum (numbuf, p_input_line), buf); | 
|---|
| 822 |  | 
|---|
| 823 | *linenum = n; | 
|---|
| 824 | return s; | 
|---|
| 825 | } | 
|---|
| 826 |  | 
|---|
| 827 | /* 1 if there is more of the current diff listing to process; | 
|---|
| 828 | 0 if not; -1 if ran out of memory. */ | 
|---|
| 829 |  | 
|---|
| 830 | int | 
|---|
| 831 | another_hunk (enum diff difftype, bool rev) | 
|---|
| 832 | { | 
|---|
| 833 | register char *s; | 
|---|
| 834 | register LINENUM context = 0; | 
|---|
| 835 | register size_t chars_read; | 
|---|
| 836 | char numbuf0[LINENUM_LENGTH_BOUND + 1]; | 
|---|
| 837 | char numbuf1[LINENUM_LENGTH_BOUND + 1]; | 
|---|
| 838 | char numbuf2[LINENUM_LENGTH_BOUND + 1]; | 
|---|
| 839 | char numbuf3[LINENUM_LENGTH_BOUND + 1]; | 
|---|
| 840 |  | 
|---|
| 841 | while (p_end >= 0) { | 
|---|
| 842 | if (p_end == p_efake) | 
|---|
| 843 | p_end = p_bfake;            /* don't free twice */ | 
|---|
| 844 | else | 
|---|
| 845 | free(p_line[p_end]); | 
|---|
| 846 | p_end--; | 
|---|
| 847 | } | 
|---|
| 848 | assert(p_end == -1); | 
|---|
| 849 | p_efake = -1; | 
|---|
| 850 |  | 
|---|
| 851 | p_max = hunkmax;                    /* gets reduced when --- found */ | 
|---|
| 852 | if (difftype == CONTEXT_DIFF || difftype == NEW_CONTEXT_DIFF) { | 
|---|
| 853 | file_offset line_beginning = file_tell (pfp); | 
|---|
| 854 | /* file pos of the current line */ | 
|---|
| 855 | LINENUM repl_beginning = 0;     /* index of --- line */ | 
|---|
| 856 | register LINENUM fillcnt = 0;   /* #lines of missing ptrn or repl */ | 
|---|
| 857 | register LINENUM fillsrc;       /* index of first line to copy */ | 
|---|
| 858 | register LINENUM filldst;       /* index of first missing line */ | 
|---|
| 859 | bool ptrn_spaces_eaten = false; /* ptrn was slightly misformed */ | 
|---|
| 860 | bool some_context = false;      /* (perhaps internal) context seen */ | 
|---|
| 861 | register bool repl_could_be_missing = true; | 
|---|
| 862 | bool ptrn_missing = false;      /* The pattern was missing.  */ | 
|---|
| 863 | bool repl_missing = false;      /* Likewise for replacement.  */ | 
|---|
| 864 | file_offset repl_backtrack_position = 0; | 
|---|
| 865 | /* file pos of first repl line */ | 
|---|
| 866 | LINENUM repl_patch_line;        /* input line number for same */ | 
|---|
| 867 | LINENUM repl_context;           /* context for same */ | 
|---|
| 868 | LINENUM ptrn_prefix_context = -1; /* lines in pattern prefix context */ | 
|---|
| 869 | LINENUM ptrn_suffix_context = -1; /* lines in pattern suffix context */ | 
|---|
| 870 | LINENUM repl_prefix_context = -1; /* lines in replac. prefix context */ | 
|---|
| 871 | LINENUM ptrn_copiable = 0;      /* # of copiable lines in ptrn */ | 
|---|
| 872 | LINENUM repl_copiable = 0;      /* Likewise for replacement.  */ | 
|---|
| 873 |  | 
|---|
| 874 | /* Pacify `gcc -Wall'.  */ | 
|---|
| 875 | fillsrc = filldst = repl_patch_line = repl_context = 0; | 
|---|
| 876 |  | 
|---|
| 877 | chars_read = get_line (); | 
|---|
| 878 | if (chars_read == (size_t) -1 | 
|---|
| 879 | || chars_read <= 8 | 
|---|
| 880 | || strncmp (buf, "********", 8) != 0) { | 
|---|
| 881 | next_intuit_at(line_beginning,p_input_line); | 
|---|
| 882 | return chars_read == (size_t) -1 ? -1 : 0; | 
|---|
| 883 | } | 
|---|
| 884 | p_hunk_beg = p_input_line + 1; | 
|---|
| 885 | while (p_end < p_max) { | 
|---|
| 886 | chars_read = get_line (); | 
|---|
| 887 | if (chars_read == (size_t) -1) | 
|---|
| 888 | return -1; | 
|---|
| 889 | if (!chars_read) { | 
|---|
| 890 | if (repl_beginning && repl_could_be_missing) { | 
|---|
| 891 | repl_missing = true; | 
|---|
| 892 | goto hunk_done; | 
|---|
| 893 | } | 
|---|
| 894 | if (p_max - p_end < 4) { | 
|---|
| 895 | strcpy (buf, "  \n");  /* assume blank lines got chopped */ | 
|---|
| 896 | chars_read = 3; | 
|---|
| 897 | } else { | 
|---|
| 898 | fatal ("unexpected end of file in patch"); | 
|---|
| 899 | } | 
|---|
| 900 | } | 
|---|
| 901 | p_end++; | 
|---|
| 902 | if (p_end == hunkmax) | 
|---|
| 903 | fatal ("unterminated hunk starting at line %s; giving up at line %s: %s", | 
|---|
| 904 | format_linenum (numbuf0, pch_hunk_beg ()), | 
|---|
| 905 | format_linenum (numbuf1, p_input_line), buf); | 
|---|
| 906 | assert(p_end < hunkmax); | 
|---|
| 907 | p_Char[p_end] = *buf; | 
|---|
| 908 | p_len[p_end] = 0; | 
|---|
| 909 | p_line[p_end] = 0; | 
|---|
| 910 | switch (*buf) { | 
|---|
| 911 | case '*': | 
|---|
| 912 | if (strnEQ(buf, "********", 8)) { | 
|---|
| 913 | if (repl_beginning && repl_could_be_missing) { | 
|---|
| 914 | repl_missing = true; | 
|---|
| 915 | goto hunk_done; | 
|---|
| 916 | } | 
|---|
| 917 | else | 
|---|
| 918 | fatal ("unexpected end of hunk at line %s", | 
|---|
| 919 | format_linenum (numbuf0, p_input_line)); | 
|---|
| 920 | } | 
|---|
| 921 | if (p_end != 0) { | 
|---|
| 922 | if (repl_beginning && repl_could_be_missing) { | 
|---|
| 923 | repl_missing = true; | 
|---|
| 924 | goto hunk_done; | 
|---|
| 925 | } | 
|---|
| 926 | fatal ("unexpected `***' at line %s: %s", | 
|---|
| 927 | format_linenum (numbuf0, p_input_line), buf); | 
|---|
| 928 | } | 
|---|
| 929 | context = 0; | 
|---|
| 930 | p_len[p_end] = strlen (buf); | 
|---|
| 931 | if (! (p_line[p_end] = savestr (buf))) { | 
|---|
| 932 | p_end--; | 
|---|
| 933 | return -1; | 
|---|
| 934 | } | 
|---|
| 935 | for (s = buf;  *s && !ISDIGIT (*s);  s++) | 
|---|
| 936 | continue; | 
|---|
| 937 | if (strnEQ(s,"0,0",3)) | 
|---|
| 938 | remove_prefix (s, 2); | 
|---|
| 939 | s = scan_linenum (s, &p_first); | 
|---|
| 940 | if (*s == ',') { | 
|---|
| 941 | while (*s && !ISDIGIT (*s)) | 
|---|
| 942 | s++; | 
|---|
| 943 | scan_linenum (s, &p_ptrn_lines); | 
|---|
| 944 | p_ptrn_lines += 1 - p_first; | 
|---|
| 945 | } | 
|---|
| 946 | else if (p_first) | 
|---|
| 947 | p_ptrn_lines = 1; | 
|---|
| 948 | else { | 
|---|
| 949 | p_ptrn_lines = 0; | 
|---|
| 950 | p_first = 1; | 
|---|
| 951 | } | 
|---|
| 952 | p_max = p_ptrn_lines + 6;       /* we need this much at least */ | 
|---|
| 953 | while (p_max >= hunkmax) | 
|---|
| 954 | if (! grow_hunkmax ()) | 
|---|
| 955 | return -1; | 
|---|
| 956 | p_max = hunkmax; | 
|---|
| 957 | break; | 
|---|
| 958 | case '-': | 
|---|
| 959 | if (buf[1] != '-') | 
|---|
| 960 | goto change_line; | 
|---|
| 961 | if (ptrn_prefix_context == -1) | 
|---|
| 962 | ptrn_prefix_context = context; | 
|---|
| 963 | ptrn_suffix_context = context; | 
|---|
| 964 | if (repl_beginning | 
|---|
| 965 | || (p_end | 
|---|
| 966 | != p_ptrn_lines + 1 + (p_Char[p_end - 1] == '\n'))) | 
|---|
| 967 | { | 
|---|
| 968 | if (p_end == 1) | 
|---|
| 969 | { | 
|---|
| 970 | /* `Old' lines were omitted.  Set up to fill | 
|---|
| 971 | them in from `new' context lines.  */ | 
|---|
| 972 | ptrn_missing = true; | 
|---|
| 973 | p_end = p_ptrn_lines + 1; | 
|---|
| 974 | ptrn_prefix_context = ptrn_suffix_context = -1; | 
|---|
| 975 | fillsrc = p_end + 1; | 
|---|
| 976 | filldst = 1; | 
|---|
| 977 | fillcnt = p_ptrn_lines; | 
|---|
| 978 | } | 
|---|
| 979 | else if (! repl_beginning) | 
|---|
| 980 | fatal ("%s `---' at line %s; check line numbers at line %s", | 
|---|
| 981 | (p_end <= p_ptrn_lines | 
|---|
| 982 | ? "Premature" | 
|---|
| 983 | : "Overdue"), | 
|---|
| 984 | format_linenum (numbuf0, p_input_line), | 
|---|
| 985 | format_linenum (numbuf1, p_hunk_beg)); | 
|---|
| 986 | else if (! repl_could_be_missing) | 
|---|
| 987 | fatal ("duplicate `---' at line %s; check line numbers at line %s", | 
|---|
| 988 | format_linenum (numbuf0, p_input_line), | 
|---|
| 989 | format_linenum (numbuf1, | 
|---|
| 990 | p_hunk_beg + repl_beginning)); | 
|---|
| 991 | else | 
|---|
| 992 | { | 
|---|
| 993 | repl_missing = true; | 
|---|
| 994 | goto hunk_done; | 
|---|
| 995 | } | 
|---|
| 996 | } | 
|---|
| 997 | repl_beginning = p_end; | 
|---|
| 998 | repl_backtrack_position = file_tell (pfp); | 
|---|
| 999 | repl_patch_line = p_input_line; | 
|---|
| 1000 | repl_context = context; | 
|---|
| 1001 | p_len[p_end] = strlen (buf); | 
|---|
| 1002 | if (! (p_line[p_end] = savestr (buf))) | 
|---|
| 1003 | { | 
|---|
| 1004 | p_end--; | 
|---|
| 1005 | return -1; | 
|---|
| 1006 | } | 
|---|
| 1007 | p_Char[p_end] = '='; | 
|---|
| 1008 | for (s = buf;  *s && ! ISDIGIT (*s);  s++) | 
|---|
| 1009 | continue; | 
|---|
| 1010 | s = scan_linenum (s, &p_newfirst); | 
|---|
| 1011 | if (*s == ',') | 
|---|
| 1012 | { | 
|---|
| 1013 | do | 
|---|
| 1014 | { | 
|---|
| 1015 | if (!*++s) | 
|---|
| 1016 | malformed (); | 
|---|
| 1017 | } | 
|---|
| 1018 | while (! ISDIGIT (*s)); | 
|---|
| 1019 | scan_linenum (s, &p_repl_lines); | 
|---|
| 1020 | p_repl_lines += 1 - p_newfirst; | 
|---|
| 1021 | } | 
|---|
| 1022 | else if (p_newfirst) | 
|---|
| 1023 | p_repl_lines = 1; | 
|---|
| 1024 | else | 
|---|
| 1025 | { | 
|---|
| 1026 | p_repl_lines = 0; | 
|---|
| 1027 | p_newfirst = 1; | 
|---|
| 1028 | } | 
|---|
| 1029 | p_max = p_repl_lines + p_end; | 
|---|
| 1030 | while (p_max >= hunkmax) | 
|---|
| 1031 | if (! grow_hunkmax ()) | 
|---|
| 1032 | return -1; | 
|---|
| 1033 | if (p_repl_lines != ptrn_copiable | 
|---|
| 1034 | && (p_prefix_context != 0 | 
|---|
| 1035 | || context != 0 | 
|---|
| 1036 | || p_repl_lines != 1)) | 
|---|
| 1037 | repl_could_be_missing = false; | 
|---|
| 1038 | context = 0; | 
|---|
| 1039 | break; | 
|---|
| 1040 | case '+':  case '!': | 
|---|
| 1041 | repl_could_be_missing = false; | 
|---|
| 1042 | change_line: | 
|---|
| 1043 | s = buf + 1; | 
|---|
| 1044 | chars_read--; | 
|---|
| 1045 | if (*s == '\n' && canonicalize) { | 
|---|
| 1046 | strcpy (s, " \n"); | 
|---|
| 1047 | chars_read = 2; | 
|---|
| 1048 | } | 
|---|
| 1049 | if (*s == ' ' || *s == '\t') { | 
|---|
| 1050 | s++; | 
|---|
| 1051 | chars_read--; | 
|---|
| 1052 | } else if (repl_beginning && repl_could_be_missing) { | 
|---|
| 1053 | repl_missing = true; | 
|---|
| 1054 | goto hunk_done; | 
|---|
| 1055 | } | 
|---|
| 1056 | if (! repl_beginning) | 
|---|
| 1057 | { | 
|---|
| 1058 | if (ptrn_prefix_context == -1) | 
|---|
| 1059 | ptrn_prefix_context = context; | 
|---|
| 1060 | } | 
|---|
| 1061 | else | 
|---|
| 1062 | { | 
|---|
| 1063 | if (repl_prefix_context == -1) | 
|---|
| 1064 | repl_prefix_context = context; | 
|---|
| 1065 | } | 
|---|
| 1066 | chars_read -= | 
|---|
| 1067 | (1 < chars_read | 
|---|
| 1068 | && p_end == (repl_beginning ? p_max : p_ptrn_lines) | 
|---|
| 1069 | && incomplete_line ()); | 
|---|
| 1070 | p_len[p_end] = chars_read; | 
|---|
| 1071 | if (! (p_line[p_end] = savebuf (s, chars_read))) { | 
|---|
| 1072 | p_end--; | 
|---|
| 1073 | return -1; | 
|---|
| 1074 | } | 
|---|
| 1075 | context = 0; | 
|---|
| 1076 | break; | 
|---|
| 1077 | case '\t': case '\n':       /* assume spaces got eaten */ | 
|---|
| 1078 | s = buf; | 
|---|
| 1079 | if (*buf == '\t') { | 
|---|
| 1080 | s++; | 
|---|
| 1081 | chars_read--; | 
|---|
| 1082 | } | 
|---|
| 1083 | if (repl_beginning && repl_could_be_missing && | 
|---|
| 1084 | (!ptrn_spaces_eaten || difftype == NEW_CONTEXT_DIFF) ) { | 
|---|
| 1085 | repl_missing = true; | 
|---|
| 1086 | goto hunk_done; | 
|---|
| 1087 | } | 
|---|
| 1088 | chars_read -= | 
|---|
| 1089 | (1 < chars_read | 
|---|
| 1090 | && p_end == (repl_beginning ? p_max : p_ptrn_lines) | 
|---|
| 1091 | && incomplete_line ()); | 
|---|
| 1092 | p_len[p_end] = chars_read; | 
|---|
| 1093 | if (! (p_line[p_end] = savebuf (buf, chars_read))) { | 
|---|
| 1094 | p_end--; | 
|---|
| 1095 | return -1; | 
|---|
| 1096 | } | 
|---|
| 1097 | if (p_end != p_ptrn_lines + 1) { | 
|---|
| 1098 | ptrn_spaces_eaten |= (repl_beginning != 0); | 
|---|
| 1099 | some_context = true; | 
|---|
| 1100 | context++; | 
|---|
| 1101 | if (repl_beginning) | 
|---|
| 1102 | repl_copiable++; | 
|---|
| 1103 | else | 
|---|
| 1104 | ptrn_copiable++; | 
|---|
| 1105 | p_Char[p_end] = ' '; | 
|---|
| 1106 | } | 
|---|
| 1107 | break; | 
|---|
| 1108 | case ' ': | 
|---|
| 1109 | s = buf + 1; | 
|---|
| 1110 | chars_read--; | 
|---|
| 1111 | if (*s == '\n' && canonicalize) { | 
|---|
| 1112 | strcpy (s, "\n"); | 
|---|
| 1113 | chars_read = 2; | 
|---|
| 1114 | } | 
|---|
| 1115 | if (*s == ' ' || *s == '\t') { | 
|---|
| 1116 | s++; | 
|---|
| 1117 | chars_read--; | 
|---|
| 1118 | } else if (repl_beginning && repl_could_be_missing) { | 
|---|
| 1119 | repl_missing = true; | 
|---|
| 1120 | goto hunk_done; | 
|---|
| 1121 | } | 
|---|
| 1122 | some_context = true; | 
|---|
| 1123 | context++; | 
|---|
| 1124 | if (repl_beginning) | 
|---|
| 1125 | repl_copiable++; | 
|---|
| 1126 | else | 
|---|
| 1127 | ptrn_copiable++; | 
|---|
| 1128 | chars_read -= | 
|---|
| 1129 | (1 < chars_read | 
|---|
| 1130 | && p_end == (repl_beginning ? p_max : p_ptrn_lines) | 
|---|
| 1131 | && incomplete_line ()); | 
|---|
| 1132 | p_len[p_end] = chars_read; | 
|---|
| 1133 | if (! (p_line[p_end] = savebuf (buf + 2, chars_read))) { | 
|---|
| 1134 | p_end--; | 
|---|
| 1135 | return -1; | 
|---|
| 1136 | } | 
|---|
| 1137 | break; | 
|---|
| 1138 | default: | 
|---|
| 1139 | if (repl_beginning && repl_could_be_missing) { | 
|---|
| 1140 | repl_missing = true; | 
|---|
| 1141 | goto hunk_done; | 
|---|
| 1142 | } | 
|---|
| 1143 | malformed (); | 
|---|
| 1144 | } | 
|---|
| 1145 | } | 
|---|
| 1146 |  | 
|---|
| 1147 | hunk_done: | 
|---|
| 1148 | if (p_end >=0 && !repl_beginning) | 
|---|
| 1149 | fatal ("no `---' found in patch at line %s", | 
|---|
| 1150 | format_linenum (numbuf0, pch_hunk_beg ())); | 
|---|
| 1151 |  | 
|---|
| 1152 | if (repl_missing) { | 
|---|
| 1153 |  | 
|---|
| 1154 | /* reset state back to just after --- */ | 
|---|
| 1155 | p_input_line = repl_patch_line; | 
|---|
| 1156 | context = repl_context; | 
|---|
| 1157 | for (p_end--; p_end > repl_beginning; p_end--) | 
|---|
| 1158 | free(p_line[p_end]); | 
|---|
| 1159 | Fseek (pfp, repl_backtrack_position, SEEK_SET); | 
|---|
| 1160 |  | 
|---|
| 1161 | /* redundant 'new' context lines were omitted - set */ | 
|---|
| 1162 | /* up to fill them in from the old file context */ | 
|---|
| 1163 | fillsrc = 1; | 
|---|
| 1164 | filldst = repl_beginning+1; | 
|---|
| 1165 | fillcnt = p_repl_lines; | 
|---|
| 1166 | p_end = p_max; | 
|---|
| 1167 | } | 
|---|
| 1168 | else if (! ptrn_missing && ptrn_copiable != repl_copiable) | 
|---|
| 1169 | fatal ("context mangled in hunk at line %s", | 
|---|
| 1170 | format_linenum (numbuf0, p_hunk_beg)); | 
|---|
| 1171 | else if (!some_context && fillcnt == 1) { | 
|---|
| 1172 | /* the first hunk was a null hunk with no context */ | 
|---|
| 1173 | /* and we were expecting one line -- fix it up. */ | 
|---|
| 1174 | while (filldst < p_end) { | 
|---|
| 1175 | p_line[filldst] = p_line[filldst+1]; | 
|---|
| 1176 | p_Char[filldst] = p_Char[filldst+1]; | 
|---|
| 1177 | p_len[filldst] = p_len[filldst+1]; | 
|---|
| 1178 | filldst++; | 
|---|
| 1179 | } | 
|---|
| 1180 | #if 0 | 
|---|
| 1181 | repl_beginning--;           /* this doesn't need to be fixed */ | 
|---|
| 1182 | #endif | 
|---|
| 1183 | p_end--; | 
|---|
| 1184 | p_first++;                  /* do append rather than insert */ | 
|---|
| 1185 | fillcnt = 0; | 
|---|
| 1186 | p_ptrn_lines = 0; | 
|---|
| 1187 | } | 
|---|
| 1188 |  | 
|---|
| 1189 | p_prefix_context = ((repl_prefix_context == -1 | 
|---|
| 1190 | || (ptrn_prefix_context != -1 | 
|---|
| 1191 | && ptrn_prefix_context < repl_prefix_context)) | 
|---|
| 1192 | ? ptrn_prefix_context : repl_prefix_context); | 
|---|
| 1193 | p_suffix_context = ((ptrn_suffix_context != -1 | 
|---|
| 1194 | && ptrn_suffix_context < context) | 
|---|
| 1195 | ? ptrn_suffix_context : context); | 
|---|
| 1196 | assert (p_prefix_context != -1 && p_suffix_context != -1); | 
|---|
| 1197 |  | 
|---|
| 1198 | if (difftype == CONTEXT_DIFF | 
|---|
| 1199 | && (fillcnt | 
|---|
| 1200 | || (p_first > 1 | 
|---|
| 1201 | && p_prefix_context + p_suffix_context < ptrn_copiable))) { | 
|---|
| 1202 | if (verbosity == VERBOSE) | 
|---|
| 1203 | say ("%s\n%s\n%s\n", | 
|---|
| 1204 | "(Fascinating -- this is really a new-style context diff but without", | 
|---|
| 1205 | "the telltale extra asterisks on the *** line that usually indicate", | 
|---|
| 1206 | "the new style...)"); | 
|---|
| 1207 | diff_type = difftype = NEW_CONTEXT_DIFF; | 
|---|
| 1208 | } | 
|---|
| 1209 |  | 
|---|
| 1210 | /* if there were omitted context lines, fill them in now */ | 
|---|
| 1211 | if (fillcnt) { | 
|---|
| 1212 | p_bfake = filldst;          /* remember where not to free() */ | 
|---|
| 1213 | p_efake = filldst + fillcnt - 1; | 
|---|
| 1214 | while (fillcnt-- > 0) { | 
|---|
| 1215 | while (fillsrc <= p_end && fillsrc != repl_beginning | 
|---|
| 1216 | && p_Char[fillsrc] != ' ') | 
|---|
| 1217 | fillsrc++; | 
|---|
| 1218 | if (p_end < fillsrc || fillsrc == repl_beginning) | 
|---|
| 1219 | { | 
|---|
| 1220 | fatal ("replacement text or line numbers mangled in hunk at line %s", | 
|---|
| 1221 | format_linenum (numbuf0, p_hunk_beg)); | 
|---|
| 1222 | } | 
|---|
| 1223 | p_line[filldst] = p_line[fillsrc]; | 
|---|
| 1224 | p_Char[filldst] = p_Char[fillsrc]; | 
|---|
| 1225 | p_len[filldst] = p_len[fillsrc]; | 
|---|
| 1226 | fillsrc++; filldst++; | 
|---|
| 1227 | } | 
|---|
| 1228 | while (fillsrc <= p_end && fillsrc != repl_beginning) | 
|---|
| 1229 | { | 
|---|
| 1230 | if (p_Char[fillsrc] == ' ') | 
|---|
| 1231 | fatal ("replacement text or line numbers mangled in hunk at line %s", | 
|---|
| 1232 | format_linenum (numbuf0, p_hunk_beg)); | 
|---|
| 1233 | fillsrc++; | 
|---|
| 1234 | } | 
|---|
| 1235 | if (debug & 64) | 
|---|
| 1236 | printf ("fillsrc %s, filldst %s, rb %s, e+1 %s\n", | 
|---|
| 1237 | format_linenum (numbuf0, fillsrc), | 
|---|
| 1238 | format_linenum (numbuf1, filldst), | 
|---|
| 1239 | format_linenum (numbuf2, repl_beginning), | 
|---|
| 1240 | format_linenum (numbuf3, p_end + 1)); | 
|---|
| 1241 | assert(fillsrc==p_end+1 || fillsrc==repl_beginning); | 
|---|
| 1242 | assert(filldst==p_end+1 || filldst==repl_beginning); | 
|---|
| 1243 | } | 
|---|
| 1244 | } | 
|---|
| 1245 | else if (difftype == UNI_DIFF) { | 
|---|
| 1246 | file_offset line_beginning = file_tell (pfp); | 
|---|
| 1247 | /* file pos of the current line */ | 
|---|
| 1248 | register LINENUM fillsrc;       /* index of old lines */ | 
|---|
| 1249 | register LINENUM filldst;       /* index of new lines */ | 
|---|
| 1250 | char ch = '\0'; | 
|---|
| 1251 |  | 
|---|
| 1252 | chars_read = get_line (); | 
|---|
| 1253 | if (chars_read == (size_t) -1 | 
|---|
| 1254 | || chars_read <= 4 | 
|---|
| 1255 | || strncmp (buf, "@@ -", 4) != 0) { | 
|---|
| 1256 | next_intuit_at(line_beginning,p_input_line); | 
|---|
| 1257 | return chars_read == (size_t) -1 ? -1 : 0; | 
|---|
| 1258 | } | 
|---|
| 1259 | s = scan_linenum (buf + 4, &p_first); | 
|---|
| 1260 | if (*s == ',') | 
|---|
| 1261 | s = scan_linenum (s + 1, &p_ptrn_lines); | 
|---|
| 1262 | else | 
|---|
| 1263 | p_ptrn_lines = 1; | 
|---|
| 1264 | if (*s == ' ') s++; | 
|---|
| 1265 | if (*s != '+') | 
|---|
| 1266 | malformed (); | 
|---|
| 1267 | s = scan_linenum (s + 1, &p_newfirst); | 
|---|
| 1268 | if (*s == ',') | 
|---|
| 1269 | s = scan_linenum (s + 1, &p_repl_lines); | 
|---|
| 1270 | else | 
|---|
| 1271 | p_repl_lines = 1; | 
|---|
| 1272 | if (*s == ' ') s++; | 
|---|
| 1273 | if (*s != '@') | 
|---|
| 1274 | malformed (); | 
|---|
| 1275 | if (!p_ptrn_lines) | 
|---|
| 1276 | p_first++;                  /* do append rather than insert */ | 
|---|
| 1277 | if (!p_repl_lines) | 
|---|
| 1278 | p_newfirst++; | 
|---|
| 1279 | p_max = p_ptrn_lines + p_repl_lines + 1; | 
|---|
| 1280 | while (p_max >= hunkmax) | 
|---|
| 1281 | if (! grow_hunkmax ()) | 
|---|
| 1282 | return -1; | 
|---|
| 1283 | fillsrc = 1; | 
|---|
| 1284 | filldst = fillsrc + p_ptrn_lines; | 
|---|
| 1285 | p_end = filldst + p_repl_lines; | 
|---|
| 1286 | sprintf (buf, "*** %s,%s ****\n", | 
|---|
| 1287 | format_linenum (numbuf0, p_first), | 
|---|
| 1288 | format_linenum (numbuf1, p_first + p_ptrn_lines - 1)); | 
|---|
| 1289 | p_len[0] = strlen (buf); | 
|---|
| 1290 | if (! (p_line[0] = savestr (buf))) { | 
|---|
| 1291 | p_end = -1; | 
|---|
| 1292 | return -1; | 
|---|
| 1293 | } | 
|---|
| 1294 | p_Char[0] = '*'; | 
|---|
| 1295 | sprintf (buf, "--- %s,%s ----\n", | 
|---|
| 1296 | format_linenum (numbuf0, p_newfirst), | 
|---|
| 1297 | format_linenum (numbuf1, p_newfirst + p_repl_lines - 1)); | 
|---|
| 1298 | p_len[filldst] = strlen (buf); | 
|---|
| 1299 | if (! (p_line[filldst] = savestr (buf))) { | 
|---|
| 1300 | p_end = 0; | 
|---|
| 1301 | return -1; | 
|---|
| 1302 | } | 
|---|
| 1303 | p_Char[filldst++] = '='; | 
|---|
| 1304 | p_prefix_context = -1; | 
|---|
| 1305 | p_hunk_beg = p_input_line + 1; | 
|---|
| 1306 | while (fillsrc <= p_ptrn_lines || filldst <= p_end) { | 
|---|
| 1307 | chars_read = get_line (); | 
|---|
| 1308 | if (!chars_read) { | 
|---|
| 1309 | if (p_max - filldst < 3) { | 
|---|
| 1310 | strcpy (buf, " \n");  /* assume blank lines got chopped */ | 
|---|
| 1311 | chars_read = 2; | 
|---|
| 1312 | } else { | 
|---|
| 1313 | fatal ("unexpected end of file in patch"); | 
|---|
| 1314 | } | 
|---|
| 1315 | } | 
|---|
| 1316 | if (chars_read == (size_t) -1) | 
|---|
| 1317 | s = 0; | 
|---|
| 1318 | else if (*buf == '\t' || *buf == '\n') { | 
|---|
| 1319 | ch = ' ';               /* assume the space got eaten */ | 
|---|
| 1320 | s = savebuf (buf, chars_read); | 
|---|
| 1321 | } | 
|---|
| 1322 | else { | 
|---|
| 1323 | ch = *buf; | 
|---|
| 1324 | s = savebuf (buf+1, --chars_read); | 
|---|
| 1325 | } | 
|---|
| 1326 | if (!s) { | 
|---|
| 1327 | while (--filldst > p_ptrn_lines) | 
|---|
| 1328 | free(p_line[filldst]); | 
|---|
| 1329 | p_end = fillsrc-1; | 
|---|
| 1330 | return -1; | 
|---|
| 1331 | } | 
|---|
| 1332 | switch (ch) { | 
|---|
| 1333 | case '-': | 
|---|
| 1334 | if (fillsrc > p_ptrn_lines) { | 
|---|
| 1335 | free(s); | 
|---|
| 1336 | p_end = filldst-1; | 
|---|
| 1337 | malformed (); | 
|---|
| 1338 | } | 
|---|
| 1339 | chars_read -= fillsrc == p_ptrn_lines && incomplete_line (); | 
|---|
| 1340 | p_Char[fillsrc] = ch; | 
|---|
| 1341 | p_line[fillsrc] = s; | 
|---|
| 1342 | p_len[fillsrc++] = chars_read; | 
|---|
| 1343 | break; | 
|---|
| 1344 | case '=': | 
|---|
| 1345 | ch = ' '; | 
|---|
| 1346 | /* FALL THROUGH */ | 
|---|
| 1347 | case ' ': | 
|---|
| 1348 | if (fillsrc > p_ptrn_lines) { | 
|---|
| 1349 | free(s); | 
|---|
| 1350 | while (--filldst > p_ptrn_lines) | 
|---|
| 1351 | free(p_line[filldst]); | 
|---|
| 1352 | p_end = fillsrc-1; | 
|---|
| 1353 | malformed (); | 
|---|
| 1354 | } | 
|---|
| 1355 | context++; | 
|---|
| 1356 | chars_read -= fillsrc == p_ptrn_lines && incomplete_line (); | 
|---|
| 1357 | p_Char[fillsrc] = ch; | 
|---|
| 1358 | p_line[fillsrc] = s; | 
|---|
| 1359 | p_len[fillsrc++] = chars_read; | 
|---|
| 1360 | s = savebuf (s, chars_read); | 
|---|
| 1361 | if (!s) { | 
|---|
| 1362 | while (--filldst > p_ptrn_lines) | 
|---|
| 1363 | free(p_line[filldst]); | 
|---|
| 1364 | p_end = fillsrc-1; | 
|---|
| 1365 | return -1; | 
|---|
| 1366 | } | 
|---|
| 1367 | /* FALL THROUGH */ | 
|---|
| 1368 | case '+': | 
|---|
| 1369 | if (filldst > p_end) { | 
|---|
| 1370 | free(s); | 
|---|
| 1371 | while (--filldst > p_ptrn_lines) | 
|---|
| 1372 | free(p_line[filldst]); | 
|---|
| 1373 | p_end = fillsrc-1; | 
|---|
| 1374 | malformed (); | 
|---|
| 1375 | } | 
|---|
| 1376 | chars_read -= filldst == p_end && incomplete_line (); | 
|---|
| 1377 | p_Char[filldst] = ch; | 
|---|
| 1378 | p_line[filldst] = s; | 
|---|
| 1379 | p_len[filldst++] = chars_read; | 
|---|
| 1380 | break; | 
|---|
| 1381 | default: | 
|---|
| 1382 | p_end = filldst; | 
|---|
| 1383 | malformed (); | 
|---|
| 1384 | } | 
|---|
| 1385 | if (ch != ' ') { | 
|---|
| 1386 | if (p_prefix_context == -1) | 
|---|
| 1387 | p_prefix_context = context; | 
|---|
| 1388 | context = 0; | 
|---|
| 1389 | } | 
|---|
| 1390 | }/* while */ | 
|---|
| 1391 | if (p_prefix_context == -1) | 
|---|
| 1392 | malformed (); | 
|---|
| 1393 | p_suffix_context = context; | 
|---|
| 1394 | } | 
|---|
| 1395 | else {                              /* normal diff--fake it up */ | 
|---|
| 1396 | char hunk_type; | 
|---|
| 1397 | register int i; | 
|---|
| 1398 | LINENUM min, max; | 
|---|
| 1399 | file_offset line_beginning = file_tell (pfp); | 
|---|
| 1400 |  | 
|---|
| 1401 | p_prefix_context = p_suffix_context = 0; | 
|---|
| 1402 | chars_read = get_line (); | 
|---|
| 1403 | if (chars_read == (size_t) -1 || !chars_read || !ISDIGIT (*buf)) { | 
|---|
| 1404 | next_intuit_at(line_beginning,p_input_line); | 
|---|
| 1405 | return chars_read == (size_t) -1 ? -1 : 0; | 
|---|
| 1406 | } | 
|---|
| 1407 | s = scan_linenum (buf, &p_first); | 
|---|
| 1408 | if (*s == ',') { | 
|---|
| 1409 | s = scan_linenum (s + 1, &p_ptrn_lines); | 
|---|
| 1410 | p_ptrn_lines += 1 - p_first; | 
|---|
| 1411 | } | 
|---|
| 1412 | else | 
|---|
| 1413 | p_ptrn_lines = (*s != 'a'); | 
|---|
| 1414 | hunk_type = *s; | 
|---|
| 1415 | if (hunk_type == 'a') | 
|---|
| 1416 | p_first++;                  /* do append rather than insert */ | 
|---|
| 1417 | s = scan_linenum (s + 1, &min); | 
|---|
| 1418 | if (*s == ',') | 
|---|
| 1419 | scan_linenum (s + 1, &max); | 
|---|
| 1420 | else | 
|---|
| 1421 | max = min; | 
|---|
| 1422 | if (hunk_type == 'd') | 
|---|
| 1423 | min++; | 
|---|
| 1424 | p_end = p_ptrn_lines + 1 + max - min + 1; | 
|---|
| 1425 | while (p_end >= hunkmax) | 
|---|
| 1426 | if (! grow_hunkmax ()) | 
|---|
| 1427 | { | 
|---|
| 1428 | p_end = -1; | 
|---|
| 1429 | return -1; | 
|---|
| 1430 | } | 
|---|
| 1431 | p_newfirst = min; | 
|---|
| 1432 | p_repl_lines = max - min + 1; | 
|---|
| 1433 | sprintf (buf, "*** %s,%s\n", | 
|---|
| 1434 | format_linenum (numbuf0, p_first), | 
|---|
| 1435 | format_linenum (numbuf1, p_first + p_ptrn_lines - 1)); | 
|---|
| 1436 | p_len[0] = strlen (buf); | 
|---|
| 1437 | if (! (p_line[0] = savestr (buf))) { | 
|---|
| 1438 | p_end = -1; | 
|---|
| 1439 | return -1; | 
|---|
| 1440 | } | 
|---|
| 1441 | p_Char[0] = '*'; | 
|---|
| 1442 | for (i=1; i<=p_ptrn_lines; i++) { | 
|---|
| 1443 | chars_read = get_line (); | 
|---|
| 1444 | if (chars_read == (size_t) -1) | 
|---|
| 1445 | { | 
|---|
| 1446 | p_end = i - 1; | 
|---|
| 1447 | return -1; | 
|---|
| 1448 | } | 
|---|
| 1449 | if (!chars_read) | 
|---|
| 1450 | fatal ("unexpected end of file in patch at line %s", | 
|---|
| 1451 | format_linenum (numbuf0, p_input_line)); | 
|---|
| 1452 | if (buf[0] != '<' || (buf[1] != ' ' && buf[1] != '\t')) | 
|---|
| 1453 | fatal ("`<' expected at line %s of patch", | 
|---|
| 1454 | format_linenum (numbuf0, p_input_line)); | 
|---|
| 1455 | chars_read -= 2 + (i == p_ptrn_lines && incomplete_line ()); | 
|---|
| 1456 | p_len[i] = chars_read; | 
|---|
| 1457 | if (! (p_line[i] = savebuf (buf + 2, chars_read))) { | 
|---|
| 1458 | p_end = i-1; | 
|---|
| 1459 | return -1; | 
|---|
| 1460 | } | 
|---|
| 1461 | p_Char[i] = '-'; | 
|---|
| 1462 | } | 
|---|
| 1463 | if (hunk_type == 'c') { | 
|---|
| 1464 | chars_read = get_line (); | 
|---|
| 1465 | if (chars_read == (size_t) -1) | 
|---|
| 1466 | { | 
|---|
| 1467 | p_end = i - 1; | 
|---|
| 1468 | return -1; | 
|---|
| 1469 | } | 
|---|
| 1470 | if (! chars_read) | 
|---|
| 1471 | fatal ("unexpected end of file in patch at line %s", | 
|---|
| 1472 | format_linenum (numbuf0, p_input_line)); | 
|---|
| 1473 | if (*buf != '-') | 
|---|
| 1474 | fatal ("`---' expected at line %s of patch", | 
|---|
| 1475 | format_linenum (numbuf0, p_input_line)); | 
|---|
| 1476 | } | 
|---|
| 1477 | sprintf (buf, "--- %s,%s\n", | 
|---|
| 1478 | format_linenum (numbuf0, min), | 
|---|
| 1479 | format_linenum (numbuf1, max)); | 
|---|
| 1480 | p_len[i] = strlen (buf); | 
|---|
| 1481 | if (! (p_line[i] = savestr (buf))) { | 
|---|
| 1482 | p_end = i-1; | 
|---|
| 1483 | return -1; | 
|---|
| 1484 | } | 
|---|
| 1485 | p_Char[i] = '='; | 
|---|
| 1486 | for (i++; i<=p_end; i++) { | 
|---|
| 1487 | chars_read = get_line (); | 
|---|
| 1488 | if (chars_read == (size_t) -1) | 
|---|
| 1489 | { | 
|---|
| 1490 | p_end = i - 1; | 
|---|
| 1491 | return -1; | 
|---|
| 1492 | } | 
|---|
| 1493 | if (!chars_read) | 
|---|
| 1494 | fatal ("unexpected end of file in patch at line %s", | 
|---|
| 1495 | format_linenum (numbuf0, p_input_line)); | 
|---|
| 1496 | if (buf[0] != '>' || (buf[1] != ' ' && buf[1] != '\t')) | 
|---|
| 1497 | fatal ("`>' expected at line %s of patch", | 
|---|
| 1498 | format_linenum (numbuf0, p_input_line)); | 
|---|
| 1499 | chars_read -= 2 + (i == p_end && incomplete_line ()); | 
|---|
| 1500 | p_len[i] = chars_read; | 
|---|
| 1501 | if (! (p_line[i] = savebuf (buf + 2, chars_read))) { | 
|---|
| 1502 | p_end = i-1; | 
|---|
| 1503 | return -1; | 
|---|
| 1504 | } | 
|---|
| 1505 | p_Char[i] = '+'; | 
|---|
| 1506 | } | 
|---|
| 1507 | } | 
|---|
| 1508 | if (rev)                            /* backwards patch? */ | 
|---|
| 1509 | if (!pch_swap()) | 
|---|
| 1510 | say ("Not enough memory to swap next hunk!\n"); | 
|---|
| 1511 | if (debug & 2) { | 
|---|
| 1512 | LINENUM i; | 
|---|
| 1513 | char special; | 
|---|
| 1514 |  | 
|---|
| 1515 | for (i=0; i <= p_end; i++) { | 
|---|
| 1516 | if (i == p_ptrn_lines) | 
|---|
| 1517 | special = '^'; | 
|---|
| 1518 | else | 
|---|
| 1519 | special = ' '; | 
|---|
| 1520 | fprintf (stderr, "%s %c %c ", format_linenum (numbuf0, i), | 
|---|
| 1521 | p_Char[i], special); | 
|---|
| 1522 | pch_write_line (i, stderr); | 
|---|
| 1523 | fflush (stderr); | 
|---|
| 1524 | } | 
|---|
| 1525 | } | 
|---|
| 1526 | if (p_end+1 < hunkmax)      /* paranoia reigns supreme... */ | 
|---|
| 1527 | p_Char[p_end+1] = '^';  /* add a stopper for apply_hunk */ | 
|---|
| 1528 | return 1; | 
|---|
| 1529 | } | 
|---|
| 1530 |  | 
|---|
| 1531 | static size_t | 
|---|
| 1532 | get_line (void) | 
|---|
| 1533 | { | 
|---|
| 1534 | return pget_line (p_indent, p_rfc934_nesting, p_strip_trailing_cr, | 
|---|
| 1535 | p_pass_comments_through); | 
|---|
| 1536 | } | 
|---|
| 1537 |  | 
|---|
| 1538 | /* Input a line from the patch file, worrying about indentation. | 
|---|
| 1539 | Strip up to INDENT characters' worth of leading indentation. | 
|---|
| 1540 | Then remove up to RFC934_NESTING instances of leading "- ". | 
|---|
| 1541 | If STRIP_TRAILING_CR is true, remove any trailing carriage-return. | 
|---|
| 1542 | Unless PASS_COMMENTS_THROUGH is true, ignore any resulting lines | 
|---|
| 1543 | that begin with '#'; they're comments. | 
|---|
| 1544 | Ignore any partial lines at end of input, but warn about them. | 
|---|
| 1545 | Succeed if a line was read; it is terminated by "\n\0" for convenience. | 
|---|
| 1546 | Return the number of characters read, including '\n' but not '\0'. | 
|---|
| 1547 | Return -1 if we ran out of memory.  */ | 
|---|
| 1548 |  | 
|---|
| 1549 | static size_t | 
|---|
| 1550 | pget_line (int indent, int rfc934_nesting, bool strip_trailing_cr, | 
|---|
| 1551 | bool pass_comments_through) | 
|---|
| 1552 | { | 
|---|
| 1553 | register FILE *fp = pfp; | 
|---|
| 1554 | register int c; | 
|---|
| 1555 | register int i; | 
|---|
| 1556 | register char *b; | 
|---|
| 1557 | register size_t s; | 
|---|
| 1558 |  | 
|---|
| 1559 | do | 
|---|
| 1560 | { | 
|---|
| 1561 | i = 0; | 
|---|
| 1562 | for (;;) | 
|---|
| 1563 | { | 
|---|
| 1564 | c = getc (fp); | 
|---|
| 1565 | if (c == EOF) | 
|---|
| 1566 | { | 
|---|
| 1567 | if (ferror (fp)) | 
|---|
| 1568 | read_fatal (); | 
|---|
| 1569 | return 0; | 
|---|
| 1570 | } | 
|---|
| 1571 | if (indent <= i) | 
|---|
| 1572 | break; | 
|---|
| 1573 | if (c == ' ' || c == 'X') | 
|---|
| 1574 | i++; | 
|---|
| 1575 | else if (c == '\t') | 
|---|
| 1576 | i = (i + 8) & ~7; | 
|---|
| 1577 | else | 
|---|
| 1578 | break; | 
|---|
| 1579 | } | 
|---|
| 1580 |  | 
|---|
| 1581 | i = 0; | 
|---|
| 1582 | b = buf; | 
|---|
| 1583 |  | 
|---|
| 1584 | while (c == '-' && 0 <= --rfc934_nesting) | 
|---|
| 1585 | { | 
|---|
| 1586 | c = getc (fp); | 
|---|
| 1587 | if (c == EOF) | 
|---|
| 1588 | goto patch_ends_in_middle_of_line; | 
|---|
| 1589 | if (c != ' ') | 
|---|
| 1590 | { | 
|---|
| 1591 | i = 1; | 
|---|
| 1592 | b[0] = '-'; | 
|---|
| 1593 | break; | 
|---|
| 1594 | } | 
|---|
| 1595 | c = getc (fp); | 
|---|
| 1596 | if (c == EOF) | 
|---|
| 1597 | goto patch_ends_in_middle_of_line; | 
|---|
| 1598 | } | 
|---|
| 1599 |  | 
|---|
| 1600 | s = bufsize; | 
|---|
| 1601 |  | 
|---|
| 1602 | for (;;) | 
|---|
| 1603 | { | 
|---|
| 1604 | if (i == s - 1) | 
|---|
| 1605 | { | 
|---|
| 1606 | s *= 2; | 
|---|
| 1607 | b = realloc (b, s); | 
|---|
| 1608 | if (!b) | 
|---|
| 1609 | { | 
|---|
| 1610 | if (!using_plan_a) | 
|---|
| 1611 | memory_fatal (); | 
|---|
| 1612 | return (size_t) -1; | 
|---|
| 1613 | } | 
|---|
| 1614 | buf = b; | 
|---|
| 1615 | bufsize = s; | 
|---|
| 1616 | } | 
|---|
| 1617 | b[i++] = c; | 
|---|
| 1618 | if (c == '\n') | 
|---|
| 1619 | break; | 
|---|
| 1620 | c = getc (fp); | 
|---|
| 1621 | if (c == EOF) | 
|---|
| 1622 | goto patch_ends_in_middle_of_line; | 
|---|
| 1623 | } | 
|---|
| 1624 |  | 
|---|
| 1625 | p_input_line++; | 
|---|
| 1626 | } | 
|---|
| 1627 | while (*b == '#' && !pass_comments_through); | 
|---|
| 1628 |  | 
|---|
| 1629 | if (strip_trailing_cr && 2 <= i && b[i - 2] == '\r') | 
|---|
| 1630 | b[i-- - 2] = '\n'; | 
|---|
| 1631 | b[i] = '\0'; | 
|---|
| 1632 | return i; | 
|---|
| 1633 |  | 
|---|
| 1634 | patch_ends_in_middle_of_line: | 
|---|
| 1635 | if (ferror (fp)) | 
|---|
| 1636 | read_fatal (); | 
|---|
| 1637 | say ("patch unexpectedly ends in middle of line\n"); | 
|---|
| 1638 | return 0; | 
|---|
| 1639 | } | 
|---|
| 1640 |  | 
|---|
| 1641 | static bool | 
|---|
| 1642 | incomplete_line (void) | 
|---|
| 1643 | { | 
|---|
| 1644 | register FILE *fp = pfp; | 
|---|
| 1645 | register int c; | 
|---|
| 1646 | register file_offset line_beginning = file_tell (fp); | 
|---|
| 1647 |  | 
|---|
| 1648 | if (getc (fp) == '\\') | 
|---|
| 1649 | { | 
|---|
| 1650 | while ((c = getc (fp)) != '\n'  &&  c != EOF) | 
|---|
| 1651 | continue; | 
|---|
| 1652 | return true; | 
|---|
| 1653 | } | 
|---|
| 1654 | else | 
|---|
| 1655 | { | 
|---|
| 1656 | /* We don't trust ungetc.  */ | 
|---|
| 1657 | Fseek (pfp, line_beginning, SEEK_SET); | 
|---|
| 1658 | return false; | 
|---|
| 1659 | } | 
|---|
| 1660 | } | 
|---|
| 1661 |  | 
|---|
| 1662 | /* Reverse the old and new portions of the current hunk. */ | 
|---|
| 1663 |  | 
|---|
| 1664 | bool | 
|---|
| 1665 | pch_swap (void) | 
|---|
| 1666 | { | 
|---|
| 1667 | char **tp_line;             /* the text of the hunk */ | 
|---|
| 1668 | size_t *tp_len;             /* length of each line */ | 
|---|
| 1669 | char *tp_char;              /* +, -, and ! */ | 
|---|
| 1670 | register LINENUM i; | 
|---|
| 1671 | register LINENUM n; | 
|---|
| 1672 | bool blankline = false; | 
|---|
| 1673 | register char *s; | 
|---|
| 1674 |  | 
|---|
| 1675 | i = p_first; | 
|---|
| 1676 | p_first = p_newfirst; | 
|---|
| 1677 | p_newfirst = i; | 
|---|
| 1678 |  | 
|---|
| 1679 | /* make a scratch copy */ | 
|---|
| 1680 |  | 
|---|
| 1681 | tp_line = p_line; | 
|---|
| 1682 | tp_len = p_len; | 
|---|
| 1683 | tp_char = p_Char; | 
|---|
| 1684 | p_line = 0; /* force set_hunkmax to allocate again */ | 
|---|
| 1685 | p_len = 0; | 
|---|
| 1686 | p_Char = 0; | 
|---|
| 1687 | set_hunkmax(); | 
|---|
| 1688 | if (!p_line || !p_len || !p_Char) { | 
|---|
| 1689 | if (p_line) | 
|---|
| 1690 | free (p_line); | 
|---|
| 1691 | p_line = tp_line; | 
|---|
| 1692 | if (p_len) | 
|---|
| 1693 | free (p_len); | 
|---|
| 1694 | p_len = tp_len; | 
|---|
| 1695 | if (p_Char) | 
|---|
| 1696 | free (p_Char); | 
|---|
| 1697 | p_Char = tp_char; | 
|---|
| 1698 | return false;           /* not enough memory to swap hunk! */ | 
|---|
| 1699 | } | 
|---|
| 1700 |  | 
|---|
| 1701 | /* now turn the new into the old */ | 
|---|
| 1702 |  | 
|---|
| 1703 | i = p_ptrn_lines + 1; | 
|---|
| 1704 | if (tp_char[i] == '\n') {           /* account for possible blank line */ | 
|---|
| 1705 | blankline = true; | 
|---|
| 1706 | i++; | 
|---|
| 1707 | } | 
|---|
| 1708 | if (p_efake >= 0) {                 /* fix non-freeable ptr range */ | 
|---|
| 1709 | if (p_efake <= i) | 
|---|
| 1710 | n = p_end - i + 1; | 
|---|
| 1711 | else | 
|---|
| 1712 | n = -i; | 
|---|
| 1713 | p_efake += n; | 
|---|
| 1714 | p_bfake += n; | 
|---|
| 1715 | } | 
|---|
| 1716 | for (n=0; i <= p_end; i++,n++) { | 
|---|
| 1717 | p_line[n] = tp_line[i]; | 
|---|
| 1718 | p_Char[n] = tp_char[i]; | 
|---|
| 1719 | if (p_Char[n] == '+') | 
|---|
| 1720 | p_Char[n] = '-'; | 
|---|
| 1721 | p_len[n] = tp_len[i]; | 
|---|
| 1722 | } | 
|---|
| 1723 | if (blankline) { | 
|---|
| 1724 | i = p_ptrn_lines + 1; | 
|---|
| 1725 | p_line[n] = tp_line[i]; | 
|---|
| 1726 | p_Char[n] = tp_char[i]; | 
|---|
| 1727 | p_len[n] = tp_len[i]; | 
|---|
| 1728 | n++; | 
|---|
| 1729 | } | 
|---|
| 1730 | assert(p_Char[0] == '='); | 
|---|
| 1731 | p_Char[0] = '*'; | 
|---|
| 1732 | for (s=p_line[0]; *s; s++) | 
|---|
| 1733 | if (*s == '-') | 
|---|
| 1734 | *s = '*'; | 
|---|
| 1735 |  | 
|---|
| 1736 | /* now turn the old into the new */ | 
|---|
| 1737 |  | 
|---|
| 1738 | assert(tp_char[0] == '*'); | 
|---|
| 1739 | tp_char[0] = '='; | 
|---|
| 1740 | for (s=tp_line[0]; *s; s++) | 
|---|
| 1741 | if (*s == '*') | 
|---|
| 1742 | *s = '-'; | 
|---|
| 1743 | for (i=0; n <= p_end; i++,n++) { | 
|---|
| 1744 | p_line[n] = tp_line[i]; | 
|---|
| 1745 | p_Char[n] = tp_char[i]; | 
|---|
| 1746 | if (p_Char[n] == '-') | 
|---|
| 1747 | p_Char[n] = '+'; | 
|---|
| 1748 | p_len[n] = tp_len[i]; | 
|---|
| 1749 | } | 
|---|
| 1750 | assert(i == p_ptrn_lines + 1); | 
|---|
| 1751 | i = p_ptrn_lines; | 
|---|
| 1752 | p_ptrn_lines = p_repl_lines; | 
|---|
| 1753 | p_repl_lines = i; | 
|---|
| 1754 | if (tp_line) | 
|---|
| 1755 | free (tp_line); | 
|---|
| 1756 | if (tp_len) | 
|---|
| 1757 | free (tp_len); | 
|---|
| 1758 | if (tp_char) | 
|---|
| 1759 | free (tp_char); | 
|---|
| 1760 | return true; | 
|---|
| 1761 | } | 
|---|
| 1762 |  | 
|---|
| 1763 | /* Return whether file WHICH (false = old, true = new) appears to nonexistent. | 
|---|
| 1764 | Return 1 for empty, 2 for nonexistent.  */ | 
|---|
| 1765 |  | 
|---|
| 1766 | int | 
|---|
| 1767 | pch_says_nonexistent (bool which) | 
|---|
| 1768 | { | 
|---|
| 1769 | return p_says_nonexistent[which]; | 
|---|
| 1770 | } | 
|---|
| 1771 |  | 
|---|
| 1772 | /* Return timestamp of patch header for file WHICH (false = old, true = new), | 
|---|
| 1773 | or -1 if there was no timestamp or an error in the timestamp.  */ | 
|---|
| 1774 |  | 
|---|
| 1775 | time_t | 
|---|
| 1776 | pch_timestamp (bool which) | 
|---|
| 1777 | { | 
|---|
| 1778 | return p_timestamp[which]; | 
|---|
| 1779 | } | 
|---|
| 1780 |  | 
|---|
| 1781 | /* Return the specified line position in the old file of the old context. */ | 
|---|
| 1782 |  | 
|---|
| 1783 | LINENUM | 
|---|
| 1784 | pch_first (void) | 
|---|
| 1785 | { | 
|---|
| 1786 | return p_first; | 
|---|
| 1787 | } | 
|---|
| 1788 |  | 
|---|
| 1789 | /* Return the number of lines of old context. */ | 
|---|
| 1790 |  | 
|---|
| 1791 | LINENUM | 
|---|
| 1792 | pch_ptrn_lines (void) | 
|---|
| 1793 | { | 
|---|
| 1794 | return p_ptrn_lines; | 
|---|
| 1795 | } | 
|---|
| 1796 |  | 
|---|
| 1797 | /* Return the probable line position in the new file of the first line. */ | 
|---|
| 1798 |  | 
|---|
| 1799 | LINENUM | 
|---|
| 1800 | pch_newfirst (void) | 
|---|
| 1801 | { | 
|---|
| 1802 | return p_newfirst; | 
|---|
| 1803 | } | 
|---|
| 1804 |  | 
|---|
| 1805 | /* Return the number of lines in the replacement text including context. */ | 
|---|
| 1806 |  | 
|---|
| 1807 | LINENUM | 
|---|
| 1808 | pch_repl_lines (void) | 
|---|
| 1809 | { | 
|---|
| 1810 | return p_repl_lines; | 
|---|
| 1811 | } | 
|---|
| 1812 |  | 
|---|
| 1813 | /* Return the number of lines in the whole hunk. */ | 
|---|
| 1814 |  | 
|---|
| 1815 | LINENUM | 
|---|
| 1816 | pch_end (void) | 
|---|
| 1817 | { | 
|---|
| 1818 | return p_end; | 
|---|
| 1819 | } | 
|---|
| 1820 |  | 
|---|
| 1821 | /* Return the number of context lines before the first changed line. */ | 
|---|
| 1822 |  | 
|---|
| 1823 | LINENUM | 
|---|
| 1824 | pch_prefix_context (void) | 
|---|
| 1825 | { | 
|---|
| 1826 | return p_prefix_context; | 
|---|
| 1827 | } | 
|---|
| 1828 |  | 
|---|
| 1829 | /* Return the number of context lines after the last changed line. */ | 
|---|
| 1830 |  | 
|---|
| 1831 | LINENUM | 
|---|
| 1832 | pch_suffix_context (void) | 
|---|
| 1833 | { | 
|---|
| 1834 | return p_suffix_context; | 
|---|
| 1835 | } | 
|---|
| 1836 |  | 
|---|
| 1837 | /* Return the length of a particular patch line. */ | 
|---|
| 1838 |  | 
|---|
| 1839 | size_t | 
|---|
| 1840 | pch_line_len (LINENUM line) | 
|---|
| 1841 | { | 
|---|
| 1842 | return p_len[line]; | 
|---|
| 1843 | } | 
|---|
| 1844 |  | 
|---|
| 1845 | /* Return the control character (+, -, *, !, etc) for a patch line. */ | 
|---|
| 1846 |  | 
|---|
| 1847 | char | 
|---|
| 1848 | pch_char (LINENUM line) | 
|---|
| 1849 | { | 
|---|
| 1850 | return p_Char[line]; | 
|---|
| 1851 | } | 
|---|
| 1852 |  | 
|---|
| 1853 | /* Return a pointer to a particular patch line. */ | 
|---|
| 1854 |  | 
|---|
| 1855 | char * | 
|---|
| 1856 | pfetch (LINENUM line) | 
|---|
| 1857 | { | 
|---|
| 1858 | return p_line[line]; | 
|---|
| 1859 | } | 
|---|
| 1860 |  | 
|---|
| 1861 | /* Output a patch line.  */ | 
|---|
| 1862 |  | 
|---|
| 1863 | bool | 
|---|
| 1864 | pch_write_line (LINENUM line, FILE *file) | 
|---|
| 1865 | { | 
|---|
| 1866 | bool after_newline = p_line[line][p_len[line] - 1] == '\n'; | 
|---|
| 1867 | if (! fwrite (p_line[line], sizeof (*p_line[line]), p_len[line], file)) | 
|---|
| 1868 | write_fatal (); | 
|---|
| 1869 | return after_newline; | 
|---|
| 1870 | } | 
|---|
| 1871 |  | 
|---|
| 1872 | /* Return where in the patch file this hunk began, for error messages. */ | 
|---|
| 1873 |  | 
|---|
| 1874 | LINENUM | 
|---|
| 1875 | pch_hunk_beg (void) | 
|---|
| 1876 | { | 
|---|
| 1877 | return p_hunk_beg; | 
|---|
| 1878 | } | 
|---|
| 1879 |  | 
|---|
| 1880 | /* Is the newline-terminated line a valid `ed' command for patch | 
|---|
| 1881 | input?  If so, return the command character; if not, return 0. | 
|---|
| 1882 | This accepts accepts just a subset of the valid commands, but it's | 
|---|
| 1883 | good enough in practice.  */ | 
|---|
| 1884 |  | 
|---|
| 1885 | static char | 
|---|
| 1886 | get_ed_command_letter (char const *line) | 
|---|
| 1887 | { | 
|---|
| 1888 | char const *p = line; | 
|---|
| 1889 | char letter; | 
|---|
| 1890 | bool pair = false; | 
|---|
| 1891 | if (! ISDIGIT (*p)) | 
|---|
| 1892 | return 0; | 
|---|
| 1893 | while (ISDIGIT (*++p)) | 
|---|
| 1894 | continue; | 
|---|
| 1895 | if (*p == ',') | 
|---|
| 1896 | { | 
|---|
| 1897 | if (! ISDIGIT (*++p)) | 
|---|
| 1898 | return 0; | 
|---|
| 1899 | while (ISDIGIT (*++p)) | 
|---|
| 1900 | continue; | 
|---|
| 1901 | pair = true; | 
|---|
| 1902 | } | 
|---|
| 1903 | letter = *p++; | 
|---|
| 1904 |  | 
|---|
| 1905 | switch (letter) | 
|---|
| 1906 | { | 
|---|
| 1907 | case 'a': | 
|---|
| 1908 | case 'i': | 
|---|
| 1909 | if (pair) | 
|---|
| 1910 | return 0; | 
|---|
| 1911 | break; | 
|---|
| 1912 |  | 
|---|
| 1913 | case 'c': | 
|---|
| 1914 | case 'd': | 
|---|
| 1915 | break; | 
|---|
| 1916 |  | 
|---|
| 1917 | case 's': | 
|---|
| 1918 | if (strncmp (p, "/.//", 4) != 0) | 
|---|
| 1919 | return 0; | 
|---|
| 1920 | p += 4; | 
|---|
| 1921 | break; | 
|---|
| 1922 |  | 
|---|
| 1923 | default: | 
|---|
| 1924 | return 0; | 
|---|
| 1925 | } | 
|---|
| 1926 |  | 
|---|
| 1927 | while (*p == ' ' || *p == '\t') | 
|---|
| 1928 | p++; | 
|---|
| 1929 | if (*p == '\n') | 
|---|
| 1930 | return letter; | 
|---|
| 1931 | return 0; | 
|---|
| 1932 | } | 
|---|
| 1933 |  | 
|---|
| 1934 | /* Apply an ed script by feeding ed itself. */ | 
|---|
| 1935 |  | 
|---|
| 1936 | void | 
|---|
| 1937 | do_ed_script (FILE *ofp) | 
|---|
| 1938 | { | 
|---|
| 1939 | static char const ed_program[] = ed_PROGRAM; | 
|---|
| 1940 |  | 
|---|
| 1941 | register file_offset beginning_of_this_line; | 
|---|
| 1942 | register FILE *pipefp = 0; | 
|---|
| 1943 | register size_t chars_read; | 
|---|
| 1944 |  | 
|---|
| 1945 | if (! dry_run && ! skip_rest_of_patch) { | 
|---|
| 1946 | int exclusive = TMPOUTNAME_needs_removal ? 0 : O_EXCL; | 
|---|
| 1947 | assert (! inerrno); | 
|---|
| 1948 | TMPOUTNAME_needs_removal = 1; | 
|---|
| 1949 | copy_file (inname, TMPOUTNAME, exclusive, instat.st_mode); | 
|---|
| 1950 | sprintf (buf, "%s %s%s", ed_program, verbosity == VERBOSE ? "" : "- ", | 
|---|
| 1951 | TMPOUTNAME); | 
|---|
| 1952 | fflush (stdout); | 
|---|
| 1953 | pipefp = popen(buf, binary_transput ? "wb" : "w"); | 
|---|
| 1954 | if (!pipefp) | 
|---|
| 1955 | pfatal ("Can't open pipe to %s", quotearg (buf)); | 
|---|
| 1956 | } | 
|---|
| 1957 | for (;;) { | 
|---|
| 1958 | char ed_command_letter; | 
|---|
| 1959 | beginning_of_this_line = file_tell (pfp); | 
|---|
| 1960 | chars_read = get_line (); | 
|---|
| 1961 | if (! chars_read) { | 
|---|
| 1962 | next_intuit_at(beginning_of_this_line,p_input_line); | 
|---|
| 1963 | break; | 
|---|
| 1964 | } | 
|---|
| 1965 | ed_command_letter = get_ed_command_letter (buf); | 
|---|
| 1966 | if (ed_command_letter) { | 
|---|
| 1967 | if (pipefp) | 
|---|
| 1968 | if (! fwrite (buf, sizeof *buf, chars_read, pipefp)) | 
|---|
| 1969 | write_fatal (); | 
|---|
| 1970 | if (ed_command_letter != 'd' && ed_command_letter != 's') { | 
|---|
| 1971 | p_pass_comments_through = true; | 
|---|
| 1972 | while ((chars_read = get_line ()) != 0) { | 
|---|
| 1973 | if (pipefp) | 
|---|
| 1974 | if (! fwrite (buf, sizeof *buf, chars_read, pipefp)) | 
|---|
| 1975 | write_fatal (); | 
|---|
| 1976 | if (chars_read == 2  &&  strEQ (buf, ".\n")) | 
|---|
| 1977 | break; | 
|---|
| 1978 | } | 
|---|
| 1979 | p_pass_comments_through = false; | 
|---|
| 1980 | } | 
|---|
| 1981 | } | 
|---|
| 1982 | else { | 
|---|
| 1983 | next_intuit_at(beginning_of_this_line,p_input_line); | 
|---|
| 1984 | break; | 
|---|
| 1985 | } | 
|---|
| 1986 | } | 
|---|
| 1987 | if (!pipefp) | 
|---|
| 1988 | return; | 
|---|
| 1989 | if (fwrite ("w\nq\n", sizeof (char), (size_t) 4, pipefp) == 0 | 
|---|
| 1990 | || fflush (pipefp) != 0) | 
|---|
| 1991 | write_fatal (); | 
|---|
| 1992 | if (pclose (pipefp) != 0) | 
|---|
| 1993 | fatal ("%s FAILED", ed_program); | 
|---|
| 1994 |  | 
|---|
| 1995 | if (ofp) | 
|---|
| 1996 | { | 
|---|
| 1997 | FILE *ifp = fopen (TMPOUTNAME, binary_transput ? "rb" : "r"); | 
|---|
| 1998 | int c; | 
|---|
| 1999 | if (!ifp) | 
|---|
| 2000 | pfatal ("can't open `%s'", TMPOUTNAME); | 
|---|
| 2001 | while ((c = getc (ifp)) != EOF) | 
|---|
| 2002 | if (putc (c, ofp) == EOF) | 
|---|
| 2003 | write_fatal (); | 
|---|
| 2004 | if (ferror (ifp) || fclose (ifp) != 0) | 
|---|
| 2005 | read_fatal (); | 
|---|
| 2006 | } | 
|---|
| 2007 | } | 
|---|