X-Git-Url: https://pd.if.org/git/?p=pdutils;a=blobdiff_plain;f=utils%2Fcmp%2Fcmp.c;fp=utils%2Fcmp%2Fcmp.c;h=a1c05722bde5a378f8b4444dfefb72a860a64773;hp=0000000000000000000000000000000000000000;hb=4daa873acbfc240e9ecc350e74c14bbfd58fabc9;hpb=b6d847ae20c32744d508eced2be3132c3fa8c5b9 diff --git a/utils/cmp/cmp.c b/utils/cmp/cmp.c new file mode 100644 index 0000000..a1c0572 --- /dev/null +++ b/utils/cmp/cmp.c @@ -0,0 +1,163 @@ +/* + * 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); +}