]> pd.if.org Git - pdutils/blob - posix/cmp/cmp.c
rename utils to posix
[pdutils] / posix / cmp / cmp.c
1 /*
2  * cmp.c - compare two files
3  *
4  * Version: 2008-1.01
5  * Build:   c89 -o cmp cmp.c
6  * Source:  <http://pdcore.sourceforge.net/>
7  * Spec:    <http://www.opengroup.org/onlinepubs/9699919799/utilities/cmp.html>
8  *
9  * This is free and unencumbered software released into the public domain,
10  * provided "as is", without warranty of any kind, express or implied. See the
11  * file UNLICENSE and the website <http://unlicense.org> for further details.
12  */
13
14
15 #define _POSIX_SOURCE
16
17 #include <errno.h>
18 #include <fcntl.h>
19 #include <locale.h>
20 #include <stdio.h>
21 #include <stdlib.h>
22 #include <string.h>
23 #include <sys/types.h>
24 #include <unistd.h>
25
26 #define USAGE      "usage: cmp [-l|-s] file1 file2\n"
27 #define ELSMUTEXCL "Options -l and -s are mutually exclusive"
28 #define EBOTHSTDIN "Input files must be different"
29 #define BUFSIZE    4096
30 #define SYSERR     1
31 #define APPERR     0
32
33 static int cmpfiles(int fd1, char *fn1, int fd2, char *fn2);
34 static void fatal(int errtype, char *s);
35
36 static int optl, opts;
37
38
39 int main(int argc, char **argv)
40 {
41     extern int opterr, optind;
42     int c, exitstatus = 0;
43     int fd1, fd2;
44     char *fn1, *fn2;
45
46     setlocale(LC_ALL, "");
47     opterr = 0;
48
49     while ((c = getopt(argc, argv, "ls")) != -1)
50         switch (c)
51         {
52         case 'l':
53             optl = 1;
54             break;
55         case 's':
56             opts = 1;
57             break;
58         default:
59             fprintf(stderr, USAGE);
60             exit(2);
61         }
62
63     argc -= optind;
64     argv += optind;
65
66     if (optl && opts)
67         fatal(APPERR, ELSMUTEXCL);
68
69     if (argc != 2)
70         fatal(APPERR, USAGE);
71
72     fn1 = argv[0];
73     if (strcmp(fn1, "-") == 0)
74         fd1 = STDIN_FILENO;
75     else
76         if ((fd1 = open(fn1, O_RDONLY)) == -1)
77             fatal(SYSERR, fn1);
78
79     fn2 = argv[1];
80     if (strcmp(fn2, "-") == 0)
81         fd2 = STDIN_FILENO;
82     else
83         if ((fd2 = open(fn2, O_RDONLY)) == -1)
84             fatal(SYSERR, fn2);
85
86     if (fd1 == STDIN_FILENO && fd2 == STDIN_FILENO)
87         fatal(APPERR, EBOTHSTDIN);
88
89     exitstatus = cmpfiles(fd1, fn1, fd2, fn2);
90
91     if (fd1 != STDIN_FILENO && (close(fd1) == -1))
92         fatal(SYSERR, fn1);
93
94     if (fd2 != STDIN_FILENO && (close(fd2) == -1))
95         fatal(SYSERR, fn2);
96
97     return(exitstatus);
98 }
99
100
101 int cmpfiles(int fd1, char *fn1, int fd2, char *fn2)
102 {
103     unsigned char buf1[BUFSIZE], buf2[BUFSIZE];
104     ssize_t n1, n2, byte = 1, line = 1;
105     int cnt, i, eof = 0, differ = 0, shorter = 0;
106
107     while (! eof)
108     {
109         if ((n1 = read(fd1, buf1, BUFSIZE)) == -1)
110             fatal(SYSERR, fn1);
111
112         if ((n2 = read(fd2, buf2, BUFSIZE)) == -1)
113             fatal(SYSERR, fn2);
114
115         if (n1 != BUFSIZE || n2 != BUFSIZE)
116         {
117             eof = 1;
118             if (n1 != n2)
119                 shorter = (n1 < n2) ? 1 : 2;
120         }
121
122         cnt = (n1 < n2) ? n1 : n2;
123         for (i = 0; i < cnt; i++)
124         {
125             if (buf1[i] != buf2[i])
126             {
127                 if (! differ && ! optl && ! opts)
128                 {
129                     printf("%s %s differ: char %d, line %d\n", fn1, fn2, byte, line);
130                     return(1);  /* only need to report first mismatch */
131                 }
132
133                 differ = 1;
134
135                 if (optl)
136                     printf("%d %o %o\n", byte, buf1[i], buf2[i]);
137             }
138
139             byte++;
140             if (buf1[i] == '\n')
141                 line++;
142         }
143     }
144
145     if (shorter && (optl || (! opts && ! differ)))
146     {
147         differ = 1;
148         fprintf(stderr, "cmp: EOF on %s\n", (shorter == 1 ? fn1 : fn2));
149     }
150
151     return(differ || shorter);
152 }
153
154
155 void fatal(int errtype, char *s)
156 {
157     if (errtype == SYSERR)
158         fprintf(stderr, "cmp: %s: %s\n", s, strerror(errno));
159     else
160         fprintf(stderr, "cmp: %s\n", s);
161
162     exit(2);
163 }