maint: make update-copyright handle more cases
[coreutils.git] / src / join.c
blob756a7be6e7c9c4bc2168e82f000c6932da0d5f26
1 /* join - join lines of two files on a common field
2 Copyright (C) 91, 1995-2006, 2008-2009 Free Software Foundation, Inc.
4 This program is free software: you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation, either version 3 of the License, or
7 (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program. If not, see <http://www.gnu.org/licenses/>.
17 Written by Mike Haertel, mike@gnu.ai.mit.edu. */
19 #include <config.h>
21 #include <assert.h>
22 #include <sys/types.h>
23 #include <getopt.h>
25 #include "system.h"
26 #include "error.h"
27 #include "linebuffer.h"
28 #include "memcasecmp.h"
29 #include "quote.h"
30 #include "stdio--.h"
31 #include "xmemcoll.h"
32 #include "xstrtol.h"
33 #include "argmatch.h"
35 /* The official name of this program (e.g., no `g' prefix). */
36 #define PROGRAM_NAME "join"
38 #define AUTHORS proper_name ("Mike Haertel")
40 #define join system_join
42 #define SWAPLINES(a, b) do { \
43 struct line *tmp = a; \
44 a = b; \
45 b = tmp; \
46 } while (0);
48 /* An element of the list identifying which fields to print for each
49 output line. */
50 struct outlist
52 /* File number: 0, 1, or 2. 0 means use the join field.
53 1 means use the first file argument, 2 the second. */
54 int file;
56 /* Field index (zero-based), specified only when FILE is 1 or 2. */
57 size_t field;
59 struct outlist *next;
62 /* A field of a line. */
63 struct field
65 char *beg; /* First character in field. */
66 size_t len; /* The length of the field. */
69 /* A line read from an input file. */
70 struct line
72 struct linebuffer buf; /* The line itself. */
73 size_t nfields; /* Number of elements in `fields'. */
74 size_t nfields_allocated; /* Number of elements allocated for `fields'. */
75 struct field *fields;
78 /* One or more consecutive lines read from a file that all have the
79 same join field value. */
80 struct seq
82 size_t count; /* Elements used in `lines'. */
83 size_t alloc; /* Elements allocated in `lines'. */
84 struct line **lines;
87 /* The previous line read from each file. */
88 static struct line *prevline[2] = {NULL, NULL};
90 /* This provides an extra line buffer for each file. We need these if we
91 try to read two consecutive lines into the same buffer, since we don't
92 want to overwrite the previous buffer before we check order. */
93 static struct line *spareline[2] = {NULL, NULL};
95 /* True if the LC_COLLATE locale is hard. */
96 static bool hard_LC_COLLATE;
98 /* If nonzero, print unpairable lines in file 1 or 2. */
99 static bool print_unpairables_1, print_unpairables_2;
101 /* If nonzero, print pairable lines. */
102 static bool print_pairables;
104 /* If nonzero, we have seen at least one unpairable line. */
105 static bool seen_unpairable;
107 /* If nonzero, we have warned about disorder in that file. */
108 static bool issued_disorder_warning[2];
110 /* Empty output field filler. */
111 static char const *empty_filler;
113 /* Field to join on; SIZE_MAX means they haven't been determined yet. */
114 static size_t join_field_1 = SIZE_MAX;
115 static size_t join_field_2 = SIZE_MAX;
117 /* List of fields to print. */
118 static struct outlist outlist_head;
120 /* Last element in `outlist', where a new element can be added. */
121 static struct outlist *outlist_end = &outlist_head;
123 /* Tab character separating fields. If negative, fields are separated
124 by any nonempty string of blanks, otherwise by exactly one
125 tab character whose value (when cast to unsigned char) equals TAB. */
126 static int tab = -1;
128 /* If nonzero, check that the input is correctly ordered. */
129 static enum
131 CHECK_ORDER_DEFAULT,
132 CHECK_ORDER_ENABLED,
133 CHECK_ORDER_DISABLED
134 } check_input_order;
136 enum
138 CHECK_ORDER_OPTION = CHAR_MAX + 1,
139 NOCHECK_ORDER_OPTION
143 static struct option const longopts[] =
145 {"ignore-case", no_argument, NULL, 'i'},
146 {"check-order", no_argument, NULL, CHECK_ORDER_OPTION},
147 {"nocheck-order", no_argument, NULL, NOCHECK_ORDER_OPTION},
148 {GETOPT_HELP_OPTION_DECL},
149 {GETOPT_VERSION_OPTION_DECL},
150 {NULL, 0, NULL, 0}
153 /* Used to print non-joining lines */
154 static struct line uni_blank;
156 /* If nonzero, ignore case when comparing join fields. */
157 static bool ignore_case;
159 void
160 usage (int status)
162 if (status != EXIT_SUCCESS)
163 fprintf (stderr, _("Try `%s --help' for more information.\n"),
164 program_name);
165 else
167 printf (_("\
168 Usage: %s [OPTION]... FILE1 FILE2\n\
170 program_name);
171 fputs (_("\
172 For each pair of input lines with identical join fields, write a line to\n\
173 standard output. The default join field is the first, delimited\n\
174 by whitespace. When FILE1 or FILE2 (not both) is -, read standard input.\n\
176 -a FILENUM print unpairable lines coming from file FILENUM, where\n\
177 FILENUM is 1 or 2, corresponding to FILE1 or FILE2\n\
178 -e EMPTY replace missing input fields with EMPTY\n\
179 "), stdout);
180 fputs (_("\
181 -i, --ignore-case ignore differences in case when comparing fields\n\
182 -j FIELD equivalent to `-1 FIELD -2 FIELD'\n\
183 -o FORMAT obey FORMAT while constructing output line\n\
184 -t CHAR use CHAR as input and output field separator\n\
185 "), stdout);
186 fputs (_("\
187 -v FILENUM like -a FILENUM, but suppress joined output lines\n\
188 -1 FIELD join on this FIELD of file 1\n\
189 -2 FIELD join on this FIELD of file 2\n\
190 --check-order check that the input is correctly sorted, even\n\
191 if all input lines are pairable\n\
192 --nocheck-order do not check that the input is correctly sorted\n\
193 "), stdout);
194 fputs (HELP_OPTION_DESCRIPTION, stdout);
195 fputs (VERSION_OPTION_DESCRIPTION, stdout);
196 fputs (_("\
198 Unless -t CHAR is given, leading blanks separate fields and are ignored,\n\
199 else fields are separated by CHAR. Any FIELD is a field number counted\n\
200 from 1. FORMAT is one or more comma or blank separated specifications,\n\
201 each being `FILENUM.FIELD' or `0'. Default FORMAT outputs the join field,\n\
202 the remaining fields from FILE1, the remaining fields from FILE2, all\n\
203 separated by CHAR.\n\
205 Important: FILE1 and FILE2 must be sorted on the join fields.\n\
206 E.g., use `sort -k 1b,1' if `join' has no options.\n\
207 Note, comparisons honor the rules specified by `LC_COLLATE'.\n\
208 If the input is not sorted and some lines cannot be joined, a\n\
209 warning message will be given.\n\
210 "), stdout);
211 emit_bug_reporting_address ();
213 exit (status);
216 /* Record a field in LINE, with location FIELD and size LEN. */
218 static void
219 extract_field (struct line *line, char *field, size_t len)
221 if (line->nfields >= line->nfields_allocated)
223 line->fields = X2NREALLOC (line->fields, &line->nfields_allocated);
225 line->fields[line->nfields].beg = field;
226 line->fields[line->nfields].len = len;
227 ++(line->nfields);
230 /* Fill in the `fields' structure in LINE. */
232 static void
233 xfields (struct line *line)
235 char *ptr = line->buf.buffer;
236 char const *lim = ptr + line->buf.length - 1;
238 if (ptr == lim)
239 return;
241 if (0 <= tab)
243 char *sep;
244 for (; (sep = memchr (ptr, tab, lim - ptr)) != NULL; ptr = sep + 1)
245 extract_field (line, ptr, sep - ptr);
247 else
249 /* Skip leading blanks before the first field. */
250 while (isblank (to_uchar (*ptr)))
251 if (++ptr == lim)
252 return;
256 char *sep;
257 for (sep = ptr + 1; sep != lim && ! isblank (to_uchar (*sep)); sep++)
258 continue;
259 extract_field (line, ptr, sep - ptr);
260 if (sep == lim)
261 return;
262 for (ptr = sep + 1; ptr != lim && isblank (to_uchar (*ptr)); ptr++)
263 continue;
265 while (ptr != lim);
268 extract_field (line, ptr, lim - ptr);
271 static void
272 freeline (struct line *line)
274 free (line->fields);
275 free (line->buf.buffer);
276 line->buf.buffer = NULL;
279 /* Return <0 if the join field in LINE1 compares less than the one in LINE2;
280 >0 if it compares greater; 0 if it compares equal.
281 Report an error and exit if the comparison fails.
282 Use join fields JF_1 and JF_2 respectively. */
284 static int
285 keycmp (struct line const *line1, struct line const *line2,
286 size_t jf_1, size_t jf_2)
288 /* Start of field to compare in each file. */
289 char *beg1;
290 char *beg2;
292 size_t len1;
293 size_t len2; /* Length of fields to compare. */
294 int diff;
296 if (jf_1 < line1->nfields)
298 beg1 = line1->fields[jf_1].beg;
299 len1 = line1->fields[jf_1].len;
301 else
303 beg1 = NULL;
304 len1 = 0;
307 if (jf_2 < line2->nfields)
309 beg2 = line2->fields[jf_2].beg;
310 len2 = line2->fields[jf_2].len;
312 else
314 beg2 = NULL;
315 len2 = 0;
318 if (len1 == 0)
319 return len2 == 0 ? 0 : -1;
320 if (len2 == 0)
321 return 1;
323 if (ignore_case)
325 /* FIXME: ignore_case does not work with NLS (in particular,
326 with multibyte chars). */
327 diff = memcasecmp (beg1, beg2, MIN (len1, len2));
329 else
331 if (hard_LC_COLLATE)
332 return xmemcoll (beg1, len1, beg2, len2);
333 diff = memcmp (beg1, beg2, MIN (len1, len2));
336 if (diff)
337 return diff;
338 return len1 < len2 ? -1 : len1 != len2;
341 /* Check that successive input lines PREV and CURRENT from input file
342 WHATFILE are presented in order, unless the user may be relying on
343 the GNU extension that input lines may be out of order if no input
344 lines are unpairable.
346 If the user specified --nocheck-order, the check is not made.
347 If the user specified --check-order, the problem is fatal.
348 Otherwise (the default), the message is simply a warning.
350 A message is printed at most once per input file. */
352 static void
353 check_order (const struct line *prev,
354 const struct line *current,
355 int whatfile)
357 if (check_input_order != CHECK_ORDER_DISABLED
358 && ((check_input_order == CHECK_ORDER_ENABLED) || seen_unpairable))
360 if (!issued_disorder_warning[whatfile-1])
362 size_t join_field = whatfile == 1 ? join_field_1 : join_field_2;
363 if (keycmp (prev, current, join_field, join_field) > 0)
365 error ((check_input_order == CHECK_ORDER_ENABLED
366 ? EXIT_FAILURE : 0),
367 0, _("file %d is not in sorted order"), whatfile);
369 /* If we get to here, the message was just a warning, but we
370 want only to issue it once. */
371 issued_disorder_warning[whatfile-1] = true;
377 static inline void
378 reset_line (struct line *line)
380 line->nfields = 0;
383 static struct line *
384 init_linep (struct line **linep)
386 struct line *line = xmalloc (sizeof *line);
387 memset (line, '\0', sizeof *line);
388 *linep = line;
389 return line;
392 /* Read a line from FP into LINE and split it into fields.
393 Return true if successful. */
395 static bool
396 get_line (FILE *fp, struct line **linep, int which)
398 struct line *line = *linep;
400 if (line == prevline[which - 1])
402 SWAPLINES (line, spareline[which - 1]);
403 *linep = line;
406 if (line)
407 reset_line (line);
408 else
409 line = init_linep (linep);
411 if (! readlinebuffer (&line->buf, fp))
413 if (ferror (fp))
414 error (EXIT_FAILURE, errno, _("read error"));
415 freeline (line);
416 return false;
419 xfields (line);
421 if (prevline[which - 1])
422 check_order (prevline[which - 1], line, which);
424 prevline[which - 1] = line;
425 return true;
428 static void
429 free_spareline (void)
431 size_t i;
433 for (i = 0; i < ARRAY_CARDINALITY (spareline); i++)
435 if (spareline[i])
437 freeline (spareline[i]);
438 free (spareline[i]);
443 static void
444 initseq (struct seq *seq)
446 seq->count = 0;
447 seq->alloc = 0;
448 seq->lines = NULL;
451 /* Read a line from FP and add it to SEQ. Return true if successful. */
453 static bool
454 getseq (FILE *fp, struct seq *seq, int whichfile)
456 if (seq->count == seq->alloc)
458 size_t i;
459 seq->lines = X2NREALLOC (seq->lines, &seq->alloc);
460 for (i = seq->count; i < seq->alloc; i++)
461 seq->lines[i] = NULL;
464 if (get_line (fp, &seq->lines[seq->count], whichfile))
466 ++seq->count;
467 return true;
469 return false;
472 /* Read a line from FP and add it to SEQ, as the first item if FIRST is
473 true, else as the next. */
474 static bool
475 advance_seq (FILE *fp, struct seq *seq, bool first, int whichfile)
477 if (first)
478 seq->count = 0;
480 return getseq (fp, seq, whichfile);
483 static void
484 delseq (struct seq *seq)
486 size_t i;
487 for (i = 0; i < seq->alloc; i++)
488 if (seq->lines[i])
490 if (seq->lines[i]->buf.buffer)
491 freeline (seq->lines[i]);
492 free (seq->lines[i]);
494 free (seq->lines);
498 /* Print field N of LINE if it exists and is nonempty, otherwise
499 `empty_filler' if it is nonempty. */
501 static void
502 prfield (size_t n, struct line const *line)
504 size_t len;
506 if (n < line->nfields)
508 len = line->fields[n].len;
509 if (len)
510 fwrite (line->fields[n].beg, 1, len, stdout);
511 else if (empty_filler)
512 fputs (empty_filler, stdout);
514 else if (empty_filler)
515 fputs (empty_filler, stdout);
518 /* Print the join of LINE1 and LINE2. */
520 static void
521 prjoin (struct line const *line1, struct line const *line2)
523 const struct outlist *outlist;
524 char output_separator = tab < 0 ? ' ' : tab;
526 outlist = outlist_head.next;
527 if (outlist)
529 const struct outlist *o;
531 o = outlist;
532 while (1)
534 size_t field;
535 struct line const *line;
537 if (o->file == 0)
539 if (line1 == &uni_blank)
541 line = line2;
542 field = join_field_2;
544 else
546 line = line1;
547 field = join_field_1;
550 else
552 line = (o->file == 1 ? line1 : line2);
553 field = o->field;
555 prfield (field, line);
556 o = o->next;
557 if (o == NULL)
558 break;
559 putchar (output_separator);
561 putchar ('\n');
563 else
565 size_t i;
567 if (line1 == &uni_blank)
569 struct line const *t;
570 t = line1;
571 line1 = line2;
572 line2 = t;
574 prfield (join_field_1, line1);
575 for (i = 0; i < join_field_1 && i < line1->nfields; ++i)
577 putchar (output_separator);
578 prfield (i, line1);
580 for (i = join_field_1 + 1; i < line1->nfields; ++i)
582 putchar (output_separator);
583 prfield (i, line1);
586 for (i = 0; i < join_field_2 && i < line2->nfields; ++i)
588 putchar (output_separator);
589 prfield (i, line2);
591 for (i = join_field_2 + 1; i < line2->nfields; ++i)
593 putchar (output_separator);
594 prfield (i, line2);
596 putchar ('\n');
600 /* Print the join of the files in FP1 and FP2. */
602 static void
603 join (FILE *fp1, FILE *fp2)
605 struct seq seq1, seq2;
606 struct line **linep = xmalloc (sizeof *linep);
607 int diff;
608 bool eof1, eof2, checktail;
610 *linep = NULL;
612 /* Read the first line of each file. */
613 initseq (&seq1);
614 getseq (fp1, &seq1, 1);
615 initseq (&seq2);
616 getseq (fp2, &seq2, 2);
618 while (seq1.count && seq2.count)
620 size_t i;
621 diff = keycmp (seq1.lines[0], seq2.lines[0],
622 join_field_1, join_field_2);
623 if (diff < 0)
625 if (print_unpairables_1)
626 prjoin (seq1.lines[0], &uni_blank);
627 advance_seq (fp1, &seq1, true, 1);
628 seen_unpairable = true;
629 continue;
631 if (diff > 0)
633 if (print_unpairables_2)
634 prjoin (&uni_blank, seq2.lines[0]);
635 advance_seq (fp2, &seq2, true, 2);
636 seen_unpairable = true;
637 continue;
640 /* Keep reading lines from file1 as long as they continue to
641 match the current line from file2. */
642 eof1 = false;
644 if (!advance_seq (fp1, &seq1, false, 1))
646 eof1 = true;
647 ++seq1.count;
648 break;
650 while (!keycmp (seq1.lines[seq1.count - 1], seq2.lines[0],
651 join_field_1, join_field_2));
653 /* Keep reading lines from file2 as long as they continue to
654 match the current line from file1. */
655 eof2 = false;
657 if (!advance_seq (fp2, &seq2, false, 2))
659 eof2 = true;
660 ++seq2.count;
661 break;
663 while (!keycmp (seq1.lines[0], seq2.lines[seq2.count - 1],
664 join_field_1, join_field_2));
666 if (print_pairables)
668 for (i = 0; i < seq1.count - 1; ++i)
670 size_t j;
671 for (j = 0; j < seq2.count - 1; ++j)
672 prjoin (seq1.lines[i], seq2.lines[j]);
676 if (!eof1)
678 SWAPLINES (seq1.lines[0], seq1.lines[seq1.count - 1]);
679 seq1.count = 1;
681 else
682 seq1.count = 0;
684 if (!eof2)
686 SWAPLINES (seq2.lines[0], seq2.lines[seq2.count - 1]);
687 seq2.count = 1;
689 else
690 seq2.count = 0;
693 /* If the user did not specify --check-order, and the we read the
694 tail ends of both inputs to verify that they are in order. We
695 skip the rest of the tail once we have issued a warning for that
696 file, unless we actually need to print the unpairable lines. */
697 if (check_input_order != CHECK_ORDER_DISABLED
698 && !(issued_disorder_warning[0] && issued_disorder_warning[1]))
699 checktail = true;
700 else
701 checktail = false;
703 if ((print_unpairables_1 || checktail) && seq1.count)
705 if (print_unpairables_1)
706 prjoin (seq1.lines[0], &uni_blank);
707 seen_unpairable = true;
708 while (get_line (fp1, linep, 1))
710 if (print_unpairables_1)
711 prjoin (*linep, &uni_blank);
712 if (issued_disorder_warning[0] && !print_unpairables_1)
713 break;
717 if ((print_unpairables_2 || checktail) && seq2.count)
719 if (print_unpairables_2)
720 prjoin (&uni_blank, seq2.lines[0]);
721 seen_unpairable = true;
722 while (get_line (fp2, linep, 2))
724 if (print_unpairables_2)
725 prjoin (&uni_blank, *linep);
726 if (issued_disorder_warning[1] && !print_unpairables_2)
727 break;
731 free (*linep);
733 free (linep);
734 delseq (&seq1);
735 delseq (&seq2);
738 /* Add a field spec for field FIELD of file FILE to `outlist'. */
740 static void
741 add_field (int file, size_t field)
743 struct outlist *o;
745 assert (file == 0 || file == 1 || file == 2);
746 assert (file != 0 || field == 0);
748 o = xmalloc (sizeof *o);
749 o->file = file;
750 o->field = field;
751 o->next = NULL;
753 /* Add to the end of the list so the fields are in the right order. */
754 outlist_end->next = o;
755 outlist_end = o;
758 /* Convert a string of decimal digits, STR (the 1-based join field number),
759 to an integral value. Upon successful conversion, return one less
760 (the zero-based field number). Silently convert too-large values
761 to SIZE_MAX - 1. Otherwise, if a value cannot be converted, give a
762 diagnostic and exit. */
764 static size_t
765 string_to_join_field (char const *str)
767 size_t result;
768 unsigned long int val;
769 verify (SIZE_MAX <= ULONG_MAX);
771 strtol_error s_err = xstrtoul (str, NULL, 10, &val, "");
772 if (s_err == LONGINT_OVERFLOW || (s_err == LONGINT_OK && SIZE_MAX < val))
773 val = SIZE_MAX;
774 else if (s_err != LONGINT_OK || val == 0)
775 error (EXIT_FAILURE, 0, _("invalid field number: %s"), quote (str));
777 result = val - 1;
779 return result;
782 /* Convert a single field specifier string, S, to a *FILE_INDEX, *FIELD_INDEX
783 pair. In S, the field index string is 1-based; *FIELD_INDEX is zero-based.
784 If S is valid, return true. Otherwise, give a diagnostic and exit. */
786 static void
787 decode_field_spec (const char *s, int *file_index, size_t *field_index)
789 /* The first character must be 0, 1, or 2. */
790 switch (s[0])
792 case '0':
793 if (s[1])
795 /* `0' must be all alone -- no `.FIELD'. */
796 error (EXIT_FAILURE, 0, _("invalid field specifier: %s"), quote (s));
798 *file_index = 0;
799 *field_index = 0;
800 break;
802 case '1':
803 case '2':
804 if (s[1] != '.')
805 error (EXIT_FAILURE, 0, _("invalid field specifier: %s"), quote (s));
806 *file_index = s[0] - '0';
807 *field_index = string_to_join_field (s + 2);
808 break;
810 default:
811 error (EXIT_FAILURE, 0,
812 _("invalid file number in field spec: %s"), quote (s));
814 /* Tell gcc -W -Wall that we can't get beyond this point.
815 This avoids a warning (otherwise legit) that the caller's copies
816 of *file_index and *field_index might be used uninitialized. */
817 abort ();
819 break;
823 /* Add the comma or blank separated field spec(s) in STR to `outlist'. */
825 static void
826 add_field_list (char *str)
828 char *p = str;
832 int file_index;
833 size_t field_index;
834 char const *spec_item = p;
836 p = strpbrk (p, ", \t");
837 if (p)
838 *p++ = '\0';
839 decode_field_spec (spec_item, &file_index, &field_index);
840 add_field (file_index, field_index);
842 while (p);
845 /* Set the join field *VAR to VAL, but report an error if *VAR is set
846 more than once to incompatible values. */
848 static void
849 set_join_field (size_t *var, size_t val)
851 if (*var != SIZE_MAX && *var != val)
853 unsigned long int var1 = *var + 1;
854 unsigned long int val1 = val + 1;
855 error (EXIT_FAILURE, 0, _("incompatible join fields %lu, %lu"),
856 var1, val1);
858 *var = val;
861 /* Status of command-line arguments. */
863 enum operand_status
865 /* This argument must be an operand, i.e., one of the files to be
866 joined. */
867 MUST_BE_OPERAND,
869 /* This might be the argument of the preceding -j1 or -j2 option,
870 or it might be an operand. */
871 MIGHT_BE_J1_ARG,
872 MIGHT_BE_J2_ARG,
874 /* This might be the argument of the preceding -o option, or it might be
875 an operand. */
876 MIGHT_BE_O_ARG
879 /* Add NAME to the array of input file NAMES with operand statuses
880 OPERAND_STATUS; currently there are NFILES names in the list. */
882 static void
883 add_file_name (char *name, char *names[2],
884 int operand_status[2], int joption_count[2], int *nfiles,
885 int *prev_optc_status, int *optc_status)
887 int n = *nfiles;
889 if (n == 2)
891 bool op0 = (operand_status[0] == MUST_BE_OPERAND);
892 char *arg = names[op0];
893 switch (operand_status[op0])
895 case MUST_BE_OPERAND:
896 error (0, 0, _("extra operand %s"), quote (name));
897 usage (EXIT_FAILURE);
899 case MIGHT_BE_J1_ARG:
900 joption_count[0]--;
901 set_join_field (&join_field_1, string_to_join_field (arg));
902 break;
904 case MIGHT_BE_J2_ARG:
905 joption_count[1]--;
906 set_join_field (&join_field_2, string_to_join_field (arg));
907 break;
909 case MIGHT_BE_O_ARG:
910 add_field_list (arg);
911 break;
913 if (!op0)
915 operand_status[0] = operand_status[1];
916 names[0] = names[1];
918 n = 1;
921 operand_status[n] = *prev_optc_status;
922 names[n] = name;
923 *nfiles = n + 1;
924 if (*prev_optc_status == MIGHT_BE_O_ARG)
925 *optc_status = MIGHT_BE_O_ARG;
929 main (int argc, char **argv)
931 int optc_status;
932 int prev_optc_status = MUST_BE_OPERAND;
933 int operand_status[2];
934 int joption_count[2] = { 0, 0 };
935 char *names[2];
936 FILE *fp1, *fp2;
937 int optc;
938 int nfiles = 0;
939 int i;
941 initialize_main (&argc, &argv);
942 set_program_name (argv[0]);
943 setlocale (LC_ALL, "");
944 bindtextdomain (PACKAGE, LOCALEDIR);
945 textdomain (PACKAGE);
946 hard_LC_COLLATE = hard_locale (LC_COLLATE);
948 atexit (close_stdout);
949 atexit (free_spareline);
951 print_pairables = true;
952 seen_unpairable = false;
953 issued_disorder_warning[0] = issued_disorder_warning[1] = false;
954 check_input_order = CHECK_ORDER_DEFAULT;
956 while ((optc = getopt_long (argc, argv, "-a:e:i1:2:j:o:t:v:",
957 longopts, NULL))
958 != -1)
960 optc_status = MUST_BE_OPERAND;
962 switch (optc)
964 case 'v':
965 print_pairables = false;
966 /* Fall through. */
968 case 'a':
970 unsigned long int val;
971 if (xstrtoul (optarg, NULL, 10, &val, "") != LONGINT_OK
972 || (val != 1 && val != 2))
973 error (EXIT_FAILURE, 0,
974 _("invalid field number: %s"), quote (optarg));
975 if (val == 1)
976 print_unpairables_1 = true;
977 else
978 print_unpairables_2 = true;
980 break;
982 case 'e':
983 if (empty_filler && ! STREQ (empty_filler, optarg))
984 error (EXIT_FAILURE, 0,
985 _("conflicting empty-field replacement strings"));
986 empty_filler = optarg;
987 break;
989 case 'i':
990 ignore_case = true;
991 break;
993 case '1':
994 set_join_field (&join_field_1, string_to_join_field (optarg));
995 break;
997 case '2':
998 set_join_field (&join_field_2, string_to_join_field (optarg));
999 break;
1001 case 'j':
1002 if ((optarg[0] == '1' || optarg[0] == '2') && !optarg[1]
1003 && optarg == argv[optind - 1] + 2)
1005 /* The argument was either "-j1" or "-j2". */
1006 bool is_j2 = (optarg[0] == '2');
1007 joption_count[is_j2]++;
1008 optc_status = MIGHT_BE_J1_ARG + is_j2;
1010 else
1012 set_join_field (&join_field_1, string_to_join_field (optarg));
1013 set_join_field (&join_field_2, join_field_1);
1015 break;
1017 case 'o':
1018 add_field_list (optarg);
1019 optc_status = MIGHT_BE_O_ARG;
1020 break;
1022 case 't':
1024 unsigned char newtab = optarg[0];
1025 if (! newtab)
1026 error (EXIT_FAILURE, 0, _("empty tab"));
1027 if (optarg[1])
1029 if (STREQ (optarg, "\\0"))
1030 newtab = '\0';
1031 else
1032 error (EXIT_FAILURE, 0, _("multi-character tab %s"),
1033 quote (optarg));
1035 if (0 <= tab && tab != newtab)
1036 error (EXIT_FAILURE, 0, _("incompatible tabs"));
1037 tab = newtab;
1039 break;
1041 case NOCHECK_ORDER_OPTION:
1042 check_input_order = CHECK_ORDER_DISABLED;
1043 break;
1045 case CHECK_ORDER_OPTION:
1046 check_input_order = CHECK_ORDER_ENABLED;
1047 break;
1049 case 1: /* Non-option argument. */
1050 add_file_name (optarg, names, operand_status, joption_count,
1051 &nfiles, &prev_optc_status, &optc_status);
1052 break;
1054 case_GETOPT_HELP_CHAR;
1056 case_GETOPT_VERSION_CHAR (PROGRAM_NAME, AUTHORS);
1058 default:
1059 usage (EXIT_FAILURE);
1062 prev_optc_status = optc_status;
1065 /* Process any operands after "--". */
1066 prev_optc_status = MUST_BE_OPERAND;
1067 while (optind < argc)
1068 add_file_name (argv[optind++], names, operand_status, joption_count,
1069 &nfiles, &prev_optc_status, &optc_status);
1071 if (nfiles != 2)
1073 if (nfiles == 0)
1074 error (0, 0, _("missing operand"));
1075 else
1076 error (0, 0, _("missing operand after %s"), quote (argv[argc - 1]));
1077 usage (EXIT_FAILURE);
1080 /* If "-j1" was specified and it turns out not to have had an argument,
1081 treat it as "-j 1". Likewise for -j2. */
1082 for (i = 0; i < 2; i++)
1083 if (joption_count[i] != 0)
1085 set_join_field (&join_field_1, i);
1086 set_join_field (&join_field_2, i);
1089 if (join_field_1 == SIZE_MAX)
1090 join_field_1 = 0;
1091 if (join_field_2 == SIZE_MAX)
1092 join_field_2 = 0;
1094 fp1 = STREQ (names[0], "-") ? stdin : fopen (names[0], "r");
1095 if (!fp1)
1096 error (EXIT_FAILURE, errno, "%s", names[0]);
1097 fp2 = STREQ (names[1], "-") ? stdin : fopen (names[1], "r");
1098 if (!fp2)
1099 error (EXIT_FAILURE, errno, "%s", names[1]);
1100 if (fp1 == fp2)
1101 error (EXIT_FAILURE, errno, _("both files cannot be standard input"));
1102 join (fp1, fp2);
1104 if (fclose (fp1) != 0)
1105 error (EXIT_FAILURE, errno, "%s", names[0]);
1106 if (fclose (fp2) != 0)
1107 error (EXIT_FAILURE, errno, "%s", names[1]);
1109 if (issued_disorder_warning[0] || issued_disorder_warning[1])
1110 exit (EXIT_FAILURE);
1111 else
1112 exit (EXIT_SUCCESS);