|
|
1.1 ! root 1: /* ! 2: * Copyright (c) 1987 Regents of the University of California. ! 3: * All rights reserved. ! 4: * ! 5: * Redistribution and use in source and binary forms are permitted ! 6: * provided that the above copyright notice and this paragraph are ! 7: * duplicated in all such forms and that any documentation, ! 8: * advertising materials, and other materials related to such ! 9: * distribution and use acknowledge that the software was developed ! 10: * by the University of California, Berkeley. The name of the ! 11: * University may not be used to endorse or promote products derived ! 12: * from this software without specific prior written permission. ! 13: * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR ! 14: * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED ! 15: * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. ! 16: */ ! 17: ! 18: #ifndef lint ! 19: char copyright[] = ! 20: "@(#) Copyright (c) 1987 Regents of the University of California.\n\ ! 21: All rights reserved.\n"; ! 22: #endif /* not lint */ ! 23: ! 24: #ifndef lint ! 25: static char sccsid[] = "@(#)cmp.c 4.9 (Berkeley) 6/18/88"; ! 26: #endif /* not lint */ ! 27: ! 28: #include <sys/param.h> ! 29: #include <sys/file.h> ! 30: #include <sys/stat.h> ! 31: #include <stdio.h> ! 32: #include <ctype.h> ! 33: #include <errno.h> ! 34: ! 35: #define DIFF 1 /* found differences */ ! 36: #define ERR 2 /* error during run */ ! 37: #define NO 0 /* no/false */ ! 38: #define OK 0 /* didn't find differences */ ! 39: #define YES 1 /* yes/true */ ! 40: ! 41: static int fd1, fd2, /* file descriptors */ ! 42: silent = NO; /* if silent run */ ! 43: static short all = NO; /* if report all differences */ ! 44: static u_char buf1[MAXBSIZE], /* read buffers */ ! 45: buf2[MAXBSIZE]; ! 46: static char *file1, *file2; /* file names */ ! 47: ! 48: main(argc, argv) ! 49: int argc; ! 50: char **argv; ! 51: { ! 52: extern char *optarg; ! 53: extern int optind; ! 54: int ch; ! 55: u_long otoi(); ! 56: ! 57: while ((ch = getopt(argc, argv, "ls")) != EOF) ! 58: switch(ch) { ! 59: case 'l': /* print all differences */ ! 60: all = YES; ! 61: break; ! 62: case 's': /* silent run */ ! 63: silent = YES; ! 64: break; ! 65: case '?': ! 66: default: ! 67: usage(); ! 68: } ! 69: argv += optind; ! 70: argc -= optind; ! 71: ! 72: if (argc < 2 || argc > 4) ! 73: usage(); ! 74: ! 75: /* open up files; "-" is stdin */ ! 76: file1 = argv[0]; ! 77: if (strcmp(file1, "-") && (fd1 = open(file1, O_RDONLY, 0)) < 0) ! 78: error(file1); ! 79: file2 = argv[1]; ! 80: if ((fd2 = open(file2, O_RDONLY, 0)) < 0) ! 81: error(file2); ! 82: ! 83: /* handle skip arguments */ ! 84: if (argc > 2) { ! 85: skip(otoi(argv[2]), fd1, file1); ! 86: if (argc == 4) ! 87: skip(otoi(argv[3]), fd2, file2); ! 88: } ! 89: cmp(); ! 90: /*NOTREACHED*/ ! 91: } ! 92: ! 93: /* ! 94: * skip -- ! 95: * skip first part of file ! 96: */ ! 97: static ! 98: skip(dist, fd, fname) ! 99: register u_long dist; /* length in bytes, to skip */ ! 100: register int fd; /* file descriptor */ ! 101: char *fname; /* file name for error */ ! 102: { ! 103: register int rlen; /* read length */ ! 104: register int nread; ! 105: ! 106: for (; dist; dist -= rlen) { ! 107: rlen = MIN(dist, sizeof(buf1)); ! 108: if ((nread = read(fd, buf1, rlen)) != rlen) { ! 109: if (nread < 0) ! 110: error(fname); ! 111: else ! 112: endoffile(fname); ! 113: } ! 114: } ! 115: } ! 116: ! 117: static ! 118: cmp() ! 119: { ! 120: register u_char *C1, *C2; /* traveling pointers */ ! 121: register int cnt, /* counter */ ! 122: len1, len2; /* read lengths */ ! 123: register long byte, /* byte count */ ! 124: line; /* line count */ ! 125: short dfound = NO; /* if difference found */ ! 126: ! 127: for (byte = 0, line = 1;;) { ! 128: switch(len1 = read(fd1, buf1, MAXBSIZE)) { ! 129: case -1: ! 130: error(file1); ! 131: case 0: ! 132: /* ! 133: * read of file 1 just failed, find out ! 134: * if there's anything left in file 2 ! 135: */ ! 136: switch(read(fd2, buf2, 1)) { ! 137: case -1: ! 138: error(file2); ! 139: case 0: ! 140: exit(dfound ? DIFF : OK); ! 141: default: ! 142: endoffile(file1); ! 143: } ! 144: } ! 145: /* ! 146: * file1 might be stdio, which means that a read of less than ! 147: * MAXBSIZE might not mean an EOF. So, read whatever we read ! 148: * from file1 from file2. ! 149: */ ! 150: if ((len2 = read(fd2, buf2, len1)) == -1) ! 151: error(file2); ! 152: if (bcmp(buf1, buf2, len2)) { ! 153: if (silent) ! 154: exit(DIFF); ! 155: if (all) { ! 156: dfound = YES; ! 157: for (C1 = buf1, C2 = buf2, cnt = len2; cnt--; ++C1, ++C2) { ! 158: ++byte; ! 159: if (*C1 != *C2) ! 160: printf("%6ld %3o %3o\n", byte, *C1, *C2); ! 161: } ! 162: } ! 163: else for (C1 = buf1, C2 = buf2;; ++C1, ++C2) { ! 164: ++byte; ! 165: if (*C1 != *C2) { ! 166: printf("%s %s differ: char %ld, line %ld\n", file1, file2, byte, line); ! 167: exit(DIFF); ! 168: } ! 169: if (*C1 == '\n') ! 170: ++line; ! 171: } ! 172: } ! 173: else { ! 174: byte += len2; ! 175: /* ! 176: * here's the real performance problem, we've got to ! 177: * count the stupid lines, which means that -l is a ! 178: * *much* faster version, i.e., unless you really ! 179: * *want* to know the line number, run -s or -l. ! 180: */ ! 181: if (!silent && !all) ! 182: for (C1 = buf1, cnt = len2; cnt--;) ! 183: if (*C1++ == '\n') ! 184: ++line; ! 185: } ! 186: /* ! 187: * couldn't read as much from file2 as from file1; checked ! 188: * here because there might be a difference before we got ! 189: * to this point, which would have precedence. ! 190: */ ! 191: if (len2 < len1) ! 192: endoffile(file2); ! 193: } ! 194: } ! 195: ! 196: /* ! 197: * otoi -- ! 198: * octal/decimal string to u_long ! 199: */ ! 200: static u_long ! 201: otoi(C) ! 202: register char *C; /* argument string */ ! 203: { ! 204: register u_long val; /* return value */ ! 205: register int base; /* number base */ ! 206: ! 207: base = (*C == '0') ? 8 : 10; ! 208: for (val = 0; isdigit(*C); ++C) ! 209: val = val * base + *C - '0'; ! 210: return(val); ! 211: } ! 212: ! 213: /* ! 214: * error -- ! 215: * print I/O error message and die ! 216: */ ! 217: static ! 218: error(filename) ! 219: char *filename; ! 220: { ! 221: extern int errno; ! 222: int sverrno; ! 223: ! 224: if (!silent) { ! 225: sverrno = errno; ! 226: (void)fprintf(stderr, "cmp: %s: ", filename); ! 227: errno = sverrno; ! 228: perror((char *)NULL); ! 229: } ! 230: exit(ERR); ! 231: } ! 232: ! 233: /* ! 234: * endoffile -- ! 235: * print end-of-file message and exit indicating the files were different ! 236: */ ! 237: static ! 238: endoffile(filename) ! 239: char *filename; ! 240: { ! 241: /* 32V put this message on stdout, S5 does it on stderr. */ ! 242: if (!silent) ! 243: (void)fprintf(stderr, "cmp: EOF on %s\n", filename); ! 244: exit(DIFF); ! 245: } ! 246: ! 247: /* ! 248: * usage -- ! 249: * print usage and die ! 250: */ ! 251: static ! 252: usage() ! 253: { ! 254: fputs("usage: cmp [-ls] file1 file2 [skip1] [skip2]\n", stderr); ! 255: exit(ERR); ! 256: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.