Annotation of 43BSDTahoe/new/patch/pch.c, revision 1.1.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.