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. */
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 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\
211 emit_bug_reporting_address ();
216 /* Record a field in LINE, with location FIELD and size LEN. */
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
;
230 /* Fill in the `fields' structure in LINE. */
233 xfields (struct line
*line
)
235 char *ptr
= line
->buf
.buffer
;
236 char const *lim
= ptr
+ line
->buf
.length
- 1;
244 for (; (sep
= memchr (ptr
, tab
, lim
- ptr
)) != NULL
; ptr
= sep
+ 1)
245 extract_field (line
, ptr
, sep
- ptr
);
249 /* Skip leading blanks before the first field. */
250 while (isblank (to_uchar (*ptr
)))
257 for (sep
= ptr
+ 1; sep
!= lim
&& ! isblank (to_uchar (*sep
)); sep
++)
259 extract_field (line
, ptr
, sep
- ptr
);
262 for (ptr
= sep
+ 1; ptr
!= lim
&& isblank (to_uchar (*ptr
)); ptr
++)
268 extract_field (line
, ptr
, lim
- ptr
);
272 freeline (struct line
*line
)
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. */
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. */
293 size_t len2
; /* Length of fields to compare. */
296 if (jf_1
< line1
->nfields
)
298 beg1
= line1
->fields
[jf_1
].beg
;
299 len1
= line1
->fields
[jf_1
].len
;
307 if (jf_2
< line2
->nfields
)
309 beg2
= line2
->fields
[jf_2
].beg
;
310 len2
= line2
->fields
[jf_2
].len
;
319 return len2
== 0 ? 0 : -1;
325 /* FIXME: ignore_case does not work with NLS (in particular,
326 with multibyte chars). */
327 diff
= memcasecmp (beg1
, beg2
, MIN (len1
, len2
));
332 return xmemcoll (beg1
, len1
, beg2
, len2
);
333 diff
= memcmp (beg1
, beg2
, MIN (len1
, len2
));
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. */
353 check_order (const struct line
*prev
,
354 const struct line
*current
,
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
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;
378 reset_line (struct line
*line
)
384 init_linep (struct line
**linep
)
386 struct line
*line
= xmalloc (sizeof *line
);
387 memset (line
, '\0', sizeof *line
);
392 /* Read a line from FP into LINE and split it into fields.
393 Return true if successful. */
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]);
409 line
= init_linep (linep
);
411 if (! readlinebuffer (&line
->buf
, fp
))
414 error (EXIT_FAILURE
, errno
, _("read error"));
421 if (prevline
[which
- 1])
422 check_order (prevline
[which
- 1], line
, which
);
424 prevline
[which
- 1] = line
;
429 free_spareline (void)
433 for (i
= 0; i
< ARRAY_CARDINALITY (spareline
); i
++)
437 freeline (spareline
[i
]);
444 initseq (struct seq
*seq
)
451 /* Read a line from FP and add it to SEQ. Return true if successful. */
454 getseq (FILE *fp
, struct seq
*seq
, int whichfile
)
456 if (seq
->count
== seq
->alloc
)
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
))
472 /* Read a line from FP and add it to SEQ, as the first item if FIRST is
473 true, else as the next. */
475 advance_seq (FILE *fp
, struct seq
*seq
, bool first
, int whichfile
)
480 return getseq (fp
, seq
, whichfile
);
484 delseq (struct seq
*seq
)
487 for (i
= 0; i
< seq
->alloc
; i
++)
490 if (seq
->lines
[i
]->buf
.buffer
)
491 freeline (seq
->lines
[i
]);
492 free (seq
->lines
[i
]);
498 /* Print field N of LINE if it exists and is nonempty, otherwise
499 `empty_filler' if it is nonempty. */
502 prfield (size_t n
, struct line
const *line
)
506 if (n
< line
->nfields
)
508 len
= line
->fields
[n
].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. */
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
;
529 const struct outlist
*o
;
535 struct line
const *line
;
539 if (line1
== &uni_blank
)
542 field
= join_field_2
;
547 field
= join_field_1
;
552 line
= (o
->file
== 1 ? line1
: line2
);
555 prfield (field
, line
);
559 putchar (output_separator
);
567 if (line1
== &uni_blank
)
569 struct line
const *t
;
574 prfield (join_field_1
, line1
);
575 for (i
= 0; i
< join_field_1
&& i
< line1
->nfields
; ++i
)
577 putchar (output_separator
);
580 for (i
= join_field_1
+ 1; i
< line1
->nfields
; ++i
)
582 putchar (output_separator
);
586 for (i
= 0; i
< join_field_2
&& i
< line2
->nfields
; ++i
)
588 putchar (output_separator
);
591 for (i
= join_field_2
+ 1; i
< line2
->nfields
; ++i
)
593 putchar (output_separator
);
600 /* Print the join of the files in FP1 and FP2. */
603 join (FILE *fp1
, FILE *fp2
)
605 struct seq seq1
, seq2
;
606 struct line
**linep
= xmalloc (sizeof *linep
);
608 bool eof1
, eof2
, checktail
;
612 /* Read the first line of each file. */
614 getseq (fp1
, &seq1
, 1);
616 getseq (fp2
, &seq2
, 2);
618 while (seq1
.count
&& seq2
.count
)
621 diff
= keycmp (seq1
.lines
[0], seq2
.lines
[0],
622 join_field_1
, join_field_2
);
625 if (print_unpairables_1
)
626 prjoin (seq1
.lines
[0], &uni_blank
);
627 advance_seq (fp1
, &seq1
, true, 1);
628 seen_unpairable
= true;
633 if (print_unpairables_2
)
634 prjoin (&uni_blank
, seq2
.lines
[0]);
635 advance_seq (fp2
, &seq2
, true, 2);
636 seen_unpairable
= true;
640 /* Keep reading lines from file1 as long as they continue to
641 match the current line from file2. */
644 if (!advance_seq (fp1
, &seq1
, false, 1))
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. */
657 if (!advance_seq (fp2
, &seq2
, false, 2))
663 while (!keycmp (seq1
.lines
[0], seq2
.lines
[seq2
.count
- 1],
664 join_field_1
, join_field_2
));
668 for (i
= 0; i
< seq1
.count
- 1; ++i
)
671 for (j
= 0; j
< seq2
.count
- 1; ++j
)
672 prjoin (seq1
.lines
[i
], seq2
.lines
[j
]);
678 SWAPLINES (seq1
.lines
[0], seq1
.lines
[seq1
.count
- 1]);
686 SWAPLINES (seq2
.lines
[0], seq2
.lines
[seq2
.count
- 1]);
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]))
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
)
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
)
738 /* Add a field spec for field FIELD of file FILE to `outlist'. */
741 add_field (int file
, size_t field
)
745 assert (file
== 0 || file
== 1 || file
== 2);
746 assert (file
!= 0 || field
== 0);
748 o
= xmalloc (sizeof *o
);
753 /* Add to the end of the list so the fields are in the right order. */
754 outlist_end
->next
= 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. */
765 string_to_join_field (char const *str
)
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
))
774 else if (s_err
!= LONGINT_OK
|| val
== 0)
775 error (EXIT_FAILURE
, 0, _("invalid field number: %s"), quote (str
));
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. */
787 decode_field_spec (const char *s
, int *file_index
, size_t *field_index
)
789 /* The first character must be 0, 1, or 2. */
795 /* `0' must be all alone -- no `.FIELD'. */
796 error (EXIT_FAILURE
, 0, _("invalid field specifier: %s"), quote (s
));
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);
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. */
823 /* Add the comma or blank separated field spec(s) in STR to `outlist'. */
826 add_field_list (char *str
)
834 char const *spec_item
= p
;
836 p
= strpbrk (p
, ", \t");
839 decode_field_spec (spec_item
, &file_index
, &field_index
);
840 add_field (file_index
, field_index
);
845 /* Set the join field *VAR to VAL, but report an error if *VAR is set
846 more than once to incompatible values. */
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"),
861 /* Status of command-line arguments. */
865 /* This argument must be an operand, i.e., one of the files to be
869 /* This might be the argument of the preceding -j1 or -j2 option,
870 or it might be an operand. */
874 /* This might be the argument of the preceding -o option, or it might be
879 /* Add NAME to the array of input file NAMES with operand statuses
880 OPERAND_STATUS; currently there are NFILES names in the list. */
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
)
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
:
901 set_join_field (&join_field_1
, string_to_join_field (arg
));
904 case MIGHT_BE_J2_ARG
:
906 set_join_field (&join_field_2
, string_to_join_field (arg
));
910 add_field_list (arg
);
915 operand_status
[0] = operand_status
[1];
921 operand_status
[n
] = *prev_optc_status
;
924 if (*prev_optc_status
== MIGHT_BE_O_ARG
)
925 *optc_status
= MIGHT_BE_O_ARG
;
929 main (int argc
, char **argv
)
932 int prev_optc_status
= MUST_BE_OPERAND
;
933 int operand_status
[2];
934 int joption_count
[2] = { 0, 0 };
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:",
960 optc_status
= MUST_BE_OPERAND
;
965 print_pairables
= false;
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
));
976 print_unpairables_1
= true;
978 print_unpairables_2
= true;
983 if (empty_filler
&& ! STREQ (empty_filler
, optarg
))
984 error (EXIT_FAILURE
, 0,
985 _("conflicting empty-field replacement strings"));
986 empty_filler
= optarg
;
994 set_join_field (&join_field_1
, string_to_join_field (optarg
));
998 set_join_field (&join_field_2
, string_to_join_field (optarg
));
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
;
1012 set_join_field (&join_field_1
, string_to_join_field (optarg
));
1013 set_join_field (&join_field_2
, join_field_1
);
1018 add_field_list (optarg
);
1019 optc_status
= MIGHT_BE_O_ARG
;
1024 unsigned char newtab
= optarg
[0];
1026 error (EXIT_FAILURE
, 0, _("empty tab"));
1029 if (STREQ (optarg
, "\\0"))
1032 error (EXIT_FAILURE
, 0, _("multi-character tab %s"),
1035 if (0 <= tab
&& tab
!= newtab
)
1036 error (EXIT_FAILURE
, 0, _("incompatible tabs"));
1041 case NOCHECK_ORDER_OPTION
:
1042 check_input_order
= CHECK_ORDER_DISABLED
;
1045 case CHECK_ORDER_OPTION
:
1046 check_input_order
= CHECK_ORDER_ENABLED
;
1049 case 1: /* Non-option argument. */
1050 add_file_name (optarg
, names
, operand_status
, joption_count
,
1051 &nfiles
, &prev_optc_status
, &optc_status
);
1054 case_GETOPT_HELP_CHAR
;
1056 case_GETOPT_VERSION_CHAR (PROGRAM_NAME
, AUTHORS
);
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
);
1074 error (0, 0, _("missing operand"));
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
)
1091 if (join_field_2
== SIZE_MAX
)
1094 fp1
= STREQ (names
[0], "-") ? stdin
: fopen (names
[0], "r");
1096 error (EXIT_FAILURE
, errno
, "%s", names
[0]);
1097 fp2
= STREQ (names
[1], "-") ? stdin
: fopen (names
[1], "r");
1099 error (EXIT_FAILURE
, errno
, "%s", names
[1]);
1101 error (EXIT_FAILURE
, errno
, _("both files cannot be standard input"));
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
);
1112 exit (EXIT_SUCCESS
);