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