1: #ifndef lint
   2: static char sccsid[] = "@(#)patch.c	5.8 (Berkeley) 5/18/86";
   3: #endif not lint
   4: 
   5: /* patch - a program to apply diffs to original files
   6:  *
   7:  * $Header: patch.c,v 1.3 85/03/26 15:07:43 lwall Exp $
   8:  *
   9:  * Copyright 1984, Larry Wall
  10:  *
  11:  * This program may be copied as long as you don't try to make any
  12:  * money off of it, or pretend that you wrote it.
  13:  *
  14:  * $Log:	patch.c,v $
  15:  * 85/08/15 van%ucbmonet@berkeley
  16:  * Changes for 4.3bsd diff -c.
  17:  *
  18:  * Revision 1.3  85/03/26  15:07:43  lwall
  19:  * Frozen.
  20:  *
  21:  * Revision 1.2.1.9  85/03/12  17:03:35  lwall
  22:  * Changed pfp->_file to fileno(pfp).
  23:  *
  24:  * Revision 1.2.1.8  85/03/12  16:30:43  lwall
  25:  * Check i_ptr and i_womp to make sure they aren't null before freeing.
  26:  * Also allow ed output to be suppressed.
  27:  *
  28:  * Revision 1.2.1.7  85/03/12  15:56:13  lwall
  29:  * Added -p option from jromine@uci-750a.
  30:  *
  31:  * Revision 1.2.1.6  85/03/12  12:12:51  lwall
  32:  * Now checks for normalness of file to patch.
  33:  *
  34:  * Revision 1.2.1.5  85/03/12  11:52:12  lwall
  35:  * Added -D (#ifdef) option from joe@fluke.
  36:  *
  37:  * Revision 1.2.1.4  84/12/06  11:14:15  lwall
  38:  * Made smarter about SCCS subdirectories.
  39:  *
  40:  * Revision 1.2.1.3  84/12/05  11:18:43  lwall
  41:  * Added -l switch to do loose string comparison.
  42:  *
  43:  * Revision 1.2.1.2  84/12/04  09:47:13  lwall
  44:  * Failed hunk count not reset on multiple patch file.
  45:  *
  46:  * Revision 1.2.1.1  84/12/04  09:42:37  lwall
  47:  * Branch for sdcrdcf changes.
  48:  *
  49:  * Revision 1.2  84/11/29  13:29:51  lwall
  50:  * Linted.  Identifiers uniqified.  Fixed i_ptr malloc() bug.  Fixed
  51:  * multiple calls to mktemp().  Will now work on machines that can only
  52:  * read 32767 chars.  Added -R option for diffs with new and old swapped.
  53:  * Various cosmetic changes.
  54:  *
  55:  * Revision 1.1  84/11/09  17:03:58  lwall
  56:  * Initial revision
  57:  *
  58:  */
  59: 
  60: #define DEBUGGING
  61: 
  62: /* shut lint up about the following when return value ignored */
  63: 
  64: #define Signal (void)signal
  65: #define Unlink (void)unlink
  66: #define Lseek (void)lseek
  67: #define Fseek (void)fseek
  68: #define Fstat (void)fstat
  69: #define Pclose (void)pclose
  70: #define Close (void)close
  71: #define Fclose (void)fclose
  72: #define Fflush (void)fflush
  73: #define Sprintf (void)sprintf
  74: #define Mktemp (void)mktemp
  75: #define Strcpy (void)strcpy
  76: #define Strcat (void)strcat
  77: 
  78: #include <stdio.h>
  79: #include <assert.h>
  80: #include <sys/types.h>
  81: #include <sys/stat.h>
  82: #include <ctype.h>
  83: #include <signal.h>
  84: 
  85: /* constants */
  86: 
  87: #define TRUE (1)
  88: #define FALSE (0)
  89: 
  90: #define MAXHUNKSIZE 2000
  91: #define MAXLINELEN 1024
  92: #define BUFFERSIZE 1024
  93: #define ORIGEXT ".orig"
  94: #define SCCSPREFIX "s."
  95: #define GET "get -e %s"
  96: #define RCSSUFFIX ",v"
  97: #define CHECKOUT "co -l %s"
  98: 
  99: /* handy definitions */
 100: 
 101: #define Null(t) ((t)0)
 102: #define Nullch Null(char *)
 103: #define Nullfp Null(FILE *)
 104: 
 105: #define Ctl(ch) (ch & 037)
 106: 
 107: #define strNE(s1,s2) (strcmp(s1,s2))
 108: #define strEQ(s1,s2) (!strcmp(s1,s2))
 109: #define strnNE(s1,s2,l) (strncmp(s1,s2,l))
 110: #define strnEQ(s1,s2,l) (!strncmp(s1,s2,l))
 111: 
 112: /* typedefs */
 113: 
 114: typedef char bool;
 115: typedef long LINENUM;           /* must be signed */
 116: typedef unsigned MEM;           /* what to feed malloc */
 117: 
 118: /* globals */
 119: 
 120: int Argc;               /* guess */
 121: char **Argv;
 122: 
 123: struct stat filestat;           /* file statistics area */
 124: 
 125: char serrbuf[BUFSIZ];           /* buffer for stderr */
 126: char buf[MAXLINELEN];           /* general purpose buffer */
 127: FILE *pfp = Nullfp;         /* patch file pointer */
 128: FILE *ofp = Nullfp;         /* output file pointer */
 129: FILE *rejfp = Nullfp;           /* reject file pointer */
 130: 
 131: LINENUM input_lines = 0;        /* how long is input file in lines */
 132: LINENUM last_frozen_line = 0;       /* how many input lines have been */
 133:                     /* irretractibly output */
 134: 
 135: #define MAXFILEC 2
 136: int filec = 0;              /* how many file arguments? */
 137: char *filearg[MAXFILEC];
 138: 
 139: char *outname = Nullch;
 140: char rejname[128];
 141: 
 142: char *origext = Nullch;
 143: 
 144: char TMPOUTNAME[] = "/tmp/patchoXXXXXX";
 145: char TMPINNAME[] = "/tmp/patchiXXXXXX"; /* you might want /usr/tmp here */
 146: char TMPREJNAME[] = "/tmp/patchrXXXXXX";
 147: char TMPPATNAME[] = "/tmp/patchpXXXXXX";
 148: 
 149: LINENUM last_offset = 0;
 150: #ifdef DEBUGGING
 151: int debug = 0;
 152: #endif
 153: bool verbose = TRUE;
 154: bool reverse = FALSE;
 155: bool noreverse = FALSE;
 156: bool skip_this_patch = FALSE;
 157: bool usepath = FALSE;
 158: bool canonicalize = FALSE;
 159: 
 160: #define CONTEXT_DIFF 1
 161: #define NORMAL_DIFF 2
 162: #define ED_DIFF 3
 163: #define NEW_CONTEXT_DIFF 4
 164: int diff_type = 0;
 165: 
 166: int do_defines = 0;         /* patch using ifdef, ifndef, etc. */
 167: char if_defined[128];           /* #ifdef xyzzy */
 168: char not_defined[128];          /* #ifndef xyzzy */
 169: char else_defined[] = "#else\n";    /* #else */
 170: char end_defined[128];          /* #endif xyzzy */
 171: 
 172: char *revision = Nullch;        /* prerequisite revision, if any */
 173: 
 174: /* procedures */
 175: 
 176: LINENUM locate_hunk();
 177: bool patch_match();
 178: bool similar();
 179: char *malloc();
 180: char *savestr();
 181: char *strcpy();
 182: char *strcat();
 183: char *sprintf();        /* usually */
 184: int my_exit();
 185: bool rev_in_string();
 186: char *fetchname();
 187: long atol();
 188: long lseek();
 189: char *mktemp();
 190: 
 191: /* patch type */
 192: 
 193: bool there_is_another_patch();
 194: bool another_hunk();
 195: char *pfetch();
 196: int pch_line_len();
 197: LINENUM pch_first();
 198: LINENUM pch_ptrn_lines();
 199: LINENUM pch_newfirst();
 200: LINENUM pch_repl_lines();
 201: LINENUM pch_end();
 202: LINENUM pch_context();
 203: LINENUM pch_hunk_beg();
 204: char pch_char();
 205: char *pfetch();
 206: char *pgets();
 207: 
 208: /* input file type */
 209: 
 210: char *ifetch();
 211: 
 212: /* apply a context patch to a named file */
 213: 
 214: main(argc,argv)
 215: int argc;
 216: char **argv;
 217: {
 218:     LINENUM where;
 219:     int hunk = 0;
 220:     int failed = 0;
 221:     int i;
 222: 
 223:     setbuf(stderr,serrbuf);
 224:     for (i = 0; i<MAXFILEC; i++)
 225:     filearg[i] = Nullch;
 226:     Mktemp(TMPOUTNAME);
 227:     Mktemp(TMPINNAME);
 228:     Mktemp(TMPREJNAME);
 229:     Mktemp(TMPPATNAME);
 230: 
 231:     /* parse switches */
 232:     Argc = argc;
 233:     Argv = argv;
 234:     get_some_switches();
 235: 
 236:     /* make sure we clean up /tmp in case of disaster */
 237:     set_signals();
 238: 
 239:     for (
 240:     open_patch_file(filearg[1]);
 241:     there_is_another_patch();
 242:     reinitialize_almost_everything()
 243:     ) {                 /* for each patch in patch file */
 244: 
 245:     if (outname == Nullch)
 246:         outname = savestr(filearg[0]);
 247: 
 248:     /* initialize the patched file */
 249:     init_output(TMPOUTNAME);
 250: 
 251:     /* for ed script just up and do it and exit */
 252:     if (diff_type == ED_DIFF) {
 253:         do_ed_script();
 254:         continue;
 255:     }
 256: 
 257:     /* initialize reject file */
 258:     init_reject(TMPREJNAME);
 259: 
 260:     /* find out where all the lines are */
 261:     scan_input(filearg[0]);
 262: 
 263:     /* from here on, open no standard i/o files, because malloc */
 264:     /* might misfire */
 265: 
 266:     /* apply each hunk of patch */
 267:     hunk = 0;
 268:     failed = 0;
 269:     while (another_hunk()) {
 270:         hunk++;
 271:         where = locate_hunk();
 272:         if (hunk == 1 && where == Null(LINENUM)) {
 273:                     /* dwim for reversed patch? */
 274:         pch_swap();
 275:         reverse = !reverse;
 276:         where = locate_hunk();  /* try again */
 277:         if (where == Null(LINENUM)) {
 278:             pch_swap();     /* no, put it back to normal */
 279:             reverse = !reverse;
 280:         } else if (noreverse) {
 281:             pch_swap();     /* put it back to normal */
 282:             reverse = !reverse;
 283:             say("Ignoring previously applied (or reversed) patch.\n");
 284:             skip_this_patch = TRUE;
 285:         }
 286:         else {
 287:             say("%seversed (or previously applied) patch detected!  %s -R.\n",
 288:             reverse ? "R" : "Unr",
 289:             reverse ? "Assuming" : "Ignoring");
 290:         }
 291:         }
 292:         if (where == Null(LINENUM) || skip_this_patch) {
 293:         abort_hunk();
 294:         failed++;
 295:         if (verbose)
 296:             say("Hunk #%d failed.\n",hunk);
 297:         }
 298:         else {
 299:         apply_hunk(where);
 300:         if (verbose)
 301:             if (last_offset)
 302:             say("Hunk #%d succeeded (offset %d line%s).\n",
 303:               hunk,last_offset,last_offset==1?"":"s");
 304:             else
 305:             say("Hunk #%d succeeded.\n", hunk);
 306:         }
 307:     }
 308: 
 309:     assert(hunk);
 310: 
 311:     /* finish spewing out the new file */
 312:     spew_output();
 313: 
 314:     /* and put the output where desired */
 315:     ignore_signals();
 316:     move_file(TMPOUTNAME,outname);
 317:     Fclose(rejfp);
 318:     rejfp = Nullfp;
 319:     if (failed) {
 320:         if (!*rejname) {
 321:         Strcpy(rejname, outname);
 322:         Strcat(rejname, ".rej");
 323:         }
 324:         say("%d out of %d hunks failed--saving rejects to %s\n",
 325:         failed, hunk, rejname);
 326:         move_file(TMPREJNAME,rejname);
 327:     }
 328:     set_signals();
 329:     }
 330:     my_exit(0);
 331: }
 332: 
 333: reinitialize_almost_everything()
 334: {
 335:     re_patch();
 336:     re_input();
 337: 
 338:     input_lines = 0;
 339:     last_frozen_line = 0;
 340: 
 341:     filec = 0;
 342:     if (filearg[0] != Nullch) {
 343:     free(filearg[0]);
 344:     filearg[0] = Nullch;
 345:     }
 346: 
 347:     if (outname != Nullch) {
 348:     free(outname);
 349:     outname = Nullch;
 350:     }
 351: 
 352:     last_offset = 0;
 353: 
 354:     diff_type = 0;
 355: 
 356:     if (revision != Nullch) {
 357:     free(revision);
 358:     revision = Nullch;
 359:     }
 360: 
 361:     reverse = FALSE;
 362:     skip_this_patch = FALSE;
 363: 
 364:     get_some_switches();
 365: 
 366:     if (filec >= 2)
 367:     fatal("You may not change to a different patch file.\n");
 368: }
 369: 
 370: get_some_switches()
 371: {
 372:     register char *s;
 373: 
 374:     rejname[0] = '\0';
 375:     if (!Argc)
 376:     return;
 377:     for (Argc--,Argv++; Argc; Argc--,Argv++) {
 378:     s = Argv[0];
 379:     if (strEQ(s,"+")) {
 380:         return;         /* + will be skipped by for loop */
 381:     }
 382:     if (*s != '-' || !s[1]) {
 383:         if (filec == MAXFILEC)
 384:         fatal("Too many file arguments.\n");
 385:         filearg[filec++] = savestr(s);
 386:     }
 387:     else {
 388:         switch (*++s) {
 389:         case 'b':
 390:         origext = savestr(Argv[1]);
 391:         Argc--,Argv++;
 392:         break;
 393:         case 'c':
 394:         diff_type = CONTEXT_DIFF;
 395:         break;
 396:         case 'd':
 397:         if (chdir(Argv[1]) < 0)
 398:             fatal("Can't cd to %s.\n",Argv[1]);
 399:         Argc--,Argv++;
 400:         break;
 401:         case 'D':
 402:             do_defines++;
 403:         Sprintf(if_defined, "#ifdef %s\n", Argv[1]);
 404:         Sprintf(not_defined, "#ifndef %s\n", Argv[1]);
 405:         Sprintf(end_defined, "#endif %s\n", Argv[1]);
 406:         Argc--,Argv++;
 407:         break;
 408:         case 'e':
 409:         diff_type = ED_DIFF;
 410:         break;
 411:         case 'l':
 412:         canonicalize = TRUE;
 413:         break;
 414:         case 'n':
 415:         diff_type = NORMAL_DIFF;
 416:         break;
 417:         case 'o':
 418:         outname = savestr(Argv[1]);
 419:         Argc--,Argv++;
 420:         break;
 421:         case 'p':
 422:         usepath = TRUE; /* do not strip path names */
 423:         break;
 424:         case 'r':
 425:         Strcpy(rejname,Argv[1]);
 426:         Argc--,Argv++;
 427:         break;
 428:         case 'R':
 429:         reverse = TRUE;
 430:         break;
 431:         case 'N':
 432:         noreverse = TRUE;
 433:         break;
 434:         case 's':
 435:         verbose = FALSE;
 436:         break;
 437: #ifdef DEBUGGING
 438:         case 'x':
 439:         debug = atoi(s+1);
 440:         break;
 441: #endif
 442:         default:
 443:         fatal("Unrecognized switch: %s\n",Argv[0]);
 444:         }
 445:     }
 446:     }
 447: }
 448: 
 449: LINENUM
 450: locate_hunk()
 451: {
 452:     register LINENUM first_guess = pch_first() + last_offset;
 453:     register LINENUM offset;
 454:     LINENUM pat_lines = pch_ptrn_lines();
 455:     register LINENUM max_pos_offset = input_lines - first_guess
 456:                 - pat_lines + 1;
 457:     register LINENUM max_neg_offset = first_guess - last_frozen_line - 1
 458:                 - pch_context();
 459: 
 460:     if (!pat_lines)         /* null range matches always */
 461:     return first_guess;
 462:     if (max_neg_offset >= first_guess)  /* do not try lines < 0 */
 463:     max_neg_offset = first_guess - 1;
 464:     if (first_guess <= input_lines && patch_match(first_guess,(LINENUM)0))
 465:     return first_guess;
 466:     for (offset = 1; ; offset++) {
 467:     bool check_after = (offset <= max_pos_offset);
 468:     bool check_before = (offset <= max_pos_offset);
 469: 
 470:     if (check_after && patch_match(first_guess,offset)) {
 471: #ifdef DEBUGGING
 472:         if (debug & 1)
 473:         printf("Offset changing from %d to %d\n",last_offset,offset);
 474: #endif
 475:         last_offset = offset;
 476:         return first_guess+offset;
 477:     }
 478:     else if (check_before && patch_match(first_guess,-offset)) {
 479: #ifdef DEBUGGING
 480:         if (debug & 1)
 481:         printf("Offset changing from %d to %d\n",last_offset,-offset);
 482: #endif
 483:         last_offset = -offset;
 484:         return first_guess-offset;
 485:     }
 486:     else if (!check_before && !check_after)
 487:         return Null(LINENUM);
 488:     }
 489: }
 490: 
 491: /* we did not find the pattern, dump out the hunk so they can handle it */
 492: 
 493: abort_hunk()
 494: {
 495:     register LINENUM i;
 496:     register LINENUM pat_end = pch_end();
 497:     /* add in last_offset to guess the same as the previous successful hunk */
 498:     int oldfirst = pch_first() + last_offset;
 499:     int newfirst = pch_newfirst() + last_offset;
 500:     int oldlast = oldfirst + pch_ptrn_lines() - 1;
 501:     int newlast = newfirst + pch_repl_lines() - 1;
 502: 
 503:     fprintf(rejfp,"***************\n");
 504:     for (i=0; i<=pat_end; i++) {
 505:     switch (pch_char(i)) {
 506:     case '*':
 507:         if (diff_type == NEW_CONTEXT_DIFF)
 508:         fprintf(rejfp,"*** %d,%d ****\n", oldfirst, oldlast);
 509:         else
 510:         fprintf(rejfp,"*** %d,%d\n", oldfirst, oldlast);
 511:         break;
 512:     case '=':
 513:         fprintf(rejfp,"--- %d,%d -----\n", newfirst, newlast);
 514:         break;
 515:     case '\n':
 516:         fprintf(rejfp,"%s", pfetch(i));
 517:         break;
 518:     case ' ': case '-': case '+': case '!':
 519:         fprintf(rejfp,"%c %s", pch_char(i), pfetch(i));
 520:         break;
 521:     default:
 522:         say("Fatal internal error in abort_hunk().\n");
 523:         abort();
 524:     }
 525:     }
 526: }
 527: 
 528: /* we found where to apply it (we hope), so do it */
 529: 
 530: apply_hunk(where)
 531: LINENUM where;
 532: {
 533:     register LINENUM old = 1;
 534:     register LINENUM lastline = pch_ptrn_lines();
 535:     register LINENUM new = lastline+1;
 536:     register int def_state = 0; /* -1 = ifndef, 1 = ifdef */
 537: 
 538:     where--;
 539:     while (pch_char(new) == '=' || pch_char(new) == '\n')
 540:     new++;
 541: 
 542:     while (old <= lastline) {
 543:     if (pch_char(old) == '-') {
 544:         copy_till(where + old - 1);
 545:         if (do_defines) {
 546:         if (def_state == 0) {
 547:             fputs(not_defined, ofp);
 548:             def_state = -1;
 549:         } else
 550:         if (def_state == 1) {
 551:             fputs(else_defined, ofp);
 552:             def_state = 2;
 553:         }
 554:         fputs(pfetch(old), ofp);
 555:         }
 556:         last_frozen_line++;
 557:         old++;
 558:     }
 559:     else if (pch_char(new) == '+') {
 560:         copy_till(where + old - 1);
 561:         if (do_defines) {
 562:         if (def_state == -1) {
 563:             fputs(else_defined, ofp);
 564:             def_state = 2;
 565:         } else
 566:         if (def_state == 0) {
 567:             fputs(if_defined, ofp);
 568:             def_state = 1;
 569:         }
 570:         }
 571:         fputs(pfetch(new),ofp);
 572:         new++;
 573:     }
 574:     else {
 575:         if (pch_char(new) != pch_char(old)) {
 576:         say("Out-of-sync patch, lines %d,%d\n",
 577:             pch_hunk_beg() + old - 1,
 578:             pch_hunk_beg() + new - 1);
 579: #ifdef DEBUGGING
 580:         printf("oldchar = '%c', newchar = '%c'\n",
 581:             pch_char(old), pch_char(new));
 582: #endif
 583:         my_exit(1);
 584:         }
 585:         if (pch_char(new) == '!') {
 586:         copy_till(where + old - 1);
 587:         if (do_defines) {
 588:            fputs(not_defined,ofp);
 589:            def_state = -1;
 590:         }
 591:         while (pch_char(old) == '!') {
 592:             if (do_defines) {
 593:             fputs(pfetch(old),ofp);
 594:             }
 595:             last_frozen_line++;
 596:             old++;
 597:         }
 598:         if (do_defines) {
 599:             fputs(else_defined, ofp);
 600:             def_state = 2;
 601:         }
 602:         while (pch_char(new) == '!') {
 603:             fputs(pfetch(new),ofp);
 604:             new++;
 605:         }
 606:         if (do_defines) {
 607:             fputs(end_defined, ofp);
 608:             def_state = 0;
 609:         }
 610:         }
 611:         else {
 612:         assert(pch_char(new) == ' ');
 613:         old++;
 614:         new++;
 615:         }
 616:     }
 617:     }
 618:     if (new <= pch_end() && pch_char(new) == '+') {
 619:     copy_till(where + old - 1);
 620:     if (do_defines) {
 621:         if (def_state == 0) {
 622:             fputs(if_defined, ofp);
 623:         def_state = 1;
 624:         } else
 625:         if (def_state == -1) {
 626:         fputs(else_defined, ofp);
 627:         def_state = 2;
 628:         }
 629:     }
 630:     while (new <= pch_end() && pch_char(new) == '+') {
 631:         fputs(pfetch(new),ofp);
 632:         new++;
 633:     }
 634:     }
 635:     if (do_defines && def_state) {
 636:     fputs(end_defined, ofp);
 637:     }
 638: }
 639: 
 640: do_ed_script()
 641: {
 642:     FILE *pipefp, *popen();
 643:     bool this_line_is_command = FALSE;
 644:     register char *t;
 645:     long beginning_of_this_line;
 646: 
 647:     Unlink(TMPOUTNAME);
 648:     copy_file(filearg[0],TMPOUTNAME);
 649:     if (verbose)
 650:     Sprintf(buf,"/bin/ed %s",TMPOUTNAME);
 651:     else
 652:     Sprintf(buf,"/bin/ed - %s",TMPOUTNAME);
 653:     pipefp = popen(buf,"w");
 654:     for (;;) {
 655:     beginning_of_this_line = ftell(pfp);
 656:     if (pgets(buf,sizeof buf,pfp) == Nullch) {
 657:         next_intuit_at(beginning_of_this_line);
 658:         break;
 659:     }
 660:     for (t=buf; isdigit(*t) || *t == ','; t++) ;
 661:     this_line_is_command = (isdigit(*buf) &&
 662:       (*t == 'd' || *t == 'c' || *t == 'a') );
 663:     if (this_line_is_command) {
 664:         fputs(buf,pipefp);
 665:         if (*t != 'd') {
 666:         while (pgets(buf,sizeof buf,pfp) != Nullch) {
 667:             fputs(buf,pipefp);
 668:             if (strEQ(buf,".\n"))
 669:             break;
 670:         }
 671:         }
 672:     }
 673:     else {
 674:         next_intuit_at(beginning_of_this_line);
 675:         break;
 676:     }
 677:     }
 678:     fprintf(pipefp,"w\n");
 679:     fprintf(pipefp,"q\n");
 680:     Fflush(pipefp);
 681:     Pclose(pipefp);
 682:     ignore_signals();
 683:     move_file(TMPOUTNAME,outname);
 684:     set_signals();
 685: }
 686: 
 687: init_output(name)
 688: char *name;
 689: {
 690:     ofp = fopen(name,"w");
 691:     if (ofp == Nullfp)
 692:     fatal("patch: can't create %s.\n",name);
 693: }
 694: 
 695: init_reject(name)
 696: char *name;
 697: {
 698:     rejfp = fopen(name,"w");
 699:     if (rejfp == Nullfp)
 700:     fatal("patch: can't create %s.\n",name);
 701: }
 702: 
 703: move_file(from,to)
 704: char *from, *to;
 705: {
 706:     char bakname[512];
 707:     register char *s;
 708:     int fromfd;
 709:     register int i;
 710: 
 711:     /* to stdout? */
 712: 
 713:     if (strEQ(to,"-")) {
 714: #ifdef DEBUGGING
 715:     if (debug & 4)
 716:         say("Moving %s to stdout.\n",from);
 717: #endif
 718:     fromfd = open(from,0);
 719:     if (fromfd < 0)
 720:         fatal("patch: internal error, can't reopen %s\n",from);
 721:     while ((i=read(fromfd,buf,sizeof buf)) > 0)
 722:         if (write(1,buf,i) != 1)
 723:         fatal("patch: write failed\n");
 724:     Close(fromfd);
 725:     return;
 726:     }
 727: 
 728:     Strcpy(bakname,to);
 729:     Strcat(bakname,origext?origext:ORIGEXT);
 730:     if (stat(to,&filestat) >= 0) {  /* output file exists */
 731:     dev_t to_device = filestat.st_dev;
 732:     ino_t to_inode  = filestat.st_ino;
 733:     char *simplename = bakname;
 734: 
 735:     for (s=bakname; *s; s++) {
 736:         if (*s == '/')
 737:         simplename = s+1;
 738:     }
 739:     /* find a backup name that is not the same file */
 740:     while (stat(bakname,&filestat) >= 0 &&
 741:         to_device == filestat.st_dev && to_inode == filestat.st_ino) {
 742:         for (s=simplename; *s && !islower(*s); s++) ;
 743:         if (*s)
 744:         *s = toupper(*s);
 745:         else
 746:         Strcpy(simplename, simplename+1);
 747:     }
 748:     while (unlink(bakname) >= 0) ;  /* while() is for benefit of Eunice */
 749: #ifdef DEBUGGING
 750:     if (debug & 4)
 751:         say("Moving %s to %s.\n",to,bakname);
 752: #endif
 753:     if (link(to,bakname) < 0) {
 754:         say("patch: can't backup %s, output is in %s\n",
 755:         to,from);
 756:         return;
 757:     }
 758:     while (unlink(to) >= 0) ;
 759:     }
 760: #ifdef DEBUGGING
 761:     if (debug & 4)
 762:     say("Moving %s to %s.\n",from,to);
 763: #endif
 764:     if (link(from,to) < 0) {        /* different file system? */
 765:     int tofd;
 766: 
 767:     tofd = creat(to,0666);
 768:     if (tofd < 0) {
 769:         say("patch: can't create %s, output is in %s.\n",
 770:           to, from);
 771:         return;
 772:     }
 773:     fromfd = open(from,0);
 774:     if (fromfd < 0)
 775:         fatal("patch: internal error, can't reopen %s\n",from);
 776:     while ((i=read(fromfd,buf,sizeof buf)) > 0)
 777:         if (write(tofd,buf,i) != i)
 778:         fatal("patch: write failed\n");
 779:     Close(fromfd);
 780:     Close(tofd);
 781:     }
 782:     Unlink(from);
 783: }
 784: 
 785: copy_file(from,to)
 786: char *from, *to;
 787: {
 788:     int tofd;
 789:     int fromfd;
 790:     register int i;
 791: 
 792:     tofd = creat(to,0666);
 793:     if (tofd < 0)
 794:     fatal("patch: can't create %s.\n", to);
 795:     fromfd = open(from,0);
 796:     if (fromfd < 0)
 797:     fatal("patch: internal error, can't reopen %s\n",from);
 798:     while ((i=read(fromfd,buf,sizeof buf)) > 0)
 799:     if (write(tofd,buf,i) != i)
 800:         fatal("patch: write (%s) failed\n", to);
 801:     Close(fromfd);
 802:     Close(tofd);
 803: }
 804: 
 805: copy_till(lastline)
 806: register LINENUM lastline;
 807: {
 808:     if (last_frozen_line > lastline)
 809:     say("patch: misordered hunks! output will be garbled.\n");
 810:     while (last_frozen_line < lastline) {
 811:     dump_line(++last_frozen_line);
 812:     }
 813: }
 814: 
 815: spew_output()
 816: {
 817:     copy_till(input_lines);     /* dump remainder of file */
 818:     Fclose(ofp);
 819:     ofp = Nullfp;
 820: }
 821: 
 822: dump_line(line)
 823: LINENUM line;
 824: {
 825:     register char *s;
 826: 
 827:     for (s=ifetch(line,0); putc(*s,ofp) != '\n'; s++) ;
 828: }
 829: 
 830: /* does the patch pattern match at line base+offset? */
 831: 
 832: bool
 833: patch_match(base,offset)
 834: LINENUM base;
 835: LINENUM offset;
 836: {
 837:     register LINENUM pline;
 838:     register LINENUM iline;
 839:     register LINENUM pat_lines = pch_ptrn_lines();
 840: 
 841:     for (pline = 1, iline=base+offset; pline <= pat_lines; pline++,iline++) {
 842:     if (canonicalize) {
 843:         if (!similar(ifetch(iline,(offset >= 0)),
 844:              pfetch(pline),
 845:              pch_line_len(pline) ))
 846:         return FALSE;
 847:     }
 848:     else if (strnNE(ifetch(iline,(offset >= 0)),
 849:            pfetch(pline),
 850:            pch_line_len(pline) ))
 851:         return FALSE;
 852:     }
 853:     return TRUE;
 854: }
 855: 
 856: /* match two lines with canonicalized white space */
 857: 
 858: bool
 859: similar(a,b,len)
 860: register char *a, *b;
 861: register int len;
 862: {
 863:     while (len) {
 864:     if (isspace(*b)) {      /* whitespace (or \n) to match? */
 865:         if (!isspace(*a))       /* no corresponding whitespace? */
 866:         return FALSE;
 867:         while (len && isspace(*b) && *b != '\n')
 868:         b++,len--;      /* skip pattern whitespace */
 869:         while (isspace(*a) && *a != '\n')
 870:         a++;            /* skip target whitespace */
 871:         if (*a == '\n' || *b == '\n')
 872:         return (*a == *b);  /* should end in sync */
 873:     }
 874:     else if (*a++ != *b++)      /* match non-whitespace chars */
 875:         return FALSE;
 876:     else
 877:         len--;          /* probably not necessary */
 878:     }
 879:     return TRUE;            /* actually, this is not reached */
 880:                     /* since there is always a \n */
 881: }
 882: 
 883: /* input file with indexable lines abstract type */
 884: 
 885: bool using_plan_a = TRUE;
 886: static long i_size;         /* size of the input file */
 887: static char *i_womp;            /* plan a buffer for entire file */
 888: static char **i_ptr;            /* pointers to lines in i_womp */
 889: 
 890: static int tifd = -1;           /* plan b virtual string array */
 891: static char *tibuf[2];          /* plan b buffers */
 892: static LINENUM tiline[2] = {-1,-1}; /* 1st line in each buffer */
 893: static LINENUM lines_per_buf;       /* how many lines per buffer */
 894: static int tireclen;            /* length of records in tmp file */
 895: 
 896: re_input()
 897: {
 898:     if (using_plan_a) {
 899:     i_size = 0;
 900:     /*NOSTRICT*/
 901:     if (i_ptr != Null(char**))
 902:         free((char *)i_ptr);
 903:     if (i_womp != Nullch)
 904:         free(i_womp);
 905:     i_womp = Nullch;
 906:     i_ptr = Null(char **);
 907:     }
 908:     else {
 909:     using_plan_a = TRUE;        /* maybe the next one is smaller */
 910:     Close(tifd);
 911:     tifd = -1;
 912:     free(tibuf[0]);
 913:     free(tibuf[1]);
 914:     tibuf[0] = tibuf[1] = Nullch;
 915:     tiline[0] = tiline[1] = -1;
 916:     tireclen = 0;
 917:     }
 918: }
 919: 
 920: scan_input(filename)
 921: char *filename;
 922: {
 923:     bool plan_a();
 924: 
 925:     if (!plan_a(filename))
 926:     plan_b(filename);
 927: }
 928: 
 929: /* try keeping everything in memory */
 930: 
 931: bool
 932: plan_a(filename)
 933: char *filename;
 934: {
 935:     int ifd;
 936:     register char *s;
 937:     register LINENUM iline;
 938: 
 939:     if (stat(filename,&filestat) < 0) {
 940:     Sprintf(buf,"RCS/%s%s",filename,RCSSUFFIX);
 941:     if (stat(buf,&filestat) >= 0 || stat(buf+4,&filestat) >= 0) {
 942:         Sprintf(buf,CHECKOUT,filename);
 943:         if (verbose)
 944:         say("Can't find %s--attempting to check it out from RCS.\n",
 945:             filename);
 946:         if (system(buf) || stat(filename,&filestat))
 947:         fatal("Can't check out %s.\n",filename);
 948:     }
 949:     else {
 950:         Sprintf(buf,"SCCS/%s%s",SCCSPREFIX,filename);
 951:         if (stat(buf,&filestat) >= 0 || stat(buf+5,&filestat) >= 0) {
 952:         Sprintf(buf,GET,filename);
 953:         if (verbose)
 954:             say("Can't find %s--attempting to get it from SCCS.\n",
 955:             filename);
 956:         if (system(buf) || stat(filename,&filestat))
 957:             fatal("Can't get %s.\n",filename);
 958:         }
 959:         else
 960:         fatal("Can't find %s.\n",filename);
 961:     }
 962:     }
 963:     if ((filestat.st_mode & S_IFMT) & ~S_IFREG)
 964:     fatal("%s is not a normal file--can't patch.\n",filename);
 965:     i_size = filestat.st_size;
 966:     /*NOSTRICT*/
 967:     i_womp = malloc((MEM)(i_size+2));
 968:     if (i_womp == Nullch)
 969:     return FALSE;
 970:     if ((ifd = open(filename,0)) < 0)
 971:     fatal("Can't open file %s\n",filename);
 972:     /*NOSTRICT*/
 973:     if (read(ifd,i_womp,(int)i_size) != i_size) {
 974:     Close(ifd);
 975:     free(i_womp);
 976:     return FALSE;
 977:     }
 978:     Close(ifd);
 979:     if (i_womp[i_size-1] != '\n')
 980:     i_womp[i_size++] = '\n';
 981:     i_womp[i_size] = '\0';
 982: 
 983:     /* count the lines in the buffer so we know how many pointers we need */
 984: 
 985:     iline = 0;
 986:     for (s=i_womp; *s; s++) {
 987:     if (*s == '\n')
 988:         iline++;
 989:     }
 990:     /*NOSTRICT*/
 991:     i_ptr = (char **)malloc((MEM)((iline + 2) * sizeof(char *)));
 992:     if (i_ptr == Null(char **)) {   /* shucks, it was a near thing */
 993:     free((char *)i_womp);
 994:     return FALSE;
 995:     }
 996: 
 997:     /* now scan the buffer and build pointer array */
 998: 
 999:     iline = 1;
1000:     i_ptr[iline] = i_womp;
1001:     for (s=i_womp; *s; s++) {
1002:     if (*s == '\n')
1003:         i_ptr[++iline] = s+1;   /* these are NOT null terminated */
1004:     }
1005:     input_lines = iline - 1;
1006: 
1007:     /* now check for revision, if any */
1008: 
1009:     if (revision != Nullch) {
1010:     if (!rev_in_string(i_womp)) {
1011:         ask("This file doesn't appear to be the %s version--patch anyway? [n] ",
1012:         revision);
1013:         if (*buf != 'y')
1014:         fatal("Aborted.\n");
1015:     }
1016:     else if (verbose)
1017:         say("Good.  This file appears to be the %s version.\n",
1018:         revision);
1019:     }
1020:     return TRUE;            /* plan a will work */
1021: }
1022: 
1023: /* keep (virtually) nothing in memory */
1024: 
1025: plan_b(filename)
1026: char *filename;
1027: {
1028:     FILE *ifp;
1029:     register int i = 0;
1030:     register int maxlen = 1;
1031:     bool found_revision = (revision == Nullch);
1032: 
1033:     using_plan_a = FALSE;
1034:     if ((ifp = fopen(filename,"r")) == Nullfp)
1035:     fatal("Can't open file %s\n",filename);
1036:     if ((tifd = creat(TMPINNAME,0666)) < 0)
1037:     fatal("Can't open file %s\n",TMPINNAME);
1038:     while (fgets(buf,sizeof buf, ifp) != Nullch) {
1039:     if (revision != Nullch && !found_revision && rev_in_string(buf))
1040:         found_revision = TRUE;
1041:     if ((i = strlen(buf)) > maxlen)
1042:         maxlen = i;         /* find longest line */
1043:     }
1044:     if (revision != Nullch) {
1045:     if (!found_revision) {
1046:         ask("This file doesn't appear to be the %s version--patch anyway? [n] ",
1047:         revision);
1048:         if (*buf != 'y')
1049:         fatal("Aborted.\n");
1050:     }
1051:     else if (verbose)
1052:         say("Good.  This file appears to be the %s version.\n",
1053:         revision);
1054:     }
1055:     Fseek(ifp,0L,0);        /* rewind file */
1056:     lines_per_buf = BUFFERSIZE / maxlen;
1057:     tireclen = maxlen;
1058:     tibuf[0] = malloc((MEM)(BUFFERSIZE + 1));
1059:     tibuf[1] = malloc((MEM)(BUFFERSIZE + 1));
1060:     if (tibuf[1] == Nullch)
1061:     fatal("Can't seem to get enough memory.\n");
1062:     for (i=1; ; i++) {
1063:     if (! (i % lines_per_buf))  /* new block */
1064:         if (write(tifd,tibuf[0],BUFFERSIZE) < BUFFERSIZE)
1065:         fatal("patch: can't write temp file.\n");
1066:     if (fgets(tibuf[0] + maxlen * (i%lines_per_buf), maxlen + 1, ifp)
1067:       == Nullch) {
1068:         input_lines = i - 1;
1069:         if (i % lines_per_buf)
1070:         if (write(tifd,tibuf[0],BUFFERSIZE) < BUFFERSIZE)
1071:             fatal("patch: can't write temp file.\n");
1072:         break;
1073:     }
1074:     }
1075:     Fclose(ifp);
1076:     Close(tifd);
1077:     if ((tifd = open(TMPINNAME,0)) < 0) {
1078:     fatal("Can't reopen file %s\n",TMPINNAME);
1079:     }
1080: }
1081: 
1082: /* fetch a line from the input file, \n terminated, not necessarily \0 */
1083: char *
1084: ifetch(line,whichbuf)
1085: register LINENUM line;
1086: int whichbuf;               /* ignored when file in memory */
1087: {
1088:     if (line < 1 || line > input_lines)
1089:     return "";
1090:     if (using_plan_a)
1091:     return i_ptr[line];
1092:     else {
1093:     LINENUM offline = line % lines_per_buf;
1094:     LINENUM baseline = line - offline;
1095: 
1096:     if (tiline[0] == baseline)
1097:         whichbuf = 0;
1098:     else if (tiline[1] == baseline)
1099:         whichbuf = 1;
1100:     else {
1101:         tiline[whichbuf] = baseline;
1102:         Lseek(tifd,(long)baseline / lines_per_buf * BUFFERSIZE,0);
1103:         if (read(tifd,tibuf[whichbuf],BUFFERSIZE) < 0)
1104:         fatal("Error reading tmp file %s.\n",TMPINNAME);
1105:     }
1106:     return tibuf[whichbuf] + (tireclen*offline);
1107:     }
1108: }
1109: 
1110: /* patch abstract type */
1111: 
1112: static long p_filesize;         /* size of the patch file */
1113: static LINENUM p_first;         /* 1st line number */
1114: static LINENUM p_newfirst;      /* 1st line number of replacement */
1115: static LINENUM p_ptrn_lines;        /* # lines in pattern */
1116: static LINENUM p_repl_lines;        /* # lines in replacement text */
1117: static LINENUM p_end = -1;      /* last line in hunk */
1118: static LINENUM p_max;           /* max allowed value of p_end */
1119: static LINENUM p_context = 3;       /* # of context lines */
1120: static LINENUM p_input_line = 0;    /* current line # from patch file */
1121: static char *p_line[MAXHUNKSIZE];   /* the text of the hunk */
1122: static char p_char[MAXHUNKSIZE];    /* +, -, and ! */
1123: static int p_len[MAXHUNKSIZE];      /* length of each line */
1124: static int p_indent;            /* indent to patch */
1125: static long p_base;         /* where to intuit this time */
1126: static long p_start;            /* where intuit found a patch */
1127: 
1128: re_patch()
1129: {
1130:     p_first = (LINENUM)0;
1131:     p_newfirst = (LINENUM)0;
1132:     p_ptrn_lines = (LINENUM)0;
1133:     p_repl_lines = (LINENUM)0;
1134:     p_end = (LINENUM)-1;
1135:     p_max = (LINENUM)0;
1136:     p_indent = 0;
1137: }
1138: 
1139: open_patch_file(filename)
1140: char *filename;
1141: {
1142:     if (filename == Nullch || !*filename || strEQ(filename,"-")) {
1143:     pfp = fopen(TMPPATNAME,"w");
1144:     if (pfp == Nullfp)
1145:         fatal("patch: can't create %s.\n",TMPPATNAME);
1146:     while (fgets(buf,sizeof buf,stdin) != NULL)
1147:         fputs(buf,pfp);
1148:     Fclose(pfp);
1149:     filename = TMPPATNAME;
1150:     }
1151:     pfp = fopen(filename,"r");
1152:     if (pfp == Nullfp)
1153:     fatal("patch file %s not found\n",filename);
1154:     Fstat(fileno(pfp), &filestat);
1155:     p_filesize = filestat.st_size;
1156:     next_intuit_at(0L);         /* start at the beginning */
1157: }
1158: 
1159: bool
1160: there_is_another_patch()
1161: {
1162:     bool no_input_file = (filearg[0] == Nullch);
1163: 
1164:     if (p_base != 0L && p_base >= p_filesize) {
1165:     if (verbose)
1166:         say("done\n");
1167:     return FALSE;
1168:     }
1169:     if (verbose)
1170:     say("Hmm...");
1171:     diff_type = intuit_diff_type();
1172:     if (!diff_type) {
1173:     if (p_base != 0L) {
1174:         if (verbose)
1175:         say("  Ignoring the trailing garbage.\ndone\n");
1176:     }
1177:     else
1178:         say("  I can't seem to find a patch in there anywhere.\n");
1179:     return FALSE;
1180:     }
1181:     if (verbose)
1182:     say("  %sooks like %s to me...\n",
1183:         (p_base == 0L ? "L" : "The next patch l"),
1184:         diff_type == CONTEXT_DIFF ? "a context diff" :
1185:         diff_type == NEW_CONTEXT_DIFF ? "a new-style context diff" :
1186:         diff_type == NORMAL_DIFF ? "a normal diff" :
1187:         "an ed script" );
1188:     if (p_indent && verbose)
1189:     say("(Patch is indented %d space%s.)\n",p_indent,p_indent==1?"":"s");
1190:     skip_to(p_start);
1191:     if (no_input_file) {
1192:     while (filearg[0] == Nullch) {
1193:         ask("File to patch: ");
1194:         filearg[0] = fetchname(buf);
1195:     }
1196:     if (verbose) {
1197:         say("Patching file %s...\n",filearg[0]);
1198:     }
1199:     }
1200:     return TRUE;
1201: }
1202: 
1203: intuit_diff_type()
1204: {
1205:     long this_line = 0;
1206:     long previous_line;
1207:     long first_command_line = -1;
1208:     bool last_line_was_command = FALSE;
1209:     bool this_line_is_command = FALSE;
1210:     bool last_line_was_stars = FALSE;
1211:     bool this_line_is_stars = FALSE;
1212:     register int indent;
1213:     register char *s, *t;
1214:     char *oldname = Nullch;
1215:     char *newname = Nullch;
1216:     bool no_filearg = (filearg[0] == Nullch);
1217: 
1218:     Fseek(pfp,p_base,0);
1219:     for (;;) {
1220:     previous_line = this_line;
1221:     last_line_was_command = this_line_is_command;
1222:     last_line_was_stars = this_line_is_stars;
1223:     this_line = ftell(pfp);
1224:     indent = 0;
1225:     if (fgets(buf,sizeof buf,pfp) == Nullch) {
1226:         if (first_command_line >= 0L) {
1227:                     /* nothing but deletes!? */
1228:         p_start = first_command_line;
1229:         return ED_DIFF;
1230:         }
1231:         else {
1232:         p_start = this_line;
1233:         return 0;
1234:         }
1235:     }
1236:     for (s = buf; *s == ' ' || *s == '\t'; s++) {
1237:         if (*s == '\t')
1238:         indent += 8 - (indent % 8);
1239:         else
1240:         indent++;
1241:     }
1242:     for (t=s; isdigit(*t) || *t == ','; t++) ;
1243:     this_line_is_command = (isdigit(*s) &&
1244:       (*t == 'd' || *t == 'c' || *t == 'a') );
1245:     if (first_command_line < 0L && this_line_is_command) {
1246:         first_command_line = this_line;
1247:         p_indent = indent;      /* assume this for now */
1248:     }
1249:     if (strnEQ(s,"*** ",4))
1250:         oldname = fetchname(s+4);
1251:     else if (strnEQ(s,"--- ",4)) {
1252:         newname = fetchname(s+4);
1253:         if (no_filearg) {
1254:         if (oldname && newname) {
1255:             if (strlen(oldname) < strlen(newname))
1256:             filearg[0] = oldname;
1257:             else
1258:             filearg[0] = newname;
1259:         }
1260:         else if (oldname)
1261:             filearg[0] = oldname;
1262:         else if (newname)
1263:             filearg[0] = newname;
1264:         }
1265:     }
1266:     else if (strnEQ(s,"Index:",6)) {
1267:         if (no_filearg)
1268:         filearg[0] = fetchname(s+6);
1269:                     /* this filearg might get limboed */
1270:     }
1271:     else if (strnEQ(s,"Prereq:",7)) {
1272:         for (t=s+7; isspace(*t); t++) ;
1273:         revision = savestr(t);
1274:         for (t=revision; *t && !isspace(*t); t++) ;
1275:         *t = '\0';
1276:         if (!*revision) {
1277:         free(revision);
1278:         revision = Nullch;
1279:         }
1280:     }
1281:     if ((!diff_type || diff_type == ED_DIFF) &&
1282:       first_command_line >= 0L &&
1283:       strEQ(s,".\n") ) {
1284:         p_indent = indent;
1285:         p_start = first_command_line;
1286:         return ED_DIFF;
1287:     }
1288:     this_line_is_stars = strnEQ(s,"********",8);
1289:     if ((!diff_type || diff_type == CONTEXT_DIFF) && last_line_was_stars &&
1290:          strnEQ(s,"*** ",4)) {
1291:         /* if this is a new context diff the character just before */
1292:         /* the newline is a '*'. */
1293:         while (*s != '\n')
1294:         s++;
1295:         p_indent = indent;
1296:         p_start = previous_line;
1297:         return (*(s-1) == '*' ? NEW_CONTEXT_DIFF : CONTEXT_DIFF);
1298:     }
1299:     if ((!diff_type || diff_type == NORMAL_DIFF) &&
1300:       last_line_was_command &&
1301:       (strnEQ(s,"< ",2) || strnEQ(s,"> ",2)) ) {
1302:         p_start = previous_line;
1303:         p_indent = indent;
1304:         return NORMAL_DIFF;
1305:     }
1306:     }
1307: }
1308: 
1309: char *
1310: fetchname(at)
1311: char *at;
1312: {
1313:     char *s = savestr(at);
1314:     char *name;
1315:     register char *t;
1316:     char tmpbuf[200];
1317: 
1318:     for (t=s; isspace(*t); t++) ;
1319:     name = t;
1320:     for (; *t && !isspace(*t); t++)
1321:     if (!usepath)
1322:         if (*t == '/')
1323:         name = t+1;
1324:     *t = '\0';
1325:     name = savestr(name);
1326:     Sprintf(tmpbuf,"RCS/%s",name);
1327:     free(s);
1328:     if (stat(name,&filestat) < 0) {
1329:     Strcat(tmpbuf,RCSSUFFIX);
1330:     if (stat(tmpbuf,&filestat) < 0 && stat(tmpbuf+4,&filestat) < 0) {
1331:         Sprintf(tmpbuf,"SCCS/%s%s",SCCSPREFIX,name);
1332:         if (stat(tmpbuf,&filestat) < 0 && stat(tmpbuf+5,&filestat) < 0) {
1333:         free(name);
1334:         name = Nullch;
1335:         }
1336:     }
1337:     }
1338:     return name;
1339: }
1340: 
1341: next_intuit_at(file_pos)
1342: long file_pos;
1343: {
1344:     p_base = file_pos;
1345: }
1346: 
1347: skip_to(file_pos)
1348: long file_pos;
1349: {
1350:     char *ret;
1351: 
1352:     assert(p_base <= file_pos);
1353:     if (verbose && p_base < file_pos) {
1354:     Fseek(pfp,p_base,0);
1355:     say("The text leading up to this was:\n--------------------------\n");
1356:     while (ftell(pfp) < file_pos) {
1357:         ret = fgets(buf,sizeof buf,pfp);
1358:         assert(ret != Nullch);
1359:         say("|%s",buf);
1360:     }
1361:     say("--------------------------\n");
1362:     }
1363:     else
1364:     Fseek(pfp,file_pos,0);
1365: }
1366: 
1367: bool
1368: another_hunk()
1369: {
1370:     register char *s;
1371:     char *ret;
1372:     register int context = 0;
1373: 
1374:     while (p_end >= 0) {
1375:     free(p_line[p_end--]);
1376:     }
1377:     assert(p_end == -1);
1378: 
1379:     p_max = MAXHUNKSIZE;        /* gets reduced when --- found */
1380:     if (diff_type == CONTEXT_DIFF) {
1381:     long line_beginning = ftell(pfp);
1382:     LINENUM repl_beginning = 0;
1383: 
1384:     ret = pgets(buf,sizeof buf, pfp);
1385:     if (ret == Nullch || strnNE(buf,"********",8)) {
1386:         next_intuit_at(line_beginning);
1387:         return FALSE;
1388:     }
1389:     p_context = 100;
1390:     while (p_end < p_max) {
1391:         ret = pgets(buf,sizeof buf, pfp);
1392:         if (ret == Nullch) {
1393:         if (p_max - p_end < 4)
1394:             Strcpy(buf,"  \n"); /* assume blank lines got chopped */
1395:         else
1396:             fatal("Unexpected end of file in patch.\n");
1397:         }
1398:         p_input_line++;
1399:         if (strnEQ(buf,"********",8))
1400:         fatal("Unexpected end of hunk at line %d.\n",
1401:             p_input_line);
1402:         p_char[++p_end] = *buf;
1403:         switch (*buf) {
1404:         case '*':
1405:         if (p_end != 0)
1406:             fatal("Unexpected *** at line %d: %s", p_input_line, buf);
1407:         context = 0;
1408:         p_line[p_end] = savestr(buf);
1409:         for (s=buf; *s && !isdigit(*s); s++) ;
1410:         if (!isdigit(*s))
1411:             fatal("Malformed patch at line %d: %s", p_input_line, buf);
1412:         p_first = (LINENUM) atol(s);
1413:         while (isdigit(*s)) s++;
1414:         for (; *s && !isdigit(*s); s++) ;
1415:         if (!isdigit(*s))
1416:             p_ptrn_lines = 1;
1417:         else
1418:             p_ptrn_lines = ((LINENUM)atol(s)) - p_first + 1;
1419:         break;
1420:         case '-':
1421:         if (buf[1] == '-') {
1422:             if (p_end != p_ptrn_lines + 1 &&
1423:             p_end != p_ptrn_lines + 2)
1424:             fatal("Unexpected --- at line %d: %s",
1425:                 p_input_line,buf);
1426:             repl_beginning = p_end;
1427:             context = 0;
1428:             p_line[p_end] = savestr(buf);
1429:             p_char[p_end] = '=';
1430:             for (s=buf; *s && !isdigit(*s); s++) ;
1431:             if (!isdigit(*s))
1432:             fatal("Malformed patch at line %d: %s",
1433:                   p_input_line, buf);
1434:             p_newfirst = (LINENUM) atol(s);
1435:             while (isdigit(*s)) s++;
1436:             for (; *s && !isdigit(*s); s++) ;
1437:             if (!isdigit(*s))
1438:             p_max = p_newfirst;
1439:             else
1440:             p_max = ((LINENUM)atol(s));
1441:             p_max += 1 + p_end - p_newfirst;
1442:             if (p_max >= MAXHUNKSIZE)
1443:             fatal("Hunk too large (%d lines) at line %d: %s",
1444:                   p_max - p_end, p_input_line, buf);
1445:             break;
1446:         }
1447:         /* FALL THROUGH */
1448:         case '+': case '!':
1449:         if (context > 0) {
1450:             if (context < p_context)
1451:             p_context = context;
1452:             context = -100;
1453:         }
1454:         p_line[p_end] = savestr(buf+2);
1455:         break;
1456:         case '\t': case '\n':   /* assume the 2 spaces got eaten */
1457:         p_line[p_end] = savestr(buf);
1458:         if (p_end != p_ptrn_lines + 1) {
1459:             context++;
1460:             p_char[p_end] = ' ';
1461:         }
1462:         break;
1463:         case ' ':
1464:         context++;
1465:         p_line[p_end] = savestr(buf+2);
1466:         break;
1467:         default:
1468:         fatal("Malformed patch at line %d: %s",p_input_line,buf);
1469:         }
1470:         /* set up p_len for strncmp() so we don't have to */
1471:         /* assume null termination */
1472:         if (p_line[p_end])
1473:         p_len[p_end] = strlen(p_line[p_end]);
1474:         else
1475:         p_len[p_end] = 0;
1476:     }
1477:     if (p_end >=0 && !p_ptrn_lines)
1478:         fatal("No --- found in patch at line %d\n", pch_hunk_beg());
1479:     p_repl_lines = p_end - repl_beginning;
1480:     p_char[p_end+1] = '^';  /* add a stopper for apply_hunk */
1481:     }
1482:     else if (diff_type == NEW_CONTEXT_DIFF) {
1483:     long line_beginning = ftell(pfp);
1484:     LINENUM repl_beginning = 0;
1485:     LINENUM fillcnt = 0;
1486:     LINENUM fillsrc;
1487:     LINENUM filldst;
1488: 
1489:     ret = pgets(buf,sizeof buf, pfp);
1490:     if (ret == Nullch || strnNE(buf,"********",8)) {
1491:         next_intuit_at(line_beginning);
1492:         return FALSE;
1493:     }
1494:     p_context = 0;
1495:     while (p_end < p_max) {
1496:         ret = pgets(buf,sizeof buf, pfp);
1497:         if (ret == Nullch) {
1498:         if (p_max - p_end < 4)
1499:             Strcpy(buf,"  \n"); /* assume blank lines got chopped */
1500:         else
1501:             fatal("Unexpected end of file in patch.\n");
1502:         }
1503:         p_input_line++;
1504:         p_char[++p_end] = *buf;
1505:         switch (*buf) {
1506:         case '*':   /* another hunk */
1507:         if (strnEQ(buf,"********",8))
1508:             fatal("Unexpected end of hunk at line %d.\n",
1509:                 p_input_line);
1510: 
1511:         if (p_end != 0)
1512:             fatal("Unexpected *** at line %d: %s", p_input_line, buf);
1513:         context = 0;
1514:         p_line[p_end] = savestr(buf);
1515:         for (s=buf; *s && !isdigit(*s); s++) ;
1516:         if (!isdigit(*s))
1517:             fatal("Malformed patch at line %d: %s", p_input_line, buf);
1518:         p_first = (LINENUM) atol(s);
1519:         while (isdigit(*s)) s++;
1520:         for (; *s && !isdigit(*s); s++) ;
1521:         if (!isdigit(*s))
1522:             p_ptrn_lines = 1;
1523:         else
1524:             p_ptrn_lines = ((LINENUM)atol(s)) - p_first + 1;
1525:         break;
1526:         case '-':
1527:         if (buf[1] == '-') {
1528:             if (p_end != p_ptrn_lines + 1) {
1529:             if (p_end == 1) {
1530:                 /* `old' lines were omitted - set up to fill them */
1531:                 /* in from 'new' context lines. */
1532:                 p_end = p_ptrn_lines + 1;
1533:                 fillsrc = p_end + 1;
1534:                 filldst = 1;
1535:                 fillcnt = p_ptrn_lines;
1536:             } else
1537:                 fatal("Unexpected --- at line %d: %s",
1538:                 p_input_line,buf);
1539:             }
1540:             repl_beginning = p_end;
1541:             p_line[p_end] = savestr(buf);
1542:             p_char[p_end] = '=';
1543:             for (s=buf; *s && !isdigit(*s); s++) ;
1544:             if (!isdigit(*s))
1545:             fatal("Malformed patch at line %d: %s",
1546:                   p_input_line, buf);
1547:             p_newfirst = (LINENUM) atol(s);
1548:             while (isdigit(*s)) s++;
1549:             for (; *s && !isdigit(*s); s++) ;
1550:             if (!isdigit(*s))
1551:             p_max = p_newfirst;
1552:             else
1553:             p_max = ((LINENUM)atol(s));
1554:             p_max += 1 + p_end - p_newfirst;
1555:             if (p_max >= MAXHUNKSIZE)
1556:             fatal("Hunk too large (%d lines) at line %d: %s",
1557:                   p_max - p_end, p_input_line, buf);
1558:             if (p_max - p_end == context) {
1559:             /* redundant 'new' context lines were omitted */
1560:             /* set up to fill them in from the the old file's */
1561:             /* context */
1562:             fillsrc = 1;
1563:             filldst = p_end + 1;
1564:             fillcnt = p_max - repl_beginning;
1565:             p_end = p_max;
1566:             }
1567:             break;
1568:         }
1569:         /* FALL THROUGH */
1570:         case '+': case '!':
1571:         if (context > 0 && p_context == 0) {
1572:             p_context = context;
1573:         }
1574:         p_line[p_end] = savestr(buf+2);
1575:         break;
1576:         case '\t': case '\n':   /* assume the 2 spaces got eaten */
1577:         p_line[p_end] = savestr(buf);
1578:         context++;
1579:         p_char[p_end] = ' ';
1580:         break;
1581:         case ' ':
1582:         context++;
1583:         p_line[p_end] = savestr(buf+2);
1584:         break;
1585:         default:
1586:         fatal("Malformed patch at line %d: %s",p_input_line,buf);
1587:         }
1588:         /* set up p_len for strncmp() so we don't have to */
1589:         /* assume null termination */
1590:         if (p_line[p_end])
1591:         p_len[p_end] = strlen(p_line[p_end]);
1592:         else
1593:         p_len[p_end] = 0;
1594:     }
1595:     if (p_end >=0 && !p_ptrn_lines)
1596:         fatal("No --- found in patch at line %d\n", pch_hunk_beg());
1597: 
1598:     /* if there were omitted context lines, fill them in */
1599:     if (fillcnt) {
1600:         while (fillcnt-- > 0) {
1601:         while (p_char[fillsrc] != ' ')
1602:             fillsrc++;
1603:         if (p_line[fillsrc])
1604:             p_line[filldst] = savestr (p_line[fillsrc]);
1605:         else
1606:             p_line[filldst] = p_line[fillsrc];
1607:         p_char[filldst] = p_char[fillsrc];
1608:         p_len[filldst] = p_len[fillsrc];
1609:         fillsrc++; filldst++;
1610:         }
1611:         assert(filldst==p_end+1 || filldst==repl_beginning);
1612:     }
1613:     p_repl_lines = p_end - repl_beginning;
1614:     p_char[p_end+1] = '^';  /* add a stopper for apply_hunk */
1615:     }
1616:     else {              /* normal diff--fake it up */
1617:     char hunk_type;
1618:     register int i;
1619:     LINENUM min, max;
1620:     long line_beginning = ftell(pfp);
1621: 
1622:     p_context = 0;
1623:     ret = pgets(buf,sizeof buf, pfp);
1624:     p_input_line++;
1625:     if (ret == Nullch || !isdigit(*buf)) {
1626:         next_intuit_at(line_beginning);
1627:         return FALSE;
1628:     }
1629:     p_first = (LINENUM)atol(buf);
1630:     for (s=buf; isdigit(*s); s++) ;
1631:     if (*s == ',') {
1632:         p_ptrn_lines = (LINENUM)atol(++s) - p_first + 1;
1633:         while (isdigit(*s)) s++;
1634:     }
1635:     else
1636:         p_ptrn_lines = (*s != 'a');
1637:     hunk_type = *s;
1638:     if (hunk_type == 'a')
1639:         p_first++;          /* do append rather than insert */
1640:     min = (LINENUM)atol(++s);
1641:     for (; isdigit(*s); s++) ;
1642:     if (*s == ',')
1643:         max = (LINENUM)atol(++s);
1644:     else
1645:         max = min;
1646:     if (hunk_type == 'd')
1647:         min++;
1648:     p_end = p_ptrn_lines + 1 + max - min + 1;
1649:     p_newfirst = min;
1650:     p_repl_lines = max - min + 1;
1651:     Sprintf(buf,"*** %d,%d\n", p_first, p_first + p_ptrn_lines - 1);
1652:     p_line[0] = savestr(buf);
1653:     p_char[0] = '*';
1654:     for (i=1; i<=p_ptrn_lines; i++) {
1655:         ret = pgets(buf,sizeof buf, pfp);
1656:         p_input_line++;
1657:         if (ret == Nullch)
1658:         fatal("Unexpected end of file in patch at line %d.\n",
1659:           p_input_line);
1660:         if (*buf != '<')
1661:         fatal("< expected at line %d of patch.\n", p_input_line);
1662:         p_line[i] = savestr(buf+2);
1663:         if (p_line[i])
1664:         p_len[i] = strlen(p_line[i]);
1665:         else
1666:         p_len[i] = 0;
1667:         p_char[i] = '-';
1668:     }
1669:     if (hunk_type == 'c') {
1670:         ret = pgets(buf,sizeof buf, pfp);
1671:         p_input_line++;
1672:         if (ret == Nullch)
1673:         fatal("Unexpected end of file in patch at line %d.\n",
1674:             p_input_line);
1675:         if (*buf != '-')
1676:         fatal("--- expected at line %d of patch.\n", p_input_line);
1677:     }
1678:     Sprintf(buf,"--- %d,%d\n",min,max);
1679:     p_line[i] = savestr(buf);
1680:     p_char[i] = '=';
1681:     for (i++; i<=p_end; i++) {
1682:         ret = pgets(buf,sizeof buf, pfp);
1683:         p_input_line++;
1684:         if (ret == Nullch)
1685:         fatal("Unexpected end of file in patch at line %d.\n",
1686:             p_input_line);
1687:         if (*buf != '>')
1688:         fatal("> expected at line %d of patch.\n", p_input_line);
1689:         p_line[i] = savestr(buf+2);
1690:         /* set up p_len for strncmp() so we don't have to */
1691:         /* assume null termination */
1692:         if (p_line[i])
1693:         p_len[i] = strlen(p_line[i]);
1694:         else
1695:         p_len[i] = 0;
1696:         p_char[i] = '+';
1697:     }
1698:     }
1699:     if (reverse)            /* backwards patch? */
1700:     pch_swap();
1701: #ifdef DEBUGGING
1702:     if (debug & 2) {
1703:     int i;
1704:     char special;
1705: 
1706:     for (i=0; i <= p_end; i++) {
1707:         if (i == p_ptrn_lines)
1708:         special = '^';
1709:         else
1710:         special = ' ';
1711:         printf("%3d %c %c %s",i,p_char[i],special,p_line[i]);
1712:     }
1713:     }
1714: #endif
1715:     return TRUE;
1716: }
1717: 
1718: char *
1719: pgets(bf,sz,fp)
1720: char *bf;
1721: int sz;
1722: FILE *fp;
1723: {
1724:     char *ret = fgets(bf,sz,fp);
1725:     register char *s;
1726:     register int indent = 0;
1727: 
1728:     if (p_indent && ret != Nullch) {
1729:     for (s=buf; indent < p_indent && (*s == ' ' || *s == '\t'); s++) {
1730:         if (*s == '\t')
1731:         indent += 8 - (indent % 7);
1732:         else
1733:         indent++;
1734:     }
1735:     if (buf != s)
1736:         Strcpy(buf,s);
1737:     }
1738:     return ret;
1739: }
1740: 
1741: pch_swap()
1742: {
1743:     char *tp_line[MAXHUNKSIZE];     /* the text of the hunk */
1744:     char tp_char[MAXHUNKSIZE];      /* +, -, and ! */
1745:     int tp_len[MAXHUNKSIZE];        /* length of each line */
1746:     register LINENUM i, n;
1747:     bool blankline = FALSE;
1748:     register char *s;
1749: 
1750:     i = p_first;
1751:     p_first = p_newfirst;
1752:     p_newfirst = i;
1753: 
1754:     /* make a scratch copy */
1755: 
1756:     for (i=0; i<=p_end; i++) {
1757:     tp_line[i] = p_line[i];
1758:     tp_char[i] = p_char[i];
1759:     tp_len[i] = p_len[i];
1760:     }
1761: 
1762:     /* now turn the new into the old */
1763: 
1764:     i = p_ptrn_lines + 1;
1765:     if (tp_char[i] == '\n') {       /* account for possible blank line */
1766:     blankline = TRUE;
1767:     i++;
1768:     }
1769:     for (n=0; i <= p_end; i++,n++) {
1770:     p_line[n] = tp_line[i];
1771:     p_char[n] = tp_char[i];
1772:     if (p_char[n] == '+')
1773:         p_char[n] = '-';
1774:     p_len[n] = tp_len[i];
1775:     }
1776:     if (blankline) {
1777:     i = p_ptrn_lines + 1;
1778:     p_line[n] = tp_line[i];
1779:     p_char[n] = tp_char[i];
1780:     p_len[n] = tp_len[i];
1781:     n++;
1782:     }
1783:     assert(p_char[0] == '=');
1784:     p_char[0] = '*';
1785:     for (s=p_line[0]; *s; s++)
1786:     if (*s == '-')
1787:         *s = '*';
1788: 
1789:     /* now turn the old into the new */
1790: 
1791:     assert(tp_char[0] == '*');
1792:     tp_char[0] = '=';
1793:     for (s=tp_line[0]; *s; s++)
1794:     if (*s == '*')
1795:         *s = '-';
1796:     for (i=0; n <= p_end; i++,n++) {
1797:     p_line[n] = tp_line[i];
1798:     p_char[n] = tp_char[i];
1799:     if (p_char[n] == '-')
1800:         p_char[n] = '+';
1801:     p_len[n] = tp_len[i];
1802:     }
1803:     assert(i == p_ptrn_lines + 1);
1804:     i = p_ptrn_lines;
1805:     p_ptrn_lines = p_repl_lines;
1806:     p_repl_lines = i;
1807: }
1808: 
1809: LINENUM
1810: pch_first()
1811: {
1812:     return p_first;
1813: }
1814: 
1815: LINENUM
1816: pch_ptrn_lines()
1817: {
1818:     return p_ptrn_lines;
1819: }
1820: 
1821: LINENUM
1822: pch_newfirst()
1823: {
1824:     return p_newfirst;
1825: }
1826: 
1827: LINENUM
1828: pch_repl_lines()
1829: {
1830:     return p_repl_lines;
1831: }
1832: 
1833: LINENUM
1834: pch_end()
1835: {
1836:     return p_end;
1837: }
1838: 
1839: LINENUM
1840: pch_context()
1841: {
1842:     return p_context;
1843: }
1844: 
1845: pch_line_len(line)
1846: LINENUM line;
1847: {
1848:     return p_len[line];
1849: }
1850: 
1851: char
1852: pch_char(line)
1853: LINENUM line;
1854: {
1855:     return p_char[line];
1856: }
1857: 
1858: char *
1859: pfetch(line)
1860: LINENUM line;
1861: {
1862:     return p_line[line];
1863: }
1864: 
1865: LINENUM
1866: pch_hunk_beg()
1867: {
1868:     return p_input_line - p_end - 1;
1869: }
1870: 
1871: char *
1872: savestr(s)
1873: register char *s;
1874: {
1875:     register char  *rv,
1876:                    *t;
1877: 
1878:     t = s;
1879:     while (*t++);
1880:     rv = malloc((MEM) (t - s));
1881:     if (rv == NULL)
1882:     fatal ("patch: out of memory (savestr)\n");
1883:     t = rv;
1884:     while (*t++ = *s++);
1885:     return rv;
1886: }
1887: 
1888: my_exit(status)
1889: int status;
1890: {
1891:     Unlink(TMPINNAME);
1892:     Unlink(TMPOUTNAME);
1893:     Unlink(TMPREJNAME);
1894:     Unlink(TMPPATNAME);
1895:     exit(status);
1896: }
1897: 
1898: #ifdef lint
1899: 
1900: /*VARARGS ARGSUSED*/
1901: say(pat) char *pat; { ; }
1902: /*VARARGS ARGSUSED*/
1903: fatal(pat) char *pat; { ; }
1904: /*VARARGS ARGSUSED*/
1905: ask(pat) char *pat; { ; }
1906: 
1907: #else lint
1908: 
1909: say(pat,arg1,arg2,arg3)
1910: char *pat;
1911: int arg1,arg2,arg3;
1912: {
1913:     fprintf(stderr,pat,arg1,arg2,arg3);
1914:     Fflush(stderr);
1915: }
1916: 
1917: fatal(pat,arg1,arg2,arg3)
1918: char *pat;
1919: int arg1,arg2,arg3;
1920: {
1921:     say(pat,arg1,arg2,arg3);
1922:     my_exit(1);
1923: }
1924: 
1925: ask(pat,arg1,arg2,arg3)
1926: char *pat;
1927: int arg1,arg2,arg3;
1928: {
1929:     int ttyfd = open("/dev/tty",2);
1930:     int r;
1931: 
1932:     say(pat,arg1,arg2,arg3);
1933:     if (ttyfd >= 0) {
1934:     r = read(ttyfd, buf, sizeof buf);
1935:     Close(ttyfd);
1936:     }
1937:     else
1938:     r = read(2, buf, sizeof buf);
1939:     if (r <= 0)
1940:     buf[0] = 0;
1941: }
1942: #endif lint
1943: 
1944: bool
1945: rev_in_string(string)
1946: char *string;
1947: {
1948:     register char *s;
1949:     register int patlen;
1950: 
1951:     if (revision == Nullch)
1952:     return TRUE;
1953:     patlen = strlen(revision);
1954:     for (s = string; *s; s++) {
1955:     if (isspace(*s) && strnEQ(s+1,revision,patlen) &&
1956:         isspace(s[patlen+1] )) {
1957:         return TRUE;
1958:     }
1959:     }
1960:     return FALSE;
1961: }
1962: 
1963: set_signals()
1964: {
1965:     /*NOSTRICT*/
1966:     if (signal(SIGHUP, SIG_IGN) != SIG_IGN)
1967:     Signal(SIGHUP, my_exit);
1968:     /*NOSTRICT*/
1969:     if (signal(SIGINT, SIG_IGN) != SIG_IGN)
1970:     Signal(SIGINT, my_exit);
1971: }
1972: 
1973: ignore_signals()
1974: {
1975:     /*NOSTRICT*/
1976:     Signal(SIGHUP, SIG_IGN);
1977:     /*NOSTRICT*/
1978:     Signal(SIGINT, SIG_IGN);
1979: }

