pch.c revision 50488
1/* $FreeBSD: head/gnu/usr.bin/patch/pch.c 50488 1999-08-28 05:11:36Z peter $ 2 * 3 * $Log: pch.c,v $ 4 * Revision 1.14 1998/01/21 15:10:14 ache 5 * Add -I or --index-first option to take Index: precedence over context diff, 6 * as it was in hacked FreeBSD version 7 * 8 * Revision 1.13 1998/01/21 14:37:23 ache 9 * Resurrect patch 2.1 without FreeBSD Index: hack 10 * 11 * Revision 1.8.2.2 1998/01/03 23:52:05 ache 12 * MFC: ctype and Index over +++/--- precedence 13 * 14 * Revision 1.11 1998/01/03 23:42:56 ache 15 * Back out Index over +++/--- precedence. 16 * It maybe right, if patch was FreeBSD-own program, but it break compatibility 17 * with pre-existent patches in other systems. 18 * The example is big ncurses patch which don't apply on FreeBSD 19 * due to "fixed" precedence. 20 * 21 * Revision 1.10 1997/10/23 02:44:22 ache 22 * Add (unsigned char) cast to ctype macros 23 * 24 * Revision 1.9 1997/02/13 21:10:43 jmg 25 * Fix a problem with patch in that is will always default, even when the 26 * controlling terminal is closed. Now the function ask() will return 1 when th 27 * input is known to come from a file or terminal, or it will return 0 when ther 28 * was a read error. 29 * 30 * Modified the question "Skip patch?" so that on an error from ask it will skip 31 * the patch instead of looping. 32 * 33 * Closes PR#777 34 * 35 * 2.2 candidate 36 * 37 * Revision 1.8 1996/04/12 11:37:32 markm 38 * Attempt to break a $Log: pch.c,v $ 39 * Attempt to break a Revision 1.14 1998/01/21 15:10:14 ache 40 * Attempt to break a Add -I or --index-first option to take Index: precedence over context diff, 41 * Attempt to break a as it was in hacked FreeBSD version 42 * Attempt to break a 43 * Attempt to break a Revision 1.13 1998/01/21 14:37:23 ache 44 * Attempt to break a Resurrect patch 2.1 without FreeBSD Index: hack 45 * Attempt to break a 46 * Attempt to break a Revision 1.8.2.2 1998/01/03 23:52:05 ache 47 * Attempt to break a MFC: ctype and Index over +++/--- precedence 48 * Attempt to break a 49 * Attempt to break a Revision 1.11 1998/01/03 23:42:56 ache 50 * Attempt to break a Back out Index over +++/--- precedence. 51 * Attempt to break a It maybe right, if patch was FreeBSD-own program, but it break compatibility 52 * Attempt to break a with pre-existent patches in other systems. 53 * Attempt to break a The example is big ncurses patch which don't apply on FreeBSD 54 * Attempt to break a due to "fixed" precedence. 55 * Attempt to break a 56 * Attempt to break a Revision 1.10 1997/10/23 02:44:22 ache 57 * Attempt to break a Add (unsigned char) cast to ctype macros 58 * Attempt to break a 59 * Attempt to break a Revision 1.9 1997/02/13 21:10:43 jmg 60 * Attempt to break a Fix a problem with patch in that is will always default, even when the 61 * Attempt to break a controlling terminal is closed. Now the function ask() will return 1 when th 62 * Attempt to break a input is known to come from a file or terminal, or it will return 0 when ther 63 * Attempt to break a was a read error. 64 * Attempt to break a 65 * Attempt to break a Modified the question "Skip patch?" so that on an error from ask it will skip 66 * Attempt to break a the patch instead of looping. 67 * Attempt to break a 68 * Attempt to break a Closes PR#777 69 * Attempt to break a 70 * Attempt to break a 2.2 candidate 71 * Attempt to break a snafu where a *** /--- (minus space) 72 * was fouling up a comment in the checked-out code. 73 * 74 * Revision 1.7 1996/04/11 10:13:40 markm 75 * Priorities were broken. If there was an Index: line and *** /--- lines 76 * with valid names, the *** /---names were taken first. 77 * this broke eg: 78 * Index: foo/Makefile 79 * ========== 80 * RCS <blah> 81 * Retrieving <blah> 82 * diff <blah> 83 * *** Makefile <blah> 84 * --- Makefile <blah> 85 * 86 * By trying to patch the Makefile in the _curent_ directory, rather than 87 * the one in the foo/ directory. 88 * 89 * Revision 1.6 1995/09/14 04:33:35 gibbs 90 * Give "Index" specified filenames preference over other filenames specified 91 * in the diff. This makes it so that diffs containing files in different 92 * subdirectories that have the same name not patch the same file. For example 93 * a diff with patches to Makefile, des/Makefile, usr.bin/Makefile would attempt 94 * to patch Makefile three times. 95 * 96 * Revision 1.5 1995/05/30 05:02:35 rgrimes 97 * Remove trailing whitespace. 98 * 99 * Revision 1.4 1994/02/25 21:46:07 phk 100 * added the -C/-check again. 101 * 102 * Revision 1.3 1994/02/17 22:20:36 jkh 103 * Put this back - I was somehow under the erroneous impression that patch was in 104 * ports, until I saw the the commit messages, that is! :-) All changed backed out. 105 * 106 * Revision 1.2 1994/02/17 22:16:05 jkh 107 * From Poul-Henning Kamp - Implement a -C option to verify the integrity of 108 * a patch before actually applying it. 109 * 110 * Revision 1.1.1.1 1993/06/19 14:21:52 paul 111 * b-maked patch-2.10 112 * 113 * Revision 2.0.2.0 90/05/01 22:17:51 davison 114 * patch12u: unidiff support added 115 * 116 * Revision 2.0.1.7 88/06/03 15:13:28 lwall 117 * patch10: Can now find patches in shar scripts. 118 * patch10: Hunks that swapped and then swapped back could core dump. 119 * 120 * Revision 2.0.1.6 87/06/04 16:18:13 lwall 121 * pch_swap didn't swap p_bfake and p_efake. 122 * 123 * Revision 2.0.1.5 87/01/30 22:47:42 lwall 124 * Improved responses to mangled patches. 125 * 126 * Revision 2.0.1.4 87/01/05 16:59:53 lwall 127 * New-style context diffs caused double call to free(). 128 * 129 * Revision 2.0.1.3 86/11/14 10:08:33 lwall 130 * Fixed problem where a long pattern wouldn't grow the hunk. 131 * Also restored p_input_line when backtracking so error messages are right. 132 * 133 * Revision 2.0.1.2 86/11/03 17:49:52 lwall 134 * New-style delete triggers spurious assertion error. 135 * 136 * Revision 2.0.1.1 86/10/29 15:52:08 lwall 137 * Could falsely report new-style context diff. 138 * 139 * Revision 2.0 86/09/17 15:39:37 lwall 140 * Baseline for netwide release. 141 * 142 */ 143 144#include "EXTERN.h" 145#include "common.h" 146#include "util.h" 147#include "INTERN.h" 148#include "pch.h" 149 150/* Patch (diff listing) abstract type. */ 151 152static long p_filesize; /* size of the patch file */ 153static LINENUM p_first; /* 1st line number */ 154static LINENUM p_newfirst; /* 1st line number of replacement */ 155static LINENUM p_ptrn_lines; /* # lines in pattern */ 156static LINENUM p_repl_lines; /* # lines in replacement text */ 157static LINENUM p_end = -1; /* last line in hunk */ 158static LINENUM p_max; /* max allowed value of p_end */ 159static LINENUM p_context = 3; /* # of context lines */ 160static LINENUM p_input_line = 0; /* current line # from patch file */ 161static char **p_line = Null(char**); /* the text of the hunk */ 162static short *p_len = Null(short*); /* length of each line */ 163static char *p_Char = Nullch; /* +, -, and ! */ 164static int hunkmax = INITHUNKMAX; /* size of above arrays to begin with */ 165static int p_indent; /* indent to patch */ 166static LINENUM p_base; /* where to intuit this time */ 167static LINENUM p_bline; /* line # of p_base */ 168static LINENUM p_start; /* where intuit found a patch */ 169static LINENUM p_sline; /* and the line number for it */ 170static LINENUM p_hunk_beg; /* line number of current hunk */ 171static LINENUM p_efake = -1; /* end of faked up lines--don't free */ 172static LINENUM p_bfake = -1; /* beg of faked up lines */ 173 174/* Prepare to look for the next patch in the patch file. */ 175 176void 177re_patch() 178{ 179 p_first = Nulline; 180 p_newfirst = Nulline; 181 p_ptrn_lines = Nulline; 182 p_repl_lines = Nulline; 183 p_end = (LINENUM)-1; 184 p_max = Nulline; 185 p_indent = 0; 186} 187 188/* Open the patch file at the beginning of time. */ 189 190void 191open_patch_file(filename) 192char *filename; 193{ 194 if (filename == Nullch || !*filename || strEQ(filename, "-")) { 195 pfp = fopen(TMPPATNAME, "w"); 196 if (pfp == Nullfp) 197 pfatal2("can't create %s", TMPPATNAME); 198 while (fgets(buf, sizeof buf, stdin) != Nullch) 199 fputs(buf, pfp); 200 Fclose(pfp); 201 filename = TMPPATNAME; 202 } 203 pfp = fopen(filename, "r"); 204 if (pfp == Nullfp) 205 pfatal2("patch file %s not found", filename); 206 Fstat(fileno(pfp), &filestat); 207 p_filesize = filestat.st_size; 208 next_intuit_at(0L,1L); /* start at the beginning */ 209 set_hunkmax(); 210} 211 212/* Make sure our dynamically realloced tables are malloced to begin with. */ 213 214void 215set_hunkmax() 216{ 217#ifndef lint 218 if (p_line == Null(char**)) 219 p_line = (char**) malloc((MEM)hunkmax * sizeof(char *)); 220 if (p_len == Null(short*)) 221 p_len = (short*) malloc((MEM)hunkmax * sizeof(short)); 222#endif 223 if (p_Char == Nullch) 224 p_Char = (char*) malloc((MEM)hunkmax * sizeof(char)); 225} 226 227/* Enlarge the arrays containing the current hunk of patch. */ 228 229void 230grow_hunkmax() 231{ 232 hunkmax *= 2; 233 /* 234 * Note that on most systems, only the p_line array ever gets fresh memory 235 * since p_len can move into p_line's old space, and p_Char can move into 236 * p_len's old space. Not on PDP-11's however. But it doesn't matter. 237 */ 238 assert(p_line != Null(char**) && p_len != Null(short*) && p_Char != Nullch); 239#ifndef lint 240 p_line = (char**) realloc((char*)p_line, (MEM)hunkmax * sizeof(char *)); 241 p_len = (short*) realloc((char*)p_len, (MEM)hunkmax * sizeof(short)); 242 p_Char = (char*) realloc((char*)p_Char, (MEM)hunkmax * sizeof(char)); 243#endif 244 if (p_line != Null(char**) && p_len != Null(short*) && p_Char != Nullch) 245 return; 246 if (!using_plan_a) 247 fatal1("out of memory\n"); 248 out_of_mem = TRUE; /* whatever is null will be allocated again */ 249 /* from within plan_a(), of all places */ 250} 251 252/* True if the remainder of the patch file contains a diff of some sort. */ 253 254bool 255there_is_another_patch() 256{ 257 if (p_base != 0L && p_base >= p_filesize) { 258 if (verbose) 259 say1("done\n"); 260 return FALSE; 261 } 262 if (verbose) 263 say1("Hmm..."); 264 diff_type = intuit_diff_type(); 265 if (!diff_type) { 266 if (p_base != 0L) { 267 if (verbose) 268 say1(" Ignoring the trailing garbage.\ndone\n"); 269 } 270 else 271 say1(" I can't seem to find a patch in there anywhere.\n"); 272 return FALSE; 273 } 274 if (verbose) 275 say3(" %sooks like %s to me...\n", 276 (p_base == 0L ? "L" : "The next patch l"), 277 diff_type == UNI_DIFF ? "a unified diff" : 278 diff_type == CONTEXT_DIFF ? "a context diff" : 279 diff_type == NEW_CONTEXT_DIFF ? "a new-style context diff" : 280 diff_type == NORMAL_DIFF ? "a normal diff" : 281 "an ed script" ); 282 if (p_indent && verbose) 283 say3("(Patch is indented %d space%s.)\n", p_indent, p_indent==1?"":"s"); 284 skip_to(p_start,p_sline); 285 while (filearg[0] == Nullch) { 286 if (force || batch) { 287 say1("No file to patch. Skipping...\n"); 288 filearg[0] = savestr(bestguess); 289 skip_rest_of_patch = TRUE; 290 return TRUE; 291 } 292 (void) ask1("File to patch: "); 293 if (*buf != '\n') { 294 if (bestguess) 295 free(bestguess); 296 bestguess = savestr(buf); 297 filearg[0] = fetchname(buf, 0, FALSE); 298 } 299 if (filearg[0] == Nullch) { 300 if (ask1("No file found--skip this patch? [n] ")) { 301 if (*buf != 'y') { 302 continue; 303 } 304 } 305 if (verbose) 306 say1("Skipping patch...\n"); 307 filearg[0] = fetchname(bestguess, 0, TRUE); 308 skip_rest_of_patch = TRUE; 309 return TRUE; 310 } 311 } 312 return TRUE; 313} 314 315/* Determine what kind of diff is in the remaining part of the patch file. */ 316 317int 318intuit_diff_type() 319{ 320 Reg4 long this_line = 0; 321 Reg5 long previous_line; 322 Reg6 long first_command_line = -1; 323 long fcl_line; 324 Reg7 bool last_line_was_command = FALSE; 325 Reg8 bool this_is_a_command = FALSE; 326 Reg9 bool stars_last_line = FALSE; 327 Reg10 bool stars_this_line = FALSE; 328 Reg3 int indent; 329 Reg1 char *s; 330 Reg2 char *t; 331 char *indtmp = Nullch; 332 char *oldtmp = Nullch; 333 char *newtmp = Nullch; 334 char *indname = Nullch; 335 char *oldname = Nullch; 336 char *newname = Nullch; 337 Reg11 int retval; 338 bool no_filearg = (filearg[0] == Nullch); 339 extern int index_first; 340 341 ok_to_create_file = FALSE; 342 Fseek(pfp, p_base, 0); 343 p_input_line = p_bline - 1; 344 for (;;) { 345 previous_line = this_line; 346 last_line_was_command = this_is_a_command; 347 stars_last_line = stars_this_line; 348 this_line = ftell(pfp); 349 indent = 0; 350 p_input_line++; 351 if (fgets(buf, sizeof buf, pfp) == Nullch) { 352 if (first_command_line >= 0L) { 353 /* nothing but deletes!? */ 354 p_start = first_command_line; 355 p_sline = fcl_line; 356 retval = ED_DIFF; 357 goto scan_exit; 358 } 359 else { 360 p_start = this_line; 361 p_sline = p_input_line; 362 retval = 0; 363 goto scan_exit; 364 } 365 } 366 for (s = buf; *s == ' ' || *s == '\t' || *s == 'X'; s++) { 367 if (*s == '\t') 368 indent += 8 - (indent % 8); 369 else 370 indent++; 371 } 372 for (t=s; isdigit((unsigned char)*t) || *t == ','; t++) ; 373 this_is_a_command = (isdigit((unsigned char)*s) && 374 (*t == 'd' || *t == 'c' || *t == 'a') ); 375 if (first_command_line < 0L && this_is_a_command) { 376 first_command_line = this_line; 377 fcl_line = p_input_line; 378 p_indent = indent; /* assume this for now */ 379 } 380 if (!stars_last_line && strnEQ(s, "*** ", 4)) 381 oldtmp = savestr(s+4); 382 else if (strnEQ(s, "--- ", 4)) 383 newtmp = savestr(s+4); 384 else if (strnEQ(s, "+++ ", 4)) 385 oldtmp = savestr(s+4); /* pretend it is the old name */ 386 else if (strnEQ(s, "Index:", 6)) 387 indtmp = savestr(s+6); 388 else if (strnEQ(s, "Prereq:", 7)) { 389 for (t=s+7; isspace((unsigned char)*t); t++) ; 390 revision = savestr(t); 391 for (t=revision; *t && !isspace((unsigned char)*t); t++) ; 392 *t = '\0'; 393 if (!*revision) { 394 free(revision); 395 revision = Nullch; 396 } 397 } 398 if ((!diff_type || diff_type == ED_DIFF) && 399 first_command_line >= 0L && 400 strEQ(s, ".\n") ) { 401 p_indent = indent; 402 p_start = first_command_line; 403 p_sline = fcl_line; 404 retval = ED_DIFF; 405 goto scan_exit; 406 } 407 if ((!diff_type || diff_type == UNI_DIFF) && strnEQ(s, "@@ -", 4)) { 408 if (!atol(s+3)) 409 ok_to_create_file = TRUE; 410 p_indent = indent; 411 p_start = this_line; 412 p_sline = p_input_line; 413 retval = UNI_DIFF; 414 goto scan_exit; 415 } 416 stars_this_line = strnEQ(s, "********", 8); 417 if ((!diff_type || diff_type == CONTEXT_DIFF) && stars_last_line && 418 strnEQ(s, "*** ", 4)) { 419 if (!atol(s+4)) 420 ok_to_create_file = TRUE; 421 /* if this is a new context diff the character just before */ 422 /* the newline is a '*'. */ 423 while (*s != '\n') 424 s++; 425 p_indent = indent; 426 p_start = previous_line; 427 p_sline = p_input_line - 1; 428 retval = (*(s-1) == '*' ? NEW_CONTEXT_DIFF : CONTEXT_DIFF); 429 goto scan_exit; 430 } 431 if ((!diff_type || diff_type == NORMAL_DIFF) && 432 last_line_was_command && 433 (strnEQ(s, "< ", 2) || strnEQ(s, "> ", 2)) ) { 434 p_start = previous_line; 435 p_sline = p_input_line - 1; 436 p_indent = indent; 437 retval = NORMAL_DIFF; 438 goto scan_exit; 439 } 440 } 441 scan_exit: 442 if (no_filearg) { 443 if (indtmp != Nullch) 444 indname = fetchname(indtmp, strippath, ok_to_create_file); 445 if (oldtmp != Nullch) 446 oldname = fetchname(oldtmp, strippath, ok_to_create_file); 447 if (newtmp != Nullch) 448 newname = fetchname(newtmp, strippath, ok_to_create_file); 449 if (index_first && indname) 450 filearg[0] = savestr(indname); 451 else if (oldname && newname) { 452 if (strlen(oldname) < strlen(newname)) 453 filearg[0] = savestr(oldname); 454 else 455 filearg[0] = savestr(newname); 456 } else if (indname) 457 filearg[0] = savestr(indname); 458 else if (oldname) 459 filearg[0] = savestr(oldname); 460 else if (newname) 461 filearg[0] = savestr(newname); 462 } 463 if (bestguess) { 464 free(bestguess); 465 bestguess = Nullch; 466 } 467 if (filearg[0] != Nullch) 468 bestguess = savestr(filearg[0]); 469 else if (indtmp != Nullch) 470 bestguess = fetchname(indtmp, strippath, TRUE); 471 else { 472 if (oldtmp != Nullch) 473 oldname = fetchname(oldtmp, strippath, TRUE); 474 if (newtmp != Nullch) 475 newname = fetchname(newtmp, strippath, TRUE); 476 if (oldname && newname) { 477 if (strlen(oldname) < strlen(newname)) 478 bestguess = savestr(oldname); 479 else 480 bestguess = savestr(newname); 481 } 482 else if (oldname) 483 bestguess = savestr(oldname); 484 else if (newname) 485 bestguess = savestr(newname); 486 } 487 if (indtmp != Nullch) 488 free(indtmp); 489 if (oldtmp != Nullch) 490 free(oldtmp); 491 if (newtmp != Nullch) 492 free(newtmp); 493 if (indname != Nullch) 494 free(indname); 495 if (oldname != Nullch) 496 free(oldname); 497 if (newname != Nullch) 498 free(newname); 499 return retval; 500} 501 502/* Remember where this patch ends so we know where to start up again. */ 503 504void 505next_intuit_at(file_pos,file_line) 506long file_pos; 507long file_line; 508{ 509 p_base = file_pos; 510 p_bline = file_line; 511} 512 513/* Basically a verbose fseek() to the actual diff listing. */ 514 515void 516skip_to(file_pos,file_line) 517long file_pos; 518long file_line; 519{ 520 char *ret; 521 522 assert(p_base <= file_pos); 523 if (verbose && p_base < file_pos) { 524 Fseek(pfp, p_base, 0); 525 say1("The text leading up to this was:\n--------------------------\n"); 526 while (ftell(pfp) < file_pos) { 527 ret = fgets(buf, sizeof buf, pfp); 528 assert(ret != Nullch); 529 say2("|%s", buf); 530 } 531 say1("--------------------------\n"); 532 } 533 else 534 Fseek(pfp, file_pos, 0); 535 p_input_line = file_line - 1; 536} 537 538/* Make this a function for better debugging. */ 539static void 540malformed () 541{ 542 fatal3("malformed patch at line %ld: %s", p_input_line, buf); 543 /* about as informative as "Syntax error" in C */ 544} 545 546/* True if there is more of the current diff listing to process. */ 547 548bool 549another_hunk() 550{ 551 Reg1 char *s; 552 Reg8 char *ret; 553 Reg2 int context = 0; 554 555 while (p_end >= 0) { 556 if (p_end == p_efake) 557 p_end = p_bfake; /* don't free twice */ 558 else 559 free(p_line[p_end]); 560 p_end--; 561 } 562 assert(p_end == -1); 563 p_efake = -1; 564 565 p_max = hunkmax; /* gets reduced when --- found */ 566 if (diff_type == CONTEXT_DIFF || diff_type == NEW_CONTEXT_DIFF) { 567 long line_beginning = ftell(pfp); 568 /* file pos of the current line */ 569 LINENUM repl_beginning = 0; /* index of --- line */ 570 Reg4 LINENUM fillcnt = 0; /* #lines of missing ptrn or repl */ 571 Reg5 LINENUM fillsrc; /* index of first line to copy */ 572 Reg6 LINENUM filldst; /* index of first missing line */ 573 bool ptrn_spaces_eaten = FALSE; /* ptrn was slightly misformed */ 574 Reg9 bool repl_could_be_missing = TRUE; 575 /* no + or ! lines in this hunk */ 576 bool repl_missing = FALSE; /* we are now backtracking */ 577 long repl_backtrack_position = 0; 578 /* file pos of first repl line */ 579 LINENUM repl_patch_line; /* input line number for same */ 580 Reg7 LINENUM ptrn_copiable = 0; 581 /* # of copiable lines in ptrn */ 582 583 ret = pgets(buf, sizeof buf, pfp); 584 p_input_line++; 585 if (ret == Nullch || strnNE(buf, "********", 8)) { 586 next_intuit_at(line_beginning,p_input_line); 587 return FALSE; 588 } 589 p_context = 100; 590 p_hunk_beg = p_input_line + 1; 591 while (p_end < p_max) { 592 line_beginning = ftell(pfp); 593 ret = pgets(buf, sizeof buf, pfp); 594 p_input_line++; 595 if (ret == Nullch) { 596 if (p_max - p_end < 4) 597 Strcpy(buf, " \n"); /* assume blank lines got chopped */ 598 else { 599 if (repl_beginning && repl_could_be_missing) { 600 repl_missing = TRUE; 601 goto hunk_done; 602 } 603 fatal1("unexpected end of file in patch\n"); 604 } 605 } 606 p_end++; 607 assert(p_end < hunkmax); 608 p_Char[p_end] = *buf; 609#ifdef zilog 610 p_line[(short)p_end] = Nullch; 611#else 612 p_line[p_end] = Nullch; 613#endif 614 switch (*buf) { 615 case '*': 616 if (strnEQ(buf, "********", 8)) { 617 if (repl_beginning && repl_could_be_missing) { 618 repl_missing = TRUE; 619 goto hunk_done; 620 } 621 else 622 fatal2("unexpected end of hunk at line %ld\n", 623 p_input_line); 624 } 625 if (p_end != 0) { 626 if (repl_beginning && repl_could_be_missing) { 627 repl_missing = TRUE; 628 goto hunk_done; 629 } 630 fatal3("unexpected *** at line %ld: %s", p_input_line, buf); 631 } 632 context = 0; 633 p_line[p_end] = savestr(buf); 634 if (out_of_mem) { 635 p_end--; 636 return FALSE; 637 } 638 for (s=buf; *s && !isdigit((unsigned char)*s); s++) ; 639 if (!*s) 640 malformed (); 641 if (strnEQ(s,"0,0",3)) 642 strcpy(s,s+2); 643 p_first = (LINENUM) atol(s); 644 while (isdigit((unsigned char)*s)) s++; 645 if (*s == ',') { 646 for (; *s && !isdigit((unsigned char)*s); s++) ; 647 if (!*s) 648 malformed (); 649 p_ptrn_lines = ((LINENUM)atol(s)) - p_first + 1; 650 } 651 else if (p_first) 652 p_ptrn_lines = 1; 653 else { 654 p_ptrn_lines = 0; 655 p_first = 1; 656 } 657 p_max = p_ptrn_lines + 6; /* we need this much at least */ 658 while (p_max >= hunkmax) 659 grow_hunkmax(); 660 p_max = hunkmax; 661 break; 662 case '-': 663 if (buf[1] == '-') { 664 if (repl_beginning || 665 (p_end != p_ptrn_lines + 1 + (p_Char[p_end-1] == '\n'))) 666 { 667 if (p_end == 1) { 668 /* `old' lines were omitted - set up to fill */ 669 /* them in from 'new' context lines. */ 670 p_end = p_ptrn_lines + 1; 671 fillsrc = p_end + 1; 672 filldst = 1; 673 fillcnt = p_ptrn_lines; 674 } 675 else { 676 if (repl_beginning) { 677 if (repl_could_be_missing){ 678 repl_missing = TRUE; 679 goto hunk_done; 680 } 681 fatal3( 682"duplicate \"---\" at line %ld--check line numbers at line %ld\n", 683 p_input_line, p_hunk_beg + repl_beginning); 684 } 685 else { 686 fatal4( 687"%s \"---\" at line %ld--check line numbers at line %ld\n", 688 (p_end <= p_ptrn_lines 689 ? "Premature" 690 : "Overdue" ), 691 p_input_line, p_hunk_beg); 692 } 693 } 694 } 695 repl_beginning = p_end; 696 repl_backtrack_position = ftell(pfp); 697 repl_patch_line = p_input_line; 698 p_line[p_end] = savestr(buf); 699 if (out_of_mem) { 700 p_end--; 701 return FALSE; 702 } 703 p_Char[p_end] = '='; 704 for (s=buf; *s && !isdigit((unsigned char)*s); s++) ; 705 if (!*s) 706 malformed (); 707 p_newfirst = (LINENUM) atol(s); 708 while (isdigit((unsigned char)*s)) s++; 709 if (*s == ',') { 710 for (; *s && !isdigit((unsigned char)*s); s++) ; 711 if (!*s) 712 malformed (); 713 p_repl_lines = ((LINENUM)atol(s)) - p_newfirst + 1; 714 } 715 else if (p_newfirst) 716 p_repl_lines = 1; 717 else { 718 p_repl_lines = 0; 719 p_newfirst = 1; 720 } 721 p_max = p_repl_lines + p_end; 722 if (p_max > MAXHUNKSIZE) 723 fatal4("hunk too large (%ld lines) at line %ld: %s", 724 p_max, p_input_line, buf); 725 while (p_max >= hunkmax) 726 grow_hunkmax(); 727 if (p_repl_lines != ptrn_copiable 728 && (p_context != 0 || p_repl_lines != 1)) 729 repl_could_be_missing = FALSE; 730 break; 731 } 732 goto change_line; 733 case '+': case '!': 734 repl_could_be_missing = FALSE; 735 change_line: 736 if (buf[1] == '\n' && canonicalize) 737 strcpy(buf+1," \n"); 738 if (!isspace((unsigned char)buf[1]) && buf[1] != '>' && buf[1] != '<' && 739 repl_beginning && repl_could_be_missing) { 740 repl_missing = TRUE; 741 goto hunk_done; 742 } 743 if (context >= 0) { 744 if (context < p_context) 745 p_context = context; 746 context = -1000; 747 } 748 p_line[p_end] = savestr(buf+2); 749 if (out_of_mem) { 750 p_end--; 751 return FALSE; 752 } 753 break; 754 case '\t': case '\n': /* assume the 2 spaces got eaten */ 755 if (repl_beginning && repl_could_be_missing && 756 (!ptrn_spaces_eaten || diff_type == NEW_CONTEXT_DIFF) ) { 757 repl_missing = TRUE; 758 goto hunk_done; 759 } 760 p_line[p_end] = savestr(buf); 761 if (out_of_mem) { 762 p_end--; 763 return FALSE; 764 } 765 if (p_end != p_ptrn_lines + 1) { 766 ptrn_spaces_eaten |= (repl_beginning != 0); 767 context++; 768 if (!repl_beginning) 769 ptrn_copiable++; 770 p_Char[p_end] = ' '; 771 } 772 break; 773 case ' ': 774 if (!isspace((unsigned char)buf[1]) && 775 repl_beginning && repl_could_be_missing) { 776 repl_missing = TRUE; 777 goto hunk_done; 778 } 779 context++; 780 if (!repl_beginning) 781 ptrn_copiable++; 782 p_line[p_end] = savestr(buf+2); 783 if (out_of_mem) { 784 p_end--; 785 return FALSE; 786 } 787 break; 788 default: 789 if (repl_beginning && repl_could_be_missing) { 790 repl_missing = TRUE; 791 goto hunk_done; 792 } 793 malformed (); 794 } 795 /* set up p_len for strncmp() so we don't have to */ 796 /* assume null termination */ 797 if (p_line[p_end]) 798 p_len[p_end] = strlen(p_line[p_end]); 799 else 800 p_len[p_end] = 0; 801 } 802 803 hunk_done: 804 if (p_end >=0 && !repl_beginning) 805 fatal2("no --- found in patch at line %ld\n", pch_hunk_beg()); 806 807 if (repl_missing) { 808 809 /* reset state back to just after --- */ 810 p_input_line = repl_patch_line; 811 for (p_end--; p_end > repl_beginning; p_end--) 812 free(p_line[p_end]); 813 Fseek(pfp, repl_backtrack_position, 0); 814 815 /* redundant 'new' context lines were omitted - set */ 816 /* up to fill them in from the old file context */ 817 if (!p_context && p_repl_lines == 1) { 818 p_repl_lines = 0; 819 p_max--; 820 } 821 fillsrc = 1; 822 filldst = repl_beginning+1; 823 fillcnt = p_repl_lines; 824 p_end = p_max; 825 } 826 else if (!p_context && fillcnt == 1) { 827 /* the first hunk was a null hunk with no context */ 828 /* and we were expecting one line -- fix it up. */ 829 while (filldst < p_end) { 830 p_line[filldst] = p_line[filldst+1]; 831 p_Char[filldst] = p_Char[filldst+1]; 832 p_len[filldst] = p_len[filldst+1]; 833 filldst++; 834 } 835#if 0 836 repl_beginning--; /* this doesn't need to be fixed */ 837#endif 838 p_end--; 839 p_first++; /* do append rather than insert */ 840 fillcnt = 0; 841 p_ptrn_lines = 0; 842 } 843 844 if (diff_type == CONTEXT_DIFF && 845 (fillcnt || (p_first > 1 && ptrn_copiable > 2*p_context)) ) { 846 if (verbose) 847 say4("%s\n%s\n%s\n", 848"(Fascinating--this is really a new-style context diff but without", 849"the telltale extra asterisks on the *** line that usually indicate", 850"the new style...)"); 851 diff_type = NEW_CONTEXT_DIFF; 852 } 853 854 /* if there were omitted context lines, fill them in now */ 855 if (fillcnt) { 856 p_bfake = filldst; /* remember where not to free() */ 857 p_efake = filldst + fillcnt - 1; 858 while (fillcnt-- > 0) { 859 while (fillsrc <= p_end && p_Char[fillsrc] != ' ') 860 fillsrc++; 861 if (fillsrc > p_end) 862 fatal2("replacement text or line numbers mangled in hunk at line %ld\n", 863 p_hunk_beg); 864 p_line[filldst] = p_line[fillsrc]; 865 p_Char[filldst] = p_Char[fillsrc]; 866 p_len[filldst] = p_len[fillsrc]; 867 fillsrc++; filldst++; 868 } 869 while (fillsrc <= p_end && fillsrc != repl_beginning && 870 p_Char[fillsrc] != ' ') 871 fillsrc++; 872#ifdef DEBUGGING 873 if (debug & 64) 874 printf("fillsrc %ld, filldst %ld, rb %ld, e+1 %ld\n", 875 fillsrc,filldst,repl_beginning,p_end+1); 876#endif 877 assert(fillsrc==p_end+1 || fillsrc==repl_beginning); 878 assert(filldst==p_end+1 || filldst==repl_beginning); 879 } 880 } 881 else if (diff_type == UNI_DIFF) { 882 long line_beginning = ftell(pfp); 883 /* file pos of the current line */ 884 Reg4 LINENUM fillsrc; /* index of old lines */ 885 Reg5 LINENUM filldst; /* index of new lines */ 886 char ch; 887 888 ret = pgets(buf, sizeof buf, pfp); 889 p_input_line++; 890 if (ret == Nullch || strnNE(buf, "@@ -", 4)) { 891 next_intuit_at(line_beginning,p_input_line); 892 return FALSE; 893 } 894 s = buf+4; 895 if (!*s) 896 malformed (); 897 p_first = (LINENUM) atol(s); 898 while (isdigit((unsigned char)*s)) s++; 899 if (*s == ',') { 900 p_ptrn_lines = (LINENUM) atol(++s); 901 while (isdigit((unsigned char)*s)) s++; 902 } else 903 p_ptrn_lines = 1; 904 if (*s == ' ') s++; 905 if (*s != '+' || !*++s) 906 malformed (); 907 p_newfirst = (LINENUM) atol(s); 908 while (isdigit((unsigned char)*s)) s++; 909 if (*s == ',') { 910 p_repl_lines = (LINENUM) atol(++s); 911 while (isdigit((unsigned char)*s)) s++; 912 } else 913 p_repl_lines = 1; 914 if (*s == ' ') s++; 915 if (*s != '@') 916 malformed (); 917 if (!p_ptrn_lines) 918 p_first++; /* do append rather than insert */ 919 p_max = p_ptrn_lines + p_repl_lines + 1; 920 while (p_max >= hunkmax) 921 grow_hunkmax(); 922 fillsrc = 1; 923 filldst = fillsrc + p_ptrn_lines; 924 p_end = filldst + p_repl_lines; 925 Sprintf(buf,"*** %ld,%ld ****\n",p_first,p_first + p_ptrn_lines - 1); 926 p_line[0] = savestr(buf); 927 if (out_of_mem) { 928 p_end = -1; 929 return FALSE; 930 } 931 p_Char[0] = '*'; 932 Sprintf(buf,"--- %ld,%ld ----\n",p_newfirst,p_newfirst+p_repl_lines-1); 933 p_line[filldst] = savestr(buf); 934 if (out_of_mem) { 935 p_end = 0; 936 return FALSE; 937 } 938 p_Char[filldst++] = '='; 939 p_context = 100; 940 context = 0; 941 p_hunk_beg = p_input_line + 1; 942 while (fillsrc <= p_ptrn_lines || filldst <= p_end) { 943 line_beginning = ftell(pfp); 944 ret = pgets(buf, sizeof buf, pfp); 945 p_input_line++; 946 if (ret == Nullch) { 947 if (p_max - filldst < 3) 948 Strcpy(buf, " \n"); /* assume blank lines got chopped */ 949 else { 950 fatal1("unexpected end of file in patch\n"); 951 } 952 } 953 if (*buf == '\t' || *buf == '\n') { 954 ch = ' '; /* assume the space got eaten */ 955 s = savestr(buf); 956 } 957 else { 958 ch = *buf; 959 s = savestr(buf+1); 960 } 961 if (out_of_mem) { 962 while (--filldst > p_ptrn_lines) 963 free(p_line[filldst]); 964 p_end = fillsrc-1; 965 return FALSE; 966 } 967 switch (ch) { 968 case '-': 969 if (fillsrc > p_ptrn_lines) { 970 free(s); 971 p_end = filldst-1; 972 malformed (); 973 } 974 p_Char[fillsrc] = ch; 975 p_line[fillsrc] = s; 976 p_len[fillsrc++] = strlen(s); 977 break; 978 case '=': 979 ch = ' '; 980 /* FALL THROUGH */ 981 case ' ': 982 if (fillsrc > p_ptrn_lines) { 983 free(s); 984 while (--filldst > p_ptrn_lines) 985 free(p_line[filldst]); 986 p_end = fillsrc-1; 987 malformed (); 988 } 989 context++; 990 p_Char[fillsrc] = ch; 991 p_line[fillsrc] = s; 992 p_len[fillsrc++] = strlen(s); 993 s = savestr(s); 994 if (out_of_mem) { 995 while (--filldst > p_ptrn_lines) 996 free(p_line[filldst]); 997 p_end = fillsrc-1; 998 return FALSE; 999 } 1000 /* FALL THROUGH */ 1001 case '+': 1002 if (filldst > p_end) { 1003 free(s); 1004 while (--filldst > p_ptrn_lines) 1005 free(p_line[filldst]); 1006 p_end = fillsrc-1; 1007 malformed (); 1008 } 1009 p_Char[filldst] = ch; 1010 p_line[filldst] = s; 1011 p_len[filldst++] = strlen(s); 1012 break; 1013 default: 1014 p_end = filldst; 1015 malformed (); 1016 } 1017 if (ch != ' ' && context > 0) { 1018 if (context < p_context) 1019 p_context = context; 1020 context = -1000; 1021 } 1022 }/* while */ 1023 } 1024 else { /* normal diff--fake it up */ 1025 char hunk_type; 1026 Reg3 int i; 1027 LINENUM min, max; 1028 long line_beginning = ftell(pfp); 1029 1030 p_context = 0; 1031 ret = pgets(buf, sizeof buf, pfp); 1032 p_input_line++; 1033 if (ret == Nullch || !isdigit((unsigned char)*buf)) { 1034 next_intuit_at(line_beginning,p_input_line); 1035 return FALSE; 1036 } 1037 p_first = (LINENUM)atol(buf); 1038 for (s=buf; isdigit((unsigned char)*s); s++) ; 1039 if (*s == ',') { 1040 p_ptrn_lines = (LINENUM)atol(++s) - p_first + 1; 1041 while (isdigit((unsigned char)*s)) s++; 1042 } 1043 else 1044 p_ptrn_lines = (*s != 'a'); 1045 hunk_type = *s; 1046 if (hunk_type == 'a') 1047 p_first++; /* do append rather than insert */ 1048 min = (LINENUM)atol(++s); 1049 for (; isdigit((unsigned char)*s); s++) ; 1050 if (*s == ',') 1051 max = (LINENUM)atol(++s); 1052 else 1053 max = min; 1054 if (hunk_type == 'd') 1055 min++; 1056 p_end = p_ptrn_lines + 1 + max - min + 1; 1057 if (p_end > MAXHUNKSIZE) 1058 fatal4("hunk too large (%ld lines) at line %ld: %s", 1059 p_end, p_input_line, buf); 1060 while (p_end >= hunkmax) 1061 grow_hunkmax(); 1062 p_newfirst = min; 1063 p_repl_lines = max - min + 1; 1064 Sprintf(buf, "*** %ld,%ld\n", p_first, p_first + p_ptrn_lines - 1); 1065 p_line[0] = savestr(buf); 1066 if (out_of_mem) { 1067 p_end = -1; 1068 return FALSE; 1069 } 1070 p_Char[0] = '*'; 1071 for (i=1; i<=p_ptrn_lines; i++) { 1072 ret = pgets(buf, sizeof buf, pfp); 1073 p_input_line++; 1074 if (ret == Nullch) 1075 fatal2("unexpected end of file in patch at line %ld\n", 1076 p_input_line); 1077 if (*buf != '<') 1078 fatal2("< expected at line %ld of patch\n", p_input_line); 1079 p_line[i] = savestr(buf+2); 1080 if (out_of_mem) { 1081 p_end = i-1; 1082 return FALSE; 1083 } 1084 p_len[i] = strlen(p_line[i]); 1085 p_Char[i] = '-'; 1086 } 1087 if (hunk_type == 'c') { 1088 ret = pgets(buf, sizeof buf, pfp); 1089 p_input_line++; 1090 if (ret == Nullch) 1091 fatal2("unexpected end of file in patch at line %ld\n", 1092 p_input_line); 1093 if (*buf != '-') 1094 fatal2("--- expected at line %ld of patch\n", p_input_line); 1095 } 1096 Sprintf(buf, "--- %ld,%ld\n", min, max); 1097 p_line[i] = savestr(buf); 1098 if (out_of_mem) { 1099 p_end = i-1; 1100 return FALSE; 1101 } 1102 p_Char[i] = '='; 1103 for (i++; i<=p_end; i++) { 1104 ret = pgets(buf, sizeof buf, pfp); 1105 p_input_line++; 1106 if (ret == Nullch) 1107 fatal2("unexpected end of file in patch at line %ld\n", 1108 p_input_line); 1109 if (*buf != '>') 1110 fatal2("> expected at line %ld of patch\n", p_input_line); 1111 p_line[i] = savestr(buf+2); 1112 if (out_of_mem) { 1113 p_end = i-1; 1114 return FALSE; 1115 } 1116 p_len[i] = strlen(p_line[i]); 1117 p_Char[i] = '+'; 1118 } 1119 } 1120 if (reverse) /* backwards patch? */ 1121 if (!pch_swap()) 1122 say1("Not enough memory to swap next hunk!\n"); 1123#ifdef DEBUGGING 1124 if (debug & 2) { 1125 int i; 1126 char special; 1127 1128 for (i=0; i <= p_end; i++) { 1129 if (i == p_ptrn_lines) 1130 special = '^'; 1131 else 1132 special = ' '; 1133 fprintf(stderr, "%3d %c %c %s", i, p_Char[i], special, p_line[i]); 1134 Fflush(stderr); 1135 } 1136 } 1137#endif 1138 if (p_end+1 < hunkmax) /* paranoia reigns supreme... */ 1139 p_Char[p_end+1] = '^'; /* add a stopper for apply_hunk */ 1140 return TRUE; 1141} 1142 1143/* Input a line from the patch file, worrying about indentation. */ 1144 1145char * 1146pgets(bf,sz,fp) 1147char *bf; 1148int sz; 1149FILE *fp; 1150{ 1151 char *ret = fgets(bf, sz, fp); 1152 Reg1 char *s; 1153 Reg2 int indent = 0; 1154 1155 if (p_indent && ret != Nullch) { 1156 for (s=buf; 1157 indent < p_indent && (*s == ' ' || *s == '\t' || *s == 'X'); s++) { 1158 if (*s == '\t') 1159 indent += 8 - (indent % 7); 1160 else 1161 indent++; 1162 } 1163 if (buf != s) 1164 Strcpy(buf, s); 1165 } 1166 return ret; 1167} 1168 1169/* Reverse the old and new portions of the current hunk. */ 1170 1171bool 1172pch_swap() 1173{ 1174 char **tp_line; /* the text of the hunk */ 1175 short *tp_len; /* length of each line */ 1176 char *tp_char; /* +, -, and ! */ 1177 Reg1 LINENUM i; 1178 Reg2 LINENUM n; 1179 bool blankline = FALSE; 1180 Reg3 char *s; 1181 1182 i = p_first; 1183 p_first = p_newfirst; 1184 p_newfirst = i; 1185 1186 /* make a scratch copy */ 1187 1188 tp_line = p_line; 1189 tp_len = p_len; 1190 tp_char = p_Char; 1191 p_line = Null(char**); /* force set_hunkmax to allocate again */ 1192 p_len = Null(short*); 1193 p_Char = Nullch; 1194 set_hunkmax(); 1195 if (p_line == Null(char**) || p_len == Null(short*) || p_Char == Nullch) { 1196#ifndef lint 1197 if (p_line == Null(char**)) 1198 free((char*)p_line); 1199 p_line = tp_line; 1200 if (p_len == Null(short*)) 1201 free((char*)p_len); 1202 p_len = tp_len; 1203#endif 1204 if (p_Char == Nullch) 1205 free((char*)p_Char); 1206 p_Char = tp_char; 1207 return FALSE; /* not enough memory to swap hunk! */ 1208 } 1209 1210 /* now turn the new into the old */ 1211 1212 i = p_ptrn_lines + 1; 1213 if (tp_char[i] == '\n') { /* account for possible blank line */ 1214 blankline = TRUE; 1215 i++; 1216 } 1217 if (p_efake >= 0) { /* fix non-freeable ptr range */ 1218 if (p_efake <= i) 1219 n = p_end - i + 1; 1220 else 1221 n = -i; 1222 p_efake += n; 1223 p_bfake += n; 1224 } 1225 for (n=0; i <= p_end; i++,n++) { 1226 p_line[n] = tp_line[i]; 1227 p_Char[n] = tp_char[i]; 1228 if (p_Char[n] == '+') 1229 p_Char[n] = '-'; 1230 p_len[n] = tp_len[i]; 1231 } 1232 if (blankline) { 1233 i = p_ptrn_lines + 1; 1234 p_line[n] = tp_line[i]; 1235 p_Char[n] = tp_char[i]; 1236 p_len[n] = tp_len[i]; 1237 n++; 1238 } 1239 assert(p_Char[0] == '='); 1240 p_Char[0] = '*'; 1241 for (s=p_line[0]; *s; s++) 1242 if (*s == '-') 1243 *s = '*'; 1244 1245 /* now turn the old into the new */ 1246 1247 assert(tp_char[0] == '*'); 1248 tp_char[0] = '='; 1249 for (s=tp_line[0]; *s; s++) 1250 if (*s == '*') 1251 *s = '-'; 1252 for (i=0; n <= p_end; i++,n++) { 1253 p_line[n] = tp_line[i]; 1254 p_Char[n] = tp_char[i]; 1255 if (p_Char[n] == '-') 1256 p_Char[n] = '+'; 1257 p_len[n] = tp_len[i]; 1258 } 1259 assert(i == p_ptrn_lines + 1); 1260 i = p_ptrn_lines; 1261 p_ptrn_lines = p_repl_lines; 1262 p_repl_lines = i; 1263#ifndef lint 1264 if (tp_line == Null(char**)) 1265 free((char*)tp_line); 1266 if (tp_len == Null(short*)) 1267 free((char*)tp_len); 1268#endif 1269 if (tp_char == Nullch) 1270 free((char*)tp_char); 1271 return TRUE; 1272} 1273 1274/* Return the specified line position in the old file of the old context. */ 1275 1276LINENUM 1277pch_first() 1278{ 1279 return p_first; 1280} 1281 1282/* Return the number of lines of old context. */ 1283 1284LINENUM 1285pch_ptrn_lines() 1286{ 1287 return p_ptrn_lines; 1288} 1289 1290/* Return the probable line position in the new file of the first line. */ 1291 1292LINENUM 1293pch_newfirst() 1294{ 1295 return p_newfirst; 1296} 1297 1298/* Return the number of lines in the replacement text including context. */ 1299 1300LINENUM 1301pch_repl_lines() 1302{ 1303 return p_repl_lines; 1304} 1305 1306/* Return the number of lines in the whole hunk. */ 1307 1308LINENUM 1309pch_end() 1310{ 1311 return p_end; 1312} 1313 1314/* Return the number of context lines before the first changed line. */ 1315 1316LINENUM 1317pch_context() 1318{ 1319 return p_context; 1320} 1321 1322/* Return the length of a particular patch line. */ 1323 1324short 1325pch_line_len(line) 1326LINENUM line; 1327{ 1328 return p_len[line]; 1329} 1330 1331/* Return the control character (+, -, *, !, etc) for a patch line. */ 1332 1333char 1334pch_char(line) 1335LINENUM line; 1336{ 1337 return p_Char[line]; 1338} 1339 1340/* Return a pointer to a particular patch line. */ 1341 1342char * 1343pfetch(line) 1344LINENUM line; 1345{ 1346 return p_line[line]; 1347} 1348 1349/* Return where in the patch file this hunk began, for error messages. */ 1350 1351LINENUM 1352pch_hunk_beg() 1353{ 1354 return p_hunk_beg; 1355} 1356 1357/* Apply an ed script by feeding ed itself. */ 1358 1359void 1360do_ed_script() 1361{ 1362 Reg1 char *t; 1363 Reg2 long beginning_of_this_line; 1364 Reg3 bool this_line_is_command = FALSE; 1365 Reg4 FILE *pipefp; 1366 1367 if (!skip_rest_of_patch) { 1368 Unlink(TMPOUTNAME); 1369 copy_file(filearg[0], TMPOUTNAME); 1370 if (verbose) 1371 Sprintf(buf, "/bin/ed %s", TMPOUTNAME); 1372 else 1373 Sprintf(buf, "/bin/ed - %s", TMPOUTNAME); 1374 pipefp = popen(buf, "w"); 1375 } 1376 for (;;) { 1377 beginning_of_this_line = ftell(pfp); 1378 if (pgets(buf, sizeof buf, pfp) == Nullch) { 1379 next_intuit_at(beginning_of_this_line,p_input_line); 1380 break; 1381 } 1382 p_input_line++; 1383 for (t=buf; isdigit((unsigned char)*t) || *t == ','; t++) ; 1384 this_line_is_command = (isdigit((unsigned char)*buf) && 1385 (*t == 'd' || *t == 'c' || *t == 'a') ); 1386 if (this_line_is_command) { 1387 if (!skip_rest_of_patch) 1388 fputs(buf, pipefp); 1389 if (*t != 'd') { 1390 while (pgets(buf, sizeof buf, pfp) != Nullch) { 1391 p_input_line++; 1392 if (!skip_rest_of_patch) 1393 fputs(buf, pipefp); 1394 if (strEQ(buf, ".\n")) 1395 break; 1396 } 1397 } 1398 } 1399 else { 1400 next_intuit_at(beginning_of_this_line,p_input_line); 1401 break; 1402 } 1403 } 1404 if (skip_rest_of_patch) 1405 return; 1406 fprintf(pipefp, "w\n"); 1407 fprintf(pipefp, "q\n"); 1408 Fflush(pipefp); 1409 Pclose(pipefp); 1410 ignore_signals(); 1411 if (move_file(TMPOUTNAME, outname) < 0) { 1412 toutkeep = TRUE; 1413 chmod(TMPOUTNAME, filemode); 1414 } 1415 else 1416 chmod(outname, filemode); 1417 set_signals(1); 1418} 1419