Annotation of 43BSD/contrib/mh/miscellany/patch/patch.c, revision 1.1.1.1

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

unix.superglobalmegacorp.com

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