Defined functions

abort_hunk defined in line 493; used 1 times
another_hunk defined in line 1367; used 2 times
apply_hunk defined in line 530; used 1 times
ask defined in line 1925; used 3 times
copy_file defined in line 785; used 1 times
copy_till defined in line 805; used 5 times
do_ed_script defined in line 640; used 1 times
dump_line defined in line 822; used 1 times
fatal defined in line 1917; used 54 times
fetchname defined in line 1309; used 5 times
get_some_switches defined in line 370; used 2 times
ifetch defined in line 1083; used 4 times
ignore_signals defined in line 1973; used 2 times
init_output defined in line 687; used 1 times
init_reject defined in line 695; used 1 times
intuit_diff_type defined in line 1203; used 1 times
locate_hunk defined in line 449; used 3 times
main defined in line 214; never used
move_file defined in line 703; used 3 times
my_exit defined in line 1888; used 6 times
next_intuit_at defined in line 1341; used 6 times
open_patch_file defined in line 1139; used 1 times
patch_match defined in line 832; used 4 times
pch_char defined in line 1851; used 17 times
pch_context defined in line 1839; used 2 times
pch_end defined in line 1833; used 4 times
pch_first defined in line 1809; used 3 times
pch_hunk_beg defined in line 1865; used 5 times
pch_line_len defined in line 1845; used 3 times
pch_newfirst defined in line 1821; used 2 times
pch_ptrn_lines defined in line 1815; used 5 times
pch_repl_lines defined in line 1827; used 2 times
pch_swap defined in line 1741; used 4 times
pfetch defined in line 1858; used 11 times
pgets defined in line 1718; used 11 times
plan_a defined in line 931; used 2 times
plan_b defined in line 1025; used 1 times
re_input defined in line 896; used 1 times
re_patch defined in line 1128; used 1 times
reinitialize_almost_everything defined in line 333; used 1 times
rev_in_string defined in line 1944; used 3 times
savestr defined in line 1871; used 23 times
say defined in line 1909; used 30 times
scan_input defined in line 920; used 1 times
set_signals defined in line 1963; used 3 times
similar defined in line 858; used 2 times
skip_to defined in line 1347; used 1 times
spew_output defined in line 815; used 1 times
there_is_another_patch defined in line 1159; used 2 times

