1 /* comm -- compare two sorted files line by line.
2 Copyright (C) 1986, 1990-1991, 1995-2005, 2008-2010 Free Software
5 This program is free software: you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation, either version 3 of the License, or
8 (at your option) any later version.
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>. */
18 /* Written by Richard Stallman and David MacKenzie. */
23 #include <sys/types.h>
25 #include "linebuffer.h"
27 #include "hard-locale.h"
33 /* The official name of this program (e.g., no `g' prefix). */
34 #define PROGRAM_NAME "comm"
37 proper_name ("Richard M. Stallman"), \
38 proper_name ("David MacKenzie")
40 /* Undefine, to avoid warning about redefinition on some systems. */
42 #define min(x, y) ((x) < (y) ? (x) : (y))
44 /* True if the LC_COLLATE locale is hard. */
45 static bool hard_LC_COLLATE
;
47 /* If true, print lines that are found only in file 1. */
48 static bool only_file_1
;
50 /* If true, print lines that are found only in file 2. */
51 static bool only_file_2
;
53 /* If true, print lines that are found in both files. */
56 /* If nonzero, we have seen at least one unpairable line. */
57 static bool seen_unpairable
;
59 /* If nonzero, we have warned about disorder in that file. */
60 static bool issued_disorder_warning
[2];
62 /* If nonzero, check that the input is correctly ordered. */
70 /* Output columns will be delimited with this string, which may be set
71 on the command-line with --output-delimiter=STR. The default is a
72 single TAB character. */
73 static char const *delimiter
;
75 /* For long options that have no equivalent short option, use a
76 non-character as a pseudo short option, starting with CHAR_MAX + 1. */
79 CHECK_ORDER_OPTION
= CHAR_MAX
+ 1,
81 OUTPUT_DELIMITER_OPTION
84 static struct option
const long_options
[] =
86 {"check-order", no_argument
, NULL
, CHECK_ORDER_OPTION
},
87 {"nocheck-order", no_argument
, NULL
, NOCHECK_ORDER_OPTION
},
88 {"output-delimiter", required_argument
, NULL
, OUTPUT_DELIMITER_OPTION
},
89 {GETOPT_HELP_OPTION_DECL
},
90 {GETOPT_VERSION_OPTION_DECL
},
99 if (status
!= EXIT_SUCCESS
)
100 fprintf (stderr
, _("Try `%s --help' for more information.\n"),
105 Usage: %s [OPTION]... FILE1 FILE2\n\
109 Compare sorted files FILE1 and FILE2 line by line.\n\
113 With no options, produce three-column output. Column one contains\n\
114 lines unique to FILE1, column two contains lines unique to FILE2,\n\
115 and column three contains lines common to both files.\n\
119 -1 suppress column 1 (lines unique to FILE1)\n\
120 -2 suppress column 2 (lines unique to FILE2)\n\
121 -3 suppress column 3 (lines that appear in both files)\n\
125 --check-order check that the input is correctly sorted, even\n\
126 if all input lines are pairable\n\
127 --nocheck-order do not check that the input is correctly sorted\n\
130 --output-delimiter=STR separate columns with STR\n\
132 fputs (HELP_OPTION_DESCRIPTION
, stdout
);
133 fputs (VERSION_OPTION_DESCRIPTION
, stdout
);
136 Note, comparisons honor the rules specified by `LC_COLLATE'.\n\
141 %s -12 file1 file2 Print only lines present in both file1 and file2.\n\
142 %s -3 file1 file2 Print lines in file1 not in file2, and vice versa.\n\
144 program_name
, program_name
);
145 emit_ancillary_info ();
150 /* Output the line in linebuffer LINE to stream STREAM
151 provided the switches say it should be output.
152 CLASS is 1 for a line found only in file 1,
153 2 for a line only in file 2, 3 for a line in both. */
156 writeline (struct linebuffer
const *line
, FILE *stream
, int class)
168 /* Print a delimiter if we are printing lines from file 1. */
170 fputs (delimiter
, stream
);
176 /* Print a delimiter if we are printing lines from file 1. */
178 fputs (delimiter
, stream
);
179 /* Print a delimiter if we are printing lines from file 2. */
181 fputs (delimiter
, stream
);
185 fwrite (line
->buffer
, sizeof (char), line
->length
, stream
);
188 /* Check that successive input lines PREV and CURRENT from input file
189 WHATFILE are presented in order.
191 If the user specified --nocheck-order, the check is not made.
192 If the user specified --check-order, the problem is fatal.
193 Otherwise (the default), the message is simply a warning.
195 A message is printed at most once per input file.
197 This funtion was copied (nearly) verbatim from `src/join.c'. */
200 check_order (struct linebuffer
const *prev
,
201 struct linebuffer
const *current
,
205 if (check_input_order
!= CHECK_ORDER_DISABLED
206 && ((check_input_order
== CHECK_ORDER_ENABLED
) || seen_unpairable
))
208 if (!issued_disorder_warning
[whatfile
- 1])
213 order
= xmemcoll (prev
->buffer
, prev
->length
- 1,
214 current
->buffer
, current
->length
- 1);
216 order
= memcmp2 (prev
->buffer
, prev
->length
- 1,
217 current
->buffer
, current
->length
- 1);
221 error ((check_input_order
== CHECK_ORDER_ENABLED
223 0, _("file %d is not in sorted order"), whatfile
);
225 /* If we get to here, the message was just a warning, but we
226 want only to issue it once. */
227 issued_disorder_warning
[whatfile
- 1] = true;
233 /* Compare INFILES[0] and INFILES[1].
234 If either is "-", use the standard input for that file.
235 Assume that each input file is sorted;
236 merge them and output the result. */
239 compare_files (char **infiles
)
241 /* For each file, we have four linebuffers in lba. */
242 struct linebuffer lba
[2][4];
244 /* thisline[i] points to the linebuffer holding the next available line
245 in file i, or is NULL if there are no lines left in that file. */
246 struct linebuffer
*thisline
[2];
248 /* all_line[i][alt[i][0]] also points to the linebuffer holding the
249 current line in file i. We keep two buffers of history around so we
250 can look two lines back when we get to the end of a file. */
251 struct linebuffer
*all_line
[2][4];
253 /* This is used to rotate through the buffers for each input file. */
256 /* streams[i] holds the input stream for file i. */
261 /* Initialize the storage. */
262 for (i
= 0; i
< 2; i
++)
264 for (j
= 0; j
< 4; j
++)
266 initbuffer (&lba
[i
][j
]);
267 all_line
[i
][j
] = &lba
[i
][j
];
272 streams
[i
] = (STREQ (infiles
[i
], "-") ? stdin
: fopen (infiles
[i
], "r"));
274 error (EXIT_FAILURE
, errno
, "%s", infiles
[i
]);
276 thisline
[i
] = readlinebuffer (all_line
[i
][alt
[i
][0]], streams
[i
]);
277 if (ferror (streams
[i
]))
278 error (EXIT_FAILURE
, errno
, "%s", infiles
[i
]);
281 while (thisline
[0] || thisline
[1])
284 bool fill_up
[2] = { false, false };
286 /* Compare the next available lines of the two files. */
290 else if (!thisline
[1])
295 order
= xmemcoll (thisline
[0]->buffer
, thisline
[0]->length
- 1,
296 thisline
[1]->buffer
, thisline
[1]->length
- 1);
299 size_t len
= min (thisline
[0]->length
, thisline
[1]->length
) - 1;
300 order
= memcmp (thisline
[0]->buffer
, thisline
[1]->buffer
, len
);
302 order
= (thisline
[0]->length
< thisline
[1]->length
304 : thisline
[0]->length
!= thisline
[1]->length
);
308 /* Output the line that is lesser. */
310 writeline (thisline
[1], stdout
, 3);
313 seen_unpairable
= true;
315 writeline (thisline
[0], stdout
, 1);
317 writeline (thisline
[1], stdout
, 2);
320 /* Step the file the line came from.
321 If the files match, step both files. */
327 for (i
= 0; i
< 2; i
++)
330 /* Rotate the buffers for this file. */
331 alt
[i
][2] = alt
[i
][1];
332 alt
[i
][1] = alt
[i
][0];
333 alt
[i
][0] = (alt
[i
][0] + 1) & 0x03;
335 thisline
[i
] = readlinebuffer (all_line
[i
][alt
[i
][0]], streams
[i
]);
338 check_order (all_line
[i
][alt
[i
][1]], thisline
[i
], i
+ 1);
340 /* If this is the end of the file we may need to re-check
341 the order of the previous two lines, since we might have
342 discovered an unpairable match since we checked before. */
343 else if (all_line
[i
][alt
[i
][2]]->buffer
)
344 check_order (all_line
[i
][alt
[i
][2]],
345 all_line
[i
][alt
[i
][1]], i
+ 1);
347 if (ferror (streams
[i
]))
348 error (EXIT_FAILURE
, errno
, "%s", infiles
[i
]);
354 for (i
= 0; i
< 2; i
++)
355 if (fclose (streams
[i
]) != 0)
356 error (EXIT_FAILURE
, errno
, "%s", infiles
[i
]);
360 main (int argc
, char **argv
)
364 initialize_main (&argc
, &argv
);
365 set_program_name (argv
[0]);
366 setlocale (LC_ALL
, "");
367 bindtextdomain (PACKAGE
, LOCALEDIR
);
368 textdomain (PACKAGE
);
369 hard_LC_COLLATE
= hard_locale (LC_COLLATE
);
371 atexit (close_stdout
);
377 seen_unpairable
= false;
378 issued_disorder_warning
[0] = issued_disorder_warning
[1] = false;
379 check_input_order
= CHECK_ORDER_DEFAULT
;
381 while ((c
= getopt_long (argc
, argv
, "123", long_options
, NULL
)) != -1)
396 case NOCHECK_ORDER_OPTION
:
397 check_input_order
= CHECK_ORDER_DISABLED
;
400 case CHECK_ORDER_OPTION
:
401 check_input_order
= CHECK_ORDER_ENABLED
;
404 case OUTPUT_DELIMITER_OPTION
:
405 if (delimiter
&& !STREQ (delimiter
, optarg
))
406 error (EXIT_FAILURE
, 0, _("multiple delimiters specified"));
410 error (EXIT_FAILURE
, 0, _("empty %s not allowed"),
411 quote ("--output-delimiter"));
415 case_GETOPT_HELP_CHAR
;
417 case_GETOPT_VERSION_CHAR (PROGRAM_NAME
, AUTHORS
);
420 usage (EXIT_FAILURE
);
423 if (argc
- optind
< 2)
426 error (0, 0, _("missing operand"));
428 error (0, 0, _("missing operand after %s"), quote (argv
[argc
- 1]));
429 usage (EXIT_FAILURE
);
432 if (2 < argc
- optind
)
434 error (0, 0, _("extra operand %s"), quote (argv
[optind
+ 2]));
435 usage (EXIT_FAILURE
);
438 /* The default delimiter is a TAB. */
442 compare_files (argv
+ optind
);
444 if (issued_disorder_warning
[0] || issued_disorder_warning
[1])