* tests/sample-test: Update copyright date to 2007.
[coreutils.git] / src / join.c
blobb113c543b1727aedc7159482fba7ef61d1096a97
1 /* join - join lines of two files on a common field
2 Copyright (C) 91, 1995-2006 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 2, or (at your option)
7 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, write to the Free Software Foundation,
16 Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
18 Written by Mike Haertel, mike@gnu.ai.mit.edu. */
20 #include <config.h>
22 #include <assert.h>
23 #include <sys/types.h>
24 #include <getopt.h>
26 #include "system.h"
27 #include "error.h"
28 #include "hard-locale.h"
29 #include "linebuffer.h"
30 #include "memcasecmp.h"
31 #include "quote.h"
32 #include "stdio--.h"
33 #include "xmemcoll.h"
34 #include "xstrtol.h"
36 /* The official name of this program (e.g., no `g' prefix). */
37 #define PROGRAM_NAME "join"
39 #define AUTHORS "Mike Haertel"
41 #define join system_join
43 /* An element of the list identifying which fields to print for each
44 output line. */
45 struct outlist
47 /* File number: 0, 1, or 2. 0 means use the join field.
48 1 means use the first file argument, 2 the second. */
49 int file;
51 /* Field index (zero-based), specified only when FILE is 1 or 2. */
52 size_t field;
54 struct outlist *next;
57 /* A field of a line. */
58 struct field
60 char *beg; /* First character in field. */
61 size_t len; /* The length of the field. */
64 /* A line read from an input file. */
65 struct line
67 struct linebuffer buf; /* The line itself. */
68 size_t nfields; /* Number of elements in `fields'. */
69 size_t nfields_allocated; /* Number of elements allocated for `fields'. */
70 struct field *fields;
73 /* One or more consecutive lines read from a file that all have the
74 same join field value. */
75 struct seq
77 size_t count; /* Elements used in `lines'. */
78 size_t alloc; /* Elements allocated in `lines'. */
79 struct line *lines;
82 /* The name this program was run with. */
83 char *program_name;
85 /* True if the LC_COLLATE locale is hard. */
86 static bool hard_LC_COLLATE;
88 /* If nonzero, print unpairable lines in file 1 or 2. */
89 static bool print_unpairables_1, print_unpairables_2;
91 /* If nonzero, print pairable lines. */
92 static bool print_pairables;
94 /* Empty output field filler. */
95 static char const *empty_filler;
97 /* Field to join on; SIZE_MAX means they haven't been determined yet. */
98 static size_t join_field_1 = SIZE_MAX;
99 static size_t join_field_2 = SIZE_MAX;
101 /* List of fields to print. */
102 static struct outlist outlist_head;
104 /* Last element in `outlist', where a new element can be added. */
105 static struct outlist *outlist_end = &outlist_head;
107 /* Tab character separating fields. If negative, fields are separated
108 by any nonempty string of blanks, otherwise by exactly one
109 tab character whose value (when cast to unsigned char) equals TAB. */
110 static int tab = -1;
112 static struct option const longopts[] =
114 {"ignore-case", no_argument, NULL, 'i'},
115 {GETOPT_HELP_OPTION_DECL},
116 {GETOPT_VERSION_OPTION_DECL},
117 {NULL, 0, NULL, 0}
120 /* Used to print non-joining lines */
121 static struct line uni_blank;
123 /* If nonzero, ignore case when comparing join fields. */
124 static bool ignore_case;
126 void
127 usage (int status)
129 if (status != EXIT_SUCCESS)
130 fprintf (stderr, _("Try `%s --help' for more information.\n"),
131 program_name);
132 else
134 printf (_("\
135 Usage: %s [OPTION]... FILE1 FILE2\n\
137 program_name);
138 fputs (_("\
139 For each pair of input lines with identical join fields, write a line to\n\
140 standard output. The default join field is the first, delimited\n\
141 by whitespace. When FILE1 or FILE2 (not both) is -, read standard input.\n\
143 -a FILENUM print unpairable lines coming from file FILENUM, where\n\
144 FILENUM is 1 or 2, corresponding to FILE1 or FILE2\n\
145 -e EMPTY replace missing input fields with EMPTY\n\
146 "), stdout);
147 fputs (_("\
148 -i, --ignore-case ignore differences in case when comparing fields\n\
149 -j FIELD equivalent to `-1 FIELD -2 FIELD'\n\
150 -o FORMAT obey FORMAT while constructing output line\n\
151 -t CHAR use CHAR as input and output field separator\n\
152 "), stdout);
153 fputs (_("\
154 -v FILENUM like -a FILENUM, but suppress joined output lines\n\
155 -1 FIELD join on this FIELD of file 1\n\
156 -2 FIELD join on this FIELD of file 2\n\
157 "), stdout);
158 fputs (HELP_OPTION_DESCRIPTION, stdout);
159 fputs (VERSION_OPTION_DESCRIPTION, stdout);
160 fputs (_("\
162 Unless -t CHAR is given, leading blanks separate fields and are ignored,\n\
163 else fields are separated by CHAR. Any FIELD is a field number counted\n\
164 from 1. FORMAT is one or more comma or blank separated specifications,\n\
165 each being `FILENUM.FIELD' or `0'. Default FORMAT outputs the join field,\n\
166 the remaining fields from FILE1, the remaining fields from FILE2, all\n\
167 separated by CHAR.\n\
169 Important: FILE1 and FILE2 must be sorted on the join fields.\n\
170 E.g., use `sort -k 1b,1' if `join' has no options.\n\
171 "), stdout);
172 printf (_("\nReport bugs to <%s>.\n"), PACKAGE_BUGREPORT);
174 exit (status);
177 /* Record a field in LINE, with location FIELD and size LEN. */
179 static void
180 extract_field (struct line *line, char *field, size_t len)
182 if (line->nfields >= line->nfields_allocated)
184 line->fields = X2NREALLOC (line->fields, &line->nfields_allocated);
186 line->fields[line->nfields].beg = field;
187 line->fields[line->nfields].len = len;
188 ++(line->nfields);
191 /* Fill in the `fields' structure in LINE. */
193 static void
194 xfields (struct line *line)
196 char *ptr = line->buf.buffer;
197 char const *lim = ptr + line->buf.length - 1;
199 if (ptr == lim)
200 return;
202 if (0 <= tab)
204 char *sep;
205 for (; (sep = memchr (ptr, tab, lim - ptr)) != NULL; ptr = sep + 1)
206 extract_field (line, ptr, sep - ptr);
208 else
210 /* Skip leading blanks before the first field. */
211 while (isblank (to_uchar (*ptr)))
212 if (++ptr == lim)
213 return;
217 char *sep;
218 for (sep = ptr + 1; sep != lim && ! isblank (to_uchar (*sep)); sep++)
219 continue;
220 extract_field (line, ptr, sep - ptr);
221 if (sep == lim)
222 return;
223 for (ptr = sep + 1; ptr != lim && isblank (to_uchar (*ptr)); ptr++)
224 continue;
226 while (ptr != lim);
229 extract_field (line, ptr, lim - ptr);
232 /* Read a line from FP into LINE and split it into fields.
233 Return true if successful. */
235 static bool
236 get_line (FILE *fp, struct line *line)
238 initbuffer (&line->buf);
240 if (! readlinebuffer (&line->buf, fp))
242 if (ferror (fp))
243 error (EXIT_FAILURE, errno, _("read error"));
244 free (line->buf.buffer);
245 line->buf.buffer = NULL;
246 return false;
249 line->nfields_allocated = 0;
250 line->nfields = 0;
251 line->fields = NULL;
252 xfields (line);
253 return true;
256 static void
257 freeline (struct line *line)
259 free (line->fields);
260 free (line->buf.buffer);
261 line->buf.buffer = NULL;
264 static void
265 initseq (struct seq *seq)
267 seq->count = 0;
268 seq->alloc = 0;
269 seq->lines = NULL;
272 /* Read a line from FP and add it to SEQ. Return true if successful. */
274 static bool
275 getseq (FILE *fp, struct seq *seq)
277 if (seq->count == seq->alloc)
278 seq->lines = X2NREALLOC (seq->lines, &seq->alloc);
280 if (get_line (fp, &seq->lines[seq->count]))
282 ++seq->count;
283 return true;
285 return false;
288 static void
289 delseq (struct seq *seq)
291 size_t i;
292 for (i = 0; i < seq->count; i++)
293 if (seq->lines[i].buf.buffer)
294 freeline (&seq->lines[i]);
295 free (seq->lines);
298 /* Return <0 if the join field in LINE1 compares less than the one in LINE2;
299 >0 if it compares greater; 0 if it compares equal.
300 Report an error and exit if the comparison fails. */
302 static int
303 keycmp (struct line const *line1, struct line const *line2)
305 /* Start of field to compare in each file. */
306 char *beg1;
307 char *beg2;
309 size_t len1;
310 size_t len2; /* Length of fields to compare. */
311 int diff;
313 if (join_field_1 < line1->nfields)
315 beg1 = line1->fields[join_field_1].beg;
316 len1 = line1->fields[join_field_1].len;
318 else
320 beg1 = NULL;
321 len1 = 0;
324 if (join_field_2 < line2->nfields)
326 beg2 = line2->fields[join_field_2].beg;
327 len2 = line2->fields[join_field_2].len;
329 else
331 beg2 = NULL;
332 len2 = 0;
335 if (len1 == 0)
336 return len2 == 0 ? 0 : -1;
337 if (len2 == 0)
338 return 1;
340 if (ignore_case)
342 /* FIXME: ignore_case does not work with NLS (in particular,
343 with multibyte chars). */
344 diff = memcasecmp (beg1, beg2, MIN (len1, len2));
346 else
348 if (hard_LC_COLLATE)
349 return xmemcoll (beg1, len1, beg2, len2);
350 diff = memcmp (beg1, beg2, MIN (len1, len2));
353 if (diff)
354 return diff;
355 return len1 < len2 ? -1 : len1 != len2;
358 /* Print field N of LINE if it exists and is nonempty, otherwise
359 `empty_filler' if it is nonempty. */
361 static void
362 prfield (size_t n, struct line const *line)
364 size_t len;
366 if (n < line->nfields)
368 len = line->fields[n].len;
369 if (len)
370 fwrite (line->fields[n].beg, 1, len, stdout);
371 else if (empty_filler)
372 fputs (empty_filler, stdout);
374 else if (empty_filler)
375 fputs (empty_filler, stdout);
378 /* Print the join of LINE1 and LINE2. */
380 static void
381 prjoin (struct line const *line1, struct line const *line2)
383 const struct outlist *outlist;
384 char output_separator = tab < 0 ? ' ' : tab;
386 outlist = outlist_head.next;
387 if (outlist)
389 const struct outlist *o;
391 o = outlist;
392 while (1)
394 size_t field;
395 struct line const *line;
397 if (o->file == 0)
399 if (line1 == &uni_blank)
401 line = line2;
402 field = join_field_2;
404 else
406 line = line1;
407 field = join_field_1;
410 else
412 line = (o->file == 1 ? line1 : line2);
413 field = o->field;
415 prfield (field, line);
416 o = o->next;
417 if (o == NULL)
418 break;
419 putchar (output_separator);
421 putchar ('\n');
423 else
425 size_t i;
427 if (line1 == &uni_blank)
429 struct line const *t;
430 t = line1;
431 line1 = line2;
432 line2 = t;
434 prfield (join_field_1, line1);
435 for (i = 0; i < join_field_1 && i < line1->nfields; ++i)
437 putchar (output_separator);
438 prfield (i, line1);
440 for (i = join_field_1 + 1; i < line1->nfields; ++i)
442 putchar (output_separator);
443 prfield (i, line1);
446 for (i = 0; i < join_field_2 && i < line2->nfields; ++i)
448 putchar (output_separator);
449 prfield (i, line2);
451 for (i = join_field_2 + 1; i < line2->nfields; ++i)
453 putchar (output_separator);
454 prfield (i, line2);
456 putchar ('\n');
460 /* Print the join of the files in FP1 and FP2. */
462 static void
463 join (FILE *fp1, FILE *fp2)
465 struct seq seq1, seq2;
466 struct line line;
467 int diff;
468 bool eof1, eof2;
470 /* Read the first line of each file. */
471 initseq (&seq1);
472 getseq (fp1, &seq1);
473 initseq (&seq2);
474 getseq (fp2, &seq2);
476 while (seq1.count && seq2.count)
478 size_t i;
479 diff = keycmp (&seq1.lines[0], &seq2.lines[0]);
480 if (diff < 0)
482 if (print_unpairables_1)
483 prjoin (&seq1.lines[0], &uni_blank);
484 freeline (&seq1.lines[0]);
485 seq1.count = 0;
486 getseq (fp1, &seq1);
487 continue;
489 if (diff > 0)
491 if (print_unpairables_2)
492 prjoin (&uni_blank, &seq2.lines[0]);
493 freeline (&seq2.lines[0]);
494 seq2.count = 0;
495 getseq (fp2, &seq2);
496 continue;
499 /* Keep reading lines from file1 as long as they continue to
500 match the current line from file2. */
501 eof1 = false;
503 if (!getseq (fp1, &seq1))
505 eof1 = true;
506 ++seq1.count;
507 break;
509 while (!keycmp (&seq1.lines[seq1.count - 1], &seq2.lines[0]));
511 /* Keep reading lines from file2 as long as they continue to
512 match the current line from file1. */
513 eof2 = false;
515 if (!getseq (fp2, &seq2))
517 eof2 = true;
518 ++seq2.count;
519 break;
521 while (!keycmp (&seq1.lines[0], &seq2.lines[seq2.count - 1]));
523 if (print_pairables)
525 for (i = 0; i < seq1.count - 1; ++i)
527 size_t j;
528 for (j = 0; j < seq2.count - 1; ++j)
529 prjoin (&seq1.lines[i], &seq2.lines[j]);
533 for (i = 0; i < seq1.count - 1; ++i)
534 freeline (&seq1.lines[i]);
535 if (!eof1)
537 seq1.lines[0] = seq1.lines[seq1.count - 1];
538 seq1.count = 1;
540 else
541 seq1.count = 0;
543 for (i = 0; i < seq2.count - 1; ++i)
544 freeline (&seq2.lines[i]);
545 if (!eof2)
547 seq2.lines[0] = seq2.lines[seq2.count - 1];
548 seq2.count = 1;
550 else
551 seq2.count = 0;
554 if (print_unpairables_1 && seq1.count)
556 prjoin (&seq1.lines[0], &uni_blank);
557 freeline (&seq1.lines[0]);
558 while (get_line (fp1, &line))
560 prjoin (&line, &uni_blank);
561 freeline (&line);
565 if (print_unpairables_2 && seq2.count)
567 prjoin (&uni_blank, &seq2.lines[0]);
568 freeline (&seq2.lines[0]);
569 while (get_line (fp2, &line))
571 prjoin (&uni_blank, &line);
572 freeline (&line);
576 delseq (&seq1);
577 delseq (&seq2);
580 /* Add a field spec for field FIELD of file FILE to `outlist'. */
582 static void
583 add_field (int file, size_t field)
585 struct outlist *o;
587 assert (file == 0 || file == 1 || file == 2);
588 assert (file != 0 || field == 0);
590 o = xmalloc (sizeof *o);
591 o->file = file;
592 o->field = field;
593 o->next = NULL;
595 /* Add to the end of the list so the fields are in the right order. */
596 outlist_end->next = o;
597 outlist_end = o;
600 /* Convert a string of decimal digits, STR (the 1-based join field number),
601 to an integral value. Upon successful conversion, return one less
602 (the zero-based field number). Silently convert too-large values
603 to SIZE_MAX - 1. Otherwise, if a value cannot be converted, give a
604 diagnostic and exit. */
606 static size_t
607 string_to_join_field (char const *str)
609 size_t result;
610 unsigned long int val;
611 verify (SIZE_MAX <= ULONG_MAX);
613 strtol_error s_err = xstrtoul (str, NULL, 10, &val, "");
614 if (s_err == LONGINT_OVERFLOW || (s_err == LONGINT_OK && SIZE_MAX < val))
615 val = SIZE_MAX;
616 else if (s_err != LONGINT_OK || val == 0)
617 error (EXIT_FAILURE, 0, _("invalid field number: %s"), quote (str));
619 result = val - 1;
621 return result;
624 /* Convert a single field specifier string, S, to a *FILE_INDEX, *FIELD_INDEX
625 pair. In S, the field index string is 1-based; *FIELD_INDEX is zero-based.
626 If S is valid, return true. Otherwise, give a diagnostic and exit. */
628 static void
629 decode_field_spec (const char *s, int *file_index, size_t *field_index)
631 /* The first character must be 0, 1, or 2. */
632 switch (s[0])
634 case '0':
635 if (s[1])
637 /* `0' must be all alone -- no `.FIELD'. */
638 error (EXIT_FAILURE, 0, _("invalid field specifier: %s"), quote (s));
640 *file_index = 0;
641 *field_index = 0;
642 break;
644 case '1':
645 case '2':
646 if (s[1] != '.')
647 error (EXIT_FAILURE, 0, _("invalid field specifier: %s"), quote (s));
648 *file_index = s[0] - '0';
649 *field_index = string_to_join_field (s + 2);
650 break;
652 default:
653 error (EXIT_FAILURE, 0,
654 _("invalid file number in field spec: %s"), quote (s));
656 /* Tell gcc -W -Wall that we can't get beyond this point.
657 This avoids a warning (otherwise legit) that the caller's copies
658 of *file_index and *field_index might be used uninitialized. */
659 abort ();
661 break;
665 /* Add the comma or blank separated field spec(s) in STR to `outlist'. */
667 static void
668 add_field_list (char *str)
670 char *p = str;
674 int file_index;
675 size_t field_index;
676 char const *spec_item = p;
678 p = strpbrk (p, ", \t");
679 if (p)
680 *p++ = '\0';
681 decode_field_spec (spec_item, &file_index, &field_index);
682 add_field (file_index, field_index);
684 while (p);
687 /* Set the join field *VAR to VAL, but report an error if *VAR is set
688 more than once to incompatible values. */
690 static void
691 set_join_field (size_t *var, size_t val)
693 if (*var != SIZE_MAX && *var != val)
695 unsigned long int var1 = *var + 1;
696 unsigned long int val1 = val + 1;
697 error (EXIT_FAILURE, 0, _("incompatible join fields %lu, %lu"),
698 var1, val1);
700 *var = val;
703 /* Status of command-line arguments. */
705 enum operand_status
707 /* This argument must be an operand, i.e., one of the files to be
708 joined. */
709 MUST_BE_OPERAND,
711 /* This might be the argument of the preceding -j1 or -j2 option,
712 or it might be an operand. */
713 MIGHT_BE_J1_ARG,
714 MIGHT_BE_J2_ARG,
716 /* This might be the argument of the preceding -o option, or it might be
717 an operand. */
718 MIGHT_BE_O_ARG
721 /* Add NAME to the array of input file NAMES with operand statuses
722 OPERAND_STATUS; currently there are NFILES names in the list. */
724 static void
725 add_file_name (char *name, char *names[2],
726 int operand_status[2], int joption_count[2], int *nfiles,
727 int *prev_optc_status, int *optc_status)
729 int n = *nfiles;
731 if (n == 2)
733 bool op0 = (operand_status[0] == MUST_BE_OPERAND);
734 char *arg = names[op0];
735 switch (operand_status[op0])
737 case MUST_BE_OPERAND:
738 error (0, 0, _("extra operand %s"), quote (name));
739 usage (EXIT_FAILURE);
741 case MIGHT_BE_J1_ARG:
742 joption_count[0]--;
743 set_join_field (&join_field_1, string_to_join_field (arg));
744 break;
746 case MIGHT_BE_J2_ARG:
747 joption_count[1]--;
748 set_join_field (&join_field_2, string_to_join_field (arg));
749 break;
751 case MIGHT_BE_O_ARG:
752 add_field_list (arg);
753 break;
755 if (!op0)
757 operand_status[0] = operand_status[1];
758 names[0] = names[1];
760 n = 1;
763 operand_status[n] = *prev_optc_status;
764 names[n] = name;
765 *nfiles = n + 1;
766 if (*prev_optc_status == MIGHT_BE_O_ARG)
767 *optc_status = MIGHT_BE_O_ARG;
771 main (int argc, char **argv)
773 int optc_status;
774 int prev_optc_status = MUST_BE_OPERAND;
775 int operand_status[2];
776 int joption_count[2] = { 0, 0 };
777 char *names[2];
778 FILE *fp1, *fp2;
779 int optc;
780 int nfiles = 0;
781 int i;
783 initialize_main (&argc, &argv);
784 program_name = argv[0];
785 setlocale (LC_ALL, "");
786 bindtextdomain (PACKAGE, LOCALEDIR);
787 textdomain (PACKAGE);
788 hard_LC_COLLATE = hard_locale (LC_COLLATE);
790 atexit (close_stdout);
792 print_pairables = true;
794 while ((optc = getopt_long (argc, argv, "-a:e:i1:2:j:o:t:v:",
795 longopts, NULL))
796 != -1)
798 optc_status = MUST_BE_OPERAND;
800 switch (optc)
802 case 'v':
803 print_pairables = false;
804 /* Fall through. */
806 case 'a':
808 unsigned long int val;
809 if (xstrtoul (optarg, NULL, 10, &val, "") != LONGINT_OK
810 || (val != 1 && val != 2))
811 error (EXIT_FAILURE, 0,
812 _("invalid field number: %s"), quote (optarg));
813 if (val == 1)
814 print_unpairables_1 = true;
815 else
816 print_unpairables_2 = true;
818 break;
820 case 'e':
821 if (empty_filler && ! STREQ (empty_filler, optarg))
822 error (EXIT_FAILURE, 0,
823 _("conflicting empty-field replacement strings"));
824 empty_filler = optarg;
825 break;
827 case 'i':
828 ignore_case = true;
829 break;
831 case '1':
832 set_join_field (&join_field_1, string_to_join_field (optarg));
833 break;
835 case '2':
836 set_join_field (&join_field_2, string_to_join_field (optarg));
837 break;
839 case 'j':
840 if ((optarg[0] == '1' || optarg[0] == '2') && !optarg[1]
841 && optarg == argv[optind - 1] + 2)
843 /* The argument was either "-j1" or "-j2". */
844 bool is_j2 = (optarg[0] == '2');
845 joption_count[is_j2]++;
846 optc_status = MIGHT_BE_J1_ARG + is_j2;
848 else
850 set_join_field (&join_field_1, string_to_join_field (optarg));
851 set_join_field (&join_field_2, join_field_1);
853 break;
855 case 'o':
856 add_field_list (optarg);
857 optc_status = MIGHT_BE_O_ARG;
858 break;
860 case 't':
862 unsigned char newtab = optarg[0];
863 if (! newtab)
864 error (EXIT_FAILURE, 0, _("empty tab"));
865 if (optarg[1])
867 if (STREQ (optarg, "\\0"))
868 newtab = '\0';
869 else
870 error (EXIT_FAILURE, 0, _("multi-character tab %s"),
871 quote (optarg));
873 if (0 <= tab && tab != newtab)
874 error (EXIT_FAILURE, 0, _("incompatible tabs"));
875 tab = newtab;
877 break;
879 case 1: /* Non-option argument. */
880 add_file_name (optarg, names, operand_status, joption_count,
881 &nfiles, &prev_optc_status, &optc_status);
882 break;
884 case_GETOPT_HELP_CHAR;
886 case_GETOPT_VERSION_CHAR (PROGRAM_NAME, AUTHORS);
888 default:
889 usage (EXIT_FAILURE);
892 prev_optc_status = optc_status;
895 /* Process any operands after "--". */
896 prev_optc_status = MUST_BE_OPERAND;
897 while (optind < argc)
898 add_file_name (argv[optind++], names, operand_status, joption_count,
899 &nfiles, &prev_optc_status, &optc_status);
901 if (nfiles != 2)
903 if (nfiles == 0)
904 error (0, 0, _("missing operand"));
905 else
906 error (0, 0, _("missing operand after %s"), quote (argv[argc - 1]));
907 usage (EXIT_FAILURE);
910 /* If "-j1" was specified and it turns out not to have had an argument,
911 treat it as "-j 1". Likewise for -j2. */
912 for (i = 0; i < 2; i++)
913 if (joption_count[i] != 0)
915 set_join_field (&join_field_1, i);
916 set_join_field (&join_field_2, i);
919 if (join_field_1 == SIZE_MAX)
920 join_field_1 = 0;
921 if (join_field_2 == SIZE_MAX)
922 join_field_2 = 0;
924 fp1 = STREQ (names[0], "-") ? stdin : fopen (names[0], "r");
925 if (!fp1)
926 error (EXIT_FAILURE, errno, "%s", names[0]);
927 fp2 = STREQ (names[1], "-") ? stdin : fopen (names[1], "r");
928 if (!fp2)
929 error (EXIT_FAILURE, errno, "%s", names[1]);
930 if (fp1 == fp2)
931 error (EXIT_FAILURE, errno, _("both files cannot be standard input"));
932 join (fp1, fp2);
934 if (fclose (fp1) != 0)
935 error (EXIT_FAILURE, errno, "%s", names[0]);
936 if (fclose (fp2) != 0)
937 error (EXIT_FAILURE, errno, "%s", names[1]);
939 exit (EXIT_SUCCESS);