[3444] | 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 | }
|
---|