Annotation of src/usr.bin/patch/patch.c, Revision 1.1
1.1 ! deraadt 1: /* patch - a program to apply diffs to original files
! 2: *
! 3: * Copyright 1986, Larry Wall
! 4: *
! 5: * This program may be copied as long as you don't try to make any
! 6: * money off of it, or pretend that you wrote it.
! 7: */
! 8:
! 9: #ifndef lint
! 10: static char rcsid[] = "$Id: patch.c,v 1.2 1993/08/02 17:55:19 mycroft Exp $";
! 11: #endif /* not lint */
! 12:
! 13: #include "INTERN.h"
! 14: #include "common.h"
! 15: #include "EXTERN.h"
! 16: #include "version.h"
! 17: #include "util.h"
! 18: #include "pch.h"
! 19: #include "inp.h"
! 20: #include "backupfile.h"
! 21:
! 22: /* procedures */
! 23:
! 24: void reinitialize_almost_everything();
! 25: void get_some_switches();
! 26: LINENUM locate_hunk();
! 27: void abort_hunk();
! 28: void apply_hunk();
! 29: void init_output();
! 30: void init_reject();
! 31: void copy_till();
! 32: void spew_output();
! 33: void dump_line();
! 34: bool patch_match();
! 35: bool similar();
! 36: void re_input();
! 37: void my_exit();
! 38:
! 39: /* TRUE if -E was specified on command line. */
! 40: static int remove_empty_files = FALSE;
! 41:
! 42: /* TRUE if -R was specified on command line. */
! 43: static int reverse_flag_specified = FALSE;
! 44:
! 45: /* Apply a set of diffs as appropriate. */
! 46:
! 47: int
! 48: main(argc,argv)
! 49: int argc;
! 50: char **argv;
! 51: {
! 52: LINENUM where;
! 53: LINENUM newwhere;
! 54: LINENUM fuzz;
! 55: LINENUM mymaxfuzz;
! 56: int hunk = 0;
! 57: int failed = 0;
! 58: int failtotal = 0;
! 59: int i;
! 60:
! 61: setbuf(stderr, serrbuf);
! 62: for (i = 0; i<MAXFILEC; i++)
! 63: filearg[i] = Nullch;
! 64:
! 65: myuid = getuid();
! 66:
! 67: /* Cons up the names of the temporary files. */
! 68: {
! 69: /* Directory for temporary files. */
! 70: char *tmpdir;
! 71: int tmpname_len;
! 72:
! 73: tmpdir = getenv ("TMPDIR");
! 74: if (tmpdir == NULL) {
! 75: tmpdir = "/tmp";
! 76: }
! 77: tmpname_len = strlen (tmpdir) + 20;
! 78:
! 79: TMPOUTNAME = (char *) malloc (tmpname_len);
! 80: strcpy (TMPOUTNAME, tmpdir);
! 81: strcat (TMPOUTNAME, "/patchoXXXXXX");
! 82: Mktemp(TMPOUTNAME);
! 83:
! 84: TMPINNAME = (char *) malloc (tmpname_len);
! 85: strcpy (TMPINNAME, tmpdir);
! 86: strcat (TMPINNAME, "/patchiXXXXXX");
! 87: Mktemp(TMPINNAME);
! 88:
! 89: TMPREJNAME = (char *) malloc (tmpname_len);
! 90: strcpy (TMPREJNAME, tmpdir);
! 91: strcat (TMPREJNAME, "/patchrXXXXXX");
! 92: Mktemp(TMPREJNAME);
! 93:
! 94: TMPPATNAME = (char *) malloc (tmpname_len);
! 95: strcpy (TMPPATNAME, tmpdir);
! 96: strcat (TMPPATNAME, "/patchpXXXXXX");
! 97: Mktemp(TMPPATNAME);
! 98: }
! 99:
! 100: {
! 101: char *v;
! 102:
! 103: v = getenv ("SIMPLE_BACKUP_SUFFIX");
! 104: if (v)
! 105: simple_backup_suffix = v;
! 106: else
! 107: simple_backup_suffix = ORIGEXT;
! 108: #ifndef NODIR
! 109: v = getenv ("VERSION_CONTROL");
! 110: backup_type = get_version (v); /* OK to pass NULL. */
! 111: #endif
! 112: }
! 113:
! 114: /* parse switches */
! 115: Argc = argc;
! 116: Argv = argv;
! 117: get_some_switches();
! 118:
! 119: /* make sure we clean up /tmp in case of disaster */
! 120: set_signals(0);
! 121:
! 122: for (
! 123: open_patch_file(filearg[1]);
! 124: there_is_another_patch();
! 125: reinitialize_almost_everything()
! 126: ) { /* for each patch in patch file */
! 127:
! 128: if (outname == Nullch)
! 129: outname = savestr(filearg[0]);
! 130:
! 131: /* for ed script just up and do it and exit */
! 132: if (diff_type == ED_DIFF) {
! 133: do_ed_script();
! 134: continue;
! 135: }
! 136:
! 137: /* initialize the patched file */
! 138: if (!skip_rest_of_patch)
! 139: init_output(TMPOUTNAME);
! 140:
! 141: /* initialize reject file */
! 142: init_reject(TMPREJNAME);
! 143:
! 144: /* find out where all the lines are */
! 145: if (!skip_rest_of_patch)
! 146: scan_input(filearg[0]);
! 147:
! 148: /* from here on, open no standard i/o files, because malloc */
! 149: /* might misfire and we can't catch it easily */
! 150:
! 151: /* apply each hunk of patch */
! 152: hunk = 0;
! 153: failed = 0;
! 154: out_of_mem = FALSE;
! 155: while (another_hunk()) {
! 156: hunk++;
! 157: fuzz = Nulline;
! 158: mymaxfuzz = pch_context();
! 159: if (maxfuzz < mymaxfuzz)
! 160: mymaxfuzz = maxfuzz;
! 161: if (!skip_rest_of_patch) {
! 162: do {
! 163: where = locate_hunk(fuzz);
! 164: if (hunk == 1 && where == Nulline && !force) {
! 165: /* dwim for reversed patch? */
! 166: if (!pch_swap()) {
! 167: if (fuzz == Nulline)
! 168: say1(
! 169: "Not enough memory to try swapped hunk! Assuming unswapped.\n");
! 170: continue;
! 171: }
! 172: reverse = !reverse;
! 173: where = locate_hunk(fuzz); /* try again */
! 174: if (where == Nulline) { /* didn't find it swapped */
! 175: if (!pch_swap()) /* put it back to normal */
! 176: fatal1("lost hunk on alloc error!\n");
! 177: reverse = !reverse;
! 178: }
! 179: else if (noreverse) {
! 180: if (!pch_swap()) /* put it back to normal */
! 181: fatal1("lost hunk on alloc error!\n");
! 182: reverse = !reverse;
! 183: say1(
! 184: "Ignoring previously applied (or reversed) patch.\n");
! 185: skip_rest_of_patch = TRUE;
! 186: }
! 187: else if (batch) {
! 188: if (verbose)
! 189: say3(
! 190: "%seversed (or previously applied) patch detected! %s -R.",
! 191: reverse ? "R" : "Unr",
! 192: reverse ? "Assuming" : "Ignoring");
! 193: }
! 194: else {
! 195: ask3(
! 196: "%seversed (or previously applied) patch detected! %s -R? [y] ",
! 197: reverse ? "R" : "Unr",
! 198: reverse ? "Assume" : "Ignore");
! 199: if (*buf == 'n') {
! 200: ask1("Apply anyway? [n] ");
! 201: if (*buf != 'y')
! 202: skip_rest_of_patch = TRUE;
! 203: where = Nulline;
! 204: reverse = !reverse;
! 205: if (!pch_swap()) /* put it back to normal */
! 206: fatal1("lost hunk on alloc error!\n");
! 207: }
! 208: }
! 209: }
! 210: } while (!skip_rest_of_patch && where == Nulline &&
! 211: ++fuzz <= mymaxfuzz);
! 212:
! 213: if (skip_rest_of_patch) { /* just got decided */
! 214: Fclose(ofp);
! 215: ofp = Nullfp;
! 216: }
! 217: }
! 218:
! 219: newwhere = pch_newfirst() + last_offset;
! 220: if (skip_rest_of_patch) {
! 221: abort_hunk();
! 222: failed++;
! 223: if (verbose)
! 224: say3("Hunk #%d ignored at %ld.\n", hunk, newwhere);
! 225: }
! 226: else if (where == Nulline) {
! 227: abort_hunk();
! 228: failed++;
! 229: if (verbose)
! 230: say3("Hunk #%d failed at %ld.\n", hunk, newwhere);
! 231: }
! 232: else {
! 233: apply_hunk(where);
! 234: if (verbose) {
! 235: say3("Hunk #%d succeeded at %ld", hunk, newwhere);
! 236: if (fuzz)
! 237: say2(" with fuzz %ld", fuzz);
! 238: if (last_offset)
! 239: say3(" (offset %ld line%s)",
! 240: last_offset, last_offset==1L?"":"s");
! 241: say1(".\n");
! 242: }
! 243: }
! 244: }
! 245:
! 246: if (out_of_mem && using_plan_a) {
! 247: Argc = Argc_last;
! 248: Argv = Argv_last;
! 249: say1("\n\nRan out of memory using Plan A--trying again...\n\n");
! 250: if (ofp)
! 251: Fclose(ofp);
! 252: ofp = Nullfp;
! 253: if (rejfp)
! 254: Fclose(rejfp);
! 255: rejfp = Nullfp;
! 256: continue;
! 257: }
! 258:
! 259: assert(hunk);
! 260:
! 261: /* finish spewing out the new file */
! 262: if (!skip_rest_of_patch)
! 263: spew_output();
! 264:
! 265: /* and put the output where desired */
! 266: ignore_signals();
! 267: if (!skip_rest_of_patch) {
! 268: struct stat statbuf;
! 269: char *realout = outname;
! 270:
! 271: if (move_file(TMPOUTNAME, outname) < 0) {
! 272: toutkeep = TRUE;
! 273: realout = TMPOUTNAME;
! 274: chmod(TMPOUTNAME, filemode);
! 275: }
! 276: else
! 277: chmod(outname, filemode);
! 278:
! 279: if (remove_empty_files && stat(realout, &statbuf) == 0
! 280: && statbuf.st_size == 0) {
! 281: if (verbose)
! 282: say2("Removing %s (empty after patching).\n", realout);
! 283: while (unlink(realout) >= 0) ; /* while is for Eunice. */
! 284: }
! 285: }
! 286: Fclose(rejfp);
! 287: rejfp = Nullfp;
! 288: if (failed) {
! 289: failtotal += failed;
! 290: if (!*rejname) {
! 291: Strcpy(rejname, outname);
! 292: #ifndef FLEXFILENAMES
! 293: {
! 294: char *s = rindex(rejname,'/');
! 295:
! 296: if (!s)
! 297: s = rejname;
! 298: if (strlen(s) > 13)
! 299: if (s[12] == '.') /* try to preserve difference */
! 300: s[12] = s[13]; /* between .h, .c, .y, etc. */
! 301: s[13] = '\0';
! 302: }
! 303: #endif
! 304: Strcat(rejname, REJEXT);
! 305: }
! 306: if (skip_rest_of_patch) {
! 307: say4("%d out of %d hunks ignored--saving rejects to %s\n",
! 308: failed, hunk, rejname);
! 309: }
! 310: else {
! 311: say4("%d out of %d hunks failed--saving rejects to %s\n",
! 312: failed, hunk, rejname);
! 313: }
! 314: if (move_file(TMPREJNAME, rejname) < 0)
! 315: trejkeep = TRUE;
! 316: }
! 317: set_signals(1);
! 318: }
! 319: my_exit(failtotal);
! 320: }
! 321:
! 322: /* Prepare to find the next patch to do in the patch file. */
! 323:
! 324: void
! 325: reinitialize_almost_everything()
! 326: {
! 327: re_patch();
! 328: re_input();
! 329:
! 330: input_lines = 0;
! 331: last_frozen_line = 0;
! 332:
! 333: filec = 0;
! 334: if (filearg[0] != Nullch && !out_of_mem) {
! 335: free(filearg[0]);
! 336: filearg[0] = Nullch;
! 337: }
! 338:
! 339: if (outname != Nullch) {
! 340: free(outname);
! 341: outname = Nullch;
! 342: }
! 343:
! 344: last_offset = 0;
! 345:
! 346: diff_type = 0;
! 347:
! 348: if (revision != Nullch) {
! 349: free(revision);
! 350: revision = Nullch;
! 351: }
! 352:
! 353: reverse = reverse_flag_specified;
! 354: skip_rest_of_patch = FALSE;
! 355:
! 356: get_some_switches();
! 357:
! 358: if (filec >= 2)
! 359: fatal1("you may not change to a different patch file\n");
! 360: }
! 361:
! 362: static char *
! 363: nextarg()
! 364: {
! 365: if (!--Argc)
! 366: fatal2("missing argument after `%s'\n", *Argv);
! 367: return *++Argv;
! 368: }
! 369:
! 370: /* Process switches and filenames up to next '+' or end of list. */
! 371:
! 372: void
! 373: get_some_switches()
! 374: {
! 375: Reg1 char *s;
! 376:
! 377: rejname[0] = '\0';
! 378: Argc_last = Argc;
! 379: Argv_last = Argv;
! 380: if (!Argc)
! 381: return;
! 382: for (Argc--,Argv++; Argc; Argc--,Argv++) {
! 383: s = Argv[0];
! 384: if (strEQ(s, "+")) {
! 385: return; /* + will be skipped by for loop */
! 386: }
! 387: if (*s != '-' || !s[1]) {
! 388: if (filec == MAXFILEC)
! 389: fatal1("too many file arguments\n");
! 390: filearg[filec++] = savestr(s);
! 391: }
! 392: else {
! 393: switch (*++s) {
! 394: case 'b':
! 395: simple_backup_suffix = savestr(nextarg());
! 396: break;
! 397: case 'B':
! 398: origprae = savestr(nextarg());
! 399: break;
! 400: case 'c':
! 401: diff_type = CONTEXT_DIFF;
! 402: break;
! 403: case 'd':
! 404: if (!*++s)
! 405: s = nextarg();
! 406: if (chdir(s) < 0)
! 407: pfatal2("can't cd to %s", s);
! 408: break;
! 409: case 'D':
! 410: do_defines = TRUE;
! 411: if (!*++s)
! 412: s = nextarg();
! 413: if (!isalpha(*s) && '_' != *s)
! 414: fatal1("argument to -D is not an identifier\n");
! 415: Sprintf(if_defined, "#ifdef %s\n", s);
! 416: Sprintf(not_defined, "#ifndef %s\n", s);
! 417: Sprintf(end_defined, "#endif /* %s */\n", s);
! 418: break;
! 419: case 'e':
! 420: diff_type = ED_DIFF;
! 421: break;
! 422: case 'E':
! 423: remove_empty_files = TRUE;
! 424: break;
! 425: case 'f':
! 426: force = TRUE;
! 427: break;
! 428: case 'F':
! 429: if (*++s == '=')
! 430: s++;
! 431: maxfuzz = atoi(s);
! 432: break;
! 433: case 'l':
! 434: canonicalize = TRUE;
! 435: break;
! 436: case 'n':
! 437: diff_type = NORMAL_DIFF;
! 438: break;
! 439: case 'N':
! 440: noreverse = TRUE;
! 441: break;
! 442: case 'o':
! 443: outname = savestr(nextarg());
! 444: break;
! 445: case 'p':
! 446: if (*++s == '=')
! 447: s++;
! 448: strippath = atoi(s);
! 449: break;
! 450: case 'r':
! 451: Strcpy(rejname, nextarg());
! 452: break;
! 453: case 'R':
! 454: reverse = TRUE;
! 455: reverse_flag_specified = TRUE;
! 456: break;
! 457: case 's':
! 458: verbose = FALSE;
! 459: break;
! 460: case 'S':
! 461: skip_rest_of_patch = TRUE;
! 462: break;
! 463: case 't':
! 464: batch = TRUE;
! 465: break;
! 466: case 'u':
! 467: diff_type = UNI_DIFF;
! 468: break;
! 469: case 'v':
! 470: version();
! 471: break;
! 472: case 'V':
! 473: #ifndef NODIR
! 474: backup_type = get_version (nextarg ());
! 475: #endif
! 476: break;
! 477: #ifdef DEBUGGING
! 478: case 'x':
! 479: debug = atoi(s+1);
! 480: break;
! 481: #endif
! 482: default:
! 483: fprintf(stderr, "patch: unrecognized option `%s'\n", Argv[0]);
! 484: fprintf(stderr, "\
! 485: Usage: patch [options] [origfile [patchfile]] [+ [options] [origfile]]...\n\
! 486: Options:\n\
! 487: [-ceEflnNRsStuv] [-b backup-ext] [-B backup-prefix] [-d directory]\n\
! 488: [-D symbol] [-Fmax-fuzz] [-o out-file] [-p[strip-count]]\n\
! 489: [-r rej-name] [-V {numbered,existing,simple}]\n");
! 490: my_exit(1);
! 491: }
! 492: }
! 493: }
! 494: }
! 495:
! 496: /* Attempt to find the right place to apply this hunk of patch. */
! 497:
! 498: LINENUM
! 499: locate_hunk(fuzz)
! 500: LINENUM fuzz;
! 501: {
! 502: Reg1 LINENUM first_guess = pch_first() + last_offset;
! 503: Reg2 LINENUM offset;
! 504: LINENUM pat_lines = pch_ptrn_lines();
! 505: Reg3 LINENUM max_pos_offset = input_lines - first_guess
! 506: - pat_lines + 1;
! 507: Reg4 LINENUM max_neg_offset = first_guess - last_frozen_line - 1
! 508: + pch_context();
! 509:
! 510: if (!pat_lines) /* null range matches always */
! 511: return first_guess;
! 512: if (max_neg_offset >= first_guess) /* do not try lines < 0 */
! 513: max_neg_offset = first_guess - 1;
! 514: if (first_guess <= input_lines && patch_match(first_guess, Nulline, fuzz))
! 515: return first_guess;
! 516: for (offset = 1; ; offset++) {
! 517: Reg5 bool check_after = (offset <= max_pos_offset);
! 518: Reg6 bool check_before = (offset <= max_neg_offset);
! 519:
! 520: if (check_after && patch_match(first_guess, offset, fuzz)) {
! 521: #ifdef DEBUGGING
! 522: if (debug & 1)
! 523: say3("Offset changing from %ld to %ld\n", last_offset, offset);
! 524: #endif
! 525: last_offset = offset;
! 526: return first_guess+offset;
! 527: }
! 528: else if (check_before && patch_match(first_guess, -offset, fuzz)) {
! 529: #ifdef DEBUGGING
! 530: if (debug & 1)
! 531: say3("Offset changing from %ld to %ld\n", last_offset, -offset);
! 532: #endif
! 533: last_offset = -offset;
! 534: return first_guess-offset;
! 535: }
! 536: else if (!check_before && !check_after)
! 537: return Nulline;
! 538: }
! 539: }
! 540:
! 541: /* We did not find the pattern, dump out the hunk so they can handle it. */
! 542:
! 543: void
! 544: abort_hunk()
! 545: {
! 546: Reg1 LINENUM i;
! 547: Reg2 LINENUM pat_end = pch_end();
! 548: /* add in last_offset to guess the same as the previous successful hunk */
! 549: LINENUM oldfirst = pch_first() + last_offset;
! 550: LINENUM newfirst = pch_newfirst() + last_offset;
! 551: LINENUM oldlast = oldfirst + pch_ptrn_lines() - 1;
! 552: LINENUM newlast = newfirst + pch_repl_lines() - 1;
! 553: char *stars = (diff_type >= NEW_CONTEXT_DIFF ? " ****" : "");
! 554: char *minuses = (diff_type >= NEW_CONTEXT_DIFF ? " ----" : " -----");
! 555:
! 556: fprintf(rejfp, "***************\n");
! 557: for (i=0; i<=pat_end; i++) {
! 558: switch (pch_char(i)) {
! 559: case '*':
! 560: if (oldlast < oldfirst)
! 561: fprintf(rejfp, "*** 0%s\n", stars);
! 562: else if (oldlast == oldfirst)
! 563: fprintf(rejfp, "*** %ld%s\n", oldfirst, stars);
! 564: else
! 565: fprintf(rejfp, "*** %ld,%ld%s\n", oldfirst, oldlast, stars);
! 566: break;
! 567: case '=':
! 568: if (newlast < newfirst)
! 569: fprintf(rejfp, "--- 0%s\n", minuses);
! 570: else if (newlast == newfirst)
! 571: fprintf(rejfp, "--- %ld%s\n", newfirst, minuses);
! 572: else
! 573: fprintf(rejfp, "--- %ld,%ld%s\n", newfirst, newlast, minuses);
! 574: break;
! 575: case '\n':
! 576: fprintf(rejfp, "%s", pfetch(i));
! 577: break;
! 578: case ' ': case '-': case '+': case '!':
! 579: fprintf(rejfp, "%c %s", pch_char(i), pfetch(i));
! 580: break;
! 581: default:
! 582: fatal1("fatal internal error in abort_hunk\n");
! 583: }
! 584: }
! 585: }
! 586:
! 587: /* We found where to apply it (we hope), so do it. */
! 588:
! 589: void
! 590: apply_hunk(where)
! 591: LINENUM where;
! 592: {
! 593: Reg1 LINENUM old = 1;
! 594: Reg2 LINENUM lastline = pch_ptrn_lines();
! 595: Reg3 LINENUM new = lastline+1;
! 596: #define OUTSIDE 0
! 597: #define IN_IFNDEF 1
! 598: #define IN_IFDEF 2
! 599: #define IN_ELSE 3
! 600: Reg4 int def_state = OUTSIDE;
! 601: Reg5 bool R_do_defines = do_defines;
! 602: Reg6 LINENUM pat_end = pch_end();
! 603:
! 604: where--;
! 605: while (pch_char(new) == '=' || pch_char(new) == '\n')
! 606: new++;
! 607:
! 608: while (old <= lastline) {
! 609: if (pch_char(old) == '-') {
! 610: copy_till(where + old - 1);
! 611: if (R_do_defines) {
! 612: if (def_state == OUTSIDE) {
! 613: fputs(not_defined, ofp);
! 614: def_state = IN_IFNDEF;
! 615: }
! 616: else if (def_state == IN_IFDEF) {
! 617: fputs(else_defined, ofp);
! 618: def_state = IN_ELSE;
! 619: }
! 620: fputs(pfetch(old), ofp);
! 621: }
! 622: last_frozen_line++;
! 623: old++;
! 624: }
! 625: else if (new > pat_end) {
! 626: break;
! 627: }
! 628: else if (pch_char(new) == '+') {
! 629: copy_till(where + old - 1);
! 630: if (R_do_defines) {
! 631: if (def_state == IN_IFNDEF) {
! 632: fputs(else_defined, ofp);
! 633: def_state = IN_ELSE;
! 634: }
! 635: else if (def_state == OUTSIDE) {
! 636: fputs(if_defined, ofp);
! 637: def_state = IN_IFDEF;
! 638: }
! 639: }
! 640: fputs(pfetch(new), ofp);
! 641: new++;
! 642: }
! 643: else if (pch_char(new) != pch_char(old)) {
! 644: say3("Out-of-sync patch, lines %ld,%ld--mangled text or line numbers, maybe?\n",
! 645: pch_hunk_beg() + old,
! 646: pch_hunk_beg() + new);
! 647: #ifdef DEBUGGING
! 648: say3("oldchar = '%c', newchar = '%c'\n",
! 649: pch_char(old), pch_char(new));
! 650: #endif
! 651: my_exit(1);
! 652: }
! 653: else if (pch_char(new) == '!') {
! 654: copy_till(where + old - 1);
! 655: if (R_do_defines) {
! 656: fputs(not_defined, ofp);
! 657: def_state = IN_IFNDEF;
! 658: }
! 659: while (pch_char(old) == '!') {
! 660: if (R_do_defines) {
! 661: fputs(pfetch(old), ofp);
! 662: }
! 663: last_frozen_line++;
! 664: old++;
! 665: }
! 666: if (R_do_defines) {
! 667: fputs(else_defined, ofp);
! 668: def_state = IN_ELSE;
! 669: }
! 670: while (pch_char(new) == '!') {
! 671: fputs(pfetch(new), ofp);
! 672: new++;
! 673: }
! 674: }
! 675: else {
! 676: assert(pch_char(new) == ' ');
! 677: old++;
! 678: new++;
! 679: if (R_do_defines && def_state != OUTSIDE) {
! 680: fputs(end_defined, ofp);
! 681: def_state = OUTSIDE;
! 682: }
! 683: }
! 684: }
! 685: if (new <= pat_end && pch_char(new) == '+') {
! 686: copy_till(where + old - 1);
! 687: if (R_do_defines) {
! 688: if (def_state == OUTSIDE) {
! 689: fputs(if_defined, ofp);
! 690: def_state = IN_IFDEF;
! 691: }
! 692: else if (def_state == IN_IFNDEF) {
! 693: fputs(else_defined, ofp);
! 694: def_state = IN_ELSE;
! 695: }
! 696: }
! 697: while (new <= pat_end && pch_char(new) == '+') {
! 698: fputs(pfetch(new), ofp);
! 699: new++;
! 700: }
! 701: }
! 702: if (R_do_defines && def_state != OUTSIDE) {
! 703: fputs(end_defined, ofp);
! 704: }
! 705: }
! 706:
! 707: /* Open the new file. */
! 708:
! 709: void
! 710: init_output(name)
! 711: char *name;
! 712: {
! 713: ofp = fopen(name, "w");
! 714: if (ofp == Nullfp)
! 715: pfatal2("can't create %s", name);
! 716: }
! 717:
! 718: /* Open a file to put hunks we can't locate. */
! 719:
! 720: void
! 721: init_reject(name)
! 722: char *name;
! 723: {
! 724: rejfp = fopen(name, "w");
! 725: if (rejfp == Nullfp)
! 726: pfatal2("can't create %s", name);
! 727: }
! 728:
! 729: /* Copy input file to output, up to wherever hunk is to be applied. */
! 730:
! 731: void
! 732: copy_till(lastline)
! 733: Reg1 LINENUM lastline;
! 734: {
! 735: Reg2 LINENUM R_last_frozen_line = last_frozen_line;
! 736:
! 737: if (R_last_frozen_line > lastline)
! 738: fatal1("misordered hunks! output would be garbled\n");
! 739: while (R_last_frozen_line < lastline) {
! 740: dump_line(++R_last_frozen_line);
! 741: }
! 742: last_frozen_line = R_last_frozen_line;
! 743: }
! 744:
! 745: /* Finish copying the input file to the output file. */
! 746:
! 747: void
! 748: spew_output()
! 749: {
! 750: #ifdef DEBUGGING
! 751: if (debug & 256)
! 752: say3("il=%ld lfl=%ld\n",input_lines,last_frozen_line);
! 753: #endif
! 754: if (input_lines)
! 755: copy_till(input_lines); /* dump remainder of file */
! 756: Fclose(ofp);
! 757: ofp = Nullfp;
! 758: }
! 759:
! 760: /* Copy one line from input to output. */
! 761:
! 762: void
! 763: dump_line(line)
! 764: LINENUM line;
! 765: {
! 766: Reg1 char *s;
! 767: Reg2 char R_newline = '\n';
! 768:
! 769: /* Note: string is not null terminated. */
! 770: for (s=ifetch(line, 0); putc(*s, ofp) != R_newline; s++) ;
! 771: }
! 772:
! 773: /* Does the patch pattern match at line base+offset? */
! 774:
! 775: bool
! 776: patch_match(base, offset, fuzz)
! 777: LINENUM base;
! 778: LINENUM offset;
! 779: LINENUM fuzz;
! 780: {
! 781: Reg1 LINENUM pline = 1 + fuzz;
! 782: Reg2 LINENUM iline;
! 783: Reg3 LINENUM pat_lines = pch_ptrn_lines() - fuzz;
! 784:
! 785: for (iline=base+offset+fuzz; pline <= pat_lines; pline++,iline++) {
! 786: if (canonicalize) {
! 787: if (!similar(ifetch(iline, (offset >= 0)),
! 788: pfetch(pline),
! 789: pch_line_len(pline) ))
! 790: return FALSE;
! 791: }
! 792: else if (strnNE(ifetch(iline, (offset >= 0)),
! 793: pfetch(pline),
! 794: pch_line_len(pline) ))
! 795: return FALSE;
! 796: }
! 797: return TRUE;
! 798: }
! 799:
! 800: /* Do two lines match with canonicalized white space? */
! 801:
! 802: bool
! 803: similar(a,b,len)
! 804: Reg1 char *a;
! 805: Reg2 char *b;
! 806: Reg3 int len;
! 807: {
! 808: while (len) {
! 809: if (isspace(*b)) { /* whitespace (or \n) to match? */
! 810: if (!isspace(*a)) /* no corresponding whitespace? */
! 811: return FALSE;
! 812: while (len && isspace(*b) && *b != '\n')
! 813: b++,len--; /* skip pattern whitespace */
! 814: while (isspace(*a) && *a != '\n')
! 815: a++; /* skip target whitespace */
! 816: if (*a == '\n' || *b == '\n')
! 817: return (*a == *b); /* should end in sync */
! 818: }
! 819: else if (*a++ != *b++) /* match non-whitespace chars */
! 820: return FALSE;
! 821: else
! 822: len--; /* probably not necessary */
! 823: }
! 824: return TRUE; /* actually, this is not reached */
! 825: /* since there is always a \n */
! 826: }
! 827:
! 828: /* Exit with cleanup. */
! 829:
! 830: void
! 831: my_exit(status)
! 832: int status;
! 833: {
! 834: Unlink(TMPINNAME);
! 835: if (!toutkeep) {
! 836: Unlink(TMPOUTNAME);
! 837: }
! 838: if (!trejkeep) {
! 839: Unlink(TMPREJNAME);
! 840: }
! 841: Unlink(TMPPATNAME);
! 842: exit(status);
! 843: }