/* * cmp.c - compare two files * * Version: 2008-1.01 * Build: c89 -o cmp cmp.c * Source: * Spec: * * This is free and unencumbered software released into the public domain, * provided "as is", without warranty of any kind, express or implied. See the * file UNLICENSE and the website for further details. */ #define _POSIX_SOURCE #include #include #include #include #include #include #include #include #define USAGE "usage: cmp [-l|-s] file1 file2\n" #define ELSMUTEXCL "Options -l and -s are mutually exclusive" #define EBOTHSTDIN "Input files must be different" #define BUFSIZE 4096 #define SYSERR 1 #define APPERR 0 static int cmpfiles(int fd1, char *fn1, int fd2, char *fn2); static void fatal(int errtype, char *s); static int optl, opts; int main(int argc, char **argv) { extern int opterr, optind; int c, exitstatus = 0; int fd1, fd2; char *fn1, *fn2; setlocale(LC_ALL, ""); opterr = 0; while ((c = getopt(argc, argv, "ls")) != -1) switch (c) { case 'l': optl = 1; break; case 's': opts = 1; break; default: fprintf(stderr, USAGE); exit(2); } argc -= optind; argv += optind; if (optl && opts) fatal(APPERR, ELSMUTEXCL); if (argc != 2) fatal(APPERR, USAGE); fn1 = argv[0]; if (strcmp(fn1, "-") == 0) fd1 = STDIN_FILENO; else if ((fd1 = open(fn1, O_RDONLY)) == -1) fatal(SYSERR, fn1); fn2 = argv[1]; if (strcmp(fn2, "-") == 0) fd2 = STDIN_FILENO; else if ((fd2 = open(fn2, O_RDONLY)) == -1) fatal(SYSERR, fn2); if (fd1 == STDIN_FILENO && fd2 == STDIN_FILENO) fatal(APPERR, EBOTHSTDIN); exitstatus = cmpfiles(fd1, fn1, fd2, fn2); if (fd1 != STDIN_FILENO && (close(fd1) == -1)) fatal(SYSERR, fn1); if (fd2 != STDIN_FILENO && (close(fd2) == -1)) fatal(SYSERR, fn2); return(exitstatus); } int cmpfiles(int fd1, char *fn1, int fd2, char *fn2) { unsigned char buf1[BUFSIZE], buf2[BUFSIZE]; ssize_t n1, n2, byte = 1, line = 1; int cnt, i, eof = 0, differ = 0, shorter = 0; while (! eof) { if ((n1 = read(fd1, buf1, BUFSIZE)) == -1) fatal(SYSERR, fn1); if ((n2 = read(fd2, buf2, BUFSIZE)) == -1) fatal(SYSERR, fn2); if (n1 != BUFSIZE || n2 != BUFSIZE) { eof = 1; if (n1 != n2) shorter = (n1 < n2) ? 1 : 2; } cnt = (n1 < n2) ? n1 : n2; for (i = 0; i < cnt; i++) { if (buf1[i] != buf2[i]) { if (! differ && ! optl && ! opts) { printf("%s %s differ: char %d, line %d\n", fn1, fn2, byte, line); return(1); /* only need to report first mismatch */ } differ = 1; if (optl) printf("%d %o %o\n", byte, buf1[i], buf2[i]); } byte++; if (buf1[i] == '\n') line++; } } if (shorter && (optl || (! opts && ! differ))) { differ = 1; fprintf(stderr, "cmp: EOF on %s\n", (shorter == 1 ? fn1 : fn2)); } return(differ || shorter); } void fatal(int errtype, char *s) { if (errtype == SYSERR) fprintf(stderr, "cmp: %s: %s\n", s, strerror(errno)); else fprintf(stderr, "cmp: %s\n", s); exit(2); }