Annotation of researchv10no/cmd/patch.c, revision 1.1

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

unix.superglobalmegacorp.com

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