1 /* paste - merge lines of files
2 Copyright (C) 1997-2005, 2008 Free Software Foundation, Inc.
3 Copyright (C) 1984 David M. Ihnat
5 This program is free software: you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation, either version 3 of the License, or
8 (at your option) any later version.
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>. */
18 /* Written by David Ihnat. */
20 /* The list of valid escape sequences has been expanded over the Unix
21 version, to include \b, \f, \r, and \v.
23 POSIX changes, bug fixes, long-named options, and cleanup
24 by David MacKenzie <djm@gnu.ai.mit.edu>.
28 -s Paste one file at a time rather than
29 one line from each file.
30 --delimiters=delim-list
31 -d delim-list Consecutively use the characters in
32 DELIM-LIST instead of tab to separate
33 merged lines. When DELIM-LIST is exhausted,
34 start again at its beginning.
35 A FILE of `-' means standard input.
36 If no FILEs are given, standard input is used. */
42 #include <sys/types.h>
47 /* The official name of this program (e.g., no `g' prefix). */
48 #define PROGRAM_NAME "paste"
51 proper_name ("David M. Ihnat"), \
52 proper_name ("David MacKenzie")
54 /* Indicates that no delimiter should be added in the current position. */
55 #define EMPTY_DELIM '\0'
57 /* If nonzero, we have read standard input at some point. */
58 static bool have_read_stdin;
60 /* If nonzero, merge subsequent lines of each file rather than
61 corresponding lines from each file in parallel. */
62 static bool serial_merge;
64 /* The delimeters between lines of input files (used cyclically). */
67 /* A pointer to the character after the end of `delims'. */
68 static char const *delim_end;
70 static struct option const longopts[] =
72 {"serial", no_argument, NULL, 's'},
73 {"delimiters", required_argument, NULL, 'd'},
74 {GETOPT_HELP_OPTION_DECL},
75 {GETOPT_VERSION_OPTION_DECL},
79 /* Set globals delims and delim_end. Copy STRPTR to DELIMS, converting
80 backslash representations of special characters in STRPTR to their actual
81 values. The set of possible backslash characters has been expanded beyond
82 that recognized by the Unix version.
83 Return 0 upon success.
84 If the string ends in an odd number of backslashes, ignore the
85 final backslash and return nonzero. */
88 collapse_escapes (char const *strptr)
90 char *strout = xstrdup (strptr);
91 bool backslash_at_end = false;
97 if (*strptr != '\\') /* Is it an escape character? */
98 *strout++ = *strptr++; /* No, just transfer it. */
104 *strout++ = EMPTY_DELIM;
136 backslash_at_end = true;
150 return backslash_at_end ? 1 : 0;
153 /* Report a write error and exit. */
155 static void write_error (void) ATTRIBUTE_NORETURN;
159 error (EXIT_FAILURE, errno, _("write error"));
163 /* Output a single byte, reporting any write errors. */
172 /* Perform column paste on the NFILES files named in FNAMPTR.
173 Return true if successful, false if one or more files could not be
177 paste_parallel (size_t nfiles, char **fnamptr)
180 /* If all files are just ready to be closed, or will be on this
181 round, the string of delimiters must be preserved.
182 delbuf[0] through delbuf[nfiles]
183 store the delimiters for closed files. */
184 char *delbuf = xmalloc (nfiles + 2);
186 /* Streams open to the files to process; NULL if the corresponding
188 FILE **fileptr = xnmalloc (nfiles + 1, sizeof *fileptr);
190 /* Number of files still open to process. */
193 /* True if any fopen got fd == STDIN_FILENO. */
194 bool opened_stdin = false;
196 /* Attempt to open all files. This could be expanded to an infinite
197 number of files, but at the (considerable) expense of remembering
198 each file and its current offset, then opening/reading/closing. */
200 for (files_open = 0; files_open < nfiles; ++files_open)
202 if (STREQ (fnamptr[files_open], "-"))
204 have_read_stdin = true;
205 fileptr[files_open] = stdin;
209 fileptr[files_open] = fopen (fnamptr[files_open], "r");
210 if (fileptr[files_open] == NULL)
211 error (EXIT_FAILURE, errno, "%s", fnamptr[files_open]);
212 else if (fileno (fileptr[files_open]) == STDIN_FILENO)
217 if (opened_stdin && have_read_stdin)
218 error (EXIT_FAILURE, 0, _("standard input is closed"));
220 /* Read a line from each file and output it to stdout separated by a
221 delimiter, until we go through the loop without successfully
222 reading from any of the files. */
226 /* Set up for the next line. */
227 bool somedone = false;
228 char const *delimptr = delims;
229 size_t delims_saved = 0; /* Number of delims saved in `delbuf'. */
232 for (i = 0; i < nfiles && files_open; i++)
234 int chr IF_LINT (= 0); /* Input character. */
235 int err IF_LINT (= 0); /* Input errno value. */
236 size_t line_length = 0; /* Number of chars in line. */
240 chr = getc (fileptr[i]);
242 if (chr != EOF && delims_saved)
244 if (fwrite (delbuf, 1, delims_saved, stdout) != delims_saved)
255 chr = getc (fileptr[i]);
260 if (line_length == 0)
262 /* EOF, read error, or closed file.
263 If an EOF or error, close the file. */
266 if (ferror (fileptr[i]))
268 error (0, err, "%s", fnamptr[i]);
271 if (fileptr[i] == stdin)
272 clearerr (fileptr[i]); /* Also clear EOF. */
273 else if (fclose (fileptr[i]) == EOF)
275 error (0, errno, "%s", fnamptr[i]);
285 /* End of this output line.
286 Is this the end of the whole thing? */
289 /* No. Some files were not closed for this line. */
292 if (fwrite (delbuf, 1, delims_saved, stdout)
299 continue; /* Next read of files, or exit. */
303 /* Closed file; add delimiter to `delbuf'. */
304 if (*delimptr != EMPTY_DELIM)
305 delbuf[delims_saved++] = *delimptr;
306 if (++delimptr == delim_end)
312 /* Some data read. */
315 /* Except for last file, replace last newline with delim. */
318 if (chr != '\n' && chr != EOF)
320 if (*delimptr != EMPTY_DELIM)
321 xputchar (*delimptr);
322 if (++delimptr == delim_end)
327 /* If the last line of the last file lacks a newline,
328 print one anyhow. POSIX requires this. */
329 char c = (chr == EOF ? '\n' : chr);
340 /* Perform serial paste on the NFILES files named in FNAMPTR.
341 Return true if no errors, false if one or more files could not be
345 paste_serial (size_t nfiles, char **fnamptr)
347 bool ok = true; /* false if open or read errors occur. */
348 int charnew, charold; /* Current and previous char read. */
349 char const *delimptr; /* Current delimiter char. */
350 FILE *fileptr; /* Open for reading current file. */
352 for (; nfiles; nfiles--, fnamptr++)
355 bool is_stdin = STREQ (*fnamptr, "-");
358 have_read_stdin = true;
363 fileptr = fopen (*fnamptr, "r");
366 error (0, errno, "%s", *fnamptr);
372 delimptr = delims; /* Set up for delimiter string. */
374 charold = getc (fileptr);
378 /* `charold' is set up. Hit it!
379 Keep reading characters, stashing them in `charnew';
380 output `charold', converting to the appropriate delimiter
381 character if needed. After the EOF, output `charold'
382 if it's a newline; otherwise, output it and then a newline. */
384 while ((charnew = getc (fileptr)) != EOF)
386 /* Process the old character. */
389 if (*delimptr != EMPTY_DELIM)
390 xputchar (*delimptr);
392 if (++delimptr == delim_end)
402 /* Hit EOF. Process that last character. */
409 if (ferror (fileptr))
411 error (0, saved_errno, "%s", *fnamptr);
415 clearerr (fileptr); /* Also clear EOF. */
416 else if (fclose (fileptr) == EOF)
418 error (0, errno, "%s", *fnamptr);
428 if (status != EXIT_SUCCESS)
429 fprintf (stderr, _("Try `%s --help' for more information.\n"),
434 Usage: %s [OPTION]... [FILE]...\n\
438 Write lines consisting of the sequentially corresponding lines from\n\
439 each FILE, separated by TABs, to standard output.\n\
440 With no FILE, or when FILE is -, read standard input.\n\
444 Mandatory arguments to long options are mandatory for short options too.\n\
447 -d, --delimiters=LIST reuse characters from LIST instead of TABs\n\
448 -s, --serial paste one file at a time instead of in parallel\n\
450 fputs (HELP_OPTION_DESCRIPTION, stdout);
451 fputs (VERSION_OPTION_DESCRIPTION, stdout);
452 /* FIXME: add a couple of examples. */
453 emit_bug_reporting_address ();
459 main (int argc, char **argv)
463 char const *delim_arg = "\t";
465 initialize_main (&argc, &argv);
466 set_program_name (argv[0]);
467 setlocale (LC_ALL, "");
468 bindtextdomain (PACKAGE, LOCALEDIR);
469 textdomain (PACKAGE);
471 atexit (close_stdout);
473 have_read_stdin = false;
474 serial_merge = false;
476 while ((optc = getopt_long (argc, argv, "d:s", longopts, NULL)) != -1)
481 /* Delimiter character(s). */
482 delim_arg = (optarg[0] == '\0' ? "\\0" : optarg);
489 case_GETOPT_HELP_CHAR;
491 case_GETOPT_VERSION_CHAR (PROGRAM_NAME, AUTHORS);
494 usage (EXIT_FAILURE);
501 if (collapse_escapes (delim_arg))
503 /* Don't use the default quoting style, because that would double the
504 number of displayed backslashes, making the diagnostic look bogus. */
505 set_quoting_style (NULL, escape_quoting_style);
506 error (EXIT_FAILURE, 0,
507 _("delimiter list ends with an unescaped backslash: %s"),
508 quotearg_colon (delim_arg));
512 ok = paste_parallel (argc - optind, &argv[optind]);
514 ok = paste_serial (argc - optind, &argv[optind]);
518 if (have_read_stdin && fclose (stdin) == EOF)
519 error (EXIT_FAILURE, errno, "-");
520 exit (ok ? EXIT_SUCCESS : EXIT_FAILURE);