TODO: add an item for a chmod optimization
[platform/upstream/coreutils.git] / src / join.c
1 /* join - join lines of two files on a common field
2    Copyright (C) 91, 1995-2006, 2008 Free Software Foundation, Inc.
3
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.
8
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.
13
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/>.
16
17    Written by Mike Haertel, mike@gnu.ai.mit.edu.  */
18
19 #include <config.h>
20
21 #include <assert.h>
22 #include <sys/types.h>
23 #include <getopt.h>
24
25 #include "system.h"
26 #include "error.h"
27 #include "hard-locale.h"
28 #include "linebuffer.h"
29 #include "memcasecmp.h"
30 #include "quote.h"
31 #include "stdio--.h"
32 #include "xmemcoll.h"
33 #include "xstrtol.h"
34 #include "argmatch.h"
35
36 /* The official name of this program (e.g., no `g' prefix).  */
37 #define PROGRAM_NAME "join"
38
39 #define AUTHORS proper_name ("Mike Haertel")
40
41 #define join system_join
42
43 #define SWAPLINES(a, b) do { \
44   struct line *tmp = a; \
45   a = b; \
46   b = tmp; \
47 } while (0);
48
49 /* An element of the list identifying which fields to print for each
50    output line.  */
51 struct outlist
52   {
53     /* File number: 0, 1, or 2.  0 means use the join field.
54        1 means use the first file argument, 2 the second.  */
55     int file;
56
57     /* Field index (zero-based), specified only when FILE is 1 or 2.  */
58     size_t field;
59
60     struct outlist *next;
61   };
62
63 /* A field of a line.  */
64 struct field
65   {
66     char *beg;                  /* First character in field.  */
67     size_t len;                 /* The length of the field.  */
68   };
69
70 /* A line read from an input file.  */
71 struct line
72   {
73     struct linebuffer buf;      /* The line itself.  */
74     size_t nfields;             /* Number of elements in `fields'.  */
75     size_t nfields_allocated;   /* Number of elements allocated for `fields'. */
76     struct field *fields;
77   };
78
79 /* One or more consecutive lines read from a file that all have the
80    same join field value.  */
81 struct seq
82   {
83     size_t count;                       /* Elements used in `lines'.  */
84     size_t alloc;                       /* Elements allocated in `lines'.  */
85     struct line **lines;
86   };
87
88 /* The previous line read from each file. */
89 static struct line *prevline[2] = {NULL, NULL};
90
91 /* This provides an extra line buffer for each file.  We need these if we
92    try to read two consecutive lines into the same buffer, since we don't
93    want to overwrite the previous buffer before we check order. */
94 static struct line *spareline[2] = {NULL, NULL};
95
96 /* True if the LC_COLLATE locale is hard.  */
97 static bool hard_LC_COLLATE;
98
99 /* If nonzero, print unpairable lines in file 1 or 2.  */
100 static bool print_unpairables_1, print_unpairables_2;
101
102 /* If nonzero, print pairable lines.  */
103 static bool print_pairables;
104
105 /* If nonzero, we have seen at least one unpairable line. */
106 static bool seen_unpairable;
107
108 /* If nonzero, we have warned about disorder in that file. */
109 static bool issued_disorder_warning[2];
110
111 /* Empty output field filler.  */
112 static char const *empty_filler;
113
114 /* Field to join on; SIZE_MAX means they haven't been determined yet.  */
115 static size_t join_field_1 = SIZE_MAX;
116 static size_t join_field_2 = SIZE_MAX;
117
118 /* List of fields to print.  */
119 static struct outlist outlist_head;
120
121 /* Last element in `outlist', where a new element can be added.  */
122 static struct outlist *outlist_end = &outlist_head;
123
124 /* Tab character separating fields.  If negative, fields are separated
125    by any nonempty string of blanks, otherwise by exactly one
126    tab character whose value (when cast to unsigned char) equals TAB.  */
127 static int tab = -1;
128
129 /* If nonzero, check that the input is correctly ordered. */
130 static enum
131   {
132     CHECK_ORDER_DEFAULT,
133     CHECK_ORDER_ENABLED,
134     CHECK_ORDER_DISABLED
135   } check_input_order;
136
137 enum
138 {
139   CHECK_ORDER_OPTION = CHAR_MAX + 1,
140   NOCHECK_ORDER_OPTION
141 };
142
143
144 static struct option const longopts[] =
145 {
146   {"ignore-case", no_argument, NULL, 'i'},
147   {"check-order", no_argument, NULL, CHECK_ORDER_OPTION},
148   {"nocheck-order", no_argument, NULL, NOCHECK_ORDER_OPTION},
149   {GETOPT_HELP_OPTION_DECL},
150   {GETOPT_VERSION_OPTION_DECL},
151   {NULL, 0, NULL, 0}
152 };
153
154 /* Used to print non-joining lines */
155 static struct line uni_blank;
156
157 /* If nonzero, ignore case when comparing join fields.  */
158 static bool ignore_case;
159
160 void
161 usage (int status)
162 {
163   if (status != EXIT_SUCCESS)
164     fprintf (stderr, _("Try `%s --help' for more information.\n"),
165              program_name);
166   else
167     {
168       printf (_("\
169 Usage: %s [OPTION]... FILE1 FILE2\n\
170 "),
171               program_name);
172       fputs (_("\
173 For each pair of input lines with identical join fields, write a line to\n\
174 standard output.  The default join field is the first, delimited\n\
175 by whitespace.  When FILE1 or FILE2 (not both) is -, read standard input.\n\
176 \n\
177   -a FILENUM        print unpairable lines coming from file FILENUM, where\n\
178                       FILENUM is 1 or 2, corresponding to FILE1 or FILE2\n\
179   -e EMPTY          replace missing input fields with EMPTY\n\
180 "), stdout);
181       fputs (_("\
182   -i, --ignore-case  ignore differences in case when comparing fields\n\
183   -j FIELD          equivalent to `-1 FIELD -2 FIELD'\n\
184   -o FORMAT         obey FORMAT while constructing output line\n\
185   -t CHAR           use CHAR as input and output field separator\n\
186 "), stdout);
187       fputs (_("\
188   -v FILENUM        like -a FILENUM, but suppress joined output lines\n\
189   -1 FIELD          join on this FIELD of file 1\n\
190   -2 FIELD          join on this FIELD of file 2\n\
191   --check-order     check that the input is correctly sorted, even\n\
192                       if all input lines are pairable\n\
193   --nocheck-order   do not check that the input is correctly sorted\n\
194 "), stdout);
195       fputs (HELP_OPTION_DESCRIPTION, stdout);
196       fputs (VERSION_OPTION_DESCRIPTION, stdout);
197       fputs (_("\
198 \n\
199 Unless -t CHAR is given, leading blanks separate fields and are ignored,\n\
200 else fields are separated by CHAR.  Any FIELD is a field number counted\n\
201 from 1.  FORMAT is one or more comma or blank separated specifications,\n\
202 each being `FILENUM.FIELD' or `0'.  Default FORMAT outputs the join field,\n\
203 the remaining fields from FILE1, the remaining fields from FILE2, all\n\
204 separated by CHAR.\n\
205 \n\
206 Important: FILE1 and FILE2 must be sorted on the join fields.\n\
207 E.g., use `sort -k 1b,1' if `join' has no options.\n\
208 If the input is not sorted and some lines cannot be joined, a\n\
209 warning message will be given.\n\
210 "), stdout);
211       emit_bug_reporting_address ();
212     }
213   exit (status);
214 }
215
216 /* Record a field in LINE, with location FIELD and size LEN.  */
217
218 static void
219 extract_field (struct line *line, char *field, size_t len)
220 {
221   if (line->nfields >= line->nfields_allocated)
222     {
223       line->fields = X2NREALLOC (line->fields, &line->nfields_allocated);
224     }
225   line->fields[line->nfields].beg = field;
226   line->fields[line->nfields].len = len;
227   ++(line->nfields);
228 }
229
230 /* Fill in the `fields' structure in LINE.  */
231
232 static void
233 xfields (struct line *line)
234 {
235   char *ptr = line->buf.buffer;
236   char const *lim = ptr + line->buf.length - 1;
237
238   if (ptr == lim)
239     return;
240
241   if (0 <= tab)
242     {
243       char *sep;
244       for (; (sep = memchr (ptr, tab, lim - ptr)) != NULL; ptr = sep + 1)
245         extract_field (line, ptr, sep - ptr);
246     }
247   else
248     {
249       /* Skip leading blanks before the first field.  */
250       while (isblank (to_uchar (*ptr)))
251         if (++ptr == lim)
252           return;
253
254       do
255         {
256           char *sep;
257           for (sep = ptr + 1; sep != lim && ! isblank (to_uchar (*sep)); sep++)
258             continue;
259           extract_field (line, ptr, sep - ptr);
260           if (sep == lim)
261             return;
262           for (ptr = sep + 1; ptr != lim && isblank (to_uchar (*ptr)); ptr++)
263             continue;
264         }
265       while (ptr != lim);
266     }
267
268   extract_field (line, ptr, lim - ptr);
269 }
270
271 static void
272 freeline (struct line *line)
273 {
274   free (line->fields);
275   free (line->buf.buffer);
276   line->buf.buffer = NULL;
277 }
278
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.  */
283
284 static int
285 keycmp (struct line const *line1, struct line const *line2,
286         size_t jf_1, size_t jf_2)
287 {
288   /* Start of field to compare in each file.  */
289   char *beg1;
290   char *beg2;
291
292   size_t len1;
293   size_t len2;          /* Length of fields to compare.  */
294   int diff;
295
296   if (jf_1 < line1->nfields)
297     {
298       beg1 = line1->fields[jf_1].beg;
299       len1 = line1->fields[jf_1].len;
300     }
301   else
302     {
303       beg1 = NULL;
304       len1 = 0;
305     }
306
307   if (jf_2 < line2->nfields)
308     {
309       beg2 = line2->fields[jf_2].beg;
310       len2 = line2->fields[jf_2].len;
311     }
312   else
313     {
314       beg2 = NULL;
315       len2 = 0;
316     }
317
318   if (len1 == 0)
319     return len2 == 0 ? 0 : -1;
320   if (len2 == 0)
321     return 1;
322
323   if (ignore_case)
324     {
325       /* FIXME: ignore_case does not work with NLS (in particular,
326          with multibyte chars).  */
327       diff = memcasecmp (beg1, beg2, MIN (len1, len2));
328     }
329   else
330     {
331       if (hard_LC_COLLATE)
332         return xmemcoll (beg1, len1, beg2, len2);
333       diff = memcmp (beg1, beg2, MIN (len1, len2));
334     }
335
336   if (diff)
337     return diff;
338   return len1 < len2 ? -1 : len1 != len2;
339 }
340
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.
345
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.
349
350    A message is printed at most once per input file. */
351
352 static void
353 check_order (const struct line *prev,
354              const struct line *current,
355              int whatfile)
356 {
357   if (check_input_order != CHECK_ORDER_DISABLED
358       && ((check_input_order == CHECK_ORDER_ENABLED) || seen_unpairable))
359     {
360       if (!issued_disorder_warning[whatfile-1])
361         {
362           size_t join_field = whatfile == 1 ? join_field_1 : join_field_2;
363           if (keycmp (prev, current, join_field, join_field) > 0)
364             {
365               error ((check_input_order == CHECK_ORDER_ENABLED
366                       ? EXIT_FAILURE : 0),
367                      0, _("file %d is not in sorted order"), whatfile);
368
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;
372             }
373         }
374     }
375 }
376
377 static inline void
378 reset_line (struct line *line)
379 {
380   line->nfields = 0;
381 }
382
383 static struct line *
384 init_linep (struct line **linep)
385 {
386   struct line *line = xmalloc (sizeof *line);
387   memset (line, '\0', sizeof *line);
388   *linep = line;
389   return line;
390 }
391
392 /* Read a line from FP into LINE and split it into fields.
393    Return true if successful.  */
394
395 static bool
396 get_line (FILE *fp, struct line **linep, int which)
397 {
398   struct line *line = *linep;
399
400   if (line == prevline[which - 1])
401     {
402       SWAPLINES (line, spareline[which - 1]);
403       *linep = line;
404     }
405
406   if (line)
407     reset_line (line);
408   else
409     line = init_linep (linep);
410
411   if (! readlinebuffer (&line->buf, fp))
412     {
413       if (ferror (fp))
414         error (EXIT_FAILURE, errno, _("read error"));
415       freeline (line);
416       return false;
417     }
418
419   xfields (line);
420
421   if (prevline[which - 1])
422     check_order (prevline[which - 1], line, which);
423
424   prevline[which - 1] = line;
425   return true;
426 }
427
428 static void
429 free_spareline (void)
430 {
431   size_t i;
432
433   for (i = 0; i < ARRAY_CARDINALITY (spareline); i++)
434     {
435       if (spareline[i])
436         {
437           freeline (spareline[i]);
438           free (spareline[i]);
439         }
440     }
441 }
442
443 static void
444 initseq (struct seq *seq)
445 {
446   seq->count = 0;
447   seq->alloc = 0;
448   seq->lines = NULL;
449 }
450
451 /* Read a line from FP and add it to SEQ.  Return true if successful.  */
452
453 static bool
454 getseq (FILE *fp, struct seq *seq, int whichfile)
455 {
456   if (seq->count == seq->alloc)
457     {
458       size_t i;
459       seq->lines = X2NREALLOC (seq->lines, &seq->alloc);
460       for (i = seq->count; i < seq->alloc; i++)
461         seq->lines[i] = NULL;
462     }
463
464   if (get_line (fp, &seq->lines[seq->count], whichfile))
465     {
466       ++seq->count;
467       return true;
468     }
469   return false;
470 }
471
472 /* Read a line from FP and add it to SEQ, as the first item if FIRST is
473    true, else as the next.  */
474 static bool
475 advance_seq (FILE *fp, struct seq *seq, bool first, int whichfile)
476 {
477   if (first)
478     seq->count = 0;
479
480   return getseq (fp, seq, whichfile);
481 }
482
483 static void
484 delseq (struct seq *seq)
485 {
486   size_t i;
487   for (i = 0; i < seq->alloc; i++)
488     if (seq->lines[i])
489       {
490         if (seq->lines[i]->buf.buffer)
491           freeline (seq->lines[i]);
492         free (seq->lines[i]);
493       }
494   free (seq->lines);
495 }
496
497
498 /* Print field N of LINE if it exists and is nonempty, otherwise
499    `empty_filler' if it is nonempty.  */
500
501 static void
502 prfield (size_t n, struct line const *line)
503 {
504   size_t len;
505
506   if (n < line->nfields)
507     {
508       len = line->fields[n].len;
509       if (len)
510         fwrite (line->fields[n].beg, 1, len, stdout);
511       else if (empty_filler)
512         fputs (empty_filler, stdout);
513     }
514   else if (empty_filler)
515     fputs (empty_filler, stdout);
516 }
517
518 /* Print the join of LINE1 and LINE2.  */
519
520 static void
521 prjoin (struct line const *line1, struct line const *line2)
522 {
523   const struct outlist *outlist;
524   char output_separator = tab < 0 ? ' ' : tab;
525
526   outlist = outlist_head.next;
527   if (outlist)
528     {
529       const struct outlist *o;
530
531       o = outlist;
532       while (1)
533         {
534           size_t field;
535           struct line const *line;
536
537           if (o->file == 0)
538             {
539               if (line1 == &uni_blank)
540                 {
541                   line = line2;
542                   field = join_field_2;
543                 }
544               else
545                 {
546                   line = line1;
547                   field = join_field_1;
548                 }
549             }
550           else
551             {
552               line = (o->file == 1 ? line1 : line2);
553               field = o->field;
554             }
555           prfield (field, line);
556           o = o->next;
557           if (o == NULL)
558             break;
559           putchar (output_separator);
560         }
561       putchar ('\n');
562     }
563   else
564     {
565       size_t i;
566
567       if (line1 == &uni_blank)
568         {
569           struct line const *t;
570           t = line1;
571           line1 = line2;
572           line2 = t;
573         }
574       prfield (join_field_1, line1);
575       for (i = 0; i < join_field_1 && i < line1->nfields; ++i)
576         {
577           putchar (output_separator);
578           prfield (i, line1);
579         }
580       for (i = join_field_1 + 1; i < line1->nfields; ++i)
581         {
582           putchar (output_separator);
583           prfield (i, line1);
584         }
585
586       for (i = 0; i < join_field_2 && i < line2->nfields; ++i)
587         {
588           putchar (output_separator);
589           prfield (i, line2);
590         }
591       for (i = join_field_2 + 1; i < line2->nfields; ++i)
592         {
593           putchar (output_separator);
594           prfield (i, line2);
595         }
596       putchar ('\n');
597     }
598 }
599
600 /* Print the join of the files in FP1 and FP2.  */
601
602 static void
603 join (FILE *fp1, FILE *fp2)
604 {
605   struct seq seq1, seq2;
606   struct line **linep = xmalloc (sizeof *linep);
607   int diff;
608   bool eof1, eof2, checktail;
609
610   *linep = NULL;
611
612   /* Read the first line of each file.  */
613   initseq (&seq1);
614   getseq (fp1, &seq1, 1);
615   initseq (&seq2);
616   getseq (fp2, &seq2, 2);
617
618   while (seq1.count && seq2.count)
619     {
620       size_t i;
621       diff = keycmp (seq1.lines[0], seq2.lines[0],
622                      join_field_1, join_field_2);
623       if (diff < 0)
624         {
625           if (print_unpairables_1)
626             prjoin (seq1.lines[0], &uni_blank);
627           advance_seq (fp1, &seq1, true, 1);
628           seen_unpairable = true;
629           continue;
630         }
631       if (diff > 0)
632         {
633           if (print_unpairables_2)
634             prjoin (&uni_blank, seq2.lines[0]);
635           advance_seq (fp2, &seq2, true, 2);
636           seen_unpairable = true;
637           continue;
638         }
639
640       /* Keep reading lines from file1 as long as they continue to
641          match the current line from file2.  */
642       eof1 = false;
643       do
644         if (!advance_seq (fp1, &seq1, false, 1))
645           {
646             eof1 = true;
647             ++seq1.count;
648             break;
649           }
650       while (!keycmp (seq1.lines[seq1.count - 1], seq2.lines[0],
651                       join_field_1, join_field_2));
652
653       /* Keep reading lines from file2 as long as they continue to
654          match the current line from file1.  */
655       eof2 = false;
656       do
657         if (!advance_seq (fp2, &seq2, false, 2))
658           {
659             eof2 = true;
660             ++seq2.count;
661             break;
662           }
663       while (!keycmp (seq1.lines[0], seq2.lines[seq2.count - 1],
664                       join_field_1, join_field_2));
665
666       if (print_pairables)
667         {
668           for (i = 0; i < seq1.count - 1; ++i)
669             {
670               size_t j;
671               for (j = 0; j < seq2.count - 1; ++j)
672                 prjoin (seq1.lines[i], seq2.lines[j]);
673             }
674         }
675
676       if (!eof1)
677         {
678           SWAPLINES (seq1.lines[0], seq1.lines[seq1.count - 1]);
679           seq1.count = 1;
680         }
681       else
682         seq1.count = 0;
683
684       if (!eof2)
685         {
686           SWAPLINES (seq2.lines[0], seq2.lines[seq2.count - 1]);
687           seq2.count = 1;
688         }
689       else
690         seq2.count = 0;
691     }
692
693   /* If the user did not specify --check-order, and the we read the
694      tail ends of both inputs to verify that they are in order.  We
695      skip the rest of the tail once we have issued a warning for that
696      file, unless we actually need to print the unpairable lines.  */
697   if (check_input_order != CHECK_ORDER_DISABLED
698       && !(issued_disorder_warning[0] && issued_disorder_warning[1]))
699     checktail = true;
700   else
701     checktail = false;
702
703   if ((print_unpairables_1 || checktail) && seq1.count)
704     {
705       if (print_unpairables_1)
706         prjoin (seq1.lines[0], &uni_blank);
707       seen_unpairable = true;
708       while (get_line (fp1, linep, 1))
709         {
710           if (print_unpairables_1)
711             prjoin (*linep, &uni_blank);
712           if (issued_disorder_warning[0] && !print_unpairables_1)
713             break;
714         }
715     }
716
717   if ((print_unpairables_2 || checktail) && seq2.count)
718     {
719       if (print_unpairables_2)
720         prjoin (&uni_blank, seq2.lines[0]);
721       seen_unpairable = true;
722       while (get_line (fp2, linep, 2))
723         {
724           if (print_unpairables_2)
725             prjoin (&uni_blank, *linep);
726           if (issued_disorder_warning[1] && !print_unpairables_2)
727             break;
728         }
729     }
730
731   free (*linep);
732
733   free (linep);
734   delseq (&seq1);
735   delseq (&seq2);
736 }
737
738 /* Add a field spec for field FIELD of file FILE to `outlist'.  */
739
740 static void
741 add_field (int file, size_t field)
742 {
743   struct outlist *o;
744
745   assert (file == 0 || file == 1 || file == 2);
746   assert (file != 0 || field == 0);
747
748   o = xmalloc (sizeof *o);
749   o->file = file;
750   o->field = field;
751   o->next = NULL;
752
753   /* Add to the end of the list so the fields are in the right order.  */
754   outlist_end->next = o;
755   outlist_end = o;
756 }
757
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.  */
763
764 static size_t
765 string_to_join_field (char const *str)
766 {
767   size_t result;
768   unsigned long int val;
769   verify (SIZE_MAX <= ULONG_MAX);
770
771   strtol_error s_err = xstrtoul (str, NULL, 10, &val, "");
772   if (s_err == LONGINT_OVERFLOW || (s_err == LONGINT_OK && SIZE_MAX < val))
773     val = SIZE_MAX;
774   else if (s_err != LONGINT_OK || val == 0)
775     error (EXIT_FAILURE, 0, _("invalid field number: %s"), quote (str));
776
777   result = val - 1;
778
779   return result;
780 }
781
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.  */
785
786 static void
787 decode_field_spec (const char *s, int *file_index, size_t *field_index)
788 {
789   /* The first character must be 0, 1, or 2.  */
790   switch (s[0])
791     {
792     case '0':
793       if (s[1])
794         {
795           /* `0' must be all alone -- no `.FIELD'.  */
796           error (EXIT_FAILURE, 0, _("invalid field specifier: %s"), quote (s));
797         }
798       *file_index = 0;
799       *field_index = 0;
800       break;
801
802     case '1':
803     case '2':
804       if (s[1] != '.')
805         error (EXIT_FAILURE, 0, _("invalid field specifier: %s"), quote (s));
806       *file_index = s[0] - '0';
807       *field_index = string_to_join_field (s + 2);
808       break;
809
810     default:
811       error (EXIT_FAILURE, 0,
812              _("invalid file number in field spec: %s"), quote (s));
813
814       /* Tell gcc -W -Wall that we can't get beyond this point.
815          This avoids a warning (otherwise legit) that the caller's copies
816          of *file_index and *field_index might be used uninitialized.  */
817       abort ();
818
819       break;
820     }
821 }
822
823 /* Add the comma or blank separated field spec(s) in STR to `outlist'.  */
824
825 static void
826 add_field_list (char *str)
827 {
828   char *p = str;
829
830   do
831     {
832       int file_index;
833       size_t field_index;
834       char const *spec_item = p;
835
836       p = strpbrk (p, ", \t");
837       if (p)
838         *p++ = '\0';
839       decode_field_spec (spec_item, &file_index, &field_index);
840       add_field (file_index, field_index);
841     }
842   while (p);
843 }
844
845 /* Set the join field *VAR to VAL, but report an error if *VAR is set
846    more than once to incompatible values.  */
847
848 static void
849 set_join_field (size_t *var, size_t val)
850 {
851   if (*var != SIZE_MAX && *var != val)
852     {
853       unsigned long int var1 = *var + 1;
854       unsigned long int val1 = val + 1;
855       error (EXIT_FAILURE, 0, _("incompatible join fields %lu, %lu"),
856              var1, val1);
857     }
858   *var = val;
859 }
860
861 /* Status of command-line arguments.  */
862
863 enum operand_status
864   {
865     /* This argument must be an operand, i.e., one of the files to be
866        joined.  */
867     MUST_BE_OPERAND,
868
869     /* This might be the argument of the preceding -j1 or -j2 option,
870        or it might be an operand.  */
871     MIGHT_BE_J1_ARG,
872     MIGHT_BE_J2_ARG,
873
874     /* This might be the argument of the preceding -o option, or it might be
875        an operand.  */
876     MIGHT_BE_O_ARG
877   };
878
879 /* Add NAME to the array of input file NAMES with operand statuses
880    OPERAND_STATUS; currently there are NFILES names in the list.  */
881
882 static void
883 add_file_name (char *name, char *names[2],
884                int operand_status[2], int joption_count[2], int *nfiles,
885                int *prev_optc_status, int *optc_status)
886 {
887   int n = *nfiles;
888
889   if (n == 2)
890     {
891       bool op0 = (operand_status[0] == MUST_BE_OPERAND);
892       char *arg = names[op0];
893       switch (operand_status[op0])
894         {
895         case MUST_BE_OPERAND:
896           error (0, 0, _("extra operand %s"), quote (name));
897           usage (EXIT_FAILURE);
898
899         case MIGHT_BE_J1_ARG:
900           joption_count[0]--;
901           set_join_field (&join_field_1, string_to_join_field (arg));
902           break;
903
904         case MIGHT_BE_J2_ARG:
905           joption_count[1]--;
906           set_join_field (&join_field_2, string_to_join_field (arg));
907           break;
908
909         case MIGHT_BE_O_ARG:
910           add_field_list (arg);
911           break;
912         }
913       if (!op0)
914         {
915           operand_status[0] = operand_status[1];
916           names[0] = names[1];
917         }
918       n = 1;
919     }
920
921   operand_status[n] = *prev_optc_status;
922   names[n] = name;
923   *nfiles = n + 1;
924   if (*prev_optc_status == MIGHT_BE_O_ARG)
925     *optc_status = MIGHT_BE_O_ARG;
926 }
927
928 int
929 main (int argc, char **argv)
930 {
931   int optc_status;
932   int prev_optc_status = MUST_BE_OPERAND;
933   int operand_status[2];
934   int joption_count[2] = { 0, 0 };
935   char *names[2];
936   FILE *fp1, *fp2;
937   int optc;
938   int nfiles = 0;
939   int i;
940
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);
947
948   atexit (close_stdout);
949   atexit (free_spareline);
950
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;
955
956   while ((optc = getopt_long (argc, argv, "-a:e:i1:2:j:o:t:v:",
957                               longopts, NULL))
958          != -1)
959     {
960       optc_status = MUST_BE_OPERAND;
961
962       switch (optc)
963         {
964         case 'v':
965             print_pairables = false;
966             /* Fall through.  */
967
968         case 'a':
969           {
970             unsigned long int val;
971             if (xstrtoul (optarg, NULL, 10, &val, "") != LONGINT_OK
972                 || (val != 1 && val != 2))
973               error (EXIT_FAILURE, 0,
974                      _("invalid field number: %s"), quote (optarg));
975             if (val == 1)
976               print_unpairables_1 = true;
977             else
978               print_unpairables_2 = true;
979           }
980           break;
981
982         case 'e':
983           if (empty_filler && ! STREQ (empty_filler, optarg))
984             error (EXIT_FAILURE, 0,
985                    _("conflicting empty-field replacement strings"));
986           empty_filler = optarg;
987           break;
988
989         case 'i':
990           ignore_case = true;
991           break;
992
993         case '1':
994           set_join_field (&join_field_1, string_to_join_field (optarg));
995           break;
996
997         case '2':
998           set_join_field (&join_field_2, string_to_join_field (optarg));
999           break;
1000
1001         case 'j':
1002           if ((optarg[0] == '1' || optarg[0] == '2') && !optarg[1]
1003               && optarg == argv[optind - 1] + 2)
1004             {
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;
1009             }
1010           else
1011             {
1012               set_join_field (&join_field_1, string_to_join_field (optarg));
1013               set_join_field (&join_field_2, join_field_1);
1014             }
1015           break;
1016
1017         case 'o':
1018           add_field_list (optarg);
1019           optc_status = MIGHT_BE_O_ARG;
1020           break;
1021
1022         case 't':
1023           {
1024             unsigned char newtab = optarg[0];
1025             if (! newtab)
1026               error (EXIT_FAILURE, 0, _("empty tab"));
1027             if (optarg[1])
1028               {
1029                 if (STREQ (optarg, "\\0"))
1030                   newtab = '\0';
1031                 else
1032                   error (EXIT_FAILURE, 0, _("multi-character tab %s"),
1033                          quote (optarg));
1034               }
1035             if (0 <= tab && tab != newtab)
1036               error (EXIT_FAILURE, 0, _("incompatible tabs"));
1037             tab = newtab;
1038           }
1039           break;
1040
1041         case NOCHECK_ORDER_OPTION:
1042           check_input_order = CHECK_ORDER_DISABLED;
1043           break;
1044
1045         case CHECK_ORDER_OPTION:
1046           check_input_order = CHECK_ORDER_ENABLED;
1047           break;
1048
1049         case 1:         /* Non-option argument.  */
1050           add_file_name (optarg, names, operand_status, joption_count,
1051                          &nfiles, &prev_optc_status, &optc_status);
1052           break;
1053
1054         case_GETOPT_HELP_CHAR;
1055
1056         case_GETOPT_VERSION_CHAR (PROGRAM_NAME, AUTHORS);
1057
1058         default:
1059           usage (EXIT_FAILURE);
1060         }
1061
1062       prev_optc_status = optc_status;
1063     }
1064
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);
1070
1071   if (nfiles != 2)
1072     {
1073       if (nfiles == 0)
1074         error (0, 0, _("missing operand"));
1075       else
1076         error (0, 0, _("missing operand after %s"), quote (argv[argc - 1]));
1077       usage (EXIT_FAILURE);
1078     }
1079
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)
1084       {
1085         set_join_field (&join_field_1, i);
1086         set_join_field (&join_field_2, i);
1087       }
1088
1089   if (join_field_1 == SIZE_MAX)
1090     join_field_1 = 0;
1091   if (join_field_2 == SIZE_MAX)
1092     join_field_2 = 0;
1093
1094   fp1 = STREQ (names[0], "-") ? stdin : fopen (names[0], "r");
1095   if (!fp1)
1096     error (EXIT_FAILURE, errno, "%s", names[0]);
1097   fp2 = STREQ (names[1], "-") ? stdin : fopen (names[1], "r");
1098   if (!fp2)
1099     error (EXIT_FAILURE, errno, "%s", names[1]);
1100   if (fp1 == fp2)
1101     error (EXIT_FAILURE, errno, _("both files cannot be standard input"));
1102   join (fp1, fp2);
1103
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]);
1108
1109   if (issued_disorder_warning[0] || issued_disorder_warning[1])
1110     exit (EXIT_FAILURE);
1111   else
1112     exit (EXIT_SUCCESS);
1113 }