1 /* paste - merge lines of files
2 Copyright (C) 1997-2016 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 delimiters 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 unsigned char line_delim
= '\n';
72 static struct option
const longopts
[] =
74 {"serial", no_argument
, NULL
, 's'},
75 {"delimiters", required_argument
, NULL
, 'd'},
76 {"zero-terminated", no_argument
, NULL
, 'z'},
77 {GETOPT_HELP_OPTION_DECL
},
78 {GETOPT_VERSION_OPTION_DECL
},
82 /* Set globals delims and delim_end. Copy STRPTR to DELIMS, converting
83 backslash representations of special characters in STRPTR to their actual
84 values. The set of possible backslash characters has been expanded beyond
85 that recognized by the Unix version.
86 Return 0 upon success.
87 If the string ends in an odd number of backslashes, ignore the
88 final backslash and return nonzero. */
91 collapse_escapes (char const *strptr
)
93 char *strout
= xstrdup (strptr
);
94 bool backslash_at_end
= false;
100 if (*strptr
!= '\\') /* Is it an escape character? */
101 *strout
++ = *strptr
++; /* No, just transfer it. */
107 *strout
++ = EMPTY_DELIM
;
139 backslash_at_end
= true;
153 return backslash_at_end
? 1 : 0;
156 /* Report a write error and exit. */
158 static void write_error (void) ATTRIBUTE_NORETURN
;
162 error (EXIT_FAILURE
, errno
, _("write error"));
166 /* Output a single byte, reporting any write errors. */
175 /* Perform column paste on the NFILES files named in FNAMPTR.
176 Return true if successful, false if one or more files could not be
180 paste_parallel (size_t nfiles
, char **fnamptr
)
183 /* If all files are just ready to be closed, or will be on this
184 round, the string of delimiters must be preserved.
185 delbuf[0] through delbuf[nfiles]
186 store the delimiters for closed files. */
187 char *delbuf
= xmalloc (nfiles
+ 2);
189 /* Streams open to the files to process; NULL if the corresponding
191 FILE **fileptr
= xnmalloc (nfiles
+ 1, sizeof *fileptr
);
193 /* Number of files still open to process. */
196 /* True if any fopen got fd == STDIN_FILENO. */
197 bool opened_stdin
= false;
199 /* Attempt to open all files. This could be expanded to an infinite
200 number of files, but at the (considerable) expense of remembering
201 each file and its current offset, then opening/reading/closing. */
203 for (files_open
= 0; files_open
< nfiles
; ++files_open
)
205 if (STREQ (fnamptr
[files_open
], "-"))
207 have_read_stdin
= true;
208 fileptr
[files_open
] = stdin
;
212 fileptr
[files_open
] = fopen (fnamptr
[files_open
], "r");
213 if (fileptr
[files_open
] == NULL
)
214 error (EXIT_FAILURE
, errno
, "%s", quotef (fnamptr
[files_open
]));
215 else if (fileno (fileptr
[files_open
]) == STDIN_FILENO
)
217 fadvise (fileptr
[files_open
], FADVISE_SEQUENTIAL
);
221 if (opened_stdin
&& have_read_stdin
)
222 error (EXIT_FAILURE
, 0, _("standard input is closed"));
224 /* Read a line from each file and output it to stdout separated by a
225 delimiter, until we go through the loop without successfully
226 reading from any of the files. */
230 /* Set up for the next line. */
231 bool somedone
= false;
232 char const *delimptr
= delims
;
233 size_t delims_saved
= 0; /* Number of delims saved in 'delbuf'. */
236 for (i
= 0; i
< nfiles
&& files_open
; i
++)
238 int chr
IF_LINT ( = 0); /* Input character. */
239 int err
IF_LINT ( = 0); /* Input errno value. */
240 bool sometodo
= false; /* Input chars to process. */
244 chr
= getc (fileptr
[i
]);
246 if (chr
!= EOF
&& delims_saved
)
248 if (fwrite (delbuf
, 1, delims_saved
, stdout
) != delims_saved
)
256 if (chr
== line_delim
)
259 chr
= getc (fileptr
[i
]);
266 /* EOF, read error, or closed file.
267 If an EOF or error, close the file. */
270 if (ferror (fileptr
[i
]))
272 error (0, err
, "%s", quotef (fnamptr
[i
]));
275 if (fileptr
[i
] == stdin
)
276 clearerr (fileptr
[i
]); /* Also clear EOF. */
277 else if (fclose (fileptr
[i
]) == EOF
)
279 error (0, errno
, "%s", quotef (fnamptr
[i
]));
289 /* End of this output line.
290 Is this the end of the whole thing? */
293 /* No. Some files were not closed for this line. */
296 if (fwrite (delbuf
, 1, delims_saved
, stdout
)
301 xputchar (line_delim
);
303 continue; /* Next read of files, or exit. */
307 /* Closed file; add delimiter to 'delbuf'. */
308 if (*delimptr
!= EMPTY_DELIM
)
309 delbuf
[delims_saved
++] = *delimptr
;
310 if (++delimptr
== delim_end
)
316 /* Some data read. */
319 /* Except for last file, replace last newline with delim. */
322 if (chr
!= line_delim
&& chr
!= EOF
)
324 if (*delimptr
!= EMPTY_DELIM
)
325 xputchar (*delimptr
);
326 if (++delimptr
== delim_end
)
331 /* If the last line of the last file lacks a newline,
332 print one anyhow. POSIX requires this. */
333 char c
= (chr
== EOF
? line_delim
: chr
);
344 /* Perform serial paste on the NFILES files named in FNAMPTR.
345 Return true if no errors, false if one or more files could not be
349 paste_serial (size_t nfiles
, char **fnamptr
)
351 bool ok
= true; /* false if open or read errors occur. */
352 int charnew
, charold
; /* Current and previous char read. */
353 char const *delimptr
; /* Current delimiter char. */
354 FILE *fileptr
; /* Open for reading current file. */
356 for (; nfiles
; nfiles
--, fnamptr
++)
359 bool is_stdin
= STREQ (*fnamptr
, "-");
362 have_read_stdin
= true;
367 fileptr
= fopen (*fnamptr
, "r");
370 error (0, errno
, "%s", quotef (*fnamptr
));
374 fadvise (fileptr
, FADVISE_SEQUENTIAL
);
377 delimptr
= delims
; /* Set up for delimiter string. */
379 charold
= getc (fileptr
);
383 /* 'charold' is set up. Hit it!
384 Keep reading characters, stashing them in 'charnew';
385 output 'charold', converting to the appropriate delimiter
386 character if needed. After the EOF, output 'charold'
387 if it's a newline; otherwise, output it and then a newline. */
389 while ((charnew
= getc (fileptr
)) != EOF
)
391 /* Process the old character. */
392 if (charold
== line_delim
)
394 if (*delimptr
!= EMPTY_DELIM
)
395 xputchar (*delimptr
);
397 if (++delimptr
== delim_end
)
407 /* Hit EOF. Process that last character. */
411 if (charold
!= line_delim
)
412 xputchar (line_delim
);
414 if (ferror (fileptr
))
416 error (0, saved_errno
, "%s", quotef (*fnamptr
));
420 clearerr (fileptr
); /* Also clear EOF. */
421 else if (fclose (fileptr
) == EOF
)
423 error (0, errno
, "%s", quotef (*fnamptr
));
433 if (status
!= EXIT_SUCCESS
)
438 Usage: %s [OPTION]... [FILE]...\n\
442 Write lines consisting of the sequentially corresponding lines from\n\
443 each FILE, separated by TABs, to standard output.\n\
447 emit_mandatory_arg_note ();
450 -d, --delimiters=LIST reuse characters from LIST instead of TABs\n\
451 -s, --serial paste one file at a time instead of in parallel\n\
454 -z, --zero-terminated line delimiter is NUL, not newline\n\
456 fputs (HELP_OPTION_DESCRIPTION
, stdout
);
457 fputs (VERSION_OPTION_DESCRIPTION
, stdout
);
458 /* FIXME: add a couple of examples. */
459 emit_ancillary_info (PROGRAM_NAME
);
465 main (int argc
, char **argv
)
469 char const *delim_arg
= "\t";
471 initialize_main (&argc
, &argv
);
472 set_program_name (argv
[0]);
473 setlocale (LC_ALL
, "");
474 bindtextdomain (PACKAGE
, LOCALEDIR
);
475 textdomain (PACKAGE
);
477 atexit (close_stdout
);
479 have_read_stdin
= false;
480 serial_merge
= false;
482 while ((optc
= getopt_long (argc
, argv
, "d:sz", longopts
, NULL
)) != -1)
487 /* Delimiter character(s). */
488 delim_arg
= (optarg
[0] == '\0' ? "\\0" : optarg
);
499 case_GETOPT_HELP_CHAR
;
501 case_GETOPT_VERSION_CHAR (PROGRAM_NAME
, AUTHORS
);
504 usage (EXIT_FAILURE
);
509 argv
[argc
++] = bad_cast ("-");
511 if (collapse_escapes (delim_arg
))
513 /* Don't use the quote() quoting style, because that would double the
514 number of displayed backslashes, making the diagnostic look bogus. */
515 error (EXIT_FAILURE
, 0,
516 _("delimiter list ends with an unescaped backslash: %s"),
517 quotearg_n_style_colon (0, c_maybe_quoting_style
, delim_arg
));
521 ok
= paste_parallel (argc
- optind
, &argv
[optind
]);
523 ok
= paste_serial (argc
- optind
, &argv
[optind
]);
527 if (have_read_stdin
&& fclose (stdin
) == EOF
)
528 error (EXIT_FAILURE
, errno
, "-");
529 return ok
? EXIT_SUCCESS
: EXIT_FAILURE
;