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