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