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