]> pd.if.org Git - pdutils/blob - utils/comm/comm.c
implemented pwd
[pdutils] / utils / comm / comm.c
1 /*
2  * comm.c - select or reject lines common to two files
3  *
4  * Version: 2008-1.01
5  * Build:   c89 -o comm comm.c
6  * Source:  <http://pdcore.sourceforge.net/>
7  * Spec:    <http://www.opengroup.org/onlinepubs/9699919799/utilities/comm.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 <unistd.h>
24
25 #define USAGE     "usage: comm [-123] file1 file2\n"
26 #define ENOMALLOC "Unable to allocate memory for read buffer"
27 #define BUFSIZE   4096
28 #define LINESIZE  64
29 #define SYSERR    1
30 #define APPERR    0
31
32 typedef struct { int     fd;
33                  char   *fn;
34                  int     eof;
35                  char    buf[BUFSIZE];
36                  size_t  bufpos;
37                  size_t  eobuf;
38                  char   *line;
39                  size_t  linesz;
40                } FINFO;
41
42 static void initfile(FINFO *file, char *fn);
43 static void cleanup(FINFO *file);
44 static void commfiles(FINFO *file1, FINFO *file2);
45 static int getline(FINFO *file);
46 static void fillbuf(FINFO *file);
47 static void fatal(int errtype, char *s);
48
49 static int opt1, opt2, opt3;
50
51
52 int main(int argc, char **argv)
53 {
54     extern int optind, opterr;
55     int c;
56     FINFO file1, file2;
57
58     setlocale(LC_ALL, "");
59     opterr = 0;
60
61     while ((c = getopt(argc, argv, "123")) != -1)
62         switch (c)
63         {
64         case '1':
65             opt1 = 1;
66             break;
67         case '2':
68             opt2 = 1;
69             break;
70         case '3':
71             opt3 = 1;
72             break;
73         default:
74             fprintf(stderr, USAGE);
75             exit(1);
76         }
77
78     argc -= optind;
79     argv += optind;
80
81     if (argc != 2)
82         fatal(APPERR, USAGE);
83
84     initfile(&file1, argv[0]);
85     initfile(&file2, argv[1]);
86
87     commfiles(&file1, &file2);
88
89     cleanup(&file1);
90     cleanup(&file2);
91
92     return(0);
93 }
94
95
96 void initfile(FINFO *file, char *fn)
97 {
98     int fd;
99
100     if (strcmp(fn, "-") == 0)
101         fd = STDIN_FILENO;
102     else
103         if ((fd = open(fn, O_RDONLY)) == -1)
104             fatal(SYSERR, fn);
105
106     file->fd     = fd;
107     file->fn     = fn;
108     file->eof    = 0;
109     file->bufpos = 0;
110     file->eobuf  = 0;
111     file->linesz = LINESIZE;
112
113     if ((file->line = malloc(file->linesz)) == NULL)
114         fatal(APPERR, ENOMALLOC);
115 }
116
117
118 void cleanup(FINFO *file)
119 {
120     free(file->line);
121
122     if (strcmp(file->fn, "-") != 0 && close(file->fd) == -1)
123         fatal(SYSERR, file->fn);
124 }
125
126
127 void commfiles(FINFO *file1, FINFO *file2)
128 {
129     int cmp;
130
131     if (getline(file1) && getline(file2))
132         while(1)
133         {
134             cmp = strcoll(file1->line, file2->line);
135
136             if (cmp == 0)
137             {
138                 if (! opt3)
139                     printf("%s%s%s\n", (opt1 ? "" : "\t"), (opt2 ? "" : "\t"), file1->line);
140
141                 if ((getline(file1) + getline(file2)) < 2)
142                     break;
143             }
144
145             else if (cmp > 0)
146             {
147                 if (! opt2)
148                     printf("%s%s\n", (opt1 ? "" : "\t"), file2->line);
149
150                 if (! getline(file2))
151                     break;
152             }
153
154             else   /* cmp < 0 */
155             {
156                 if (! opt1)
157                     printf("%s\n", file1->line);
158
159                 if (! getline(file1))
160                     break;
161             }
162         }
163
164     while(! file1->eof && ! opt1)
165     {
166         printf("%s\n", file1->line);
167         getline(file1);
168     }
169
170     while(! file2->eof && ! opt2)
171     {
172         printf("%s%s\n", (opt1 ? "" : "\t"), file2->line);
173         getline(file2);
174     }
175 }
176
177
178 int getline(FINFO *file)
179 {
180     int success = 0;
181     size_t i = 0;
182
183     if (! file->eof)
184     {
185         while(1)
186         {
187             if (i == file->linesz)
188             {
189                 file->linesz = file->linesz + LINESIZE;
190                 if ((file->line = realloc(file->line, file->linesz)) == NULL)
191                     fatal(APPERR, ENOMALLOC);
192             }
193
194             if (file->bufpos >= file->eobuf)
195             {
196                 fillbuf(file);
197                 if (file->eof)
198                 {
199                     if (i > 0)
200                     {
201                         file->line[i] = '\0';
202                         success = 1;
203                     }
204                     break;
205                 }
206             }
207
208             if (file->buf[file->bufpos] == '\n')
209             {
210                 file->bufpos++;
211                 file->line[i] = '\0';
212                 success = 1;
213                 break;
214             }
215             else
216                 file->line[i++] = file->buf[file->bufpos++];
217         }
218     }
219
220     return(success);
221 }
222
223
224 void fillbuf(FINFO *file)
225 {
226     ssize_t n;
227
228     if (! file->eof)
229     {
230         if ((n = read(file->fd, file->buf, BUFSIZE)) < 0)
231             fatal(SYSERR, file->fn);
232
233         if (n == 0)
234             file->eof = 1;
235         else
236         {
237             file->bufpos = 0;
238             file->eobuf  = n;
239         }
240     }
241 }
242
243
244 void fatal(int errtype, char *s)
245 {
246     if (errtype == SYSERR)
247         fprintf(stderr, "comm: %s: %s\n", s, strerror(errno));
248     else
249         fprintf(stderr, "comm: %s\n", s);
250
251     exit(1);
252 }