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

Defined functions

abort_hunk defined in line 522; used 3 times
apply_hunk defined in line 569; used 2 times
copy_till defined in line 712; used 6 times
dump_line defined in line 743; used 2 times
get_some_switches defined in line 365; used 3 times
init_output defined in line 690; used 2 times
init_reject defined in line 701; used 2 times
locate_hunk defined in line 477; used 3 times
main defined in line 117; never used
my_exit defined in line 811; used 12 times
patch_match defined in line 756; used 4 times
reinitialize_almost_everything defined in line 325; used 2 times
similar defined in line 783; used 2 times
spew_output defined in line 728; used 2 times

Defined variables

rcsid defined in line 1; never used

Defined macros

IN_ELSE defined in line 579; used 4 times
IN_IFDEF defined in line 578; used 3 times
IN_IFNDEF defined in line 577; used 4 times
OUTSIDE defined in line 576; used 6 times
Last modified: 1988-06-30
Generated: 2016-12-26
Generated by src2html V0.67
page hit count: 5372
Valid CSS Valid XHTML 1.0 Strict