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

Defined functions

abort_hunk defined in line 482; used 1 times
another_hunk defined in line 1353; used 2 times
apply_hunk defined in line 516; used 1 times
ask defined in line 1874; used 3 times
copy_file defined in line 771; used 1 times
copy_till defined in line 791; used 5 times
do_ed_script defined in line 626; used 1 times
dump_line defined in line 808; used 1 times
fatal defined in line 1866; used 48 times
fetchname defined in line 1295; used 5 times
get_some_switches defined in line 362; used 2 times
ifetch defined in line 1069; used 4 times
ignore_signals defined in line 1922; used 2 times
init_output defined in line 673; used 1 times
init_reject defined in line 681; used 1 times
intuit_diff_type defined in line 1189; used 1 times
locate_hunk defined in line 438; used 3 times
main defined in line 212; never used
move_file defined in line 689; used 3 times
my_exit defined in line 1837; used 6 times
next_intuit_at defined in line 1327; used 6 times
open_patch_file defined in line 1125; used 1 times
patch_match defined in line 818; used 4 times
pch_char defined in line 1800; used 17 times
pch_context defined in line 1788; used 2 times
pch_end defined in line 1782; used 4 times
pch_first defined in line 1758; used 3 times
pch_hunk_beg defined in line 1814; used 5 times
pch_line_len defined in line 1794; used 3 times
pch_newfirst defined in line 1770; used 2 times
pch_ptrn_lines defined in line 1764; used 5 times
pch_repl_lines defined in line 1776; used 2 times
pch_swap defined in line 1690; used 3 times
pfetch defined in line 1807; used 11 times
pgets defined in line 1667; used 11 times
plan_a defined in line 917; used 2 times
plan_b defined in line 1011; used 1 times
re_input defined in line 882; used 1 times
re_patch defined in line 1114; used 1 times
reinitialize_almost_everything defined in line 326; used 1 times
rev_in_string defined in line 1893; used 3 times
savestr defined in line 1820; used 22 times
say defined in line 1858; used 29 times
scan_input defined in line 906; used 1 times
set_signals defined in line 1912; used 3 times
similar defined in line 844; used 2 times
skip_to defined in line 1333; used 1 times
spew_output defined in line 801; used 1 times
there_is_another_patch defined in line 1145; 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 115 times
canonicalize defined in line 156; used 2 times
debug defined in line 151; used 7 times
diff_type defined in line 162; used 18 times
do_defines defined in line 164; used 9 times
else_defined defined in line 167; used 4 times
end_defined defined in line 168; 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 874; used 8 times
i_size defined in line 872; used 8 times
i_womp defined in line 873; used 15 times
if_defined defined in line 165; 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 879; used 6 times
not_defined defined in line 166; used 3 times
origext defined in line 142; used 3 times
outname defined in line 139; used 9 times
p_base defined in line 1111; used 9 times
p_char defined in line 1108; used 25 times
p_context defined in line 1105; used 8 times
p_end defined in line 1103; used 63 times
p_filesize defined in line 1098; used 2 times
p_first defined in line 1099; used 13 times
p_indent defined in line 1110; used 10 times
p_input_line defined in line 1106; used 21 times
p_len defined in line 1109; used 15 times
p_line defined in line 1107; used 32 times
p_max defined in line 1104; used 10 times
p_newfirst defined in line 1100; used 9 times
p_ptrn_lines defined in line 1101; used 24 times
p_repl_lines defined in line 1102; used 7 times
p_start defined in line 1112; used 6 times
rejname defined in line 140; used 7 times
reverse defined in line 154; used 9 times
revision defined in line 170; used 19 times
sccsid defined in line 2; never used
serrbuf defined in line 125; used 1 times
tibuf defined in line 877; used 12 times
tifd defined in line 876; used 9 times
tiline defined in line 878; used 5 times
tireclen defined in line 880; used 3 times
usepath defined in line 155; used 2 times
using_plan_a defined in line 871; 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 28 times

Defined macros

BUFFERSIZE defined in line 92; used 9 times
CHECKOUT defined in line 97; used 1 times
CONTEXT_DIFF defined in line 158; 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 160; used 5 times
FALSE defined in line 88; used 25 times
Fclose defined in line 71; used 4 times
Fflush defined in line 72; used 2 times
Fseek defined in line 67; used 5 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 7 times
MAXLINELEN defined in line 91; used 1 times
Mktemp defined in line 74; used 4 times
NEW_CONTEXT_DIFF defined in line 161; used 3 times
NORMAL_DIFF defined in line 159; 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 15 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-04-21
Generated: 2016-12-26
Generated by src2html V0.67
page hit count: 7324
Valid CSS Valid XHTML 1.0 Strict