|
|
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: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.