Defined variables

Argc defined in line 120; used 10 times
Argv defined in line 121; used 18 times
TMPINNAME defined in line 145; used 7 times
TMPOUTNAME defined in line 144; used 9 times
TMPPATNAME defined in line 147; used 5 times
TMPREJNAME defined in line 146; used 4 times
buf defined in line 126; used 121 times
canonicalize defined in line 158; used 2 times
debug defined in line 151; used 7 times
diff_type defined in line 164; used 19 times
do_defines defined in line 166; used 9 times
else_defined defined in line 169; used 4 times
end_defined defined in line 170; used 3 times
filearg defined in line 137; used 19 times
filec defined in line 136; used 4 times
filestat defined in line 123; used 22 times
i_ptr defined in line 888; used 8 times
i_size defined in line 886; used 8 times
i_womp defined in line 887; used 15 times
if_defined defined in line 167; used 3 times
input_lines defined in line 131; used 7 times
last_frozen_line defined in line 132; used 7 times
last_offset defined in line 149; used 11 times
lines_per_buf defined in line 893; used 6 times
noreverse defined in line 155; used 2 times
not_defined defined in line 168; used 3 times
origext defined in line 142; used 3 times
outname defined in line 139; used 9 times
p_base defined in line 1125; used 9 times
p_char defined in line 1122; used 27 times
p_context defined in line 1119; used 8 times
p_end defined in line 1117; used 65 times
p_filesize defined in line 1112; used 2 times
p_first defined in line 1113; used 13 times
p_indent defined in line 1124; used 10 times
p_input_line defined in line 1120; used 27 times
p_len defined in line 1123; used 15 times
p_line defined in line 1121; used 35 times
p_max defined in line 1118; used 19 times
p_newfirst defined in line 1114; used 11 times
p_ptrn_lines defined in line 1115; used 25 times
p_repl_lines defined in line 1116; used 7 times
p_start defined in line 1126; used 6 times
rejname defined in line 140; used 7 times
reverse defined in line 154; used 11 times
revision defined in line 172; used 19 times
sccsid defined in line 2; never used
serrbuf defined in line 125; used 1 times
skip_this_patch defined in line 156; used 3 times
tibuf defined in line 891; used 12 times
tifd defined in line 890; used 9 times
tiline defined in line 892; used 5 times
tireclen defined in line 894; used 3 times
usepath defined in line 157; used 2 times
using_plan_a defined in line 885; used 4 times
verbose defined in line 153; used 15 times

