Annotation of researchv9/X11/src/X.V11R1/util/patch/patch.c, revision 1.1.1.1

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

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.