Annotation of 43BSDReno/contrib/patch/pch.c, revision 1.1

1.1     ! root        1: /* $Header: pch.c,v 2.0.1.6 87/06/04 16:18:13 lwall Exp $
        !             2:  *
        !             3:  * $Log:       pch.c,v $
        !             4:  * Revision 2.0.1.6  87/06/04  16:18:13  lwall
        !             5:  * pch_swap didn't swap p_bfake and p_efake.
        !             6:  * 
        !             7:  * Revision 2.0.1.5  87/01/30  22:47:42  lwall
        !             8:  * Improved responses to mangled patches.
        !             9:  * 
        !            10:  * Revision 2.0.1.4  87/01/05  16:59:53  lwall
        !            11:  * New-style context diffs caused double call to free().
        !            12:  * 
        !            13:  * Revision 2.0.1.3  86/11/14  10:08:33  lwall
        !            14:  * Fixed problem where a long pattern wouldn't grow the hunk.
        !            15:  * Also restored p_input_line when backtracking so error messages are right.
        !            16:  * 
        !            17:  * Revision 2.0.1.2  86/11/03  17:49:52  lwall
        !            18:  * New-style delete triggers spurious assertion error.
        !            19:  * 
        !            20:  * Revision 2.0.1.1  86/10/29  15:52:08  lwall
        !            21:  * Could falsely report new-style context diff.
        !            22:  * 
        !            23:  * Revision 2.0  86/09/17  15:39:37  lwall
        !            24:  * Baseline for netwide release.
        !            25:  * 
        !            26:  */
        !            27: 
        !            28: #include "EXTERN.h"
        !            29: #include "common.h"
        !            30: #include "util.h"
        !            31: #include "INTERN.h"
        !            32: #include "pch.h"
        !            33: 
        !            34: /* Patch (diff listing) abstract type. */
        !            35: 
        !            36: static long p_filesize;                        /* size of the patch file */
        !            37: static LINENUM p_first;                        /* 1st line number */
        !            38: static LINENUM p_newfirst;             /* 1st line number of replacement */
        !            39: static LINENUM p_ptrn_lines;           /* # lines in pattern */
        !            40: static LINENUM p_repl_lines;           /* # lines in replacement text */
        !            41: static LINENUM p_end = -1;             /* last line in hunk */
        !            42: static LINENUM p_max;                  /* max allowed value of p_end */
        !            43: static LINENUM p_context = 3;          /* # of context lines */
        !            44: static LINENUM p_input_line = 0;       /* current line # from patch file */
        !            45: static char **p_line = Null(char**);   /* the text of the hunk */
        !            46: static short *p_len = Null(short*);    /* length of each line */
        !            47: static char *p_char = Nullch;          /* +, -, and ! */
        !            48: static int hunkmax = INITHUNKMAX;      /* size of above arrays to begin with */
        !            49: static int p_indent;                   /* indent to patch */
        !            50: static LINENUM p_base;                 /* where to intuit this time */
        !            51: static LINENUM p_bline;                        /* line # of p_base */
        !            52: static LINENUM p_start;                        /* where intuit found a patch */
        !            53: static LINENUM p_sline;                        /* and the line number for it */
        !            54: static LINENUM p_hunk_beg;             /* line number of current hunk */
        !            55: static LINENUM p_efake = -1;           /* end of faked up lines--don't free */
        !            56: static LINENUM p_bfake = -1;           /* beg of faked up lines */
        !            57: 
        !            58: /* Prepare to look for the next patch in the patch file. */
        !            59: 
        !            60: void
        !            61: re_patch()
        !            62: {
        !            63:     p_first = Nulline;
        !            64:     p_newfirst = Nulline;
        !            65:     p_ptrn_lines = Nulline;
        !            66:     p_repl_lines = Nulline;
        !            67:     p_end = (LINENUM)-1;
        !            68:     p_max = Nulline;
        !            69:     p_indent = 0;
        !            70: }
        !            71: 
        !            72: /* Open the patch file at the beginning of time. */
        !            73: 
        !            74: void
        !            75: open_patch_file(filename)
        !            76: char *filename;
        !            77: {
        !            78:     if (filename == Nullch || !*filename || strEQ(filename, "-")) {
        !            79:        pfp = fopen(TMPPATNAME, "w");
        !            80:        if (pfp == Nullfp)
        !            81:            fatal2("patch: can't create %s.\n", TMPPATNAME);
        !            82:        while (fgets(buf, sizeof buf, stdin) != Nullch)
        !            83:            fputs(buf, pfp);
        !            84:        Fclose(pfp);
        !            85:        filename = TMPPATNAME;
        !            86:     }
        !            87:     pfp = fopen(filename, "r");
        !            88:     if (pfp == Nullfp)
        !            89:        fatal2("patch file %s not found\n", filename);
        !            90:     Fstat(fileno(pfp), &filestat);
        !            91:     p_filesize = filestat.st_size;
        !            92:     next_intuit_at(0L,1L);                     /* start at the beginning */
        !            93:     set_hunkmax();
        !            94: }
        !            95: 
        !            96: /* Make sure our dynamically realloced tables are malloced to begin with. */
        !            97: 
        !            98: void
        !            99: set_hunkmax()
        !           100: {
        !           101: #ifndef lint
        !           102:     if (p_line == Null(char**))
        !           103:        p_line = (char**) malloc((MEM)hunkmax * sizeof(char *));
        !           104:     if (p_len == Null(short*))
        !           105:        p_len  = (short*) malloc((MEM)hunkmax * sizeof(short));
        !           106: #endif
        !           107:     if (p_char == Nullch)
        !           108:        p_char = (char*)  malloc((MEM)hunkmax * sizeof(char));
        !           109: }
        !           110: 
        !           111: /* Enlarge the arrays containing the current hunk of patch. */
        !           112: 
        !           113: void
        !           114: grow_hunkmax()
        !           115: {
        !           116:     hunkmax *= 2;
        !           117:     /* 
        !           118:      * Note that on most systems, only the p_line array ever gets fresh memory
        !           119:      * since p_len can move into p_line's old space, and p_char can move into
        !           120:      * p_len's old space.  Not on PDP-11's however.  But it doesn't matter.
        !           121:      */
        !           122:     assert(p_line != Null(char**) && p_len != Null(short*) && p_char != Nullch);
        !           123: #ifndef lint
        !           124:     p_line = (char**) realloc((char*)p_line, (MEM)hunkmax * sizeof(char *));
        !           125:     p_len  = (short*) realloc((char*)p_len,  (MEM)hunkmax * sizeof(short));
        !           126:     p_char = (char*)  realloc((char*)p_char, (MEM)hunkmax * sizeof(char));
        !           127: #endif
        !           128:     if (p_line != Null(char**) && p_len != Null(short*) && p_char != Nullch)
        !           129:        return;
        !           130:     if (!using_plan_a)
        !           131:        fatal1("patch: out of memory (grow_hunkmax)\n");
        !           132:     out_of_mem = TRUE;         /* whatever is null will be allocated again */
        !           133:                                /* from within plan_a(), of all places */
        !           134: }
        !           135: 
        !           136: /* True if the remainder of the patch file contains a diff of some sort. */
        !           137: 
        !           138: bool
        !           139: there_is_another_patch()
        !           140: {
        !           141:     if (p_base != 0L && p_base >= p_filesize) {
        !           142:        if (verbose)
        !           143:            say1("done\n");
        !           144:        return FALSE;
        !           145:     }
        !           146:     if (verbose)
        !           147:        say1("Hmm...");
        !           148:     diff_type = intuit_diff_type();
        !           149:     if (!diff_type) {
        !           150:        if (p_base != 0L) {
        !           151:            if (verbose)
        !           152:                say1("  Ignoring the trailing garbage.\ndone\n");
        !           153:        }
        !           154:        else
        !           155:            say1("  I can't seem to find a patch in there anywhere.\n");
        !           156:        return FALSE;
        !           157:     }
        !           158:     if (verbose)
        !           159:        say3("  %sooks like %s to me...\n",
        !           160:            (p_base == 0L ? "L" : "The next patch l"),
        !           161:            diff_type == CONTEXT_DIFF ? "a context diff" :
        !           162:            diff_type == NEW_CONTEXT_DIFF ? "a new-style context diff" :
        !           163:            diff_type == NORMAL_DIFF ? "a normal diff" :
        !           164:            "an ed script" );
        !           165:     if (p_indent && verbose)
        !           166:        say3("(Patch is indented %d space%s.)\n", p_indent, p_indent==1?"":"s");
        !           167:     skip_to(p_start,p_sline);
        !           168:     while (filearg[0] == Nullch) {
        !           169:        if (force) {
        !           170:            say1("No file to patch.  Skipping...\n");
        !           171:            filearg[0] = savestr(bestguess);
        !           172:            return TRUE;
        !           173:        }
        !           174:        ask1("File to patch: ");
        !           175:        if (*buf != '\n') {
        !           176:            if (bestguess)
        !           177:                free(bestguess);
        !           178:            bestguess = savestr(buf);
        !           179:            filearg[0] = fetchname(buf, 0, FALSE);
        !           180:        }
        !           181:        if (filearg[0] == Nullch) {
        !           182:            ask1("No file found--skip this patch? [n] ");
        !           183:            if (*buf != 'y') {
        !           184:                continue;
        !           185:            }
        !           186:            if (verbose)
        !           187:                say1("Skipping patch...\n");
        !           188:            filearg[0] = fetchname(bestguess, 0, TRUE);
        !           189:            skip_rest_of_patch = TRUE;
        !           190:            return TRUE;
        !           191:        }
        !           192:     }
        !           193:     return TRUE;
        !           194: }
        !           195: 
        !           196: /* Determine what kind of diff is in the remaining part of the patch file. */
        !           197: 
        !           198: int
        !           199: intuit_diff_type()
        !           200: {
        !           201:     Reg4 long this_line = 0;
        !           202:     Reg5 long previous_line;
        !           203:     Reg6 long first_command_line = -1;
        !           204:     long fcl_line;
        !           205:     Reg7 bool last_line_was_command = FALSE;
        !           206:     Reg8 bool this_is_a_command = FALSE;
        !           207:     Reg9 bool stars_last_line = FALSE;
        !           208:     Reg10 bool stars_this_line = FALSE;
        !           209:     Reg3 int indent;
        !           210:     Reg1 char *s;
        !           211:     Reg2 char *t;
        !           212:     char *indtmp = Nullch;
        !           213:     char *oldtmp = Nullch;
        !           214:     char *newtmp = Nullch;
        !           215:     char *indname = Nullch;
        !           216:     char *oldname = Nullch;
        !           217:     char *newname = Nullch;
        !           218:     Reg11 int retval;
        !           219:     bool no_filearg = (filearg[0] == Nullch);
        !           220: 
        !           221:     ok_to_create_file = FALSE;
        !           222:     Fseek(pfp, p_base, 0);
        !           223:     p_input_line = p_bline - 1;
        !           224:     for (;;) {
        !           225:        previous_line = this_line;
        !           226:        last_line_was_command = this_is_a_command;
        !           227:        stars_last_line = stars_this_line;
        !           228:        this_line = ftell(pfp);
        !           229:        indent = 0;
        !           230:        p_input_line++;
        !           231:        if (fgets(buf, sizeof buf, pfp) == Nullch) {
        !           232:            if (first_command_line >= 0L) {
        !           233:                                        /* nothing but deletes!? */
        !           234:                p_start = first_command_line;
        !           235:                p_sline = fcl_line;
        !           236:                retval = ED_DIFF;
        !           237:                goto scan_exit;
        !           238:            }
        !           239:            else {
        !           240:                p_start = this_line;
        !           241:                p_sline = p_input_line;
        !           242:                retval = 0;
        !           243:                goto scan_exit;
        !           244:            }
        !           245:        }
        !           246:        for (s = buf; *s == ' ' || *s == '\t'; s++) {
        !           247:            if (*s == '\t')
        !           248:                indent += 8 - (indent % 8);
        !           249:            else
        !           250:                indent++;
        !           251:        }
        !           252:        for (t=s; isdigit(*t) || *t == ','; t++) ; 
        !           253:        this_is_a_command = (isdigit(*s) &&
        !           254:          (*t == 'd' || *t == 'c' || *t == 'a') );
        !           255:        if (first_command_line < 0L && this_is_a_command) { 
        !           256:            first_command_line = this_line;
        !           257:            fcl_line = p_input_line;
        !           258:            p_indent = indent;          /* assume this for now */
        !           259:        }
        !           260:        if (!stars_last_line && strnEQ(s, "*** ", 4))
        !           261:            oldtmp = savestr(s+4);
        !           262:        else if (strnEQ(s, "--- ", 4))
        !           263:            newtmp = savestr(s+4);
        !           264:        else if (strnEQ(s, "Index:", 6))
        !           265:            indtmp = savestr(s+6);
        !           266:        else if (strnEQ(s, "Prereq:", 7)) {
        !           267:            for (t=s+7; isspace(*t); t++) ;
        !           268:            revision = savestr(t);
        !           269:            for (t=revision; *t && !isspace(*t); t++) ;
        !           270:            *t = '\0';
        !           271:            if (!*revision) {
        !           272:                free(revision);
        !           273:                revision = Nullch;
        !           274:            }
        !           275:        }
        !           276:        if ((!diff_type || diff_type == ED_DIFF) &&
        !           277:          first_command_line >= 0L &&
        !           278:          strEQ(s, ".\n") ) {
        !           279:            p_indent = indent;
        !           280:            p_start = first_command_line;
        !           281:            p_sline = fcl_line;
        !           282:            retval = ED_DIFF;
        !           283:            goto scan_exit;
        !           284:        }
        !           285:        stars_this_line = strnEQ(s, "********", 8);
        !           286:        if ((!diff_type || diff_type == CONTEXT_DIFF) && stars_last_line &&
        !           287:                 strnEQ(s, "*** ", 4)) {
        !           288:            if (!atol(s+4))
        !           289:                ok_to_create_file = TRUE;
        !           290:            /* if this is a new context diff the character just before */
        !           291:            /* the newline is a '*'. */
        !           292:            while (*s != '\n')
        !           293:                s++;
        !           294:            p_indent = indent;
        !           295:            p_start = previous_line;
        !           296:            p_sline = p_input_line - 1;
        !           297:            retval = (*(s-1) == '*' ? NEW_CONTEXT_DIFF : CONTEXT_DIFF);
        !           298:            goto scan_exit;
        !           299:        }
        !           300:        if ((!diff_type || diff_type == NORMAL_DIFF) && 
        !           301:          last_line_was_command &&
        !           302:          (strnEQ(s, "< ", 2) || strnEQ(s, "> ", 2)) ) {
        !           303:            p_start = previous_line;
        !           304:            p_sline = p_input_line - 1;
        !           305:            p_indent = indent;
        !           306:            retval = NORMAL_DIFF;
        !           307:            goto scan_exit;
        !           308:        }
        !           309:     }
        !           310:   scan_exit:
        !           311:     if (no_filearg) {
        !           312:        if (indtmp != Nullch)
        !           313:            indname = fetchname(indtmp, strippath, ok_to_create_file);
        !           314:        if (oldtmp != Nullch)
        !           315:            oldname = fetchname(oldtmp, strippath, ok_to_create_file);
        !           316:        if (newtmp != Nullch)
        !           317:            newname = fetchname(newtmp, strippath, ok_to_create_file);
        !           318:        if (oldname && newname) {
        !           319:            if (strlen(oldname) < strlen(newname))
        !           320:                filearg[0] = savestr(oldname);
        !           321:            else
        !           322:                filearg[0] = savestr(newname);
        !           323:        }
        !           324:        else if (oldname)
        !           325:            filearg[0] = savestr(oldname);
        !           326:        else if (newname)
        !           327:            filearg[0] = savestr(newname);
        !           328:        else if (indname)
        !           329:            filearg[0] = savestr(indname);
        !           330:     }
        !           331:     if (bestguess) {
        !           332:        free(bestguess);
        !           333:        bestguess = Nullch;
        !           334:     }
        !           335:     if (filearg[0] != Nullch)
        !           336:        bestguess = savestr(filearg[0]);
        !           337:     else if (indtmp != Nullch)
        !           338:        bestguess = fetchname(indtmp, strippath, TRUE);
        !           339:     else {
        !           340:        if (oldtmp != Nullch)
        !           341:            oldname = fetchname(oldtmp, strippath, TRUE);
        !           342:        if (newtmp != Nullch)
        !           343:            newname = fetchname(newtmp, strippath, TRUE);
        !           344:        if (oldname && newname) {
        !           345:            if (strlen(oldname) < strlen(newname))
        !           346:                bestguess = savestr(oldname);
        !           347:            else
        !           348:                bestguess = savestr(newname);
        !           349:        }
        !           350:        else if (oldname)
        !           351:            bestguess = savestr(oldname);
        !           352:        else if (newname)
        !           353:            bestguess = savestr(newname);
        !           354:     }
        !           355:     if (indtmp != Nullch)
        !           356:        free(indtmp);
        !           357:     if (oldtmp != Nullch)
        !           358:        free(oldtmp);
        !           359:     if (newtmp != Nullch)
        !           360:        free(newtmp);
        !           361:     if (indname != Nullch)
        !           362:        free(indname);
        !           363:     if (oldname != Nullch)
        !           364:        free(oldname);
        !           365:     if (newname != Nullch)
        !           366:        free(newname);
        !           367:     return retval;
        !           368: }
        !           369: 
        !           370: /* Remember where this patch ends so we know where to start up again. */
        !           371: 
        !           372: void
        !           373: next_intuit_at(file_pos,file_line)
        !           374: long file_pos;
        !           375: long file_line;
        !           376: {
        !           377:     p_base = file_pos;
        !           378:     p_bline = file_line;
        !           379: }
        !           380: 
        !           381: /* Basically a verbose fseek() to the actual diff listing. */
        !           382: 
        !           383: void
        !           384: skip_to(file_pos,file_line)
        !           385: long file_pos;
        !           386: long file_line;
        !           387: {
        !           388:     char *ret;
        !           389: 
        !           390:     assert(p_base <= file_pos);
        !           391:     if (verbose && p_base < file_pos) {
        !           392:        Fseek(pfp, p_base, 0);
        !           393:        say1("The text leading up to this was:\n--------------------------\n");
        !           394:        while (ftell(pfp) < file_pos) {
        !           395:            ret = fgets(buf, sizeof buf, pfp);
        !           396:            assert(ret != Nullch);
        !           397:            say2("|%s", buf);
        !           398:        }
        !           399:        say1("--------------------------\n");
        !           400:     }
        !           401:     else
        !           402:        Fseek(pfp, file_pos, 0);
        !           403:     p_input_line = file_line - 1;
        !           404: }
        !           405: 
        !           406: /* True if there is more of the current diff listing to process. */
        !           407: 
        !           408: bool
        !           409: another_hunk()
        !           410: {
        !           411:     Reg1 char *s;
        !           412:     Reg8 char *ret;
        !           413:     Reg2 int context = 0;
        !           414: 
        !           415:     while (p_end >= 0) {
        !           416:        if (p_end == p_efake)
        !           417:            p_end = p_bfake;            /* don't free twice */
        !           418:        else
        !           419:            free(p_line[p_end]);
        !           420:        p_end--;
        !           421:     }
        !           422:     assert(p_end == -1);
        !           423:     p_efake = -1;
        !           424: 
        !           425:     p_max = hunkmax;                   /* gets reduced when --- found */
        !           426:     if (diff_type == CONTEXT_DIFF || diff_type == NEW_CONTEXT_DIFF) {
        !           427:        long line_beginning = ftell(pfp);
        !           428:                                        /* file pos of the current line */
        !           429:        LINENUM repl_beginning = 0;     /* index of --- line */
        !           430:        Reg4 LINENUM fillcnt = 0;       /* #lines of missing ptrn or repl */
        !           431:        Reg5 LINENUM fillsrc;           /* index of first line to copy */
        !           432:        Reg6 LINENUM filldst;           /* index of first missing line */
        !           433:        bool ptrn_spaces_eaten = FALSE; /* ptrn was slightly misformed */
        !           434:        Reg9 bool repl_could_be_missing = TRUE;
        !           435:                                        /* no + or ! lines in this hunk */
        !           436:        bool repl_missing = FALSE;      /* we are now backtracking */
        !           437:        long repl_backtrack_position = 0;
        !           438:                                        /* file pos of first repl line */
        !           439:        LINENUM repl_patch_line;        /* input line number for same */
        !           440:        Reg7 LINENUM ptrn_copiable = 0;
        !           441:                                        /* # of copiable lines in ptrn */
        !           442: 
        !           443:        ret = pgets(buf, sizeof buf, pfp);
        !           444:        p_input_line++;
        !           445:        if (ret == Nullch || strnNE(buf, "********", 8)) {
        !           446:            next_intuit_at(line_beginning,p_input_line);
        !           447:            return FALSE;
        !           448:        }
        !           449:        p_context = 100;
        !           450:        p_hunk_beg = p_input_line + 1;
        !           451:        while (p_end < p_max) {
        !           452:            line_beginning = ftell(pfp);
        !           453:            ret = pgets(buf, sizeof buf, pfp);
        !           454:            p_input_line++;
        !           455:            if (ret == Nullch) {
        !           456:                if (p_max - p_end < 4)
        !           457:                    Strcpy(buf, "  \n");  /* assume blank lines got chopped */
        !           458:                else {
        !           459:                    if (repl_beginning && repl_could_be_missing) {
        !           460:                        repl_missing = TRUE;
        !           461:                        goto hunk_done;
        !           462:                    }
        !           463:                    fatal1("Unexpected end of file in patch.\n");
        !           464:                }
        !           465:            }
        !           466:            p_end++;
        !           467:            assert(p_end < hunkmax);
        !           468:            p_char[p_end] = *buf;
        !           469:            p_line[p_end] = Nullch;
        !           470:            switch (*buf) {
        !           471:            case '*':
        !           472:                if (strnEQ(buf, "********", 8)) {
        !           473:                    if (repl_beginning && repl_could_be_missing) {
        !           474:                        repl_missing = TRUE;
        !           475:                        goto hunk_done;
        !           476:                    }
        !           477:                    else
        !           478:                        fatal2("Unexpected end of hunk at line %ld.\n",
        !           479:                            p_input_line);
        !           480:                }
        !           481:                if (p_end != 0) {
        !           482:                    if (repl_beginning && repl_could_be_missing) {
        !           483:                        repl_missing = TRUE;
        !           484:                        goto hunk_done;
        !           485:                    }
        !           486:                    fatal3("Unexpected *** at line %ld: %s", p_input_line, buf);
        !           487:                }
        !           488:                context = 0;
        !           489:                p_line[p_end] = savestr(buf);
        !           490:                if (out_of_mem) {
        !           491:                    p_end--;
        !           492:                    return FALSE;
        !           493:                }
        !           494:                for (s=buf; *s && !isdigit(*s); s++) ;
        !           495:                if (!*s)
        !           496:                    goto malformed;
        !           497:                p_first = (LINENUM) atol(s);
        !           498:                while (isdigit(*s)) s++;
        !           499:                if (*s == ',') {
        !           500:                    for (; *s && !isdigit(*s); s++) ;
        !           501:                    if (!*s)
        !           502:                        goto malformed;
        !           503:                    p_ptrn_lines = ((LINENUM)atol(s)) - p_first + 1;
        !           504:                }
        !           505:                else if (p_first)
        !           506:                    p_ptrn_lines = 1;
        !           507:                else {
        !           508:                    p_ptrn_lines = 0;
        !           509:                    p_first = 1;
        !           510:                }
        !           511:                p_max = p_ptrn_lines + 6;       /* we need this much at least */
        !           512:                while (p_max >= hunkmax)
        !           513:                    grow_hunkmax();
        !           514:                p_max = hunkmax;
        !           515:                break;
        !           516:            case '-':
        !           517:                if (buf[1] == '-') {
        !           518:                    if (repl_beginning ||
        !           519:                        (p_end != p_ptrn_lines + 1 + (p_char[p_end-1] == '\n')))
        !           520:                    {
        !           521:                        if (p_end == 1) {
        !           522:                            /* `old' lines were omitted - set up to fill */
        !           523:                            /* them in from 'new' context lines. */
        !           524:                            p_end = p_ptrn_lines + 1;
        !           525:                            fillsrc = p_end + 1;
        !           526:                            filldst = 1;
        !           527:                            fillcnt = p_ptrn_lines;
        !           528:                        }
        !           529:                        else {
        !           530:                            if (repl_beginning) {
        !           531:                                if (repl_could_be_missing){
        !           532:                                    repl_missing = TRUE;
        !           533:                                    goto hunk_done;
        !           534:                                }
        !           535:                                fatal3(
        !           536: "Duplicate \"---\" at line %ld--check line numbers at line %ld.\n",
        !           537:                                    p_input_line, p_hunk_beg + repl_beginning);
        !           538:                            }
        !           539:                            else {
        !           540:                                fatal4(
        !           541: "%s \"---\" at line %ld--check line numbers at line %ld.\n",
        !           542:                                    (p_end <= p_ptrn_lines
        !           543:                                        ? "Premature"
        !           544:                                        : "Overdue" ),
        !           545:                                    p_input_line, p_hunk_beg);
        !           546:                            }
        !           547:                        }
        !           548:                    }
        !           549:                    repl_beginning = p_end;
        !           550:                    repl_backtrack_position = ftell(pfp);
        !           551:                    repl_patch_line = p_input_line;
        !           552:                    p_line[p_end] = savestr(buf);
        !           553:                    if (out_of_mem) {
        !           554:                        p_end--;
        !           555:                        return FALSE;
        !           556:                    }
        !           557:                    p_char[p_end] = '=';
        !           558:                    for (s=buf; *s && !isdigit(*s); s++) ;
        !           559:                    if (!*s)
        !           560:                        goto malformed;
        !           561:                    p_newfirst = (LINENUM) atol(s);
        !           562:                    while (isdigit(*s)) s++;
        !           563:                    if (*s == ',') {
        !           564:                        for (; *s && !isdigit(*s); s++) ;
        !           565:                        if (!*s)
        !           566:                            goto malformed;
        !           567:                        p_repl_lines = ((LINENUM)atol(s)) - p_newfirst + 1;
        !           568:                    }
        !           569:                    else if (p_newfirst)
        !           570:                        p_repl_lines = 1;
        !           571:                    else {
        !           572:                        p_repl_lines = 0;
        !           573:                        p_newfirst = 1;
        !           574:                    }
        !           575:                    p_max = p_repl_lines + p_end;
        !           576:                    if (p_max > MAXHUNKSIZE)
        !           577:                        fatal4("Hunk too large (%ld lines) at line %ld: %s",
        !           578:                              p_max, p_input_line, buf);
        !           579:                    while (p_max >= hunkmax)
        !           580:                        grow_hunkmax();
        !           581:                    if (p_repl_lines != ptrn_copiable)
        !           582:                        repl_could_be_missing = FALSE;
        !           583:                    break;
        !           584:                }
        !           585:                goto change_line;
        !           586:            case '+':  case '!':
        !           587:                repl_could_be_missing = FALSE;
        !           588:              change_line:
        !           589:                if (!isspace(buf[1]) && buf[1] != '>' && buf[1] != '<' &&
        !           590:                  repl_beginning && repl_could_be_missing) {
        !           591:                    repl_missing = TRUE;
        !           592:                    goto hunk_done;
        !           593:                }
        !           594:                if (context > 0) {
        !           595:                    if (context < p_context)
        !           596:                        p_context = context;
        !           597:                    context = -1000;
        !           598:                }
        !           599:                p_line[p_end] = savestr(buf+2);
        !           600:                if (out_of_mem) {
        !           601:                    p_end--;
        !           602:                    return FALSE;
        !           603:                }
        !           604:                break;
        !           605:            case '\t': case '\n':       /* assume the 2 spaces got eaten */
        !           606:                if (repl_beginning && repl_could_be_missing &&
        !           607:                  (!ptrn_spaces_eaten || diff_type == NEW_CONTEXT_DIFF) ) {
        !           608:                    repl_missing = TRUE;
        !           609:                    goto hunk_done;
        !           610:                }
        !           611:                p_line[p_end] = savestr(buf);
        !           612:                if (out_of_mem) {
        !           613:                    p_end--;
        !           614:                    return FALSE;
        !           615:                }
        !           616:                if (p_end != p_ptrn_lines + 1) {
        !           617:                    ptrn_spaces_eaten |= (repl_beginning != 0);
        !           618:                    context++;
        !           619:                    if (!repl_beginning)
        !           620:                        ptrn_copiable++;
        !           621:                    p_char[p_end] = ' ';
        !           622:                }
        !           623:                break;
        !           624:            case ' ':
        !           625:                if (!isspace(buf[1]) &&
        !           626:                  repl_beginning && repl_could_be_missing) {
        !           627:                    repl_missing = TRUE;
        !           628:                    goto hunk_done;
        !           629:                }
        !           630:                context++;
        !           631:                if (!repl_beginning)
        !           632:                    ptrn_copiable++;
        !           633:                p_line[p_end] = savestr(buf+2);
        !           634:                if (out_of_mem) {
        !           635:                    p_end--;
        !           636:                    return FALSE;
        !           637:                }
        !           638:                break;
        !           639:            default:
        !           640:                if (repl_beginning && repl_could_be_missing) {
        !           641:                    repl_missing = TRUE;
        !           642:                    goto hunk_done;
        !           643:                }
        !           644:                goto malformed;
        !           645:            }
        !           646:            /* set up p_len for strncmp() so we don't have to */
        !           647:            /* assume null termination */
        !           648:            if (p_line[p_end])
        !           649:                p_len[p_end] = strlen(p_line[p_end]);
        !           650:            else
        !           651:                p_len[p_end] = 0;
        !           652:        }
        !           653:        
        !           654:     hunk_done:
        !           655:        if (p_end >=0 && !repl_beginning)
        !           656:            fatal2("No --- found in patch at line %ld\n", pch_hunk_beg());
        !           657: 
        !           658:        if (repl_missing) {
        !           659:            
        !           660:            /* reset state back to just after --- */
        !           661:            p_input_line = repl_patch_line;
        !           662:            for (p_end--; p_end > repl_beginning; p_end--)
        !           663:                free(p_line[p_end]);
        !           664:            Fseek(pfp, repl_backtrack_position, 0);
        !           665:            
        !           666:            /* redundant 'new' context lines were omitted - set */
        !           667:            /* up to fill them in from the old file context */
        !           668:            fillsrc = 1;
        !           669:            filldst = repl_beginning+1;
        !           670:            fillcnt = p_repl_lines;
        !           671:            p_end = p_max;
        !           672:        }
        !           673: 
        !           674:        if (diff_type == CONTEXT_DIFF &&
        !           675:          (fillcnt || (p_first > 1 && ptrn_copiable > 2*p_context)) ) {
        !           676:            if (verbose)
        !           677:                say1("\
        !           678: (Fascinating--this is really a new-style context diff but without the telltale\n\
        !           679: extra asterisks on the *** line that usually indicate the new style...)\n");
        !           680:            diff_type = NEW_CONTEXT_DIFF;
        !           681:        }
        !           682:        
        !           683:        /* if there were omitted context lines, fill them in now */
        !           684:        if (fillcnt) {
        !           685:            p_bfake = filldst;          /* remember where not to free() */
        !           686:            p_efake = filldst + fillcnt - 1;
        !           687:            while (fillcnt-- > 0) {
        !           688:                while (fillsrc <= p_end && p_char[fillsrc] != ' ')
        !           689:                    fillsrc++;
        !           690:                if (fillsrc > p_end)
        !           691:                    fatal2("Replacement text or line numbers mangled in hunk at line %ld\n",
        !           692:                        p_hunk_beg);
        !           693:                p_line[filldst] = p_line[fillsrc];
        !           694:                p_char[filldst] = p_char[fillsrc];
        !           695:                p_len[filldst] = p_len[fillsrc];
        !           696:                fillsrc++; filldst++;
        !           697:            }
        !           698:            while (fillsrc <= p_end && fillsrc != repl_beginning &&
        !           699:              p_char[fillsrc] != ' ')
        !           700:                fillsrc++;
        !           701: #ifdef DEBUGGING
        !           702:            if (debug & 64)
        !           703:                printf("fillsrc %ld, filldst %ld, rb %ld, e+1 %ld\n",
        !           704:                    fillsrc,filldst,repl_beginning,p_end+1);
        !           705: #endif
        !           706:            assert(fillsrc==p_end+1 || fillsrc==repl_beginning);
        !           707:            assert(filldst==p_end+1 || filldst==repl_beginning);
        !           708:        }
        !           709:     }
        !           710:     else {                             /* normal diff--fake it up */
        !           711:        char hunk_type;
        !           712:        Reg3 int i;
        !           713:        LINENUM min, max;
        !           714:        long line_beginning = ftell(pfp);
        !           715: 
        !           716:        p_context = 0;
        !           717:        ret = pgets(buf, sizeof buf, pfp);
        !           718:        p_input_line++;
        !           719:        if (ret == Nullch || !isdigit(*buf)) {
        !           720:            next_intuit_at(line_beginning,p_input_line);
        !           721:            return FALSE;
        !           722:        }
        !           723:        p_first = (LINENUM)atol(buf);
        !           724:        for (s=buf; isdigit(*s); s++) ;
        !           725:        if (*s == ',') {
        !           726:            p_ptrn_lines = (LINENUM)atol(++s) - p_first + 1;
        !           727:            while (isdigit(*s)) s++;
        !           728:        }
        !           729:        else
        !           730:            p_ptrn_lines = (*s != 'a');
        !           731:        hunk_type = *s;
        !           732:        if (hunk_type == 'a')
        !           733:            p_first++;                  /* do append rather than insert */
        !           734:        min = (LINENUM)atol(++s);
        !           735:        for (; isdigit(*s); s++) ;
        !           736:        if (*s == ',')
        !           737:            max = (LINENUM)atol(++s);
        !           738:        else
        !           739:            max = min;
        !           740:        if (hunk_type == 'd')
        !           741:            min++;
        !           742:        p_end = p_ptrn_lines + 1 + max - min + 1;
        !           743:        if (p_end > MAXHUNKSIZE)
        !           744:            fatal4("Hunk too large (%ld lines) at line %ld: %s",
        !           745:                  p_end, p_input_line, buf);
        !           746:        while (p_end >= hunkmax)
        !           747:            grow_hunkmax();
        !           748:        p_newfirst = min;
        !           749:        p_repl_lines = max - min + 1;
        !           750:        Sprintf(buf, "*** %ld,%ld\n", p_first, p_first + p_ptrn_lines - 1);
        !           751:        p_line[0] = savestr(buf);
        !           752:        if (out_of_mem) {
        !           753:            p_end = -1;
        !           754:            return FALSE;
        !           755:        }
        !           756:        p_char[0] = '*';
        !           757:        for (i=1; i<=p_ptrn_lines; i++) {
        !           758:            ret = pgets(buf, sizeof buf, pfp);
        !           759:            p_input_line++;
        !           760:            if (ret == Nullch)
        !           761:                fatal2("Unexpected end of file in patch at line %ld.\n",
        !           762:                  p_input_line);
        !           763:            if (*buf != '<')
        !           764:                fatal2("< expected at line %ld of patch.\n", p_input_line);
        !           765:            p_line[i] = savestr(buf+2);
        !           766:            if (out_of_mem) {
        !           767:                p_end = i-1;
        !           768:                return FALSE;
        !           769:            }
        !           770:            p_len[i] = strlen(p_line[i]);
        !           771:            p_char[i] = '-';
        !           772:        }
        !           773:        if (hunk_type == 'c') {
        !           774:            ret = pgets(buf, sizeof buf, pfp);
        !           775:            p_input_line++;
        !           776:            if (ret == Nullch)
        !           777:                fatal2("Unexpected end of file in patch at line %ld.\n",
        !           778:                    p_input_line);
        !           779:            if (*buf != '-')
        !           780:                fatal2("--- expected at line %ld of patch.\n", p_input_line);
        !           781:        }
        !           782:        Sprintf(buf, "--- %ld,%ld\n", min, max);
        !           783:        p_line[i] = savestr(buf);
        !           784:        if (out_of_mem) {
        !           785:            p_end = i-1;
        !           786:            return FALSE;
        !           787:        }
        !           788:        p_char[i] = '=';
        !           789:        for (i++; i<=p_end; i++) {
        !           790:            ret = pgets(buf, sizeof buf, pfp);
        !           791:            p_input_line++;
        !           792:            if (ret == Nullch)
        !           793:                fatal2("Unexpected end of file in patch at line %ld.\n",
        !           794:                    p_input_line);
        !           795:            if (*buf != '>')
        !           796:                fatal2("> expected at line %ld of patch.\n", p_input_line);
        !           797:            p_line[i] = savestr(buf+2);
        !           798:            if (out_of_mem) {
        !           799:                p_end = i-1;
        !           800:                return FALSE;
        !           801:            }
        !           802:            p_len[i] = strlen(p_line[i]);
        !           803:            p_char[i] = '+';
        !           804:        }
        !           805:     }
        !           806:     if (reverse)                       /* backwards patch? */
        !           807:        if (!pch_swap())
        !           808:            say1("Not enough memory to swap next hunk!\n");
        !           809: #ifdef DEBUGGING
        !           810:     if (debug & 2) {
        !           811:        int i;
        !           812:        char special;
        !           813: 
        !           814:        for (i=0; i <= p_end; i++) {
        !           815:            if (i == p_ptrn_lines)
        !           816:                special = '^';
        !           817:            else
        !           818:                special = ' ';
        !           819:            fprintf(stderr, "%3d %c %c %s", i, p_char[i], special, p_line[i]);
        !           820:            Fflush(stderr);
        !           821:        }
        !           822:     }
        !           823: #endif
        !           824:     if (p_end+1 < hunkmax)     /* paranoia reigns supreme... */
        !           825:        p_char[p_end+1] = '^';  /* add a stopper for apply_hunk */
        !           826:     return TRUE;
        !           827: 
        !           828: malformed:
        !           829:     fatal3("Malformed patch at line %ld: %s", p_input_line, buf);
        !           830:                /* about as informative as "Syntax error" in C */
        !           831:     return FALSE;      /* for lint */
        !           832: }
        !           833: 
        !           834: /* Input a line from the patch file, worrying about indentation. */
        !           835: 
        !           836: char *
        !           837: pgets(bf,sz,fp)
        !           838: char *bf;
        !           839: int sz;
        !           840: FILE *fp;
        !           841: {
        !           842:     char *ret = fgets(bf, sz, fp);
        !           843:     Reg1 char *s;
        !           844:     Reg2 int indent = 0;
        !           845: 
        !           846:     if (p_indent && ret != Nullch) {
        !           847:        for (s=buf; indent < p_indent && (*s == ' ' || *s == '\t'); s++) {
        !           848:            if (*s == '\t')
        !           849:                indent += 8 - (indent % 7);
        !           850:            else
        !           851:                indent++;
        !           852:        }
        !           853:        if (buf != s)
        !           854:            Strcpy(buf, s);
        !           855:     }
        !           856:     return ret;
        !           857: }
        !           858: 
        !           859: /* Reverse the old and new portions of the current hunk. */
        !           860: 
        !           861: bool
        !           862: pch_swap()
        !           863: {
        !           864:     char **tp_line;            /* the text of the hunk */
        !           865:     short *tp_len;             /* length of each line */
        !           866:     char *tp_char;             /* +, -, and ! */
        !           867:     Reg1 LINENUM i;
        !           868:     Reg2 LINENUM n;
        !           869:     bool blankline = FALSE;
        !           870:     Reg3 char *s;
        !           871: 
        !           872:     i = p_first;
        !           873:     p_first = p_newfirst;
        !           874:     p_newfirst = i;
        !           875:     
        !           876:     /* make a scratch copy */
        !           877: 
        !           878:     tp_line = p_line;
        !           879:     tp_len = p_len;
        !           880:     tp_char = p_char;
        !           881:     p_line = Null(char**);     /* force set_hunkmax to allocate again */
        !           882:     p_len = Null(short*);
        !           883:     p_char = Nullch;
        !           884:     set_hunkmax();
        !           885:     if (p_line == Null(char**) || p_len == Null(short*) || p_char == Nullch) {
        !           886: #ifndef lint
        !           887:        if (p_line == Null(char**))
        !           888:            free((char*)p_line);
        !           889:        p_line = tp_line;
        !           890:        if (p_len == Null(short*))
        !           891:            free((char*)p_len);
        !           892:        p_len = tp_len;
        !           893: #endif
        !           894:        if (p_char == Nullch)
        !           895:            free((char*)p_char);
        !           896:        p_char = tp_char;
        !           897:        return FALSE;           /* not enough memory to swap hunk! */
        !           898:     }
        !           899: 
        !           900:     /* now turn the new into the old */
        !           901: 
        !           902:     i = p_ptrn_lines + 1;
        !           903:     if (tp_char[i] == '\n') {          /* account for possible blank line */
        !           904:        blankline = TRUE;
        !           905:        i++;
        !           906:     }
        !           907:     if (p_efake >= 0) {                        /* fix non-freeable ptr range */
        !           908:        n = p_end - i + 1;
        !           909:        if (p_efake > i)
        !           910:            n = -n;
        !           911:        p_efake += n;
        !           912:        p_bfake += n;
        !           913:     }
        !           914:     for (n=0; i <= p_end; i++,n++) {
        !           915:        p_line[n] = tp_line[i];
        !           916:        p_char[n] = tp_char[i];
        !           917:        if (p_char[n] == '+')
        !           918:            p_char[n] = '-';
        !           919:        p_len[n] = tp_len[i];
        !           920:     }
        !           921:     if (blankline) {
        !           922:        i = p_ptrn_lines + 1;
        !           923:        p_line[n] = tp_line[i];
        !           924:        p_char[n] = tp_char[i];
        !           925:        p_len[n] = tp_len[i];
        !           926:        n++;
        !           927:     }
        !           928:     assert(p_char[0] == '=');
        !           929:     p_char[0] = '*';
        !           930:     for (s=p_line[0]; *s; s++)
        !           931:        if (*s == '-')
        !           932:            *s = '*';
        !           933: 
        !           934:     /* now turn the old into the new */
        !           935: 
        !           936:     assert(tp_char[0] == '*');
        !           937:     tp_char[0] = '=';
        !           938:     for (s=tp_line[0]; *s; s++)
        !           939:        if (*s == '*')
        !           940:            *s = '-';
        !           941:     for (i=0; n <= p_end; i++,n++) {
        !           942:        p_line[n] = tp_line[i];
        !           943:        p_char[n] = tp_char[i];
        !           944:        if (p_char[n] == '-')
        !           945:            p_char[n] = '+';
        !           946:        p_len[n] = tp_len[i];
        !           947:     }
        !           948:     assert(i == p_ptrn_lines + 1);
        !           949:     i = p_ptrn_lines;
        !           950:     p_ptrn_lines = p_repl_lines;
        !           951:     p_repl_lines = i;
        !           952: #ifndef lint
        !           953:     if (tp_line == Null(char**))
        !           954:        free((char*)tp_line);
        !           955:     if (tp_len == Null(short*))
        !           956:        free((char*)tp_len);
        !           957: #endif
        !           958:     if (tp_char == Nullch)
        !           959:        free((char*)tp_char);
        !           960:     return TRUE;
        !           961: }
        !           962: 
        !           963: /* Return the specified line position in the old file of the old context. */
        !           964: 
        !           965: LINENUM
        !           966: pch_first()
        !           967: {
        !           968:     return p_first;
        !           969: }
        !           970: 
        !           971: /* Return the number of lines of old context. */
        !           972: 
        !           973: LINENUM
        !           974: pch_ptrn_lines()
        !           975: {
        !           976:     return p_ptrn_lines;
        !           977: }
        !           978: 
        !           979: /* Return the probable line position in the new file of the first line. */
        !           980: 
        !           981: LINENUM
        !           982: pch_newfirst()
        !           983: {
        !           984:     return p_newfirst;
        !           985: }
        !           986: 
        !           987: /* Return the number of lines in the replacement text including context. */
        !           988: 
        !           989: LINENUM
        !           990: pch_repl_lines()
        !           991: {
        !           992:     return p_repl_lines;
        !           993: }
        !           994: 
        !           995: /* Return the number of lines in the whole hunk. */
        !           996: 
        !           997: LINENUM
        !           998: pch_end()
        !           999: {
        !          1000:     return p_end;
        !          1001: }
        !          1002: 
        !          1003: /* Return the number of context lines before the first changed line. */
        !          1004: 
        !          1005: LINENUM
        !          1006: pch_context()
        !          1007: {
        !          1008:     return p_context;
        !          1009: }
        !          1010: 
        !          1011: /* Return the length of a particular patch line. */
        !          1012: 
        !          1013: short
        !          1014: pch_line_len(line)
        !          1015: LINENUM line;
        !          1016: {
        !          1017:     return p_len[line];
        !          1018: }
        !          1019: 
        !          1020: /* Return the control character (+, -, *, !, etc) for a patch line. */
        !          1021: 
        !          1022: char
        !          1023: pch_char(line)
        !          1024: LINENUM line;
        !          1025: {
        !          1026:     return p_char[line];
        !          1027: }
        !          1028: 
        !          1029: /* Return a pointer to a particular patch line. */
        !          1030: 
        !          1031: char *
        !          1032: pfetch(line)
        !          1033: LINENUM line;
        !          1034: {
        !          1035:     return p_line[line];
        !          1036: }
        !          1037: 
        !          1038: /* Return where in the patch file this hunk began, for error messages. */
        !          1039: 
        !          1040: LINENUM
        !          1041: pch_hunk_beg()
        !          1042: {
        !          1043:     return p_hunk_beg;
        !          1044: }
        !          1045: 
        !          1046: /* Apply an ed script by feeding ed itself. */
        !          1047: 
        !          1048: void
        !          1049: do_ed_script()
        !          1050: {
        !          1051:     Reg1 char *t;
        !          1052:     Reg2 long beginning_of_this_line;
        !          1053:     Reg3 bool this_line_is_command = FALSE;
        !          1054:     Reg4 FILE *pipefp;
        !          1055:     FILE *popen();
        !          1056: 
        !          1057:     if (!skip_rest_of_patch) {
        !          1058:        Unlink(TMPOUTNAME);
        !          1059:        copy_file(filearg[0], TMPOUTNAME);
        !          1060:        if (verbose)
        !          1061:            Sprintf(buf, "/bin/ed %s", TMPOUTNAME);
        !          1062:        else
        !          1063:            Sprintf(buf, "/bin/ed - %s", TMPOUTNAME);
        !          1064:        pipefp = popen(buf, "w");
        !          1065:     }
        !          1066:     for (;;) {
        !          1067:        beginning_of_this_line = ftell(pfp);
        !          1068:        if (pgets(buf, sizeof buf, pfp) == Nullch) {
        !          1069:            next_intuit_at(beginning_of_this_line,p_input_line);
        !          1070:            break;
        !          1071:        }
        !          1072:        p_input_line++;
        !          1073:        for (t=buf; isdigit(*t) || *t == ','; t++) ;
        !          1074:        this_line_is_command = (isdigit(*buf) &&
        !          1075:          (*t == 'd' || *t == 'c' || *t == 'a') );
        !          1076:        if (this_line_is_command) {
        !          1077:            if (!skip_rest_of_patch)
        !          1078:                fputs(buf, pipefp);
        !          1079:            if (*t != 'd') {
        !          1080:                while (pgets(buf, sizeof buf, pfp) != Nullch) {
        !          1081:                    p_input_line++;
        !          1082:                    if (!skip_rest_of_patch)
        !          1083:                        fputs(buf, pipefp);
        !          1084:                    if (strEQ(buf, ".\n"))
        !          1085:                        break;
        !          1086:                }
        !          1087:            }
        !          1088:        }
        !          1089:        else {
        !          1090:            next_intuit_at(beginning_of_this_line,p_input_line);
        !          1091:            break;
        !          1092:        }
        !          1093:     }
        !          1094:     if (skip_rest_of_patch)
        !          1095:        return;
        !          1096:     fprintf(pipefp, "w\n");
        !          1097:     fprintf(pipefp, "q\n");
        !          1098:     Fflush(pipefp);
        !          1099:     Pclose(pipefp);
        !          1100:     ignore_signals();
        !          1101:     if (move_file(TMPOUTNAME, outname) < 0) {
        !          1102:        toutkeep = TRUE;
        !          1103:        chmod(TMPOUTNAME, filemode);
        !          1104:     }
        !          1105:     else
        !          1106:        chmod(outname, filemode);
        !          1107:     set_signals();
        !          1108: }

unix.superglobalmegacorp.com

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