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

unix.superglobalmegacorp.com

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