|
|
1.1 ! root 1: /* ! 2: * This code is common between diff and /usr/lib/diffh. ! 3: * It is a restructuring and re-write of the earlier ! 4: * Tom Duff code so that reading options, opening files, ! 5: * and outputing of the differences is common. ! 6: */ ! 7: ! 8: #include "diff.h" ! 9: #ifdef COHERENT ! 10: #include <sys/stat.h> ! 11: #include <signal.h> ! 12: #else ! 13: #include <sys/types.h> ! 14: #endif ! 15: #include <path.h> ! 16: ! 17: int dflag; /* Dynamic decision about -h or not */ ! 18: int bflag; /* Strip trailing blanks, multiple blanks */ ! 19: int eflag; /* Editor script */ ! 20: int sflag; /* Sed script output (used by SCCS) */ ! 21: int rflag; /* Reversed order of printed (usually -e) */ ! 22: int nflag; /* Trailing '.' on edit script */ ! 23: int incr; /* Line number increment for `rflag' diff */ ! 24: char *csymbol; /* Symbol for C pre-processor (#ifdef) */ ! 25: int sepflag; /* On if text from both files involved */ ! 26: int caflag; /* On for a change or append */ ! 27: unsigned ninsert; /* Number of lines inserted */ ! 28: unsigned ndelete; /* Number of lines deleted */ ! 29: unsigned nunchanged; /* Number of line unchanged */ ! 30: char *tmpnam1, *tmpnam2; ! 31: FILE *fp1; /* First input stream */ ! 32: FILE *fp2; /* Second input stream */ ! 33: char *fn1, *fn2; /* Filenames */ ! 34: ! 35: char buf1[BUFSIZ]; ! 36: char buf2[BUFSIZ]; ! 37: ! 38: FILE *openfile(); ! 39: int rmexit(); ! 40: int catchsig(); ! 41: int streq(); ! 42: int bstreq(); ! 43: ! 44: int (*equal)() = streq; ! 45: ! 46: main(argc, argv) ! 47: int argc; ! 48: char *argv[]; ! 49: { ! 50: register char *ap; ! 51: register char **sargv = argv; ! 52: fsize_t size1, size2; ! 53: ! 54: while (argc>1 && argv[1][0]=='-' && argv[1][1]!='\0') { ! 55: for (ap = &argv[1][1]; *ap != '\0'; ap++) ! 56: switch (*ap) { ! 57: case 'b': ! 58: bflag = 1; ! 59: equal = bstreq; ! 60: break; ! 61: ! 62: case 'c': ! 63: if (argc < 3) ! 64: usage(); ! 65: csymbol = argv[2]; ! 66: argv++; ! 67: argc--; ! 68: break; ! 69: ! 70: case 'd': ! 71: dflag = 1; ! 72: break; ! 73: ! 74: case 'e': ! 75: eflag = rflag = 1; ! 76: break; ! 77: ! 78: case 'f': ! 79: eflag = 1; ! 80: rflag = 0; ! 81: break; ! 82: ! 83: case 'n': ! 84: eflag = nflag = 1; ! 85: rflag = 0; ! 86: break; ! 87: ! 88: case 's': ! 89: eflag = sflag = 1; ! 90: break; ! 91: ! 92: case 'h': ! 93: diffh(sargv); ! 94: break; ! 95: ! 96: default: ! 97: usage(); ! 98: } ! 99: argc--; ! 100: argv++; ! 101: } ! 102: if (argc != 3) ! 103: usage(); ! 104: if (eflag && csymbol!=NULL) ! 105: cerr("-e and -c are incompatible options"); ! 106: #ifdef COHERENT ! 107: if (signal(SIGINT, SIG_IGN) != SIG_IGN) ! 108: signal(SIGINT, catchsig); ! 109: if (signal(SIGHUP, SIG_IGN) != SIG_IGN) ! 110: signal(SIGHUP, catchsig); ! 111: if (signal(SIGTERM, SIG_IGN) != SIG_IGN) ! 112: signal(SIGTERM, catchsig); ! 113: #endif ! 114: fp1 = openfile(argv[1], argv[2], &tmpnam1, &size1); ! 115: fp2 = openfile(argv[2], argv[1], &tmpnam2, &size2); ! 116: if (dflag && (size1>NBIGF || size2>NBIGF)) ! 117: diffh(argv); ! 118: setbuf(fp1, buf1); ! 119: setbuf(fp2, buf2); ! 120: fn1 = argv[1]; ! 121: fn2 = argv[2]; ! 122: diff(fp1, fp2); ! 123: if (sflag) ! 124: printf(":I%d\n:D%d\n:U%d\n", ninsert, ndelete, nunchanged); ! 125: rmexit(ninsert || ndelete); ! 126: } ! 127: ! 128: /* ! 129: * Compare input lines for equality. ! 130: */ ! 131: bstreq(s1, s2) ! 132: register char *s1, *s2; ! 133: { ! 134: for (;;) { ! 135: if (*s1==' ' || *s1=='\t') { ! 136: do { ! 137: s1++; ! 138: } while (*s1==' ' || *s1=='\t'); ! 139: if (*s1 == '\n') { ! 140: while (*s2==' ' || *s2=='\t') ! 141: s2++; ! 142: return (*s2 == '\n'); ! 143: } ! 144: if (*s2!=' ' && *s2!='\t') ! 145: return (0); ! 146: do { ! 147: s2++; ! 148: } while (*s2==' ' || *s2=='\t'); ! 149: } else { ! 150: if (*s1 == '\n') ! 151: while (*s2==' ' || *s2=='\t') ! 152: s2++; ! 153: if (*s1++ != *s2) ! 154: return (0); ! 155: if (*s2++ == '\n') ! 156: return (1); ! 157: } ! 158: } ! 159: } ! 160: ! 161: /* ! 162: * Open the files, allowing for special standard input ! 163: * convention (`-') and directories. Copy any special ! 164: * files or pipes to a tempfile because they cannot be ! 165: * rewound. ! 166: * `ofn' is the other name, for directory concatenation. ! 167: */ ! 168: FILE * ! 169: openfile(fn, ofn, tfnp, sizep) ! 170: char *fn; ! 171: char *ofn; ! 172: char **tfnp; ! 173: fsize_t *sizep; ! 174: { ! 175: register FILE *fp; ! 176: #ifdef COHERENT ! 177: register char *cp; ! 178: register int c; ! 179: register FILE *tfp; ! 180: char fname[300]; ! 181: struct stat sb; ! 182: static int dirflag; ! 183: ! 184: again: ! 185: #endif ! 186: if (fn[0]=='-' && fn[1]=='\0') ! 187: fp = stdin; ! 188: else if ((fp = fopen(fn, "r")) == NULL) ! 189: cerr("cannot open `%s'", fn); ! 190: #ifdef COHERENT ! 191: fstat(fileno(fp), &sb); ! 192: *sizep = sb.st_size; ! 193: switch (sb.st_mode & S_IFMT) { ! 194: case S_IFDIR: ! 195: if (dirflag) ! 196: break; ! 197: dirflag++; ! 198: for (cp = ofn; *cp != '\0'; cp++) ! 199: ; ! 200: while (cp > ofn) ! 201: if (*--cp == PATHSEP) { ! 202: cp++; ! 203: break; ! 204: } ! 205: sprintf(fname, "%s%c%s", fn, PATHSEP, cp); ! 206: fn = fname; ! 207: goto again; ! 208: ! 209: case S_IFREG: ! 210: break; ! 211: ! 212: default: ! 213: *tfnp = "/tmp/difXXXXXX"; ! 214: if ((tfp = fopen(mktemp(*tfnp), "w")) == NULL) ! 215: cerr("cannot create tempfile"); ! 216: setbuf(fp, buf1); ! 217: setbuf(tfp, buf2); ! 218: while ((c = getc(fp)) != EOF) ! 219: putc(c, tfp); ! 220: fflush(tfp); ! 221: if (ferror(tfp)) ! 222: cerr("write error on tempfile"); ! 223: fclose(tfp); ! 224: if (fp != stdin) ! 225: fclose(fp); ! 226: if ((fp = fopen(*tfnp, "r")) == NULL) ! 227: cerr("cannot re-open tempfile"); ! 228: } ! 229: #endif ! 230: return (fp); ! 231: } ! 232: ! 233: /* ! 234: * Output a text line common to both files. ! 235: * This is only used by the `-c' option. ! 236: */ ! 237: text(line) ! 238: char *line; ! 239: { ! 240: ++nunchanged; ! 241: if (csymbol != NULL) ! 242: fputs(line, stdout); ! 243: } ! 244: ! 245: /* ! 246: * Output a text line from the first file. ! 247: */ ! 248: text1(line) ! 249: register char *line; ! 250: { ! 251: if (csymbol != NULL) ! 252: fputs(line, stdout); ! 253: else if (!eflag) { ! 254: fputs("< ", stdout); ! 255: fputs(line, stdout); ! 256: } ! 257: ++ndelete; ! 258: } ! 259: ! 260: /* ! 261: * Output a line that is only in ! 262: * the second file. ! 263: */ ! 264: text2(line) ! 265: register char *line; ! 266: { ! 267: if (sflag) { ! 268: putchar('\\'); ! 269: putchar('\n'); ! 270: #if REALSED ! 271: /* ! 272: * Sed is documented to strip ! 273: * leading blanks/tabs in appended ! 274: * text but doesn't. This appears ! 275: * to be a feature rather than a bug. ! 276: */ ! 277: if (line[0]==' ' || line[0]=='\t') ! 278: putchar('\\'); ! 279: #endif ! 280: while (*line != '\n') { ! 281: if (*line == '\\') ! 282: putchar(*line); ! 283: putchar(*line++); ! 284: } ! 285: } else if (eflag) { ! 286: if (!nflag && line[0]=='.' && line[1]=='\n' && line[2]=='\0') ! 287: fputs("~\n.\ns/~/./\na\n", stdout); ! 288: else ! 289: fputs(line, stdout); ! 290: } else if (csymbol != NULL) ! 291: fputs(line, stdout); ! 292: else { ! 293: fputs("> ", stdout); ! 294: fputs(line, stdout); ! 295: } ! 296: caflag = 1; ! 297: ++ninsert; ! 298: } ! 299: ! 300: /* ! 301: * Output the start of a set of ! 302: * changed lines. ! 303: * Change is from `f1',`f2' (other file is `t1,t2'). ! 304: */ ! 305: change(f1, f2, t1, t2) ! 306: unsigned f1, f2, t1, t2; ! 307: { ! 308: sepflag = 1; ! 309: if (csymbol != NULL) ! 310: printf("#ifndef %s\n", csymbol); ! 311: else if (nflag) { ! 312: printf("d%u %u\n", f1+incr, f2-f1+1); ! 313: printf("a%u %u\n", f1+incr+f2-f1, t2-t1+1); ! 314: } else { ! 315: prange(f1, f2); ! 316: if (sflag) ! 317: putchar('c'); ! 318: else if (eflag) ! 319: fputs("c\n", stdout); ! 320: else { ! 321: fputs(" c ", stdout); ! 322: prange(t1, t2); ! 323: putchar('\n'); ! 324: } ! 325: } ! 326: if (rflag) ! 327: incr += t2-t1 + f1-f2; ! 328: } ! 329: ! 330: /* ! 331: * Output a set of appended lines. ! 332: * Append after `f' the lines in ! 333: * range `t1,t2'. ! 334: */ ! 335: append(f, t1, t2) ! 336: unsigned f, t1, t2; ! 337: { ! 338: f--; ! 339: if (csymbol != NULL) ! 340: printf("#ifdef %s\n", csymbol); ! 341: else if (nflag) ! 342: printf("a%u %u\n", f+incr, t2-t1+1); ! 343: else { ! 344: prange(f, f); ! 345: if (sflag) ! 346: putchar('a'); ! 347: else if (eflag) { ! 348: fputs("a\n", stdout); ! 349: } else { ! 350: fputs(" a ", stdout); ! 351: prange(t1, t2); ! 352: putchar('\n'); ! 353: } ! 354: } ! 355: if (rflag) ! 356: incr += t2-t1+1; ! 357: } ! 358: ! 359: /* ! 360: * Output a set of deleted lines. ! 361: * Delete range `f1,f2' (other file ! 362: * number is `t'. ! 363: */ ! 364: delete(f1, f2, t) ! 365: unsigned f1, f2, t; ! 366: { ! 367: if (csymbol != NULL) ! 368: printf("#ifndef %s\n", csymbol); ! 369: else if (nflag) ! 370: printf("d%u %u\n", f1+incr, f2-f1+1); ! 371: else { ! 372: prange(f1, f2); ! 373: if (eflag) ! 374: fputs("d\n", stdout); ! 375: else ! 376: printf(" d %u\n", t-1); ! 377: } ! 378: if (rflag) ! 379: incr -= f2-f1+1; ! 380: } ! 381: ! 382: /* ! 383: * Output the middle of a set of ! 384: * changed lines. ! 385: */ ! 386: prsep() ! 387: { ! 388: if (!sepflag) ! 389: return; ! 390: sepflag = 0; ! 391: if (csymbol != NULL) ! 392: fputs("#else\n", stdout); ! 393: else if (!eflag) ! 394: fputs("---\n", stdout); ! 395: } ! 396: ! 397: /* ! 398: * Output the end part of a set ! 399: * of changed lines. ! 400: */ ! 401: prend() ! 402: { ! 403: if (csymbol != NULL) ! 404: fputs("#endif\n", stdout); ! 405: else if (caflag) { ! 406: if (sflag) ! 407: putchar('\n'); ! 408: else if (eflag && !nflag) ! 409: fputs(".\n", stdout); ! 410: } ! 411: caflag = 0; ! 412: } ! 413: ! 414: /* ! 415: * Print a line range either in the form ! 416: * `a,b' or `a' (if a==b). ! 417: */ ! 418: prange(a, b) ! 419: register unsigned a, b; ! 420: { ! 421: a += incr; ! 422: b += incr; ! 423: if (a == b) ! 424: printf("%u", a); ! 425: else ! 426: printf("%u,%u", a, b); ! 427: } ! 428: ! 429: /* ! 430: * Exit, removing any possible temmpfiles. ! 431: */ ! 432: rmexit(s) ! 433: { ! 434: if (tmpnam1 != NULL) ! 435: unlink(tmpnam1); ! 436: if (tmpnam2 != NULL) ! 437: unlink(tmpnam2); ! 438: exit(s); ! 439: } ! 440: ! 441: /* ! 442: * Catch signal and exit. ! 443: */ ! 444: catchsig() ! 445: { ! 446: rmexit(2); ! 447: } ! 448: usage() ! 449: { ! 450: fprintf(stderr, "Usage: diff [-bdefhns] [-c symbol] file1 file2\n"); ! 451: exit(2); ! 452: } ! 453: ! 454: /* VARARGS */ ! 455: cerr(x) ! 456: { ! 457: fprintf(stderr, "diff: %r\n", &x); ! 458: exit(2); ! 459: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.