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