Defined typedef's

LINENUM defined in line 115; used 85 times
MEM defined in line 116; used 5 times
bool defined in line 114; used 30 times

Defined macros

BUFFERSIZE defined in line 92; used 9 times
CHECKOUT defined in line 97; used 1 times
CONTEXT_DIFF defined in line 160; used 5 times
Close defined in line 70; used 10 times
Ctl defined in line 105; never used
DEBUGGING defined in line 60; used 9 times
ED_DIFF defined in line 162; used 5 times
FALSE defined in line 88; used 28 times
Fclose defined in line 71; used 4 times
Fflush defined in line 72; used 2 times
Fseek defined in line 67; used 4 times
Fstat defined in line 68; used 1 times
GET defined in line 95; used 1 times
Lseek defined in line 66; used 1 times
MAXFILEC defined in line 135; used 3 times
MAXHUNKSIZE defined in line 90; used 9 times
MAXLINELEN defined in line 91; used 1 times
Mktemp defined in line 74; used 4 times
NEW_CONTEXT_DIFF defined in line 163; used 4 times
NORMAL_DIFF defined in line 161; used 4 times
Null defined in line 101; used 9 times
Nullch defined in line 102; used 44 times
Nullfp defined in line 103; used 10 times
ORIGEXT defined in line 93; used 1 times
Pclose defined in line 69; used 1 times
RCSSUFFIX defined in line 96; used 2 times
SCCSPREFIX defined in line 94; used 2 times
Signal defined in line 64; used 4 times
Sprintf defined in line 73; used 13 times
Strcat defined in line 76; used 3 times
Strcpy defined in line 75; used 7 times
TRUE defined in line 87; used 17 times
Unlink defined in line 65; used 6 times
strEQ defined in line 108; used 5 times
strNE defined in line 107; never used
strnEQ defined in line 110; used 11 times
strnNE defined in line 109; used 3 times
Last modified: 1986-05-18
Generated: 2016-12-26
Generated by src2html V0.67
page hit count: 5921
Valid CSS Valid XHTML 1.0 Strict