Annotation of coherent/d/bin/diff/diff3.c, revision 1.1.1.1

1.1       root        1: /*
                      2:  * Internal part of diff3.
                      3:  * This file resides in /usr/lib/diff3.
                      4:  * It is called as:
                      5:  * /usr/lib/diff3 [options] generator
                      6:  * Generator is the generator for the tempfile
                      7:  * names (as in /tmp/d30239).  `a' and `b' are used.
                      8:  */
                      9: 
                     10: #include <stdio.h>
                     11: #include <ctype.h>
                     12: 
                     13: #define NINF   3               /* Number of input files */
                     14: 
                     15: typedef        long    SEEK;           /* May be made long */
                     16: 
                     17: /*
                     18:  * A set of changes between two files.
                     19:  * This is just pairs of ranges from each file.
                     20:  */
                     21: typedef        struct  CHANGES {
                     22:        SEEK    c_seek;         /* Seek position after header line */
                     23:        unsigned c_oldbeg;      /* Old (first) file - beginning line number */
                     24:        unsigned c_oldend;      /* end line number */
                     25:        unsigned c_newbeg;      /* New (second) file - beginning */
                     26:        unsigned c_newend;      /* end line number */
                     27: }      CHANGES;
                     28: 
                     29: int    eflag;          /* Type of ed script */
                     30: int    ndiffs;         /* Number of differences found */
                     31: unsigned lastchange[NINF];
                     32: char   line[1000];     /* Input line buffer */
                     33: 
                     34: FILE   *fp13;          /* Changes of file 1 versus file 3 */
                     35: FILE   *fp23;          /* Changes of file 2 versus file 3 */
                     36: 
                     37: FILE   *diffopen();
                     38: CHANGES        *getdiff();
                     39: 
                     40: main(argc, argv)
                     41: int argc;
                     42: char *argv[];
                     43: {
                     44:        register char *ap;
                     45: 
                     46:        if (argc>1 && *argv[1]=='-') {
                     47:                for (ap = &argv[1][1]; *ap!='\0'; ap++)
                     48:                        switch (*ap) {
                     49:                        case 'e':
                     50:                                eflag = 03;
                     51:                                break;
                     52: 
                     53:                        case 'x':
                     54:                                eflag = 01;
                     55:                                break;
                     56: 
                     57:                        case '3':
                     58:                                eflag = 02;
                     59:                                break;
                     60: 
                     61:                        default:
                     62:                                cerr("bad option `%s'", argv[1]);
                     63:                        }
                     64:                argv++;
                     65:                argc--;
                     66:        }
                     67:        if (argc != 2)
                     68:                ierr("main");
                     69:        fp13 = diffopen(argv[1], 'a');
                     70:        fp23 = diffopen(argv[1], 'b');
                     71:        collate();
                     72:        exit(ndiffs!=0);
                     73: }
                     74: 
                     75: /*
                     76:  * Open one of the difference files
                     77:  * (i.e. the output of `diff').
                     78:  * Arguments are the generator name and
                     79:  * an identifying letter.
                     80:  */
                     81: FILE *
                     82: diffopen(gener, let)
                     83: char *gener;
                     84: int let;
                     85: {
                     86:        FILE *fp;
                     87: 
                     88:        sprintf(line, "%s%c", gener, let);
                     89:        if ((fp = fopen(line, "r")) == NULL)
                     90:                cerr("cannot open intermediate file `%s'", line);
                     91:        return (fp);
                     92: }
                     93: 
                     94: /*
                     95:  * Read in one entry from the specified
                     96:  * file of differences.  The `fp'
                     97:  * argument is the stream containing one
                     98:  * of the output files of `diff'.
                     99:  */
                    100: CHANGES *
                    101: getdiff(fp)
                    102: FILE *fp;
                    103: {
                    104:        register CHANGES *cp;
                    105:        char *linep;
                    106:        register int type;
                    107: 
                    108:        while (fgets(line, sizeof line, fp) != NULL) {
                    109:                if (!isdigit(line[0]))
                    110:                        continue;
                    111:                if ((cp = (CHANGES *)malloc(sizeof (CHANGES))) == NULL)
                    112:                        cerr("out of memory for changes");
                    113:                linep = line;
                    114:                cp->c_oldbeg = cp->c_oldend = readnum(&linep);
                    115:                if (*linep == ',') {
                    116:                        linep++;
                    117:                        cp->c_oldend = readnum(&linep);
                    118:                }
                    119:                type = *linep++;
                    120:                cp->c_newbeg = cp->c_newend = readnum(&linep);
                    121:                if (*linep == ',') {
                    122:                        linep++;
                    123:                        cp->c_newend = readnum(&linep);
                    124:                }
                    125:                if (type == 'a')
                    126:                        cp->c_oldbeg++;
                    127:                else if (type == 'd')
                    128:                        cp->c_newbeg++;
                    129:                cp->c_oldend++;
                    130:                cp->c_newend++;
                    131:                cp->c_seek = ftell(fp);
                    132:                ndiffs++;
                    133:                return (cp);
                    134:        }
                    135:        return (NULL);
                    136: }
                    137: 
                    138: /*
                    139:  * Read a line number from the line.
                    140:  * The pointer is given by reference
                    141:  * so that it can be updated.
                    142:  * Leading and trailing space is skipped.
                    143:  */
                    144: readnum(npp)
                    145: register char **npp;
                    146: {
                    147:        register char *np;
                    148:        register int n = 0;
                    149: 
                    150:        np = *npp;
                    151:        while (isspace(*np))
                    152:                np++;
                    153:        while (isdigit(*np))
                    154:                n = n*10 + *np++ - '0';
                    155:        while (isspace(*np))
                    156:                np++;
                    157:        *npp = np;
                    158:        return (n);
                    159: }
                    160: 
                    161: /*
                    162:  * Read through the two difference
                    163:  * files, collating changes that we
                    164:  * encounter to produce one consistent
                    165:  * view of changes on all three files.
                    166:  */
                    167: collate()
                    168: {
                    169:        register CHANGES *p13, *p23;
                    170:        register CHANGES *n13, *n23;
                    171: 
                    172:        if ((p13 = getdiff(fp13)) != NULL)
                    173:                n13 = getdiff(fp13); else
                    174:                n13 = NULL;
                    175:        if ((p23 = getdiff(fp23)) != NULL)
                    176:                n23 = getdiff(fp23); else
                    177:                n23 = NULL;
                    178:        while (p13!=NULL || p23!=NULL) {
                    179:                /*
                    180:                 * Differences found in the
                    181:                 * first file.
                    182:                 */
                    183:                if (p23==NULL || (p13!=NULL && p13->c_newend<p23->c_newbeg)) {
                    184:                        prsep(1);
                    185:                        prchanges(1, p13, fp13);
                    186:                        prdummy(2, p13);
                    187:                        prchanges(3, p13, fp13);
                    188:                        cfree(p13);
                    189:                        if ((p13 = n13) != NULL)
                    190:                                n13 = getdiff(fp13);
                    191:                        continue;
                    192:                }
                    193:                /*
                    194:                 * Differences found in the
                    195:                 * second file.
                    196:                 */
                    197:                if (p13==NULL || (p23!=NULL && p23->c_newend<p13->c_newbeg)) {
                    198:                        prsep(2);
                    199:                        prdummy(1, p23);
                    200:                        prchanges(2, p23, fp23);
                    201:                        prchanges(3, p23, fp23);
                    202:                        cfree(p23);
                    203:                        if ((p23 = n23) != NULL)
                    204:                                p23 = getdiff(fp23);
                    205:                        continue;
                    206:                }
                    207:                /*
                    208:                 * Merge changes that overlap
                    209:                 * with next change in first file.
                    210:                 * This happens as a result of
                    211:                 * the extension of a change as below.
                    212:                 */
                    213:                if (n13!=NULL && p13->c_newend >= n13->c_newbeg) {
                    214:                        n13->c_oldbeg = p13->c_oldbeg;
                    215:                        n13->c_newbeg = p13->c_newbeg;
                    216:                        cfree(p13);
                    217:                        p13 = n13;
                    218:                        n13 = getdiff(fp13);
                    219:                        continue;
                    220:                }
                    221:                /*
                    222:                 * Do the same merge as above
                    223:                 * only for the second file of changed.
                    224:                 */
                    225:                if (n23!=NULL && p23->c_newend >= n23->c_newbeg) {
                    226:                        n23->c_oldbeg = p23->c_oldbeg;
                    227:                        n23->c_newbeg = p23->c_newbeg;
                    228:                        cfree(p23);
                    229:                        p23 = n23;
                    230:                        n23 = getdiff(fp23);
                    231:                        continue;
                    232:                }
                    233:                /*
                    234:                 * Find lines only in third file or
                    235:                 * different in all.  The difference
                    236:                 * between these two cases has to
                    237:                 * be tested by reading the actual
                    238:                 * different lines and comparing them.
                    239:                 */
                    240:                if (p13->c_newbeg == p23->c_newbeg
                    241:                 && p13->c_newend == p23->c_newend) {
                    242:                        register int mat;
                    243:                        register CHANGES *cp;
                    244:                        register FILE *fp;
                    245: 
                    246:                        mat = match12(p13, p23);
                    247:                        prsep(mat ? 3 : 0);
                    248:                        /*
                    249:                         * This masks out the editing changes
                    250:                         * desired, i.e. all different and 3 different
                    251:                         * for -e, and the individual cases for -x and -3.
                    252:                         */
                    253:                        if (eflag & (mat+01))
                    254:                                preditor(p13);
                    255:                        prchanges(1, p13, mat?NULL:fp13);
                    256:                        prchanges(2, p23, fp23);
                    257:                        /*
                    258:                         * Depends on whether a `c' or
                    259:                         * an `a' operation.
                    260:                         */
                    261:                        if (p13->c_oldend > p13->c_oldbeg) {
                    262:                                cp = p13;
                    263:                                fp = fp13;
                    264:                        } else {
                    265:                                cp = p23;
                    266:                                fp = fp23;
                    267:                        }
                    268:                        prchanges(3, cp, fp);
                    269:                        cfree(p13);
                    270:                        if ((p13 = n13) != NULL)
                    271:                                n13 = getdiff(fp13);
                    272:                        cfree(p23);
                    273:                        if ((p23 = n23) != NULL)
                    274:                                n23 = getdiff(fp23);
                    275:                        continue;
                    276:                }
                    277:                /*
                    278:                 * When a range of lines overlaps that
                    279:                 * of another range in the other change
                    280:                 * file, the ranges have to be adjusted.
                    281:                 */
                    282:                if (p13->c_newbeg < p23->c_newbeg) {
                    283:                        p23->c_oldbeg -= p23->c_newbeg-p13->c_newbeg;
                    284:                        p23->c_newbeg = p13->c_newbeg;
                    285:                } else if (p23->c_newbeg < p13->c_newbeg) {
                    286:                        p13->c_oldbeg -= p13->c_newbeg-p23->c_newbeg;
                    287:                        p13->c_newbeg = p23->c_newbeg;
                    288:                }
                    289:                if (p13->c_newend > p23->c_newend) {
                    290:                        p23->c_oldend += p13->c_newend-p23->c_newend;
                    291:                        p23->c_newend = p13->c_newend;
                    292:                } else if (p23->c_newend > p13->c_newend) {
                    293:                        p13->c_oldend += p23->c_newend-p13->c_newend;
                    294:                        p13->c_newend = p23->c_newend;
                    295:                }
                    296:        }
                    297: }
                    298: 
                    299: /*
                    300:  * Free a CHANGES node, checking first
                    301:  * to see if it is NULL.
                    302:  */
                    303: cfree(cp)
                    304: register CHANGES *cp;
                    305: {
                    306:        if (cp != NULL)
                    307:                free((char *)cp);
                    308: }
                    309: 
                    310: /*
                    311:  * Since we have only the output of two diffs,
                    312:  * we have to cross-check the output for a match
                    313:  * between files one and two.  This will use the
                    314:  * line ranges found in the c_before of each
                    315:  * CHANGES description.
                    316:  * We have to seek both file descriptors back
                    317:  * to where they were at entry upon leaving this routine.
                    318:  */
                    319: match12(cp13, cp23)
                    320: register CHANGES *cp13, *cp23;
                    321: {
                    322:        register int n;
                    323:        register char *lp;
                    324:        register int ret = 1;
                    325:        long seek13, seek23;
                    326: 
                    327:        n = cp13->c_oldend - cp13->c_oldbeg;
                    328:        if (n != cp23->c_oldend - cp23->c_oldbeg)
                    329:                return (0);
                    330:        if (n == 0)
                    331:                return (1);
                    332:        seek13 = ftell(fp13);
                    333:        seek23 = ftell(fp23);
                    334:        fseek(fp13, (long)cp13->c_seek, 0);
                    335:        fseek(fp23, (long)cp23->c_seek, 0);
                    336:        do {
                    337:                if (fgets(line, sizeof line, fp13) == NULL)
                    338:                        ierr("match12/1");
                    339:                for (lp = line; *lp++ != '\0'; )
                    340:                        ;
                    341:                if (fgets(lp, sizeof line - (lp-line), fp23) == NULL)
                    342:                        ierr("match12/2");
                    343:                if (line[0]!='<' || line[1]!=' ')
                    344:                        ierr("match12/3");
                    345:                if (*lp++!='<' || *lp++!=' ')
                    346:                        ierr("match12/4");
                    347:                if (strcmp(lp, line+2) != 0) {
                    348:                        ret = 0;
                    349:                        break;
                    350:                }
                    351:        } while (--n);
                    352:        fseek(fp13, seek13, 0);
                    353:        fseek(fp23, seek23, 0);
                    354:        return (ret);
                    355: }
                    356: 
                    357: /*
                    358:  * Print out the changes on file numbered `fn' (1-3),
                    359:  * given the CHANGES structure reference `cp'.
                    360:  * Since file 3 is always the `new' file, if `fn==3'
                    361:  * then the new range is used, otherwise the old.
                    362:  * `prt' is set, if the text needs to be printed.
                    363:  */
                    364: prchanges(fn, cp, prtfp)
                    365: int fn;
                    366: CHANGES *cp;
                    367: FILE *prtfp;
                    368: {
                    369:        register unsigned beg, end;
                    370:        register char recog;
                    371:        register int nl;
                    372:        long oseek;
                    373: 
                    374:        if (eflag)
                    375:                return;
                    376:        if (fn == 3) {
                    377:                recog = '>';
                    378:                beg = cp->c_newbeg;
                    379:                end = cp->c_newend;
                    380:        } else {
                    381:                recog = '<';
                    382:                beg = cp->c_oldbeg;
                    383:                end = cp->c_oldend;
                    384:        }
                    385:        lastchange[fn-1] = end;
                    386:        printf("%d: ", fn);
                    387:        predcom(beg, end);
                    388:        if (prtfp == NULL)
                    389:                return;
                    390:        oseek = ftell(prtfp);
                    391:        fseek(prtfp, (long)cp->c_seek, 0);
                    392:        while (fgets(line, sizeof line, prtfp) != NULL)
                    393:                if (line[0]==recog && line[1]==' ')
                    394:                        break;
                    395:        for (nl = end-beg; nl-- > 0; ) {
                    396:                if (line[0]!=recog || line[1]!=' ')
                    397:                        break;
                    398:                printf("  %s", line+2);
                    399:                if (fgets(line, sizeof line, prtfp) == NULL)
                    400:                        break;
                    401:        }
                    402:        fseek(prtfp, oseek, 0);
                    403: }
                    404: 
                    405: /*
                    406:  * Print out dummy changes.
                    407:  */
                    408: prdummy(fn, cp)
                    409: register int fn;
                    410: register CHANGES *cp;
                    411: {
                    412:        register unsigned diff;
                    413: 
                    414:        if (eflag)
                    415:                return;
                    416:        diff = lastchange[3-1] - lastchange[fn-1];
                    417:        lastchange[fn-1] = cp->c_newend-diff;
                    418:        printf("%d: ", fn);
                    419:        predcom(cp->c_newbeg-diff, cp->c_newend-diff);
                    420: }
                    421: 
                    422: /*
                    423:  * Print out an entry in the editor
                    424:  * script given the first difference
                    425:  * file (between files 1 and 3).
                    426:  * Line numbers have to be adjusted
                    427:  * because this script is printed in
                    428:  * forward order.  Special handling is
                    429:  * done for a line which is `.'
                    430:  */
                    431: preditor(cp)
                    432: register CHANGES *cp;
                    433: {
                    434:        register int nl;
                    435:        long seek13;
                    436:        static int lnadjust;
                    437: 
                    438:        predcom(cp->c_oldbeg+lnadjust, cp->c_oldend+lnadjust);
                    439:        if (cp->c_oldend > cp->c_oldbeg)
                    440:                lnadjust -= cp->c_oldend-cp->c_oldbeg;
                    441:        seek13 = ftell(fp13);
                    442:        fseek(fp13, (long)cp->c_seek, 0);
                    443:        while (fgets(line, sizeof line, fp13) != NULL)
                    444:                if (line[0]=='>' && line[1]==' ')
                    445:                        break;
                    446:        for (nl = cp->c_newend-cp->c_newbeg; nl--  > 0; ) {
                    447:                if (line[0]!='>' || line[1]!=' ')
                    448:                        break;
                    449:                if (line[2]=='.' && line[3]=='\n' && line[4]=='\0')
                    450:                        fputs("~\n.\ns/~/./\na\n", stdout);
                    451:                else
                    452:                        fputs(line+2, stdout);
                    453:                lnadjust++;
                    454:                if (fgets(line, sizeof line, fp13) == NULL)
                    455:                        break;
                    456:        }
                    457:        fputs(".\n", stdout);
                    458:        fseek(fp13, seek13, 0);
                    459: }
                    460: 
                    461: /*
                    462:  * Print out an editing command based
                    463:  * upon the range of lines given.
                    464:  * They have been adjusted in `readdiffs'
                    465:  * so that an `a' and `c' are differentiable.
                    466:  */
                    467: predcom(beg, end)
                    468: register unsigned beg, end;
                    469: {
                    470:        if (end <= beg)
                    471:                printf("%da\n", beg-1);
                    472:        else {
                    473:                printf("%d", beg);
                    474:                if (end > beg+1)
                    475:                        printf(",%d", end-1);
                    476:                printf("c\n");
                    477:        }
                    478: }
                    479: 
                    480: /*
                    481:  * Print out a separator.
                    482:  * The `fn' is which file differs.
                    483:  * If `fn' is 0, it means all files differ.
                    484:  */
                    485: prsep(fn)
                    486: register int fn;
                    487: {
                    488:        if (!eflag)
                    489:                if (fn != 0)
                    490:                        printf("====%d\n", fn); else
                    491:                        printf("====\n");
                    492: }
                    493: 
                    494: /*
                    495:  * Error routines
                    496:  */
                    497: /* VARARGS */
                    498: cerr(x)
                    499: {
                    500:        fprintf(stderr, "diff3: %r\n", &x);
                    501:        exit(2);
                    502: }
                    503: 
                    504: /*
                    505:  * Internal error.
                    506:  */
                    507: ierr(type)
                    508: char *type;
                    509: {
                    510:        cerr("internal error in %s", type);
                    511: }

unix.superglobalmegacorp.com

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