cmp.c revision 1.3
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, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 3. All advertising materials mentioning features or use of this software 14 * must display the following acknowledgement: 15 * This product includes software developed by the University of 16 * California, Berkeley and its contributors. 17 * 4. Neither the name of the University nor the names of its contributors 18 * may be used to endorse or promote products derived from this software 19 * without specific prior written permission. 20 * 21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31 * SUCH DAMAGE. 32 */ 33 34#ifndef lint 35char copyright[] = 36"@(#) Copyright (c) 1987, 1990 Regents of the University of California.\n\ 37 All rights reserved.\n"; 38#endif /* not lint */ 39 40#ifndef lint 41/*static char sccsid[] = "from: @(#)cmp.c 5.3 (Berkeley) 6/1/90";*/ 42static char rcsid[] = "$Id: cmp.c,v 1.3 1993/09/21 22:35:56 jtc Exp $"; 43#endif /* not lint */ 44 45#include <sys/param.h> 46#include <sys/file.h> 47#include <sys/stat.h> 48#include <stdio.h> 49#include <ctype.h> 50#include <errno.h> 51 52#define EXITNODIFF 0 53#define EXITDIFF 1 54#define EXITERR 2 55 56int all, fd1, fd2, silent; 57u_char buf1[MAXBSIZE], buf2[MAXBSIZE]; 58char *file1, *file2; 59 60main(argc, argv) 61 int argc; 62 char **argv; 63{ 64 extern char *optarg; 65 extern int optind; 66 int ch; 67 u_long otoi(); 68 69 while ((ch = getopt(argc, argv, "ls")) != -1) 70 switch (ch) { 71 case 'l': /* print all differences */ 72 all = 1; 73 break; 74 case 's': /* silent run */ 75 silent = 1; 76 break; 77 case '?': 78 default: 79 usage(); 80 } 81 argv += optind; 82 argc -= optind; 83 84 if (argc < 2 || argc > 4) 85 usage(); 86 87 if (all && silent) 88 usage (); 89 90 if (strcmp(file1 = argv[0], "-") == 0) 91 fd1 = 0; 92 else if ((fd1 = open(file1, O_RDONLY, 0)) < 0) 93 error(file1); 94 if (strcmp(file2 = argv[1], "-") == 0) 95 fd2 = 0; 96 else if ((fd2 = open(file2, O_RDONLY, 0)) < 0) 97 error(file2); 98 if (fd1 == fd2) { 99 fprintf(stderr, 100 "cmp: standard input may only be specified once.\n"); 101 exit(EXITERR); 102 } 103 104 /* handle skip arguments */ 105 if (argc > 2) { 106 skip(otoi(argv[2]), fd1, file1); 107 if (argc == 4) 108 skip(otoi(argv[3]), fd2, file2); 109 } 110 cmp(); 111 /*NOTREACHED*/ 112} 113 114/* 115 * skip -- 116 * skip first part of file 117 */ 118skip(dist, fd, fname) 119 register u_long dist; 120 register int fd; 121 char *fname; 122{ 123 register int rlen, nread; 124 125 for (; dist; dist -= rlen) { 126 rlen = MIN(dist, sizeof(buf1)); 127 if ((nread = read(fd, buf1, rlen)) != rlen) { 128 if (nread < 0) 129 error(fname); 130 else 131 endoffile(fname); 132 } 133 } 134} 135 136cmp() 137{ 138 register u_char *p1, *p2; 139 register int cnt, len1, len2; 140 register long byte, line; 141 int dfound = 0; 142 143 for (byte = 0, line = 1; ; ) { 144 switch (len1 = read(fd1, buf1, MAXBSIZE)) { 145 case -1: 146 error(file1); 147 case 0: 148 /* 149 * read of file 1 just failed, find out 150 * if there's anything left in file 2 151 */ 152 switch (read(fd2, buf2, 1)) { 153 case -1: 154 error(file2); 155 /* NOTREACHED */ 156 case 0: 157 exit(dfound ? EXITDIFF : EXITNODIFF); 158 /* NOTREACHED */ 159 default: 160 endoffile(file1); 161 break; 162 } 163 } 164 /* 165 * file1 might be stdio, which means that a read of less than 166 * MAXBSIZE might not mean an EOF. So, read whatever we read 167 * from file1 from file2. 168 */ 169 if ((len2 = read(fd2, buf2, len1)) == -1) 170 error(file2); 171 if (bcmp(buf1, buf2, len2)) { 172 if (silent) 173 exit(EXITDIFF); 174 if (all) { 175 dfound = 1; 176 for (p1 = buf1, p2 = buf2, cnt = len2; cnt--; 177 ++p1, ++p2) { 178 ++byte; 179 if (*p1 != *p2) 180 printf("%6ld %3o %3o\n", 181 byte, *p1, *p2); 182 } 183 } else for (p1 = buf1, p2 = buf2; ; ++p1, ++p2) { 184 ++byte; 185 if (*p1 != *p2) { 186 printf("%s %s differ: char %ld, line %ld\n", file1, file2, byte, line); 187 exit(EXITDIFF); 188 } 189 if (*p1 == '\n') 190 ++line; 191 } 192 } else { 193 byte += len2; 194 /* 195 * here's the real performance problem, we've got to 196 * count the stupid lines, which means that -l is a 197 * *much* faster version, i.e., unless you really 198 * *want* to know the line number, run -s or -l. 199 */ 200 if (!silent && !all) 201 for (p1 = buf1, cnt = len2; cnt--; ) 202 if (*p1++ == '\n') 203 ++line; 204 } 205 /* 206 * couldn't read as much from file2 as from file1; checked 207 * here because there might be a difference before we got 208 * to this point, which would have precedence. 209 */ 210 if (len2 < len1) 211 endoffile(file2); 212 } 213} 214 215/* 216 * otoi -- 217 * octal/decimal string to u_long 218 */ 219u_long 220otoi(s) 221 register char *s; 222{ 223 register u_long val; 224 register int base; 225 226 base = (*s == '0') ? 8 : 10; 227 for (val = 0; isdigit(*s); ++s) 228 val = val * base + *s - '0'; 229 return (val); 230} 231 232/* 233 * error -- 234 * print I/O error message and die 235 */ 236error(filename) 237 char *filename; 238{ 239 extern int errno; 240 char *strerror(); 241 242 if (!silent) 243 (void) fprintf(stderr, "cmp: %s: %s\n", 244 filename, strerror(errno)); 245 exit(EXITERR); 246} 247 248/* 249 * endoffile -- 250 * print end-of-file message and exit indicating the files were different 251 */ 252endoffile(filename) 253 char *filename; 254{ 255 if (!silent) 256 (void) fprintf(stderr, "cmp: EOF on %s\n", filename); 257 exit(EXITDIFF); 258} 259 260/* 261 * usage -- 262 * print usage and die 263 */ 264usage() 265{ 266 fputs("usage: cmp [-l | -s] file1 file2 [skip1] [skip2]\n", stderr); 267 exit(EXITERR); 268} 269