2 * comm.c - select or reject lines common to two files
5 * Build: c89 -o comm comm.c
6 * Source: <http://pdcore.sourceforge.net/>
7 * Spec: <http://www.opengroup.org/onlinepubs/9699919799/utilities/comm.html>
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.
25 #define USAGE "usage: comm [-123] file1 file2\n"
26 #define ENOMALLOC "Unable to allocate memory for read buffer"
32 typedef struct { int fd;
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);
49 static int opt1, opt2, opt3;
52 int main(int argc, char **argv)
54 extern int optind, opterr;
58 setlocale(LC_ALL, "");
61 while ((c = getopt(argc, argv, "123")) != -1)
74 fprintf(stderr, USAGE);
84 initfile(&file1, argv[0]);
85 initfile(&file2, argv[1]);
87 commfiles(&file1, &file2);
96 void initfile(FINFO *file, char *fn)
100 if (strcmp(fn, "-") == 0)
103 if ((fd = open(fn, O_RDONLY)) == -1)
111 file->linesz = LINESIZE;
113 if ((file->line = malloc(file->linesz)) == NULL)
114 fatal(APPERR, ENOMALLOC);
118 void cleanup(FINFO *file)
122 if (strcmp(file->fn, "-") != 0 && close(file->fd) == -1)
123 fatal(SYSERR, file->fn);
127 void commfiles(FINFO *file1, FINFO *file2)
131 if (getline(file1) && getline(file2))
134 cmp = strcoll(file1->line, file2->line);
139 printf("%s%s%s\n", (opt1 ? "" : "\t"), (opt2 ? "" : "\t"), file1->line);
141 if ((getline(file1) + getline(file2)) < 2)
148 printf("%s%s\n", (opt1 ? "" : "\t"), file2->line);
150 if (! getline(file2))
157 printf("%s\n", file1->line);
159 if (! getline(file1))
164 while(! file1->eof && ! opt1)
166 printf("%s\n", file1->line);
170 while(! file2->eof && ! opt2)
172 printf("%s%s\n", (opt1 ? "" : "\t"), file2->line);
178 int getline(FINFO *file)
187 if (i == file->linesz)
189 file->linesz = file->linesz + LINESIZE;
190 if ((file->line = realloc(file->line, file->linesz)) == NULL)
191 fatal(APPERR, ENOMALLOC);
194 if (file->bufpos >= file->eobuf)
201 file->line[i] = '\0';
208 if (file->buf[file->bufpos] == '\n')
211 file->line[i] = '\0';
216 file->line[i++] = file->buf[file->bufpos++];
224 void fillbuf(FINFO *file)
230 if ((n = read(file->fd, file->buf, BUFSIZE)) < 0)
231 fatal(SYSERR, file->fn);
244 void fatal(int errtype, char *s)
246 if (errtype == SYSERR)
247 fprintf(stderr, "comm: %s: %s\n", s, strerror(errno));
249 fprintf(stderr, "comm: %s\n", s);