Test yesterday's change to groups.
[coreutils.git] / src / paste.c
blob3cb84cf5e98f6e2ce5a2727202c982631c23e455
1 /* paste - merge lines of files
2 Copyright (C) 1997-2005 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>.
26 Options:
27 --serial
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. */
38 #include <config.h>
40 #include <stdio.h>
41 #include <getopt.h>
42 #include <sys/types.h>
43 #include "system.h"
44 #include "error.h"
46 /* The official name of this program (e.g., no `g' prefix). */
47 #define PROGRAM_NAME "paste"
49 #define AUTHORS "David M. Ihnat", "David MacKenzie"
51 /* Indicates that no delimiter should be added in the current position. */
52 #define EMPTY_DELIM '\0'
54 /* Name this program was run with. */
55 char *program_name;
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). */
65 static char *delims;
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},
76 {NULL, 0, NULL, 0}
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. */
84 static void
85 collapse_escapes (char const *strptr)
87 char *strout = xstrdup (strptr);
88 delims = strout;
90 while (*strptr)
92 if (*strptr != '\\') /* Is it an escape character? */
93 *strout++ = *strptr++; /* No, just transfer it. */
94 else
96 switch (*++strptr)
98 case '0':
99 *strout++ = EMPTY_DELIM;
100 break;
102 case 'b':
103 *strout++ = '\b';
104 break;
106 case 'f':
107 *strout++ = '\f';
108 break;
110 case 'n':
111 *strout++ = '\n';
112 break;
114 case 'r':
115 *strout++ = '\r';
116 break;
118 case 't':
119 *strout++ = '\t';
120 break;
122 case 'v':
123 *strout++ = '\v';
124 break;
126 default:
127 *strout++ = *strptr;
128 break;
130 strptr++;
133 delim_end = strout;
136 /* Report a write error and exit. */
138 static void write_error (void) ATTRIBUTE_NORETURN;
139 static void
140 write_error (void)
142 error (EXIT_FAILURE, errno, _("write error"));
143 abort ();
146 /* Output a single byte, reporting any write errors. */
148 static inline void
149 xputchar (char c)
151 if (putchar (c) < 0)
152 write_error ();
155 /* Perform column paste on the NFILES files named in FNAMPTR.
156 Return true if successful, false if one or more files could not be
157 opened or read. */
159 static bool
160 paste_parallel (size_t nfiles, char **fnamptr)
162 bool ok = true;
163 /* If all files are just ready to be closed, or will be on this
164 round, the string of delimiters must be preserved.
165 delbuf[0] through delbuf[nfiles]
166 store the delimiters for closed files. */
167 char *delbuf = xmalloc (nfiles + 2);
169 /* Streams open to the files to process; NULL if the corresponding
170 stream is closed. */
171 FILE **fileptr = xnmalloc (nfiles + 1, sizeof *fileptr);
173 /* Number of files still open to process. */
174 size_t files_open;
176 /* True if any fopen got fd == STDIN_FILENO. */
177 bool opened_stdin = false;
179 /* Attempt to open all files. This could be expanded to an infinite
180 number of files, but at the (considerable) expense of remembering
181 each file and its current offset, then opening/reading/closing. */
183 for (files_open = 0; files_open < nfiles; ++files_open)
185 if (STREQ (fnamptr[files_open], "-"))
187 have_read_stdin = true;
188 fileptr[files_open] = stdin;
190 else
192 fileptr[files_open] = fopen (fnamptr[files_open], "r");
193 if (fileptr[files_open] == NULL)
194 error (EXIT_FAILURE, errno, "%s", fnamptr[files_open]);
195 else if (fileno (fileptr[files_open]) == STDIN_FILENO)
196 opened_stdin = true;
200 if (opened_stdin && have_read_stdin)
201 error (EXIT_FAILURE, 0, _("standard input is closed"));
203 /* Read a line from each file and output it to stdout separated by a
204 delimiter, until we go through the loop without successfully
205 reading from any of the files. */
207 while (files_open)
209 /* Set up for the next line. */
210 bool somedone = false;
211 char const *delimptr = delims;
212 size_t delims_saved = 0; /* Number of delims saved in `delbuf'. */
213 size_t i;
215 for (i = 0; i < nfiles && files_open; i++)
217 int chr IF_LINT (= 0); /* Input character. */
218 int err IF_LINT (= 0); /* Input errno value. */
219 size_t line_length = 0; /* Number of chars in line. */
221 if (fileptr[i])
223 chr = getc (fileptr[i]);
224 err = errno;
225 if (chr != EOF && delims_saved)
227 if (fwrite (delbuf, 1, delims_saved, stdout) != delims_saved)
228 write_error ();
229 delims_saved = 0;
232 while (chr != EOF)
234 line_length++;
235 if (chr == '\n')
236 break;
237 xputchar (chr);
238 chr = getc (fileptr[i]);
239 err = errno;
243 if (line_length == 0)
245 /* EOF, read error, or closed file.
246 If an EOF or error, close the file. */
247 if (fileptr[i])
249 if (ferror (fileptr[i]))
251 error (0, err, "%s", fnamptr[i]);
252 ok = false;
254 if (fileptr[i] == stdin)
255 clearerr (fileptr[i]); /* Also clear EOF. */
256 else if (fclose (fileptr[i]) == EOF)
258 error (0, errno, "%s", fnamptr[i]);
259 ok = false;
262 fileptr[i] = NULL;
263 files_open--;
266 if (i + 1 == nfiles)
268 /* End of this output line.
269 Is this the end of the whole thing? */
270 if (somedone)
272 /* No. Some files were not closed for this line. */
273 if (delims_saved)
275 if (fwrite (delbuf, 1, delims_saved, stdout)
276 != delims_saved)
277 write_error ();
278 delims_saved = 0;
280 xputchar ('\n');
282 continue; /* Next read of files, or exit. */
284 else
286 /* Closed file; add delimiter to `delbuf'. */
287 if (*delimptr != EMPTY_DELIM)
288 delbuf[delims_saved++] = *delimptr;
289 if (++delimptr == delim_end)
290 delimptr = delims;
293 else
295 /* Some data read. */
296 somedone = true;
298 /* Except for last file, replace last newline with delim. */
299 if (i + 1 != nfiles)
301 if (chr != '\n' && chr != EOF)
302 xputchar (chr);
303 if (*delimptr != EMPTY_DELIM)
304 xputchar (*delimptr);
305 if (++delimptr == delim_end)
306 delimptr = delims;
308 else
310 /* If the last line of the last file lacks a newline,
311 print one anyhow. POSIX requires this. */
312 char c = (chr == EOF ? '\n' : chr);
313 xputchar (c);
318 free (fileptr);
319 free (delbuf);
320 return ok;
323 /* Perform serial paste on the NFILES files named in FNAMPTR.
324 Return true if no errors, false if one or more files could not be
325 opened or read. */
327 static bool
328 paste_serial (size_t nfiles, char **fnamptr)
330 bool ok = true; /* false if open or read errors occur. */
331 int charnew, charold; /* Current and previous char read. */
332 char const *delimptr; /* Current delimiter char. */
333 FILE *fileptr; /* Open for reading current file. */
335 for (; nfiles; nfiles--, fnamptr++)
337 int saved_errno;
338 bool is_stdin = STREQ (*fnamptr, "-");
339 if (is_stdin)
341 have_read_stdin = true;
342 fileptr = stdin;
344 else
346 fileptr = fopen (*fnamptr, "r");
347 if (fileptr == NULL)
349 error (0, errno, "%s", *fnamptr);
350 ok = false;
351 continue;
355 delimptr = delims; /* Set up for delimiter string. */
357 charold = getc (fileptr);
358 saved_errno = errno;
359 if (charold != EOF)
361 /* `charold' is set up. Hit it!
362 Keep reading characters, stashing them in `charnew';
363 output `charold', converting to the appropriate delimiter
364 character if needed. After the EOF, output `charold'
365 if it's a newline; otherwise, output it and then a newline. */
367 while ((charnew = getc (fileptr)) != EOF)
369 /* Process the old character. */
370 if (charold == '\n')
372 if (*delimptr != EMPTY_DELIM)
373 xputchar (*delimptr);
375 if (++delimptr == delim_end)
376 delimptr = delims;
378 else
379 xputchar (charold);
381 charold = charnew;
383 saved_errno = errno;
385 /* Hit EOF. Process that last character. */
386 xputchar (charold);
389 if (charold != '\n')
390 xputchar ('\n');
392 if (ferror (fileptr))
394 error (0, saved_errno, "%s", *fnamptr);
395 ok = false;
397 if (is_stdin)
398 clearerr (fileptr); /* Also clear EOF. */
399 else if (fclose (fileptr) == EOF)
401 error (0, errno, "%s", *fnamptr);
402 ok = false;
405 return ok;
408 void
409 usage (int status)
411 if (status != EXIT_SUCCESS)
412 fprintf (stderr, _("Try `%s --help' for more information.\n"),
413 program_name);
414 else
416 printf (_("\
417 Usage: %s [OPTION]... [FILE]...\n\
419 program_name);
420 fputs (_("\
421 Write lines consisting of the sequentially corresponding lines from\n\
422 each FILE, separated by TABs, to standard output.\n\
423 With no FILE, or when FILE is -, read standard input.\n\
425 "), stdout);
426 fputs (_("\
427 Mandatory arguments to long options are mandatory for short options too.\n\
428 "), stdout);
429 fputs (_("\
430 -d, --delimiters=LIST reuse characters from LIST instead of TABs\n\
431 -s, --serial paste one file at a time instead of in parallel\n\
432 "), stdout);
433 fputs (HELP_OPTION_DESCRIPTION, stdout);
434 fputs (VERSION_OPTION_DESCRIPTION, stdout);
435 /* FIXME: add a couple of examples. */
436 emit_bug_reporting_address ();
438 exit (status);
442 main (int argc, char **argv)
444 int optc;
445 bool ok;
446 char const *delim_arg = "\t";
448 initialize_main (&argc, &argv);
449 program_name = argv[0];
450 setlocale (LC_ALL, "");
451 bindtextdomain (PACKAGE, LOCALEDIR);
452 textdomain (PACKAGE);
454 atexit (close_stdout);
456 have_read_stdin = false;
457 serial_merge = false;
459 while ((optc = getopt_long (argc, argv, "d:s", longopts, NULL)) != -1)
461 switch (optc)
463 case 'd':
464 /* Delimiter character(s). */
465 delim_arg = (optarg[0] == '\0' ? "\\0" : optarg);
466 break;
468 case 's':
469 serial_merge = true;
470 break;
472 case_GETOPT_HELP_CHAR;
474 case_GETOPT_VERSION_CHAR (PROGRAM_NAME, AUTHORS);
476 default:
477 usage (EXIT_FAILURE);
481 if (optind == argc)
482 argv[argc++] = "-";
484 collapse_escapes (delim_arg);
486 if (!serial_merge)
487 ok = paste_parallel (argc - optind, &argv[optind]);
488 else
489 ok = paste_serial (argc - optind, &argv[optind]);
491 free (delims);
493 if (have_read_stdin && fclose (stdin) == EOF)
494 error (EXIT_FAILURE, errno, "-");
495 exit (ok ? EXIT_SUCCESS : EXIT_FAILURE);