id: fix infinite loop on some systems
[coreutils/ericb.git] / src / join.c
blob992a357b1775a1838ae5aa7f13169acb2e9cc630
1 /* join - join lines of two files on a common field
2 Copyright (C) 91, 1995-2006, 2008 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 If the input is not sorted and some lines cannot be joined, a\n\
208 warning message will be given.\n\
209 "), stdout);
210 emit_bug_reporting_address ();
212 exit (status);
215 /* Record a field in LINE, with location FIELD and size LEN. */
217 static void
218 extract_field (struct line *line, char *field, size_t len)
220 if (line->nfields >= line->nfields_allocated)
222 line->fields = X2NREALLOC (line->fields, &line->nfields_allocated);
224 line->fields[line->nfields].beg = field;
225 line->fields[line->nfields].len = len;
226 ++(line->nfields);
229 /* Fill in the `fields' structure in LINE. */
231 static void
232 xfields (struct line *line)
234 char *ptr = line->buf.buffer;
235 char const *lim = ptr + line->buf.length - 1;
237 if (ptr == lim)
238 return;
240 if (0 <= tab)
242 char *sep;
243 for (; (sep = memchr (ptr, tab, lim - ptr)) != NULL; ptr = sep + 1)
244 extract_field (line, ptr, sep - ptr);
246 else
248 /* Skip leading blanks before the first field. */
249 while (isblank (to_uchar (*ptr)))
250 if (++ptr == lim)
251 return;
255 char *sep;
256 for (sep = ptr + 1; sep != lim && ! isblank (to_uchar (*sep)); sep++)
257 continue;
258 extract_field (line, ptr, sep - ptr);
259 if (sep == lim)
260 return;
261 for (ptr = sep + 1; ptr != lim && isblank (to_uchar (*ptr)); ptr++)
262 continue;
264 while (ptr != lim);
267 extract_field (line, ptr, lim - ptr);
270 static void
271 freeline (struct line *line)
273 free (line->fields);
274 free (line->buf.buffer);
275 line->buf.buffer = NULL;
278 /* Return <0 if the join field in LINE1 compares less than the one in LINE2;
279 >0 if it compares greater; 0 if it compares equal.
280 Report an error and exit if the comparison fails.
281 Use join fields JF_1 and JF_2 respectively. */
283 static int
284 keycmp (struct line const *line1, struct line const *line2,
285 size_t jf_1, size_t jf_2)
287 /* Start of field to compare in each file. */
288 char *beg1;
289 char *beg2;
291 size_t len1;
292 size_t len2; /* Length of fields to compare. */
293 int diff;
295 if (jf_1 < line1->nfields)
297 beg1 = line1->fields[jf_1].beg;
298 len1 = line1->fields[jf_1].len;
300 else
302 beg1 = NULL;
303 len1 = 0;
306 if (jf_2 < line2->nfields)
308 beg2 = line2->fields[jf_2].beg;
309 len2 = line2->fields[jf_2].len;
311 else
313 beg2 = NULL;
314 len2 = 0;
317 if (len1 == 0)
318 return len2 == 0 ? 0 : -1;
319 if (len2 == 0)
320 return 1;
322 if (ignore_case)
324 /* FIXME: ignore_case does not work with NLS (in particular,
325 with multibyte chars). */
326 diff = memcasecmp (beg1, beg2, MIN (len1, len2));
328 else
330 if (hard_LC_COLLATE)
331 return xmemcoll (beg1, len1, beg2, len2);
332 diff = memcmp (beg1, beg2, MIN (len1, len2));
335 if (diff)
336 return diff;
337 return len1 < len2 ? -1 : len1 != len2;
340 /* Check that successive input lines PREV and CURRENT from input file
341 WHATFILE are presented in order, unless the user may be relying on
342 the GNU extension that input lines may be out of order if no input
343 lines are unpairable.
345 If the user specified --nocheck-order, the check is not made.
346 If the user specified --check-order, the problem is fatal.
347 Otherwise (the default), the message is simply a warning.
349 A message is printed at most once per input file. */
351 static void
352 check_order (const struct line *prev,
353 const struct line *current,
354 int whatfile)
356 if (check_input_order != CHECK_ORDER_DISABLED
357 && ((check_input_order == CHECK_ORDER_ENABLED) || seen_unpairable))
359 if (!issued_disorder_warning[whatfile-1])
361 size_t join_field = whatfile == 1 ? join_field_1 : join_field_2;
362 if (keycmp (prev, current, join_field, join_field) > 0)
364 error ((check_input_order == CHECK_ORDER_ENABLED
365 ? EXIT_FAILURE : 0),
366 0, _("file %d is not in sorted order"), whatfile);
368 /* If we get to here, the message was just a warning, but we
369 want only to issue it once. */
370 issued_disorder_warning[whatfile-1] = true;
376 static inline void
377 reset_line (struct line *line)
379 line->nfields = 0;
382 static struct line *
383 init_linep (struct line **linep)
385 struct line *line = xmalloc (sizeof *line);
386 memset (line, '\0', sizeof *line);
387 *linep = line;
388 return line;
391 /* Read a line from FP into LINE and split it into fields.
392 Return true if successful. */
394 static bool
395 get_line (FILE *fp, struct line **linep, int which)
397 struct line *line = *linep;
399 if (line == prevline[which - 1])
401 SWAPLINES (line, spareline[which - 1]);
402 *linep = line;
405 if (line)
406 reset_line (line);
407 else
408 line = init_linep (linep);
410 if (! readlinebuffer (&line->buf, fp))
412 if (ferror (fp))
413 error (EXIT_FAILURE, errno, _("read error"));
414 freeline (line);
415 return false;
418 xfields (line);
420 if (prevline[which - 1])
421 check_order (prevline[which - 1], line, which);
423 prevline[which - 1] = line;
424 return true;
427 static void
428 free_spareline (void)
430 size_t i;
432 for (i = 0; i < ARRAY_CARDINALITY (spareline); i++)
434 if (spareline[i])
436 freeline (spareline[i]);
437 free (spareline[i]);
442 static void
443 initseq (struct seq *seq)
445 seq->count = 0;
446 seq->alloc = 0;
447 seq->lines = NULL;
450 /* Read a line from FP and add it to SEQ. Return true if successful. */
452 static bool
453 getseq (FILE *fp, struct seq *seq, int whichfile)
455 if (seq->count == seq->alloc)
457 size_t i;
458 seq->lines = X2NREALLOC (seq->lines, &seq->alloc);
459 for (i = seq->count; i < seq->alloc; i++)
460 seq->lines[i] = NULL;
463 if (get_line (fp, &seq->lines[seq->count], whichfile))
465 ++seq->count;
466 return true;
468 return false;
471 /* Read a line from FP and add it to SEQ, as the first item if FIRST is
472 true, else as the next. */
473 static bool
474 advance_seq (FILE *fp, struct seq *seq, bool first, int whichfile)
476 if (first)
477 seq->count = 0;
479 return getseq (fp, seq, whichfile);
482 static void
483 delseq (struct seq *seq)
485 size_t i;
486 for (i = 0; i < seq->alloc; i++)
487 if (seq->lines[i])
489 if (seq->lines[i]->buf.buffer)
490 freeline (seq->lines[i]);
491 free (seq->lines[i]);
493 free (seq->lines);
497 /* Print field N of LINE if it exists and is nonempty, otherwise
498 `empty_filler' if it is nonempty. */
500 static void
501 prfield (size_t n, struct line const *line)
503 size_t len;
505 if (n < line->nfields)
507 len = line->fields[n].len;
508 if (len)
509 fwrite (line->fields[n].beg, 1, len, stdout);
510 else if (empty_filler)
511 fputs (empty_filler, stdout);
513 else if (empty_filler)
514 fputs (empty_filler, stdout);
517 /* Print the join of LINE1 and LINE2. */
519 static void
520 prjoin (struct line const *line1, struct line const *line2)
522 const struct outlist *outlist;
523 char output_separator = tab < 0 ? ' ' : tab;
525 outlist = outlist_head.next;
526 if (outlist)
528 const struct outlist *o;
530 o = outlist;
531 while (1)
533 size_t field;
534 struct line const *line;
536 if (o->file == 0)
538 if (line1 == &uni_blank)
540 line = line2;
541 field = join_field_2;
543 else
545 line = line1;
546 field = join_field_1;
549 else
551 line = (o->file == 1 ? line1 : line2);
552 field = o->field;
554 prfield (field, line);
555 o = o->next;
556 if (o == NULL)
557 break;
558 putchar (output_separator);
560 putchar ('\n');
562 else
564 size_t i;
566 if (line1 == &uni_blank)
568 struct line const *t;
569 t = line1;
570 line1 = line2;
571 line2 = t;
573 prfield (join_field_1, line1);
574 for (i = 0; i < join_field_1 && i < line1->nfields; ++i)
576 putchar (output_separator);
577 prfield (i, line1);
579 for (i = join_field_1 + 1; i < line1->nfields; ++i)
581 putchar (output_separator);
582 prfield (i, line1);
585 for (i = 0; i < join_field_2 && i < line2->nfields; ++i)
587 putchar (output_separator);
588 prfield (i, line2);
590 for (i = join_field_2 + 1; i < line2->nfields; ++i)
592 putchar (output_separator);
593 prfield (i, line2);
595 putchar ('\n');
599 /* Print the join of the files in FP1 and FP2. */
601 static void
602 join (FILE *fp1, FILE *fp2)
604 struct seq seq1, seq2;
605 struct line **linep = xmalloc (sizeof *linep);
606 int diff;
607 bool eof1, eof2, checktail;
609 *linep = NULL;
611 /* Read the first line of each file. */
612 initseq (&seq1);
613 getseq (fp1, &seq1, 1);
614 initseq (&seq2);
615 getseq (fp2, &seq2, 2);
617 while (seq1.count && seq2.count)
619 size_t i;
620 diff = keycmp (seq1.lines[0], seq2.lines[0],
621 join_field_1, join_field_2);
622 if (diff < 0)
624 if (print_unpairables_1)
625 prjoin (seq1.lines[0], &uni_blank);
626 advance_seq (fp1, &seq1, true, 1);
627 seen_unpairable = true;
628 continue;
630 if (diff > 0)
632 if (print_unpairables_2)
633 prjoin (&uni_blank, seq2.lines[0]);
634 advance_seq (fp2, &seq2, true, 2);
635 seen_unpairable = true;
636 continue;
639 /* Keep reading lines from file1 as long as they continue to
640 match the current line from file2. */
641 eof1 = false;
643 if (!advance_seq (fp1, &seq1, false, 1))
645 eof1 = true;
646 ++seq1.count;
647 break;
649 while (!keycmp (seq1.lines[seq1.count - 1], seq2.lines[0],
650 join_field_1, join_field_2));
652 /* Keep reading lines from file2 as long as they continue to
653 match the current line from file1. */
654 eof2 = false;
656 if (!advance_seq (fp2, &seq2, false, 2))
658 eof2 = true;
659 ++seq2.count;
660 break;
662 while (!keycmp (seq1.lines[0], seq2.lines[seq2.count - 1],
663 join_field_1, join_field_2));
665 if (print_pairables)
667 for (i = 0; i < seq1.count - 1; ++i)
669 size_t j;
670 for (j = 0; j < seq2.count - 1; ++j)
671 prjoin (seq1.lines[i], seq2.lines[j]);
675 if (!eof1)
677 SWAPLINES (seq1.lines[0], seq1.lines[seq1.count - 1]);
678 seq1.count = 1;
680 else
681 seq1.count = 0;
683 if (!eof2)
685 SWAPLINES (seq2.lines[0], seq2.lines[seq2.count - 1]);
686 seq2.count = 1;
688 else
689 seq2.count = 0;
692 /* If the user did not specify --check-order, and the we read the
693 tail ends of both inputs to verify that they are in order. We
694 skip the rest of the tail once we have issued a warning for that
695 file, unless we actually need to print the unpairable lines. */
696 if (check_input_order != CHECK_ORDER_DISABLED
697 && !(issued_disorder_warning[0] && issued_disorder_warning[1]))
698 checktail = true;
699 else
700 checktail = false;
702 if ((print_unpairables_1 || checktail) && seq1.count)
704 if (print_unpairables_1)
705 prjoin (seq1.lines[0], &uni_blank);
706 seen_unpairable = true;
707 while (get_line (fp1, linep, 1))
709 if (print_unpairables_1)
710 prjoin (*linep, &uni_blank);
711 if (issued_disorder_warning[0] && !print_unpairables_1)
712 break;
716 if ((print_unpairables_2 || checktail) && seq2.count)
718 if (print_unpairables_2)
719 prjoin (&uni_blank, seq2.lines[0]);
720 seen_unpairable = true;
721 while (get_line (fp2, linep, 2))
723 if (print_unpairables_2)
724 prjoin (&uni_blank, *linep);
725 if (issued_disorder_warning[1] && !print_unpairables_2)
726 break;
730 free (*linep);
732 free (linep);
733 delseq (&seq1);
734 delseq (&seq2);
737 /* Add a field spec for field FIELD of file FILE to `outlist'. */
739 static void
740 add_field (int file, size_t field)
742 struct outlist *o;
744 assert (file == 0 || file == 1 || file == 2);
745 assert (file != 0 || field == 0);
747 o = xmalloc (sizeof *o);
748 o->file = file;
749 o->field = field;
750 o->next = NULL;
752 /* Add to the end of the list so the fields are in the right order. */
753 outlist_end->next = o;
754 outlist_end = o;
757 /* Convert a string of decimal digits, STR (the 1-based join field number),
758 to an integral value. Upon successful conversion, return one less
759 (the zero-based field number). Silently convert too-large values
760 to SIZE_MAX - 1. Otherwise, if a value cannot be converted, give a
761 diagnostic and exit. */
763 static size_t
764 string_to_join_field (char const *str)
766 size_t result;
767 unsigned long int val;
768 verify (SIZE_MAX <= ULONG_MAX);
770 strtol_error s_err = xstrtoul (str, NULL, 10, &val, "");
771 if (s_err == LONGINT_OVERFLOW || (s_err == LONGINT_OK && SIZE_MAX < val))
772 val = SIZE_MAX;
773 else if (s_err != LONGINT_OK || val == 0)
774 error (EXIT_FAILURE, 0, _("invalid field number: %s"), quote (str));
776 result = val - 1;
778 return result;
781 /* Convert a single field specifier string, S, to a *FILE_INDEX, *FIELD_INDEX
782 pair. In S, the field index string is 1-based; *FIELD_INDEX is zero-based.
783 If S is valid, return true. Otherwise, give a diagnostic and exit. */
785 static void
786 decode_field_spec (const char *s, int *file_index, size_t *field_index)
788 /* The first character must be 0, 1, or 2. */
789 switch (s[0])
791 case '0':
792 if (s[1])
794 /* `0' must be all alone -- no `.FIELD'. */
795 error (EXIT_FAILURE, 0, _("invalid field specifier: %s"), quote (s));
797 *file_index = 0;
798 *field_index = 0;
799 break;
801 case '1':
802 case '2':
803 if (s[1] != '.')
804 error (EXIT_FAILURE, 0, _("invalid field specifier: %s"), quote (s));
805 *file_index = s[0] - '0';
806 *field_index = string_to_join_field (s + 2);
807 break;
809 default:
810 error (EXIT_FAILURE, 0,
811 _("invalid file number in field spec: %s"), quote (s));
813 /* Tell gcc -W -Wall that we can't get beyond this point.
814 This avoids a warning (otherwise legit) that the caller's copies
815 of *file_index and *field_index might be used uninitialized. */
816 abort ();
818 break;
822 /* Add the comma or blank separated field spec(s) in STR to `outlist'. */
824 static void
825 add_field_list (char *str)
827 char *p = str;
831 int file_index;
832 size_t field_index;
833 char const *spec_item = p;
835 p = strpbrk (p, ", \t");
836 if (p)
837 *p++ = '\0';
838 decode_field_spec (spec_item, &file_index, &field_index);
839 add_field (file_index, field_index);
841 while (p);
844 /* Set the join field *VAR to VAL, but report an error if *VAR is set
845 more than once to incompatible values. */
847 static void
848 set_join_field (size_t *var, size_t val)
850 if (*var != SIZE_MAX && *var != val)
852 unsigned long int var1 = *var + 1;
853 unsigned long int val1 = val + 1;
854 error (EXIT_FAILURE, 0, _("incompatible join fields %lu, %lu"),
855 var1, val1);
857 *var = val;
860 /* Status of command-line arguments. */
862 enum operand_status
864 /* This argument must be an operand, i.e., one of the files to be
865 joined. */
866 MUST_BE_OPERAND,
868 /* This might be the argument of the preceding -j1 or -j2 option,
869 or it might be an operand. */
870 MIGHT_BE_J1_ARG,
871 MIGHT_BE_J2_ARG,
873 /* This might be the argument of the preceding -o option, or it might be
874 an operand. */
875 MIGHT_BE_O_ARG
878 /* Add NAME to the array of input file NAMES with operand statuses
879 OPERAND_STATUS; currently there are NFILES names in the list. */
881 static void
882 add_file_name (char *name, char *names[2],
883 int operand_status[2], int joption_count[2], int *nfiles,
884 int *prev_optc_status, int *optc_status)
886 int n = *nfiles;
888 if (n == 2)
890 bool op0 = (operand_status[0] == MUST_BE_OPERAND);
891 char *arg = names[op0];
892 switch (operand_status[op0])
894 case MUST_BE_OPERAND:
895 error (0, 0, _("extra operand %s"), quote (name));
896 usage (EXIT_FAILURE);
898 case MIGHT_BE_J1_ARG:
899 joption_count[0]--;
900 set_join_field (&join_field_1, string_to_join_field (arg));
901 break;
903 case MIGHT_BE_J2_ARG:
904 joption_count[1]--;
905 set_join_field (&join_field_2, string_to_join_field (arg));
906 break;
908 case MIGHT_BE_O_ARG:
909 add_field_list (arg);
910 break;
912 if (!op0)
914 operand_status[0] = operand_status[1];
915 names[0] = names[1];
917 n = 1;
920 operand_status[n] = *prev_optc_status;
921 names[n] = name;
922 *nfiles = n + 1;
923 if (*prev_optc_status == MIGHT_BE_O_ARG)
924 *optc_status = MIGHT_BE_O_ARG;
928 main (int argc, char **argv)
930 int optc_status;
931 int prev_optc_status = MUST_BE_OPERAND;
932 int operand_status[2];
933 int joption_count[2] = { 0, 0 };
934 char *names[2];
935 FILE *fp1, *fp2;
936 int optc;
937 int nfiles = 0;
938 int i;
940 initialize_main (&argc, &argv);
941 set_program_name (argv[0]);
942 setlocale (LC_ALL, "");
943 bindtextdomain (PACKAGE, LOCALEDIR);
944 textdomain (PACKAGE);
945 hard_LC_COLLATE = hard_locale (LC_COLLATE);
947 atexit (close_stdout);
948 atexit (free_spareline);
950 print_pairables = true;
951 seen_unpairable = false;
952 issued_disorder_warning[0] = issued_disorder_warning[1] = false;
953 check_input_order = CHECK_ORDER_DEFAULT;
955 while ((optc = getopt_long (argc, argv, "-a:e:i1:2:j:o:t:v:",
956 longopts, NULL))
957 != -1)
959 optc_status = MUST_BE_OPERAND;
961 switch (optc)
963 case 'v':
964 print_pairables = false;
965 /* Fall through. */
967 case 'a':
969 unsigned long int val;
970 if (xstrtoul (optarg, NULL, 10, &val, "") != LONGINT_OK
971 || (val != 1 && val != 2))
972 error (EXIT_FAILURE, 0,
973 _("invalid field number: %s"), quote (optarg));
974 if (val == 1)
975 print_unpairables_1 = true;
976 else
977 print_unpairables_2 = true;
979 break;
981 case 'e':
982 if (empty_filler && ! STREQ (empty_filler, optarg))
983 error (EXIT_FAILURE, 0,
984 _("conflicting empty-field replacement strings"));
985 empty_filler = optarg;
986 break;
988 case 'i':
989 ignore_case = true;
990 break;
992 case '1':
993 set_join_field (&join_field_1, string_to_join_field (optarg));
994 break;
996 case '2':
997 set_join_field (&join_field_2, string_to_join_field (optarg));
998 break;
1000 case 'j':
1001 if ((optarg[0] == '1' || optarg[0] == '2') && !optarg[1]
1002 && optarg == argv[optind - 1] + 2)
1004 /* The argument was either "-j1" or "-j2". */
1005 bool is_j2 = (optarg[0] == '2');
1006 joption_count[is_j2]++;
1007 optc_status = MIGHT_BE_J1_ARG + is_j2;
1009 else
1011 set_join_field (&join_field_1, string_to_join_field (optarg));
1012 set_join_field (&join_field_2, join_field_1);
1014 break;
1016 case 'o':
1017 add_field_list (optarg);
1018 optc_status = MIGHT_BE_O_ARG;
1019 break;
1021 case 't':
1023 unsigned char newtab = optarg[0];
1024 if (! newtab)
1025 error (EXIT_FAILURE, 0, _("empty tab"));
1026 if (optarg[1])
1028 if (STREQ (optarg, "\\0"))
1029 newtab = '\0';
1030 else
1031 error (EXIT_FAILURE, 0, _("multi-character tab %s"),
1032 quote (optarg));
1034 if (0 <= tab && tab != newtab)
1035 error (EXIT_FAILURE, 0, _("incompatible tabs"));
1036 tab = newtab;
1038 break;
1040 case NOCHECK_ORDER_OPTION:
1041 check_input_order = CHECK_ORDER_DISABLED;
1042 break;
1044 case CHECK_ORDER_OPTION:
1045 check_input_order = CHECK_ORDER_ENABLED;
1046 break;
1048 case 1: /* Non-option argument. */
1049 add_file_name (optarg, names, operand_status, joption_count,
1050 &nfiles, &prev_optc_status, &optc_status);
1051 break;
1053 case_GETOPT_HELP_CHAR;
1055 case_GETOPT_VERSION_CHAR (PROGRAM_NAME, AUTHORS);
1057 default:
1058 usage (EXIT_FAILURE);
1061 prev_optc_status = optc_status;
1064 /* Process any operands after "--". */
1065 prev_optc_status = MUST_BE_OPERAND;
1066 while (optind < argc)
1067 add_file_name (argv[optind++], names, operand_status, joption_count,
1068 &nfiles, &prev_optc_status, &optc_status);
1070 if (nfiles != 2)
1072 if (nfiles == 0)
1073 error (0, 0, _("missing operand"));
1074 else
1075 error (0, 0, _("missing operand after %s"), quote (argv[argc - 1]));
1076 usage (EXIT_FAILURE);
1079 /* If "-j1" was specified and it turns out not to have had an argument,
1080 treat it as "-j 1". Likewise for -j2. */
1081 for (i = 0; i < 2; i++)
1082 if (joption_count[i] != 0)
1084 set_join_field (&join_field_1, i);
1085 set_join_field (&join_field_2, i);
1088 if (join_field_1 == SIZE_MAX)
1089 join_field_1 = 0;
1090 if (join_field_2 == SIZE_MAX)
1091 join_field_2 = 0;
1093 fp1 = STREQ (names[0], "-") ? stdin : fopen (names[0], "r");
1094 if (!fp1)
1095 error (EXIT_FAILURE, errno, "%s", names[0]);
1096 fp2 = STREQ (names[1], "-") ? stdin : fopen (names[1], "r");
1097 if (!fp2)
1098 error (EXIT_FAILURE, errno, "%s", names[1]);
1099 if (fp1 == fp2)
1100 error (EXIT_FAILURE, errno, _("both files cannot be standard input"));
1101 join (fp1, fp2);
1103 if (fclose (fp1) != 0)
1104 error (EXIT_FAILURE, errno, "%s", names[0]);
1105 if (fclose (fp2) != 0)
1106 error (EXIT_FAILURE, errno, "%s", names[1]);
1108 if (issued_disorder_warning[0] || issued_disorder_warning[1])
1109 exit (EXIT_FAILURE);
1110 else
1111 exit (EXIT_SUCCESS);