1 /*- 2 * Copyright 1986, Larry Wall 3 * 4 * Redistribution and use in source and binary forms, with or without 5 * modification, are permitted provided that the following condition is met: 6 * 1. Redistributions of source code must retain the above copyright notice, 7 * this condition and the following disclaimer. 8 * 9 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY 10 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 11 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 12 * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR 13 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 14 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 15 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 16 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 17 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 18 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 19 * SUCH DAMAGE. 20 * 21 * patch - a program to apply diffs to original files 22 * 23 * -C option added in 1998, original code by Marc Espie, based on FreeBSD 24 * behaviour 25 * 26 * $OpenBSD: pch.c,v 1.43 2014/11/18 17:03:35 tobias Exp $ 27 * $FreeBSD$ 28 */ 29 30 #include <sys/types.h> 31 #include <sys/stat.h> 32 33 #include <ctype.h> 34 #include <libgen.h> 35 #include <limits.h> 36 #include <stdint.h> 37 #include <stdio.h> 38 #include <stdlib.h> 39 #include <string.h> 40 #include <unistd.h> 41 42 #include "common.h" 43 #include "util.h" 44 #include "pch.h" 45 #include "pathnames.h" 46 47 /* Patch (diff listing) abstract type. */ 48 49 static off_t p_filesize; /* size of the patch file */ 50 static LINENUM p_first; /* 1st line number */ 51 static LINENUM p_newfirst; /* 1st line number of replacement */ 52 static LINENUM p_ptrn_lines; /* # lines in pattern */ 53 static LINENUM p_repl_lines; /* # lines in replacement text */ 54 static LINENUM p_end = -1; /* last line in hunk */ 55 static LINENUM p_max; /* max allowed value of p_end */ 56 static LINENUM p_context = 3; /* # of context lines */ 57 static LINENUM p_input_line = 0; /* current line # from patch file */ 58 static char **p_line = NULL;/* the text of the hunk */ 59 static unsigned short *p_len = NULL; /* length of each line */ 60 static char *p_char = NULL; /* +, -, and ! */ 61 static int hunkmax = INITHUNKMAX; /* size of above arrays to begin with */ 62 static int p_indent; /* indent to patch */ 63 static off_t p_base; /* where to intuit this time */ 64 static LINENUM p_bline; /* line # of p_base */ 65 static off_t p_start; /* where intuit found a patch */ 66 static LINENUM p_sline; /* and the line number for it */ 67 static LINENUM p_hunk_beg; /* line number of current hunk */ 68 static LINENUM p_efake = -1; /* end of faked up lines--don't free */ 69 static LINENUM p_bfake = -1; /* beg of faked up lines */ 70 static FILE *pfp = NULL; /* patch file pointer */ 71 static char *bestguess = NULL; /* guess at correct filename */ 72 73 char *source_file; 74 75 static void grow_hunkmax(void); 76 static int intuit_diff_type(void); 77 static void next_intuit_at(off_t, LINENUM); 78 static void skip_to(off_t, LINENUM); 79 static size_t pgets(bool _do_indent); 80 static char *best_name(const struct file_name *, bool); 81 static char *posix_name(const struct file_name *, bool); 82 static size_t num_components(const char *); 83 static LINENUM strtolinenum(char *, char **); 84 85 /* 86 * Prepare to look for the next patch in the patch file. 87 */ 88 void 89 re_patch(void) 90 { 91 p_first = 0; 92 p_newfirst = 0; 93 p_ptrn_lines = 0; 94 p_repl_lines = 0; 95 p_end = (LINENUM) - 1; 96 p_max = 0; 97 p_indent = 0; 98 } 99 100 /* 101 * Open the patch file at the beginning of time. 102 */ 103 void 104 open_patch_file(const char *filename) 105 { 106 struct stat filestat; 107 int nr, nw; 108 109 if (filename == NULL || *filename == '\0' || strEQ(filename, "-")) { 110 pfp = fopen(TMPPATNAME, "w"); 111 if (pfp == NULL) 112 pfatal("can't create %s", TMPPATNAME); 113 while ((nr = fread(buf, 1, buf_size, stdin)) > 0) { 114 nw = fwrite(buf, 1, nr, pfp); 115 if (nr != nw) 116 pfatal("write error to %s", TMPPATNAME); 117 } 118 if (ferror(pfp) || fclose(pfp)) 119 pfatal("can't write %s", TMPPATNAME); 120 filename = TMPPATNAME; 121 } 122 pfp = fopen(filename, "r"); 123 if (pfp == NULL) 124 pfatal("patch file %s not found", filename); 125 if (fstat(fileno(pfp), &filestat)) 126 pfatal("can't stat %s", filename); 127 p_filesize = filestat.st_size; 128 next_intuit_at(0, 1L); /* start at the beginning */ 129 set_hunkmax(); 130 } 131 132 /* 133 * Make sure our dynamically realloced tables are malloced to begin with. 134 */ 135 void 136 set_hunkmax(void) 137 { 138 if (p_line == NULL) 139 p_line = malloc(hunkmax * sizeof(char *)); 140 if (p_len == NULL) 141 p_len = malloc(hunkmax * sizeof(unsigned short)); 142 if (p_char == NULL) 143 p_char = malloc(hunkmax * sizeof(char)); 144 } 145 146 /* 147 * Enlarge the arrays containing the current hunk of patch. 148 */ 149 static void 150 grow_hunkmax(void) 151 { 152 int new_hunkmax = hunkmax * 2; 153 154 if (p_line == NULL || p_len == NULL || p_char == NULL) 155 fatal("Internal memory allocation error\n"); 156 157 p_line = reallocf(p_line, new_hunkmax * sizeof(char *)); 158 p_len = reallocf(p_len, new_hunkmax * sizeof(unsigned short)); 159 p_char = reallocf(p_char, new_hunkmax * sizeof(char)); 160 161 if (p_line != NULL && p_len != NULL && p_char != NULL) { 162 hunkmax = new_hunkmax; 163 return; 164 } 165 166 if (!using_plan_a) 167 fatal("out of memory\n"); 168 out_of_mem = true; /* whatever is null will be allocated again */ 169 /* from within plan_a(), of all places */ 170 } 171 172 /* True if the remainder of the patch file contains a diff of some sort. */ 173 174 bool 175 there_is_another_patch(void) 176 { 177 bool exists = false; 178 179 if (p_base != 0 && p_base >= p_filesize) { 180 if (verbose) 181 say("done\n"); 182 return false; 183 } 184 if (p_filesize == 0) 185 return false; 186 nonempty_patchf_seen = true; 187 if (verbose) 188 say("Hmm..."); 189 diff_type = intuit_diff_type(); 190 if (!diff_type) { 191 if (p_base != 0) { 192 if (verbose) 193 say(" Ignoring the trailing garbage.\ndone\n"); 194 } else 195 say(" I can't seem to find a patch in there anywhere.\n"); 196 return false; 197 } 198 if (verbose) 199 say(" %sooks like %s to me...\n", 200 (p_base == 0 ? "L" : "The next patch l"), 201 diff_type == UNI_DIFF ? "a unified diff" : 202 diff_type == CONTEXT_DIFF ? "a context diff" : 203 diff_type == NEW_CONTEXT_DIFF ? "a new-style context diff" : 204 diff_type == NORMAL_DIFF ? "a normal diff" : 205 "an ed script"); 206 if (p_indent && verbose) 207 say("(Patch is indented %d space%s.)\n", p_indent, 208 p_indent == 1 ? "" : "s"); 209 skip_to(p_start, p_sline); 210 while (filearg[0] == NULL) { 211 if (force || batch) { 212 say("No file to patch. Skipping...\n"); 213 filearg[0] = xstrdup(bestguess); 214 skip_rest_of_patch = true; 215 return true; 216 } 217 ask("File to patch: "); 218 if (*buf != '\n') { 219 free(bestguess); 220 bestguess = xstrdup(buf); 221 filearg[0] = fetchname(buf, &exists, 0); 222 } 223 /* 224 * fetchname can now return buf = NULL, exists = true, to 225 * indicate to the caller that /dev/null was specified. Retain 226 * previous behavior for now until this can be better evaluted. 227 */ 228 if (filearg[0] == NULL || !exists) { 229 int def_skip = *bestguess == '\0'; 230 ask("No file found--skip this patch? [%c] ", 231 def_skip ? 'y' : 'n'); 232 if (*buf == 'n' || (!def_skip && *buf != 'y')) 233 continue; 234 if (verbose) 235 say("Skipping patch...\n"); 236 free(filearg[0]); 237 filearg[0] = fetchname(bestguess, &exists, 0); 238 skip_rest_of_patch = true; 239 return true; 240 } 241 } 242 return true; 243 } 244 245 static void 246 p4_fetchname(struct file_name *name, char *str) 247 { 248 char *t, *h; 249 250 /* Skip leading whitespace. */ 251 while (isspace((unsigned char)*str)) 252 str++; 253 254 /* Remove the file revision number. */ 255 for (t = str, h = NULL; *t != '\0' && !isspace((unsigned char)*t); t++) 256 if (*t == '#') 257 h = t; 258 if (h != NULL) 259 *h = '\0'; 260 261 name->path = fetchname(str, &name->exists, strippath); 262 } 263 264 /* Determine what kind of diff is in the remaining part of the patch file. */ 265 266 static int 267 intuit_diff_type(void) 268 { 269 off_t this_line = 0, previous_line; 270 off_t first_command_line = -1; 271 LINENUM fcl_line = -1; 272 bool last_line_was_command = false, this_is_a_command = false; 273 bool stars_last_line = false, stars_this_line = false; 274 char *s, *t; 275 int indent, retval; 276 struct file_name names[MAX_FILE]; 277 int piece_of_git = 0; 278 279 memset(names, 0, sizeof(names)); 280 ok_to_create_file = false; 281 fseeko(pfp, p_base, SEEK_SET); 282 p_input_line = p_bline - 1; 283 for (;;) { 284 previous_line = this_line; 285 last_line_was_command = this_is_a_command; 286 stars_last_line = stars_this_line; 287 this_line = ftello(pfp); 288 indent = 0; 289 p_input_line++; 290 if (pgets(false) == 0) { 291 if (first_command_line >= 0) { 292 /* nothing but deletes!? */ 293 p_start = first_command_line; 294 p_sline = fcl_line; 295 retval = ED_DIFF; 296 goto scan_exit; 297 } else { 298 p_start = this_line; 299 p_sline = p_input_line; 300 retval = 0; 301 goto scan_exit; 302 } 303 } 304 for (s = buf; *s == ' ' || *s == '\t' || *s == 'X'; s++) { 305 if (*s == '\t') 306 indent += 8 - (indent % 8); 307 else 308 indent++; 309 } 310 for (t = s; isdigit((unsigned char)*t) || *t == ','; t++) 311 ; 312 this_is_a_command = (isdigit((unsigned char)*s) && 313 (*t == 'd' || *t == 'c' || *t == 'a')); 314 if (first_command_line < 0 && this_is_a_command) { 315 first_command_line = this_line; 316 fcl_line = p_input_line; 317 p_indent = indent; /* assume this for now */ 318 } 319 if (!stars_last_line && strnEQ(s, "*** ", 4)) 320 names[OLD_FILE].path = fetchname(s + 4, 321 &names[OLD_FILE].exists, strippath); 322 else if (strnEQ(s, "--- ", 4)) { 323 size_t off = 4; 324 if (piece_of_git && strippath == 957 && 325 strnEQ(s, "--- a/", 6)) 326 off = 6; 327 names[NEW_FILE].path = fetchname(s + off, 328 &names[NEW_FILE].exists, strippath); 329 } else if (strnEQ(s, "+++ ", 4)) { 330 /* pretend it is the old name */ 331 size_t off = 4; 332 if (piece_of_git && strippath == 957 && 333 strnEQ(s, "+++ b/", 6)) 334 off = 6; 335 names[OLD_FILE].path = fetchname(s + off, 336 &names[OLD_FILE].exists, strippath); 337 } else if (strnEQ(s, "Index:", 6)) 338 names[INDEX_FILE].path = fetchname(s + 6, 339 &names[INDEX_FILE].exists, strippath); 340 else if (strnEQ(s, "Prereq:", 7)) { 341 for (t = s + 7; isspace((unsigned char)*t); t++) 342 ; 343 revision = xstrdup(t); 344 for (t = revision; 345 *t && !isspace((unsigned char)*t); t++) 346 ; 347 *t = '\0'; 348 if (*revision == '\0') { 349 free(revision); 350 revision = NULL; 351 } 352 } else if (strnEQ(s, "diff --git a/", 13)) { 353 /* Git-style diffs. */ 354 piece_of_git = 1; 355 } else if (strnEQ(s, "==== ", 5)) { 356 /* Perforce-style diffs. */ 357 if ((t = strstr(s + 5, " - ")) != NULL) 358 p4_fetchname(&names[NEW_FILE], t + 3); 359 p4_fetchname(&names[OLD_FILE], s + 5); 360 } 361 if ((!diff_type || diff_type == ED_DIFF) && 362 first_command_line >= 0 && 363 strEQ(s, ".\n")) { 364 p_indent = indent; 365 p_start = first_command_line; 366 p_sline = fcl_line; 367 retval = ED_DIFF; 368 goto scan_exit; 369 } 370 if ((!diff_type || diff_type == UNI_DIFF) && strnEQ(s, "@@ -", 4)) { 371 if (strnEQ(s + 4, "0,0", 3)) 372 ok_to_create_file = true; 373 p_indent = indent; 374 p_start = this_line; 375 p_sline = p_input_line; 376 retval = UNI_DIFF; 377 goto scan_exit; 378 } 379 stars_this_line = strnEQ(s, "********", 8); 380 if ((!diff_type || diff_type == CONTEXT_DIFF) && stars_last_line && 381 strnEQ(s, "*** ", 4)) { 382 if (strtolinenum(s + 4, &s) == 0) 383 ok_to_create_file = true; 384 /* 385 * If this is a new context diff the character just 386 * at the end of the line is a '*'. 387 */ 388 while (*s && *s != '\n') 389 s++; 390 p_indent = indent; 391 p_start = previous_line; 392 p_sline = p_input_line - 1; 393 retval = (*(s - 1) == '*' ? NEW_CONTEXT_DIFF : CONTEXT_DIFF); 394 goto scan_exit; 395 } 396 if ((!diff_type || diff_type == NORMAL_DIFF) && 397 last_line_was_command && 398 (strnEQ(s, "< ", 2) || strnEQ(s, "> ", 2))) { 399 p_start = previous_line; 400 p_sline = p_input_line - 1; 401 p_indent = indent; 402 retval = NORMAL_DIFF; 403 goto scan_exit; 404 } 405 } 406 scan_exit: 407 if (retval == UNI_DIFF) { 408 /* unswap old and new */ 409 struct file_name tmp = names[OLD_FILE]; 410 names[OLD_FILE] = names[NEW_FILE]; 411 names[NEW_FILE] = tmp; 412 } 413 414 /* Invalidated */ 415 free(source_file); 416 source_file = NULL; 417 418 if (retval != 0) { 419 /* 420 * If we've successfully determined a diff type, stored in 421 * retval, path == NULL means _PATH_DEVNULL if exists is set. 422 * Explicitly specify it here to make it easier to detect later 423 * on that we're actually creating a file and not that we've 424 * just goofed something up. 425 */ 426 if (names[OLD_FILE].path != NULL) 427 source_file = xstrdup(names[OLD_FILE].path); 428 else if (names[OLD_FILE].exists) 429 source_file = xstrdup(_PATH_DEVNULL); 430 } 431 if (filearg[0] == NULL) { 432 if (posix) 433 filearg[0] = posix_name(names, ok_to_create_file); 434 else { 435 /* Ignore the Index: name for context diffs, like GNU */ 436 if (names[OLD_FILE].path != NULL || 437 names[NEW_FILE].path != NULL) { 438 free(names[INDEX_FILE].path); 439 names[INDEX_FILE].path = NULL; 440 } 441 filearg[0] = best_name(names, ok_to_create_file); 442 } 443 } 444 445 free(bestguess); 446 bestguess = NULL; 447 if (filearg[0] != NULL) 448 bestguess = xstrdup(filearg[0]); 449 else if (!ok_to_create_file) { 450 /* 451 * We don't want to create a new file but we need a 452 * filename to set bestguess. Avoid setting filearg[0] 453 * so the file is not created automatically. 454 */ 455 if (posix) 456 bestguess = posix_name(names, true); 457 else 458 bestguess = best_name(names, true); 459 } 460 free(names[OLD_FILE].path); 461 free(names[NEW_FILE].path); 462 free(names[INDEX_FILE].path); 463 return retval; 464 } 465 466 /* 467 * Remember where this patch ends so we know where to start up again. 468 */ 469 static void 470 next_intuit_at(off_t file_pos, LINENUM file_line) 471 { 472 p_base = file_pos; 473 p_bline = file_line; 474 } 475 476 /* 477 * Basically a verbose fseeko() to the actual diff listing. 478 */ 479 static void 480 skip_to(off_t file_pos, LINENUM file_line) 481 { 482 size_t len; 483 484 if (p_base > file_pos) 485 fatal("Internal error: seek %lld>%lld\n", 486 (long long)p_base, (long long)file_pos); 487 if (verbose && p_base < file_pos) { 488 fseeko(pfp, p_base, SEEK_SET); 489 say("The text leading up to this was:\n--------------------------\n"); 490 while (ftello(pfp) < file_pos) { 491 len = pgets(false); 492 if (len == 0) 493 fatal("Unexpected end of file\n"); 494 say("|%s", buf); 495 } 496 say("--------------------------\n"); 497 } else 498 fseeko(pfp, file_pos, SEEK_SET); 499 p_input_line = file_line - 1; 500 } 501 502 /* Make this a function for better debugging. */ 503 static void 504 malformed(void) 505 { 506 fatal("malformed patch at line %ld: %s", p_input_line, buf); 507 /* about as informative as "Syntax error" in C */ 508 } 509 510 /* 511 * True if the line has been discarded (i.e. it is a line saying 512 * "\ No newline at end of file".) 513 */ 514 static bool 515 remove_special_line(void) 516 { 517 int c; 518 519 c = fgetc(pfp); 520 if (c == '\\') { 521 do { 522 c = fgetc(pfp); 523 } while (c != EOF && c != '\n'); 524 525 return true; 526 } 527 if (c != EOF) 528 fseeko(pfp, -1, SEEK_CUR); 529 530 return false; 531 } 532 533 /* 534 * True if there is more of the current diff listing to process. 535 */ 536 bool 537 another_hunk(void) 538 { 539 off_t line_beginning; /* file pos of the current line */ 540 LINENUM repl_beginning; /* index of --- line */ 541 LINENUM fillcnt; /* #lines of missing ptrn or repl */ 542 LINENUM fillsrc; /* index of first line to copy */ 543 LINENUM filldst; /* index of first missing line */ 544 bool ptrn_spaces_eaten; /* ptrn was slightly malformed */ 545 bool repl_could_be_missing; /* no + or ! lines in this hunk */ 546 bool repl_missing; /* we are now backtracking */ 547 off_t repl_backtrack_position; /* file pos of first repl line */ 548 LINENUM repl_patch_line; /* input line number for same */ 549 LINENUM ptrn_copiable; /* # of copiable lines in ptrn */ 550 char *s; 551 size_t len; 552 int context = 0; 553 554 while (p_end >= 0) { 555 if (p_end == p_efake) 556 p_end = p_bfake; /* don't free twice */ 557 else 558 free(p_line[p_end]); 559 p_end--; 560 } 561 p_efake = -1; 562 563 p_max = hunkmax; /* gets reduced when --- found */ 564 if (diff_type == CONTEXT_DIFF || diff_type == NEW_CONTEXT_DIFF) { 565 line_beginning = ftello(pfp); 566 repl_beginning = 0; 567 fillcnt = 0; 568 fillsrc = 0; 569 filldst = 0; 570 ptrn_spaces_eaten = false; 571 repl_could_be_missing = true; 572 repl_missing = false; 573 repl_backtrack_position = 0; 574 repl_patch_line = 0; 575 ptrn_copiable = 0; 576 577 len = pgets(true); 578 p_input_line++; 579 if (len == 0 || strnNE(buf, "********", 8)) { 580 next_intuit_at(line_beginning, p_input_line); 581 return false; 582 } 583 p_context = 100; 584 p_hunk_beg = p_input_line + 1; 585 while (p_end < p_max) { 586 line_beginning = ftello(pfp); 587 len = pgets(true); 588 p_input_line++; 589 if (len == 0) { 590 if (repl_beginning && repl_could_be_missing) { 591 repl_missing = true; 592 goto hunk_done; 593 } 594 fatal("unexpected end of file in patch\n"); 595 } 596 p_end++; 597 if (p_end >= hunkmax) 598 fatal("Internal error: hunk larger than hunk " 599 "buffer size"); 600 p_char[p_end] = *buf; 601 p_line[p_end] = NULL; 602 switch (*buf) { 603 case '*': 604 if (strnEQ(buf, "********", 8)) { 605 if (repl_beginning && repl_could_be_missing) { 606 repl_missing = true; 607 goto hunk_done; 608 } else 609 fatal("unexpected end of hunk " 610 "at line %ld\n", 611 p_input_line); 612 } 613 if (p_end != 0) { 614 if (repl_beginning && repl_could_be_missing) { 615 repl_missing = true; 616 goto hunk_done; 617 } 618 fatal("unexpected *** at line %ld: %s", 619 p_input_line, buf); 620 } 621 context = 0; 622 p_line[p_end] = savestr(buf); 623 if (out_of_mem) { 624 p_end--; 625 return false; 626 } 627 for (s = buf; 628 *s && !isdigit((unsigned char)*s); s++) 629 ; 630 if (!*s) 631 malformed(); 632 if (strnEQ(s, "0,0", 3)) 633 memmove(s, s + 2, strlen(s + 2) + 1); 634 p_first = strtolinenum(s, &s); 635 if (*s == ',') { 636 for (; 637 *s && !isdigit((unsigned char)*s); s++) 638 ; 639 if (!*s) 640 malformed(); 641 p_ptrn_lines = strtolinenum(s, &s) - p_first + 1; 642 if (p_ptrn_lines < 0) 643 malformed(); 644 } else if (p_first) 645 p_ptrn_lines = 1; 646 else { 647 p_ptrn_lines = 0; 648 p_first = 1; 649 } 650 if (p_first >= LINENUM_MAX - p_ptrn_lines || 651 p_ptrn_lines >= LINENUM_MAX - 6) 652 malformed(); 653 654 /* we need this much at least */ 655 p_max = p_ptrn_lines + 6; 656 while (p_max >= hunkmax) 657 grow_hunkmax(); 658 p_max = hunkmax; 659 break; 660 case '-': 661 if (buf[1] == '-') { 662 if (repl_beginning || 663 (p_end != p_ptrn_lines + 1 + 664 (p_char[p_end - 1] == '\n'))) { 665 if (p_end == 1) { 666 /* 667 * `old' lines were omitted; 668 * set up to fill them in 669 * from 'new' context lines. 670 */ 671 p_end = p_ptrn_lines + 1; 672 fillsrc = p_end + 1; 673 filldst = 1; 674 fillcnt = p_ptrn_lines; 675 } else { 676 if (repl_beginning) { 677 if (repl_could_be_missing) { 678 repl_missing = true; 679 goto hunk_done; 680 } 681 fatal("duplicate \"---\" at line %ld--check line numbers at line %ld\n", 682 p_input_line, p_hunk_beg + repl_beginning); 683 } else { 684 fatal("%s \"---\" at line %ld--check line numbers at line %ld\n", 685 (p_end <= p_ptrn_lines 686 ? "Premature" 687 : "Overdue"), 688 p_input_line, p_hunk_beg); 689 } 690 } 691 } 692 repl_beginning = p_end; 693 repl_backtrack_position = ftello(pfp); 694 repl_patch_line = p_input_line; 695 p_line[p_end] = savestr(buf); 696 if (out_of_mem) { 697 p_end--; 698 return false; 699 } 700 p_char[p_end] = '='; 701 for (s = buf; *s && !isdigit((unsigned char)*s); s++) 702 ; 703 if (!*s) 704 malformed(); 705 p_newfirst = strtolinenum(s, &s); 706 if (*s == ',') { 707 for (; *s && !isdigit((unsigned char)*s); s++) 708 ; 709 if (!*s) 710 malformed(); 711 p_repl_lines = strtolinenum(s, &s) - 712 p_newfirst + 1; 713 if (p_repl_lines < 0) 714 malformed(); 715 } else if (p_newfirst) 716 p_repl_lines = 1; 717 else { 718 p_repl_lines = 0; 719 p_newfirst = 1; 720 } 721 if (p_newfirst >= LINENUM_MAX - p_repl_lines || 722 p_repl_lines >= LINENUM_MAX - p_end) 723 malformed(); 724 p_max = p_repl_lines + p_end; 725 if (p_max > MAXHUNKSIZE) 726 fatal("hunk too large (%ld lines) at line %ld: %s", 727 p_max, p_input_line, buf); 728 while (p_max >= hunkmax) 729 grow_hunkmax(); 730 if (p_repl_lines != ptrn_copiable && 731 (p_context != 0 || p_repl_lines != 1)) 732 repl_could_be_missing = false; 733 break; 734 } 735 goto change_line; 736 case '+': 737 case '!': 738 repl_could_be_missing = false; 739 change_line: 740 if (buf[1] == '\n' && canonicalize) 741 strlcpy(buf + 1, " \n", buf_size - 1); 742 if (!isspace((unsigned char)buf[1]) && 743 buf[1] != '>' && buf[1] != '<' && 744 repl_beginning && repl_could_be_missing) { 745 repl_missing = true; 746 goto hunk_done; 747 } 748 if (context >= 0) { 749 if (context < p_context) 750 p_context = context; 751 context = -1000; 752 } 753 p_line[p_end] = savestr(buf + 2); 754 if (out_of_mem) { 755 p_end--; 756 return false; 757 } 758 if (p_end == p_ptrn_lines) { 759 if (remove_special_line()) { 760 int l; 761 762 l = strlen(p_line[p_end]) - 1; 763 (p_line[p_end])[l] = 0; 764 } 765 } 766 break; 767 case '\t': 768 case '\n': /* assume the 2 spaces got eaten */ 769 if (repl_beginning && repl_could_be_missing && 770 (!ptrn_spaces_eaten || 771 diff_type == NEW_CONTEXT_DIFF)) { 772 repl_missing = true; 773 goto hunk_done; 774 } 775 p_line[p_end] = savestr(buf); 776 if (out_of_mem) { 777 p_end--; 778 return false; 779 } 780 if (p_end != p_ptrn_lines + 1) { 781 ptrn_spaces_eaten |= (repl_beginning != 0); 782 context++; 783 if (!repl_beginning) 784 ptrn_copiable++; 785 p_char[p_end] = ' '; 786 } 787 break; 788 case ' ': 789 if (!isspace((unsigned char)buf[1]) && 790 repl_beginning && repl_could_be_missing) { 791 repl_missing = true; 792 goto hunk_done; 793 } 794 context++; 795 if (!repl_beginning) 796 ptrn_copiable++; 797 p_line[p_end] = savestr(buf + 2); 798 if (out_of_mem) { 799 p_end--; 800 return false; 801 } 802 break; 803 default: 804 if (repl_beginning && repl_could_be_missing) { 805 repl_missing = true; 806 goto hunk_done; 807 } 808 malformed(); 809 } 810 /* set up p_len for strncmp() so we don't have to */ 811 /* assume null termination */ 812 if (p_line[p_end]) 813 p_len[p_end] = strlen(p_line[p_end]); 814 else 815 p_len[p_end] = 0; 816 } 817 818 hunk_done: 819 if (p_end >= 0 && !repl_beginning) 820 fatal("no --- found in patch at line %ld\n", pch_hunk_beg()); 821 822 if (repl_missing) { 823 824 /* reset state back to just after --- */ 825 p_input_line = repl_patch_line; 826 for (p_end--; p_end > repl_beginning; p_end--) 827 free(p_line[p_end]); 828 fseeko(pfp, repl_backtrack_position, SEEK_SET); 829 830 /* redundant 'new' context lines were omitted - set */ 831 /* up to fill them in from the old file context */ 832 if (!p_context && p_repl_lines == 1) { 833 p_repl_lines = 0; 834 p_max--; 835 } 836 fillsrc = 1; 837 filldst = repl_beginning + 1; 838 fillcnt = p_repl_lines; 839 p_end = p_max; 840 } else if (!p_context && fillcnt == 1) { 841 /* the first hunk was a null hunk with no context */ 842 /* and we were expecting one line -- fix it up. */ 843 while (filldst < p_end) { 844 p_line[filldst] = p_line[filldst + 1]; 845 p_char[filldst] = p_char[filldst + 1]; 846 p_len[filldst] = p_len[filldst + 1]; 847 filldst++; 848 } 849 #if 0 850 repl_beginning--; /* this doesn't need to be fixed */ 851 #endif 852 p_end--; 853 p_first++; /* do append rather than insert */ 854 fillcnt = 0; 855 p_ptrn_lines = 0; 856 } 857 if (diff_type == CONTEXT_DIFF && 858 (fillcnt || (p_first > 1 && ptrn_copiable > 2 * p_context))) { 859 if (verbose) 860 say("%s\n%s\n%s\n", 861 "(Fascinating--this is really a new-style context diff but without", 862 "the telltale extra asterisks on the *** line that usually indicate", 863 "the new style...)"); 864 diff_type = NEW_CONTEXT_DIFF; 865 } 866 /* if there were omitted context lines, fill them in now */ 867 if (fillcnt) { 868 p_bfake = filldst; /* remember where not to free() */ 869 p_efake = filldst + fillcnt - 1; 870 while (fillcnt-- > 0) { 871 while (fillsrc <= p_end && p_char[fillsrc] != ' ') 872 fillsrc++; 873 if (fillsrc > p_end) 874 fatal("replacement text or line numbers mangled in hunk at line %ld\n", 875 p_hunk_beg); 876 p_line[filldst] = p_line[fillsrc]; 877 p_char[filldst] = p_char[fillsrc]; 878 p_len[filldst] = p_len[fillsrc]; 879 fillsrc++; 880 filldst++; 881 } 882 while (fillsrc <= p_end && fillsrc != repl_beginning && 883 p_char[fillsrc] != ' ') 884 fillsrc++; 885 #ifdef DEBUGGING 886 if (debug & 64) 887 printf("fillsrc %ld, filldst %ld, rb %ld, e+1 %ld\n", 888 fillsrc, filldst, repl_beginning, p_end + 1); 889 #endif 890 if (fillsrc != p_end + 1 && fillsrc != repl_beginning) 891 malformed(); 892 if (filldst != p_end + 1 && filldst != repl_beginning) 893 malformed(); 894 } 895 if (p_line[p_end] != NULL) { 896 if (remove_special_line()) { 897 p_len[p_end] -= 1; 898 (p_line[p_end])[p_len[p_end]] = 0; 899 } 900 } 901 } else if (diff_type == UNI_DIFF) { 902 LINENUM fillold; /* index of old lines */ 903 LINENUM fillnew; /* index of new lines */ 904 char ch; 905 906 line_beginning = ftello(pfp); /* file pos of the current line */ 907 len = pgets(true); 908 p_input_line++; 909 if (len == 0 || strnNE(buf, "@@ -", 4)) { 910 next_intuit_at(line_beginning, p_input_line); 911 return false; 912 } 913 s = buf + 4; 914 if (!*s) 915 malformed(); 916 p_first = strtolinenum(s, &s); 917 if (*s == ',') { 918 p_ptrn_lines = strtolinenum(s + 1, &s); 919 } else 920 p_ptrn_lines = 1; 921 if (*s == ' ') 922 s++; 923 if (*s != '+' || !*++s) 924 malformed(); 925 p_newfirst = strtolinenum(s, &s); 926 if (*s == ',') { 927 p_repl_lines = strtolinenum(s + 1, &s); 928 } else 929 p_repl_lines = 1; 930 if (*s == ' ') 931 s++; 932 if (*s != '@') 933 malformed(); 934 if (p_first >= LINENUM_MAX - p_ptrn_lines || 935 p_newfirst > LINENUM_MAX - p_repl_lines || 936 p_ptrn_lines >= LINENUM_MAX - p_repl_lines - 1) 937 malformed(); 938 if (!p_ptrn_lines) 939 p_first++; /* do append rather than insert */ 940 p_max = p_ptrn_lines + p_repl_lines + 1; 941 while (p_max >= hunkmax) 942 grow_hunkmax(); 943 fillold = 1; 944 fillnew = fillold + p_ptrn_lines; 945 p_end = fillnew + p_repl_lines; 946 snprintf(buf, buf_size, "*** %ld,%ld ****\n", p_first, 947 p_first + p_ptrn_lines - 1); 948 p_line[0] = savestr(buf); 949 if (out_of_mem) { 950 p_end = -1; 951 return false; 952 } 953 p_char[0] = '*'; 954 snprintf(buf, buf_size, "--- %ld,%ld ----\n", p_newfirst, 955 p_newfirst + p_repl_lines - 1); 956 p_line[fillnew] = savestr(buf); 957 if (out_of_mem) { 958 p_end = 0; 959 return false; 960 } 961 p_char[fillnew++] = '='; 962 p_context = 100; 963 context = 0; 964 p_hunk_beg = p_input_line + 1; 965 while (fillold <= p_ptrn_lines || fillnew <= p_end) { 966 line_beginning = ftello(pfp); 967 len = pgets(true); 968 p_input_line++; 969 if (len == 0) { 970 if (p_max - fillnew < 3) { 971 /* assume blank lines got chopped */ 972 strlcpy(buf, " \n", buf_size); 973 } else { 974 fatal("unexpected end of file in patch\n"); 975 } 976 } 977 if (*buf == '\t' || *buf == '\n') { 978 ch = ' '; /* assume the space got eaten */ 979 s = savestr(buf); 980 } else { 981 ch = *buf; 982 s = savestr(buf + 1); 983 } 984 if (out_of_mem) { 985 while (--fillnew > p_ptrn_lines) 986 free(p_line[fillnew]); 987 p_end = fillold - 1; 988 return false; 989 } 990 switch (ch) { 991 case '-': 992 if (fillold > p_ptrn_lines) { 993 free(s); 994 p_end = fillnew - 1; 995 malformed(); 996 } 997 p_char[fillold] = ch; 998 p_line[fillold] = s; 999 p_len[fillold++] = strlen(s); 1000 if (fillold > p_ptrn_lines) { 1001 if (remove_special_line()) { 1002 p_len[fillold - 1] -= 1; 1003 s[p_len[fillold - 1]] = 0; 1004 } 1005 } 1006 break; 1007 case '=': 1008 ch = ' '; 1009 /* FALL THROUGH */ 1010 case ' ': 1011 if (fillold > p_ptrn_lines) { 1012 free(s); 1013 while (--fillnew > p_ptrn_lines) 1014 free(p_line[fillnew]); 1015 p_end = fillold - 1; 1016 malformed(); 1017 } 1018 context++; 1019 p_char[fillold] = ch; 1020 p_line[fillold] = s; 1021 p_len[fillold++] = strlen(s); 1022 s = savestr(s); 1023 if (out_of_mem) { 1024 while (--fillnew > p_ptrn_lines) 1025 free(p_line[fillnew]); 1026 p_end = fillold - 1; 1027 return false; 1028 } 1029 if (fillold > p_ptrn_lines) { 1030 if (remove_special_line()) { 1031 p_len[fillold - 1] -= 1; 1032 s[p_len[fillold - 1]] = 0; 1033 } 1034 } 1035 /* FALL THROUGH */ 1036 case '+': 1037 if (fillnew > p_end) { 1038 free(s); 1039 while (--fillnew > p_ptrn_lines) 1040 free(p_line[fillnew]); 1041 p_end = fillold - 1; 1042 malformed(); 1043 } 1044 p_char[fillnew] = ch; 1045 p_line[fillnew] = s; 1046 p_len[fillnew++] = strlen(s); 1047 if (fillold > p_ptrn_lines) { 1048 if (remove_special_line()) { 1049 p_len[fillnew - 1] -= 1; 1050 s[p_len[fillnew - 1]] = 0; 1051 } 1052 } 1053 break; 1054 default: 1055 p_end = fillnew; 1056 malformed(); 1057 } 1058 if (ch != ' ' && context > 0) { 1059 if (context < p_context) 1060 p_context = context; 1061 context = -1000; 1062 } 1063 } /* while */ 1064 } else { /* normal diff--fake it up */ 1065 char hunk_type; 1066 int i; 1067 LINENUM min, max; 1068 1069 line_beginning = ftello(pfp); 1070 p_context = 0; 1071 len = pgets(true); 1072 p_input_line++; 1073 if (len == 0 || !isdigit((unsigned char)*buf)) { 1074 next_intuit_at(line_beginning, p_input_line); 1075 return false; 1076 } 1077 p_first = strtolinenum(buf, &s); 1078 if (*s == ',') { 1079 p_ptrn_lines = strtolinenum(s + 1, &s) - p_first + 1; 1080 if (p_ptrn_lines < 0) 1081 malformed(); 1082 } else 1083 p_ptrn_lines = (*s != 'a'); 1084 hunk_type = *s; 1085 if (hunk_type == 'a') 1086 p_first++; /* do append rather than insert */ 1087 min = strtolinenum(s + 1, &s); 1088 if (*s == ',') 1089 max = strtolinenum(s + 1, &s); 1090 else 1091 max = min; 1092 if (min < 0 || min > max || max - min == LINENUM_MAX) 1093 malformed(); 1094 if (hunk_type == 'd') 1095 min++; 1096 p_newfirst = min; 1097 p_repl_lines = max - min + 1; 1098 if (p_newfirst > LINENUM_MAX - p_repl_lines || 1099 p_ptrn_lines >= LINENUM_MAX - p_repl_lines - 1) 1100 malformed(); 1101 p_end = p_ptrn_lines + p_repl_lines + 1; 1102 if (p_end > MAXHUNKSIZE) 1103 fatal("hunk too large (%ld lines) at line %ld: %s", 1104 p_end, p_input_line, buf); 1105 while (p_end >= hunkmax) 1106 grow_hunkmax(); 1107 snprintf(buf, buf_size, "*** %ld,%ld\n", p_first, 1108 p_first + p_ptrn_lines - 1); 1109 p_line[0] = savestr(buf); 1110 if (out_of_mem) { 1111 p_end = -1; 1112 return false; 1113 } 1114 p_char[0] = '*'; 1115 for (i = 1; i <= p_ptrn_lines; i++) { 1116 len = pgets(true); 1117 p_input_line++; 1118 if (len == 0) 1119 fatal("unexpected end of file in patch at line %ld\n", 1120 p_input_line); 1121 if (*buf != '<') 1122 fatal("< expected at line %ld of patch\n", 1123 p_input_line); 1124 p_line[i] = savestr(buf + 2); 1125 if (out_of_mem) { 1126 p_end = i - 1; 1127 return false; 1128 } 1129 p_len[i] = strlen(p_line[i]); 1130 p_char[i] = '-'; 1131 } 1132 1133 if (remove_special_line()) { 1134 p_len[i - 1] -= 1; 1135 (p_line[i - 1])[p_len[i - 1]] = 0; 1136 } 1137 if (hunk_type == 'c') { 1138 len = pgets(true); 1139 p_input_line++; 1140 if (len == 0) 1141 fatal("unexpected end of file in patch at line %ld\n", 1142 p_input_line); 1143 if (*buf != '-') 1144 fatal("--- expected at line %ld of patch\n", 1145 p_input_line); 1146 } 1147 snprintf(buf, buf_size, "--- %ld,%ld\n", min, max); 1148 p_line[i] = savestr(buf); 1149 if (out_of_mem) { 1150 p_end = i - 1; 1151 return false; 1152 } 1153 p_char[i] = '='; 1154 for (i++; i <= p_end; i++) { 1155 len = pgets(true); 1156 p_input_line++; 1157 if (len == 0) 1158 fatal("unexpected end of file in patch at line %ld\n", 1159 p_input_line); 1160 if (*buf != '>') 1161 fatal("> expected at line %ld of patch\n", 1162 p_input_line); 1163 /* Don't overrun if we don't have enough line */ 1164 if (len > 2) 1165 p_line[i] = savestr(buf + 2); 1166 else 1167 p_line[i] = savestr(""); 1168 1169 if (out_of_mem) { 1170 p_end = i - 1; 1171 return false; 1172 } 1173 p_len[i] = strlen(p_line[i]); 1174 p_char[i] = '+'; 1175 } 1176 1177 if (remove_special_line()) { 1178 p_len[i - 1] -= 1; 1179 (p_line[i - 1])[p_len[i - 1]] = 0; 1180 } 1181 } 1182 if (reverse) /* backwards patch? */ 1183 if (!pch_swap()) 1184 say("Not enough memory to swap next hunk!\n"); 1185 #ifdef DEBUGGING 1186 if (debug & 2) { 1187 LINENUM i; 1188 char special; 1189 1190 for (i = 0; i <= p_end; i++) { 1191 if (i == p_ptrn_lines) 1192 special = '^'; 1193 else 1194 special = ' '; 1195 fprintf(stderr, "%3ld %c %c %s", i, p_char[i], 1196 special, p_line[i]); 1197 fflush(stderr); 1198 } 1199 } 1200 #endif 1201 if (p_end + 1 < hunkmax)/* paranoia reigns supreme... */ 1202 p_char[p_end + 1] = '^'; /* add a stopper for apply_hunk */ 1203 return true; 1204 } 1205 1206 /* 1207 * Input a line from the patch file. 1208 * Worry about indentation if do_indent is true. 1209 * The line is read directly into the buf global variable which 1210 * is resized if necessary in order to hold the complete line. 1211 * Returns the number of characters read including the terminating 1212 * '\n', if any. 1213 */ 1214 size_t 1215 pgets(bool do_indent) 1216 { 1217 char *line; 1218 size_t len = 0; 1219 int indent = 0, skipped = 0; 1220 1221 line = fgetln(pfp, &len); 1222 if (line != NULL) { 1223 if (len + 1 > buf_size) { 1224 while (len + 1 > buf_size) 1225 buf_size *= 2; 1226 free(buf); 1227 buf = malloc(buf_size); 1228 if (buf == NULL) 1229 fatal("out of memory\n"); 1230 } 1231 if (do_indent == 1 && p_indent) { 1232 for (; 1233 indent < p_indent && (*line == ' ' || *line == '\t' || *line == 'X'); 1234 line++, skipped++) { 1235 if (*line == '\t') 1236 indent += 8 - (indent %7); 1237 else 1238 indent++; 1239 } 1240 } 1241 memcpy(buf, line, len - skipped); 1242 buf[len - skipped] = '\0'; 1243 } 1244 return len; 1245 } 1246 1247 1248 /* 1249 * Reverse the old and new portions of the current hunk. 1250 */ 1251 bool 1252 pch_swap(void) 1253 { 1254 char **tp_line; /* the text of the hunk */ 1255 unsigned short *tp_len;/* length of each line */ 1256 char *tp_char; /* +, -, and ! */ 1257 LINENUM i; 1258 LINENUM n; 1259 bool blankline = false; 1260 char *s; 1261 1262 i = p_first; 1263 p_first = p_newfirst; 1264 p_newfirst = i; 1265 1266 /* make a scratch copy */ 1267 1268 tp_line = p_line; 1269 tp_len = p_len; 1270 tp_char = p_char; 1271 p_line = NULL; /* force set_hunkmax to allocate again */ 1272 p_len = NULL; 1273 p_char = NULL; 1274 set_hunkmax(); 1275 if (p_line == NULL || p_len == NULL || p_char == NULL) { 1276 1277 free(p_line); 1278 p_line = tp_line; 1279 free(p_len); 1280 p_len = tp_len; 1281 free(p_char); 1282 p_char = tp_char; 1283 return false; /* not enough memory to swap hunk! */ 1284 } 1285 /* now turn the new into the old */ 1286 1287 i = p_ptrn_lines + 1; 1288 if (tp_char[i] == '\n') { /* account for possible blank line */ 1289 blankline = true; 1290 i++; 1291 } 1292 if (p_efake >= 0) { /* fix non-freeable ptr range */ 1293 if (p_efake <= i) 1294 n = p_end - i + 1; 1295 else 1296 n = -i; 1297 p_efake += n; 1298 p_bfake += n; 1299 } 1300 for (n = 0; i <= p_end; i++, n++) { 1301 p_line[n] = tp_line[i]; 1302 p_char[n] = tp_char[i]; 1303 if (p_char[n] == '+') 1304 p_char[n] = '-'; 1305 p_len[n] = tp_len[i]; 1306 } 1307 if (blankline) { 1308 i = p_ptrn_lines + 1; 1309 p_line[n] = tp_line[i]; 1310 p_char[n] = tp_char[i]; 1311 p_len[n] = tp_len[i]; 1312 n++; 1313 } 1314 if (p_char[0] != '=') 1315 fatal("Malformed patch at line %ld: expected '=' found '%c'\n", 1316 p_input_line, p_char[0]); 1317 p_char[0] = '*'; 1318 for (s = p_line[0]; *s; s++) 1319 if (*s == '-') 1320 *s = '*'; 1321 1322 /* now turn the old into the new */ 1323 1324 if (p_char[0] != '*') 1325 fatal("Malformed patch at line %ld: expected '*' found '%c'\n", 1326 p_input_line, p_char[0]); 1327 tp_char[0] = '='; 1328 for (s = tp_line[0]; *s; s++) 1329 if (*s == '*') 1330 *s = '-'; 1331 for (i = 0; n <= p_end; i++, n++) { 1332 p_line[n] = tp_line[i]; 1333 p_char[n] = tp_char[i]; 1334 if (p_char[n] == '-') 1335 p_char[n] = '+'; 1336 p_len[n] = tp_len[i]; 1337 } 1338 1339 if (i != p_ptrn_lines + 1) 1340 fatal("Malformed patch at line %ld: expected %ld lines, " 1341 "got %ld\n", 1342 p_input_line, p_ptrn_lines + 1, i); 1343 1344 i = p_ptrn_lines; 1345 p_ptrn_lines = p_repl_lines; 1346 p_repl_lines = i; 1347 1348 free(tp_line); 1349 free(tp_len); 1350 free(tp_char); 1351 1352 return true; 1353 } 1354 1355 /* 1356 * Return the specified line position in the old file of the old context. 1357 */ 1358 LINENUM 1359 pch_first(void) 1360 { 1361 return p_first; 1362 } 1363 1364 /* 1365 * Return the number of lines of old context. 1366 */ 1367 LINENUM 1368 pch_ptrn_lines(void) 1369 { 1370 return p_ptrn_lines; 1371 } 1372 1373 /* 1374 * Return the probable line position in the new file of the first line. 1375 */ 1376 LINENUM 1377 pch_newfirst(void) 1378 { 1379 return p_newfirst; 1380 } 1381 1382 /* 1383 * Return the number of lines in the replacement text including context. 1384 */ 1385 LINENUM 1386 pch_repl_lines(void) 1387 { 1388 return p_repl_lines; 1389 } 1390 1391 /* 1392 * Return the number of lines in the whole hunk. 1393 */ 1394 LINENUM 1395 pch_end(void) 1396 { 1397 return p_end; 1398 } 1399 1400 /* 1401 * Return the number of context lines before the first changed line. 1402 */ 1403 LINENUM 1404 pch_context(void) 1405 { 1406 return p_context; 1407 } 1408 1409 /* 1410 * Return the length of a particular patch line. 1411 */ 1412 unsigned short 1413 pch_line_len(LINENUM line) 1414 { 1415 return p_len[line]; 1416 } 1417 1418 /* 1419 * Return the control character (+, -, *, !, etc) for a patch line. 1420 */ 1421 char 1422 pch_char(LINENUM line) 1423 { 1424 return p_char[line]; 1425 } 1426 1427 /* 1428 * Return a pointer to a particular patch line. 1429 */ 1430 char * 1431 pfetch(LINENUM line) 1432 { 1433 return p_line[line]; 1434 } 1435 1436 /* 1437 * Return where in the patch file this hunk began, for error messages. 1438 */ 1439 LINENUM 1440 pch_hunk_beg(void) 1441 { 1442 return p_hunk_beg; 1443 } 1444 1445 /* 1446 * Apply an ed script by feeding ed itself. 1447 */ 1448 void 1449 do_ed_script(void) 1450 { 1451 char *t; 1452 off_t beginning_of_this_line; 1453 FILE *pipefp = NULL; 1454 int continuation; 1455 1456 if (!skip_rest_of_patch) { 1457 if (copy_file(filearg[0], TMPOUTNAME) < 0) { 1458 unlink(TMPOUTNAME); 1459 fatal("can't create temp file %s", TMPOUTNAME); 1460 } 1461 snprintf(buf, buf_size, "%s%s%s", _PATH_RED, 1462 verbose ? " " : " -s ", TMPOUTNAME); 1463 pipefp = popen(buf, "w"); 1464 } 1465 for (;;) { 1466 beginning_of_this_line = ftello(pfp); 1467 if (pgets(true) == 0) { 1468 next_intuit_at(beginning_of_this_line, p_input_line); 1469 break; 1470 } 1471 p_input_line++; 1472 for (t = buf; isdigit((unsigned char)*t) || *t == ','; t++) 1473 ; 1474 /* POSIX defines allowed commands as {a,c,d,i,s} */ 1475 if (isdigit((unsigned char)*buf) && 1476 (*t == 'a' || *t == 'c' || *t == 'd' || *t == 'i' || *t == 's')) { 1477 if (pipefp != NULL) 1478 fputs(buf, pipefp); 1479 if (*t == 's') { 1480 for (;;) { 1481 continuation = 0; 1482 t = strchr(buf, '\0') - 1; 1483 while (--t >= buf && *t == '\\') 1484 continuation = !continuation; 1485 if (!continuation || 1486 pgets(true) == 0) 1487 break; 1488 if (pipefp != NULL) 1489 fputs(buf, pipefp); 1490 } 1491 } else if (*t != 'd') { 1492 while (pgets(true)) { 1493 p_input_line++; 1494 if (pipefp != NULL) 1495 fputs(buf, pipefp); 1496 if (strEQ(buf, ".\n")) 1497 break; 1498 } 1499 } 1500 } else { 1501 next_intuit_at(beginning_of_this_line, p_input_line); 1502 break; 1503 } 1504 } 1505 if (pipefp == NULL) 1506 return; 1507 fprintf(pipefp, "w\n"); 1508 fprintf(pipefp, "q\n"); 1509 fflush(pipefp); 1510 pclose(pipefp); 1511 ignore_signals(); 1512 if (!check_only) { 1513 if (move_file(TMPOUTNAME, outname) < 0) { 1514 toutkeep = true; 1515 chmod(TMPOUTNAME, filemode); 1516 } else 1517 chmod(outname, filemode); 1518 } 1519 set_signals(1); 1520 } 1521 1522 /* 1523 * Choose the name of the file to be patched based on POSIX rules. 1524 * NOTE: the POSIX rules are amazingly stupid and we only follow them 1525 * if the user specified --posix or set POSIXLY_CORRECT. 1526 */ 1527 static char * 1528 posix_name(const struct file_name *names, bool assume_exists) 1529 { 1530 char *path = NULL; 1531 int i; 1532 1533 /* 1534 * POSIX states that the filename will be chosen from one 1535 * of the old, new and index names (in that order) if 1536 * the file exists relative to CWD after -p stripping. 1537 */ 1538 for (i = 0; i < MAX_FILE; i++) { 1539 if (names[i].path != NULL && names[i].exists) { 1540 path = names[i].path; 1541 break; 1542 } 1543 } 1544 if (path == NULL && !assume_exists) { 1545 /* 1546 * No files found, check to see if the diff could be 1547 * creating a new file. 1548 */ 1549 if (path == NULL && ok_to_create_file && 1550 names[NEW_FILE].path != NULL) 1551 path = names[NEW_FILE].path; 1552 } 1553 1554 return path ? xstrdup(path) : NULL; 1555 } 1556 1557 static char * 1558 compare_names(const struct file_name *names, bool assume_exists) 1559 { 1560 size_t min_components, min_baselen, min_len, tmp; 1561 char *best = NULL; 1562 char *path; 1563 int i; 1564 1565 /* 1566 * The "best" name is the one with the fewest number of path 1567 * components, the shortest basename length, and the shortest 1568 * overall length (in that order). We only use the Index: file 1569 * if neither of the old or new files could be intuited from 1570 * the diff header. 1571 */ 1572 min_components = min_baselen = min_len = SIZE_MAX; 1573 for (i = INDEX_FILE; i >= OLD_FILE; i--) { 1574 path = names[i].path; 1575 if (path == NULL || (!names[i].exists && !assume_exists)) 1576 continue; 1577 if ((tmp = num_components(path)) > min_components) 1578 continue; 1579 if (tmp < min_components) { 1580 min_components = tmp; 1581 best = path; 1582 } 1583 if ((tmp = strlen(basename(path))) > min_baselen) 1584 continue; 1585 if (tmp < min_baselen) { 1586 min_baselen = tmp; 1587 best = path; 1588 } 1589 if ((tmp = strlen(path)) > min_len) 1590 continue; 1591 min_len = tmp; 1592 best = path; 1593 } 1594 return best; 1595 } 1596 1597 /* 1598 * Choose the name of the file to be patched based the "best" one 1599 * available. 1600 */ 1601 static char * 1602 best_name(const struct file_name *names, bool assume_exists) 1603 { 1604 char *best; 1605 1606 best = compare_names(names, assume_exists); 1607 1608 /* No match? Check to see if the diff could be creating a new file. */ 1609 if (best == NULL && ok_to_create_file) 1610 best = names[NEW_FILE].path; 1611 1612 return best ? xstrdup(best) : NULL; 1613 } 1614 1615 static size_t 1616 num_components(const char *path) 1617 { 1618 size_t n; 1619 const char *cp; 1620 1621 for (n = 0, cp = path; (cp = strchr(cp, '/')) != NULL; n++, cp++) { 1622 while (*cp == '/') 1623 cp++; /* skip consecutive slashes */ 1624 } 1625 return n; 1626 } 1627 1628 /* 1629 * Convert number at NPTR into LINENUM and save address of first 1630 * character that is not a digit in ENDPTR. If conversion is not 1631 * possible, call fatal. 1632 */ 1633 static LINENUM 1634 strtolinenum(char *nptr, char **endptr) 1635 { 1636 LINENUM rv; 1637 char c; 1638 char *p; 1639 const char *errstr; 1640 1641 for (p = nptr; isdigit((unsigned char)*p); p++) 1642 ; 1643 1644 if (p == nptr) 1645 malformed(); 1646 1647 c = *p; 1648 *p = '\0'; 1649 1650 rv = strtonum(nptr, 0, LINENUM_MAX, &errstr); 1651 if (errstr != NULL) 1652 fatal("invalid line number at line %ld: `%s' is %s\n", 1653 p_input_line, nptr, errstr); 1654 1655 *p = c; 1656 *endptr = p; 1657 1658 return rv; 1659 } 1660