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. */
22 #include <sys/types.h>
27 #include "linebuffer.h"
28 #include "memcasecmp.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; \
48 /* An element of the list identifying which fields to print for each
52 /* File number: 0, 1, or 2. 0 means use the join field.
53 1 means use the first file argument, 2 the second. */
56 /* Field index (zero-based), specified only when FILE is 1 or 2. */
62 /* A field of a line. */
65 char *beg
; /* First character in field. */
66 size_t len
; /* The length of the field. */
69 /* A line read from an input file. */
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'. */
78 /* One or more consecutive lines read from a file that all have the
79 same join field value. */
82 size_t count
; /* Elements used in `lines'. */
83 size_t alloc
; /* Elements allocated in `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. */
128 /* If nonzero, check that the input is correctly ordered. */
138 CHECK_ORDER_OPTION
= CHAR_MAX
+ 1,
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
},
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
;
162 if (status
!= EXIT_SUCCESS
)
163 fprintf (stderr
, _("Try `%s --help' for more information.\n"),
168 Usage: %s [OPTION]... FILE1 FILE2\n\
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\
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\
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\
194 fputs (HELP_OPTION_DESCRIPTION
, stdout
);
195 fputs (VERSION_OPTION_DESCRIPTION
, stdout
);
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\
210 emit_bug_reporting_address ();
215 /* Record a field in LINE, with location FIELD and size LEN. */
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
;
229 /* Fill in the `fields' structure in LINE. */
232 xfields (struct line
*line
)
234 char *ptr
= line
->buf
.buffer
;
235 char const *lim
= ptr
+ line
->buf
.length
- 1;
243 for (; (sep
= memchr (ptr
, tab
, lim
- ptr
)) != NULL
; ptr
= sep
+ 1)
244 extract_field (line
, ptr
, sep
- ptr
);
248 /* Skip leading blanks before the first field. */
249 while (isblank (to_uchar (*ptr
)))
256 for (sep
= ptr
+ 1; sep
!= lim
&& ! isblank (to_uchar (*sep
)); sep
++)
258 extract_field (line
, ptr
, sep
- ptr
);
261 for (ptr
= sep
+ 1; ptr
!= lim
&& isblank (to_uchar (*ptr
)); ptr
++)
267 extract_field (line
, ptr
, lim
- ptr
);
271 freeline (struct line
*line
)
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. */
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. */
292 size_t len2
; /* Length of fields to compare. */
295 if (jf_1
< line1
->nfields
)
297 beg1
= line1
->fields
[jf_1
].beg
;
298 len1
= line1
->fields
[jf_1
].len
;
306 if (jf_2
< line2
->nfields
)
308 beg2
= line2
->fields
[jf_2
].beg
;
309 len2
= line2
->fields
[jf_2
].len
;
318 return len2
== 0 ? 0 : -1;
324 /* FIXME: ignore_case does not work with NLS (in particular,
325 with multibyte chars). */
326 diff
= memcasecmp (beg1
, beg2
, MIN (len1
, len2
));
331 return xmemcoll (beg1
, len1
, beg2
, len2
);
332 diff
= memcmp (beg1
, beg2
, MIN (len1
, len2
));
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. */
352 check_order (const struct line
*prev
,
353 const struct line
*current
,
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
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;
377 reset_line (struct line
*line
)
383 init_linep (struct line
**linep
)
385 struct line
*line
= xmalloc (sizeof *line
);
386 memset (line
, '\0', sizeof *line
);
391 /* Read a line from FP into LINE and split it into fields.
392 Return true if successful. */
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]);
408 line
= init_linep (linep
);
410 if (! readlinebuffer (&line
->buf
, fp
))
413 error (EXIT_FAILURE
, errno
, _("read error"));
420 if (prevline
[which
- 1])
421 check_order (prevline
[which
- 1], line
, which
);
423 prevline
[which
- 1] = line
;
428 free_spareline (void)
432 for (i
= 0; i
< ARRAY_CARDINALITY (spareline
); i
++)
436 freeline (spareline
[i
]);
443 initseq (struct seq
*seq
)
450 /* Read a line from FP and add it to SEQ. Return true if successful. */
453 getseq (FILE *fp
, struct seq
*seq
, int whichfile
)
455 if (seq
->count
== seq
->alloc
)
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
))
471 /* Read a line from FP and add it to SEQ, as the first item if FIRST is
472 true, else as the next. */
474 advance_seq (FILE *fp
, struct seq
*seq
, bool first
, int whichfile
)
479 return getseq (fp
, seq
, whichfile
);
483 delseq (struct seq
*seq
)
486 for (i
= 0; i
< seq
->alloc
; i
++)
489 if (seq
->lines
[i
]->buf
.buffer
)
490 freeline (seq
->lines
[i
]);
491 free (seq
->lines
[i
]);
497 /* Print field N of LINE if it exists and is nonempty, otherwise
498 `empty_filler' if it is nonempty. */
501 prfield (size_t n
, struct line
const *line
)
505 if (n
< line
->nfields
)
507 len
= line
->fields
[n
].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. */
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
;
528 const struct outlist
*o
;
534 struct line
const *line
;
538 if (line1
== &uni_blank
)
541 field
= join_field_2
;
546 field
= join_field_1
;
551 line
= (o
->file
== 1 ? line1
: line2
);
554 prfield (field
, line
);
558 putchar (output_separator
);
566 if (line1
== &uni_blank
)
568 struct line
const *t
;
573 prfield (join_field_1
, line1
);
574 for (i
= 0; i
< join_field_1
&& i
< line1
->nfields
; ++i
)
576 putchar (output_separator
);
579 for (i
= join_field_1
+ 1; i
< line1
->nfields
; ++i
)
581 putchar (output_separator
);
585 for (i
= 0; i
< join_field_2
&& i
< line2
->nfields
; ++i
)
587 putchar (output_separator
);
590 for (i
= join_field_2
+ 1; i
< line2
->nfields
; ++i
)
592 putchar (output_separator
);
599 /* Print the join of the files in FP1 and FP2. */
602 join (FILE *fp1
, FILE *fp2
)
604 struct seq seq1
, seq2
;
605 struct line
**linep
= xmalloc (sizeof *linep
);
607 bool eof1
, eof2
, checktail
;
611 /* Read the first line of each file. */
613 getseq (fp1
, &seq1
, 1);
615 getseq (fp2
, &seq2
, 2);
617 while (seq1
.count
&& seq2
.count
)
620 diff
= keycmp (seq1
.lines
[0], seq2
.lines
[0],
621 join_field_1
, join_field_2
);
624 if (print_unpairables_1
)
625 prjoin (seq1
.lines
[0], &uni_blank
);
626 advance_seq (fp1
, &seq1
, true, 1);
627 seen_unpairable
= true;
632 if (print_unpairables_2
)
633 prjoin (&uni_blank
, seq2
.lines
[0]);
634 advance_seq (fp2
, &seq2
, true, 2);
635 seen_unpairable
= true;
639 /* Keep reading lines from file1 as long as they continue to
640 match the current line from file2. */
643 if (!advance_seq (fp1
, &seq1
, false, 1))
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. */
656 if (!advance_seq (fp2
, &seq2
, false, 2))
662 while (!keycmp (seq1
.lines
[0], seq2
.lines
[seq2
.count
- 1],
663 join_field_1
, join_field_2
));
667 for (i
= 0; i
< seq1
.count
- 1; ++i
)
670 for (j
= 0; j
< seq2
.count
- 1; ++j
)
671 prjoin (seq1
.lines
[i
], seq2
.lines
[j
]);
677 SWAPLINES (seq1
.lines
[0], seq1
.lines
[seq1
.count
- 1]);
685 SWAPLINES (seq2
.lines
[0], seq2
.lines
[seq2
.count
- 1]);
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]))
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
)
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
)
737 /* Add a field spec for field FIELD of file FILE to `outlist'. */
740 add_field (int file
, size_t field
)
744 assert (file
== 0 || file
== 1 || file
== 2);
745 assert (file
!= 0 || field
== 0);
747 o
= xmalloc (sizeof *o
);
752 /* Add to the end of the list so the fields are in the right order. */
753 outlist_end
->next
= 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. */
764 string_to_join_field (char const *str
)
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
))
773 else if (s_err
!= LONGINT_OK
|| val
== 0)
774 error (EXIT_FAILURE
, 0, _("invalid field number: %s"), quote (str
));
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. */
786 decode_field_spec (const char *s
, int *file_index
, size_t *field_index
)
788 /* The first character must be 0, 1, or 2. */
794 /* `0' must be all alone -- no `.FIELD'. */
795 error (EXIT_FAILURE
, 0, _("invalid field specifier: %s"), quote (s
));
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);
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. */
822 /* Add the comma or blank separated field spec(s) in STR to `outlist'. */
825 add_field_list (char *str
)
833 char const *spec_item
= p
;
835 p
= strpbrk (p
, ", \t");
838 decode_field_spec (spec_item
, &file_index
, &field_index
);
839 add_field (file_index
, field_index
);
844 /* Set the join field *VAR to VAL, but report an error if *VAR is set
845 more than once to incompatible values. */
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"),
860 /* Status of command-line arguments. */
864 /* This argument must be an operand, i.e., one of the files to be
868 /* This might be the argument of the preceding -j1 or -j2 option,
869 or it might be an operand. */
873 /* This might be the argument of the preceding -o option, or it might be
878 /* Add NAME to the array of input file NAMES with operand statuses
879 OPERAND_STATUS; currently there are NFILES names in the list. */
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
)
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
:
900 set_join_field (&join_field_1
, string_to_join_field (arg
));
903 case MIGHT_BE_J2_ARG
:
905 set_join_field (&join_field_2
, string_to_join_field (arg
));
909 add_field_list (arg
);
914 operand_status
[0] = operand_status
[1];
920 operand_status
[n
] = *prev_optc_status
;
923 if (*prev_optc_status
== MIGHT_BE_O_ARG
)
924 *optc_status
= MIGHT_BE_O_ARG
;
928 main (int argc
, char **argv
)
931 int prev_optc_status
= MUST_BE_OPERAND
;
932 int operand_status
[2];
933 int joption_count
[2] = { 0, 0 };
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:",
959 optc_status
= MUST_BE_OPERAND
;
964 print_pairables
= false;
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
));
975 print_unpairables_1
= true;
977 print_unpairables_2
= true;
982 if (empty_filler
&& ! STREQ (empty_filler
, optarg
))
983 error (EXIT_FAILURE
, 0,
984 _("conflicting empty-field replacement strings"));
985 empty_filler
= optarg
;
993 set_join_field (&join_field_1
, string_to_join_field (optarg
));
997 set_join_field (&join_field_2
, string_to_join_field (optarg
));
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
;
1011 set_join_field (&join_field_1
, string_to_join_field (optarg
));
1012 set_join_field (&join_field_2
, join_field_1
);
1017 add_field_list (optarg
);
1018 optc_status
= MIGHT_BE_O_ARG
;
1023 unsigned char newtab
= optarg
[0];
1025 error (EXIT_FAILURE
, 0, _("empty tab"));
1028 if (STREQ (optarg
, "\\0"))
1031 error (EXIT_FAILURE
, 0, _("multi-character tab %s"),
1034 if (0 <= tab
&& tab
!= newtab
)
1035 error (EXIT_FAILURE
, 0, _("incompatible tabs"));
1040 case NOCHECK_ORDER_OPTION
:
1041 check_input_order
= CHECK_ORDER_DISABLED
;
1044 case CHECK_ORDER_OPTION
:
1045 check_input_order
= CHECK_ORDER_ENABLED
;
1048 case 1: /* Non-option argument. */
1049 add_file_name (optarg
, names
, operand_status
, joption_count
,
1050 &nfiles
, &prev_optc_status
, &optc_status
);
1053 case_GETOPT_HELP_CHAR
;
1055 case_GETOPT_VERSION_CHAR (PROGRAM_NAME
, AUTHORS
);
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
);
1073 error (0, 0, _("missing operand"));
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
)
1090 if (join_field_2
== SIZE_MAX
)
1093 fp1
= STREQ (names
[0], "-") ? stdin
: fopen (names
[0], "r");
1095 error (EXIT_FAILURE
, errno
, "%s", names
[0]);
1096 fp2
= STREQ (names
[1], "-") ? stdin
: fopen (names
[1], "r");
1098 error (EXIT_FAILURE
, errno
, "%s", names
[1]);
1100 error (EXIT_FAILURE
, errno
, _("both files cannot be standard input"));
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
);
1111 exit (EXIT_SUCCESS
);