comm: almost total rewrite; add testsuite
[oweals/busybox.git] / coreutils / comm.c
1 /* vi: set sw=4 ts=4: */
2 /*
3  * Mini comm implementation for busybox
4  *
5  * Copyright (C) 2005 by Robert Sullivan <cogito.ergo.cogito@gmail.com>
6  *
7  * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
8  */
9
10 #include "libbb.h"
11
12 #define COMM_OPT_1 (1 << 0)
13 #define COMM_OPT_2 (1 << 1)
14 #define COMM_OPT_3 (1 << 2)
15
16 /* writeline outputs the input given, appropriately aligned according to class */
17 static void writeline(char *line, int class)
18 {
19         int flags = option_mask32;
20         if (class == 0) {
21                 if (flags & COMM_OPT_1)
22                         return;
23         } else if (class == 1) {
24                 if (flags & COMM_OPT_2)
25                         return;
26                 if (!(flags & COMM_OPT_1))
27                         putchar('\t');
28         } else /*if (class == 2)*/ {
29                 if (flags & COMM_OPT_3)
30                         return;
31                 if (!(flags & COMM_OPT_1))
32                         putchar('\t');
33                 if (!(flags & COMM_OPT_2))
34                         putchar('\t');
35         }
36         puts(line);
37 }
38
39 int comm_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
40 int comm_main(int argc UNUSED_PARAM, char **argv)
41 {
42         char *thisline[2];
43         FILE *stream[2];
44         int i;
45         int order;
46
47         opt_complementary = "=2";
48         getopt32(argv, "123");
49         argv += optind;
50
51         for (i = 0; i < 2; ++i) {
52                 stream[i] = xfopen_stdin(argv[i]);
53         }
54
55         order = 0;
56         thisline[1] = thisline[0] = NULL;
57         while (1) {
58                 if (order <= 0) {
59                         free(thisline[0]);
60                         thisline[0] = xmalloc_fgetline(stream[0]);
61                 }
62                 if (order >= 0) {
63                         free(thisline[1]);
64                         thisline[1] = xmalloc_fgetline(stream[1]);
65                 }
66
67                 i = !thisline[0] + (!thisline[1] << 1);
68                 if (i)
69                         break;
70                 order = strcmp(thisline[0], thisline[1]);
71
72                 if (order >= 0)
73                         writeline(thisline[1], order ? 1 : 2);
74                 else
75                         writeline(thisline[0], 0);
76         }
77
78         /* EOF at least on one of the streams */
79         i &= 1;
80         if (thisline[i]) {
81                 /* stream[i] is not at EOF yet */
82                 /* we did not print thisline[i] yet */
83                 char *p = thisline[i];
84                 writeline(p, i);
85                 while (1) {
86                         free(p);
87                         p = xmalloc_fgetline(stream[i]);
88                         if (!p)
89                                 break;
90                         writeline(p, i);
91                 }
92         }
93
94         if (ENABLE_FEATURE_CLEAN_UP) {
95                 fclose(stream[0]);
96                 fclose(stream[1]);
97         }
98
99         return EXIT_SUCCESS;
100 }