|
DataMuseum.dkPresents historical artifacts from the history of: Commodore CBM-900 |
This is an automatic "excavation" of a thematic subset of
See our Wiki for more about Commodore CBM-900 Excavated with: AutoArchaeologist - Free & Open Source Software. |
top - download
Length: 7765 (0x1e55) Types: TextFile Notes: UNIX file Names: »diff2.c«
└─⟦f27320a65⟧ Bits:30001972 Commodore 900 hard disk image with partial source code └─⟦f4b8d8c84⟧ UNIX Filesystem └─ ⟦this⟧ »cmd/diff/diff2.c«
/* * This code is common between diff and /usr/lib/diffh. * It is a restructuring and re-write of the earlier * Tom Duff code so that reading options, opening files, * and outputing of the differences is common. */ #include "diff.h" #include <sys/stat.h> #include <signal.h> int dflag; /* Dynamic decision about -h or not */ int bflag; /* Strip trailing blanks, multiple blanks */ int eflag; /* Editor script */ int sflag; /* Sed script output (used by SCCS) */ int rflag; /* Reversed order of printed (usually -e) */ int incr; /* Line number increment for `rflag' diff */ char *csymbol; /* Symbol for C pre-processor (#ifdef) */ int sepflag; /* On if text from both files involved */ int caflag; /* On for a change or append */ unsigned ninsert; /* Number of lines inserted */ unsigned ndelete; /* Number of lines deleted */ unsigned nunchanged; /* Number of line unchanged */ char *tmpnam1, *tmpnam2; FILE *fp1; /* First input stream */ FILE *fp2; /* Second input stream */ char *fn1, *fn2; /* Filenames */ char buf1[BUFSIZ]; char buf2[BUFSIZ]; FILE *openfile(); int rmexit(); int catchsig(); int streq(); int bstreq(); int (*equal)() = streq; main(argc, argv) int argc; char *argv[]; { register char *ap; register char **sargv = argv; size_t size1, size2; while (argc>1 && argv[1][0]=='-' && argv[1][1]!='\0') { for (ap = &argv[1][1]; *ap != '\0'; ap++) switch (*ap) { case 'b': bflag = 1; equal = bstreq; break; case 'c': if (argc < 3) usage(); csymbol = argv[2]; argv++; argc--; break; case 'd': dflag = 1; break; case 'e': eflag = rflag = 1; break; case 'f': eflag = 1; rflag = 0; break; case 's': eflag = sflag = 1; break; case 'h': diffh(sargv); break; default: usage(); } argc--; argv++; } if (argc != 3) usage(); if (eflag && csymbol!=NULL) cerr("-e and -c are incompatible options"); if (signal(SIGINT, SIG_IGN) != SIG_IGN) signal(SIGINT, catchsig); if (signal(SIGHUP, SIG_IGN) != SIG_IGN) signal(SIGHUP, catchsig); if (signal(SIGTERM, SIG_IGN) != SIG_IGN) signal(SIGTERM, catchsig); fp1 = openfile(argv[1], argv[2], &tmpnam1, &size1); fp2 = openfile(argv[2], argv[1], &tmpnam2, &size2); if (dflag && (size1>NBIGF || size2>NBIGF)) diffh(argv); setbuf(fp1, buf1); setbuf(fp2, buf2); fn1 = argv[1]; fn2 = argv[2]; diff(fp1, fp2); if (sflag) printf(":I%d\n:D%d\n:U%d\n", ninsert, ndelete, nunchanged); rmexit(ninsert || ndelete); } /* * Compare input lines for equality. */ bstreq(s1, s2) register char *s1, *s2; { for (;;) { if (*s1==' ' || *s1=='\t') { do { s1++; } while (*s1==' ' || *s1=='\t'); if (*s1 == '\n') { while (*s2==' ' || *s2=='\t') s2++; return (*s2 == '\n'); } if (*s2!=' ' && *s2!='\t') return (0); do { s2++; } while (*s2==' ' || *s2=='\t'); } else { if (*s1 == '\n') while (*s2==' ' || *s2=='\t') s2++; if (*s1++ != *s2) return (0); if (*s2++ == '\n') return (1); } } } /* * Open the files, allowing for special standard input * convention (`-') and directories. Copy any special * files or pipes to a tempfile because they cannot be * rewound. * `ofn' is the other name, for directory concatenation. */ FILE * openfile(fn, ofn, tfnp, sizep) char *fn; char *ofn; char **tfnp; size_t *sizep; { register char *cp; register int c; register FILE *fp; register FILE *tfp; char fname[300]; struct stat sb; static int dirflag; again: if (fn[0]=='-' && fn[1]=='\0') fp = stdin; else if ((fp = fopen(fn, "r")) == NULL) cerr("cannot open `%s'", fn); fstat(fileno(fp), &sb); *sizep = sb.st_size; switch (sb.st_mode & S_IFMT) { case S_IFDIR: if (dirflag) break; dirflag++; for (cp = ofn; *cp != '\0'; cp++) ; while (cp > ofn) if (*--cp == '/') { cp++; break; } fn = sprintf(fname, "%s/%s", fn, cp); goto again; case S_IFREG: break; default: *tfnp = "/tmp/difXXXXXX"; if ((tfp = fopen(mktemp(*tfnp), "w")) == NULL) cerr("cannot create tempfile"); setbuf(fp, buf1); setbuf(tfp, buf2); while ((c = getc(fp)) != EOF) putc(c, tfp); fflush(tfp); if (ferror(tfp)) cerr("write error on tempfile"); fclose(tfp); if (fp != stdin) fclose(fp); if ((fp = fopen(*tfnp, "r")) == NULL) cerr("cannot re-open tempfile"); } return (fp); } /* * Output a text line common to both files. * This is only used by the `-c' option. */ text(line) char *line; { ++nunchanged; if (csymbol != NULL) fputs(line, stdout); } /* * Output a text line from the first file. */ text1(line) register char *line; { if (csymbol != NULL) fputs(line, stdout); else if (!eflag) { fputs("< ", stdout); fputs(line, stdout); } ++ndelete; } /* * Output a line that is only in * the second file. */ text2(line) register char *line; { if (sflag) { putchar('\\'); putchar('\n'); #if REALSED /* * Sed is documented to strip * leading blanks/tabs in appended * text but doesn't. This appears * to be a feature rather than a bug. */ if (line[0]==' ' || line[0]=='\t') putchar('\\'); #endif while (*line != '\n') { if (*line == '\\') putchar(*line); putchar(*line++); } } else if (eflag) { if (line[0]=='.' && line[1]=='\n' && line[2]=='\0') fputs("~\n.\ns/~/./\na\n", stdout); else fputs(line, stdout); } else if (csymbol != NULL) fputs(line, stdout); else { fputs("> ", stdout); fputs(line, stdout); } caflag = 1; ++ninsert; } /* * Output the start of a set of * changed lines. * Change is from `f1',`f2' (other file is `t1,t2'). */ change(f1, f2, t1, t2) unsigned f1, f2, t1, t2; { sepflag = 1; if (csymbol != NULL) printf("#ifndef %s\n", csymbol); else { prange(f1, f2); if (sflag) putchar('c'); else if (eflag) fputs("c\n", stdout); else { fputs(" c ", stdout); prange(t1, t2); putchar('\n'); } } if (rflag) incr += t2-t1 + f1-f2; } /* * Output a set of appended lines. * Append after `f' the lines in * range `t1,t2'. */ append(f, t1, t2) unsigned f, t1, t2; { f--; if (csymbol != NULL) printf("#ifndef %s\n", csymbol); else { prange(f, f); if (sflag) putchar('a'); else if (eflag) { fputs("a\n", stdout); } else { fputs(" a ", stdout); prange(t1, t2); putchar('\n'); } } if (rflag) incr += t2-t1+1; } /* * Output a set of deleted lines. * Delete range `f1,f2' (other file * number is `t'. */ delete(f1, f2, t) unsigned f1, f2, t; { if (csymbol != NULL) printf("#ifdef %s\n", csymbol); else { prange(f1, f2); if (eflag) fputs("d\n", stdout); else printf(" d %u\n", t-1); } if (rflag) incr -= f2-f1+1; } /* * Output the middle of a set of * changed lines. */ prsep() { if (!sepflag) return; sepflag = 0; if (csymbol != NULL) fputs("#else\n", stdout); else if (!eflag) fputs("---\n", stdout); } /* * Output the end part of a set * of changed lines. */ prend() { if (csymbol != NULL) fputs("#endif\n", stdout); else if (caflag) { if (sflag) putchar('\n'); else if (eflag) fputs(".\n", stdout); } caflag = 0; } /* * Print a line range either in the form * `a,b' or `a' (if a==b). */ prange(a, b) register unsigned a, b; { a += incr; b += incr; if (a == b) printf("%u", a); else printf("%u,%u", a, b); } /* * Exit, removing any possible temmpfiles. */ rmexit(s) { if (tmpnam1 != NULL) unlink(tmpnam1); if (tmpnam2 != NULL) unlink(tmpnam2); exit(s); } /* * Catch signal and exit. */ catchsig() { rmexit(2); } usage() { fprintf(stderr, "Usage: diff [-bdefhs] [-c symbol] file1 file2\n"); exit(2); } /* VARARGS */ cerr(x) { fprintf(stderr, "diff: %r\n", &x); exit(2); }