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