/* cat -- concatenate files and print on the standard output. This is the cat utility
Copyright (C) 1988-2018 Free Software Foundation, Inc.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>. */ The GNUv3 license
/* Differences from the Unix cat:
* Always unbuffered, -u is ignored.
* Usually much faster than other versions of cat, the difference
is especially apparent when using the -v option.
By tege@sics.se, Torbjorn Granlund, advised by rms, Richard Stallman. */
#include <config.h> Provides system specific information
#include <stdio.h> Provides standard I/O capability
#include <getopt.h> ...!includes auto-comment...
#include <sys/types.h> Provides system data types
#if HAVE_STROPTS_H Line 30
# include <stropts.h> Line 31
#endif Line 32
#include <sys/ioctl.h> ...!includes auto-comment...
#include "system.h" ...!includes auto-comment...
#include "ioblksize.h" ...!includes auto-comment...
#include "die.h" ...!includes auto-comment...
#include "error.h" ...!includes auto-comment...
#include "fadvise.h" ...!includes auto-comment...
#include "full-write.h" ...!includes auto-comment...
#include "safe-read.h" ...!includes auto-comment...
#include "xbinary-io.h" ...!includes auto-comment...
/* The official name of this program (e.g., no 'g' prefix). */
#define PROGRAM_NAME "cat" Line 45
#define AUTHORS \ Line 47
proper_name ("Torbjorn Granlund"), \ Line 48
proper_name ("Richard M. Stallman") Line 49
/* Name of input file. May be "-". */
static char const *infile; Line 52
/* Descriptor on which input file is open. */
static int input_desc; Line 55
/* Buffer for line numbers.
An 11 digit counter may overflow within an hour on a P2/466,
an 18 digit counter needs about 1000y */
#define LINE_COUNTER_BUF_LEN 20 Line 60
static char line_buf[LINE_COUNTER_BUF_LEN] = Line 61
{
' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', Line 63
' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', '0', Line 64
'\t', '\0' Line 65
}; Block 1
/* Position in 'line_buf' where printing starts. This will not change
unless the number of lines is larger than 999999. */
static char *line_num_print = line_buf + LINE_COUNTER_BUF_LEN - 8; Line 70
/* Position of the first digit in 'line_buf'. */
static char *line_num_start = line_buf + LINE_COUNTER_BUF_LEN - 3; Line 73
/* Position of the last digit in 'line_buf'. */
static char *line_num_end = line_buf + LINE_COUNTER_BUF_LEN - 3; Line 76
/* Preserves the 'cat' function's local 'newlines' between invocations. */
static int newlines2 = 0; Line 79
void Line 81
usage (int status) Line 82
{
if (status != EXIT_SUCCESS) Line 84
emit_try_help (); ...!common auto-comment...
else Line 86
{
printf (_("\ Line 88
Usage: %s [OPTION]... [FILE]...\n\ Line 89
"), Line 90
program_name); Line 91
fputs (_("\ Line 92
Concatenate FILE(s) to standard output.\n\ Line 93
"), stdout); Line 94
emit_stdin_note (); ...!common auto-comment...
fputs (_("\ Line 98
\n\
-A, --show-all equivalent to -vET\n\ Line 100
-b, --number-nonblank number nonempty output lines, overrides -n\n\ Line 101
-e equivalent to -vE\n\ Line 102
-E, --show-ends display $ at end of each line\n\ Line 103
-n, --number number all output lines\n\ Line 104
-s, --squeeze-blank suppress repeated empty output lines\n\ Line 105
"), stdout); Line 106
fputs (_("\ Line 107
-t equivalent to -vT\n\ Line 108
-T, --show-tabs display TAB characters as ^I\n\ Line 109
-u (ignored)\n\ Line 110
-v, --show-nonprinting use ^ and M- notation, except for LFD and TAB\n\ Line 111
"), stdout); Line 112
fputs (HELP_OPTION_DESCRIPTION, stdout); Line 113
fputs (VERSION_OPTION_DESCRIPTION, stdout); Line 114
printf (_("\ Line 115
\n\
Examples:\n\ Line 117
%s f - g Output f's contents, then standard input, then g's contents.\n\ Line 118
%s Copy standard input to standard output.\n\ Line 119
"), Line 120
program_name, program_name); Line 121
emit_ancillary_info (PROGRAM_NAME); Line 122
}
exit (status); Line 124
} Block 2
/* Compute the next line number. */
static void Line 129
next_line_num (void) Line 130
{
char *endp = line_num_end; Line 132
do
{
if ((*endp)++ < '9') Line 135
return; Line 136
*endp-- = '0'; Line 137
}
while (endp >= line_num_start); Line 139
if (line_num_start > line_buf) Line 140
*--line_num_start = '1'; Line 141
else Line 142
*line_buf = '>'; Line 143
if (line_num_start < line_num_print) Line 144
line_num_print--; Line 145
} Block 3
/* Plain cat. Copies the file behind 'input_desc' to STDOUT_FILENO.
Return true if successful. */
static bool Line 151
simple_cat ( Line 152
/* Pointer to the buffer, used by reads and writes. */
char *buf, Line 154
/* Number of characters preferably read or written by each read and write
call. */
size_t bufsize) Line 158
{
/* Actual number of characters read, and therefore written. */
size_t n_read; Line 161
/* Loop until the end of the file. */
while (true) Line 165
{
/* Read a block of input. */
n_read = safe_read (input_desc, buf, bufsize); Line 169...!syscalls auto-comment...
if (n_read == SAFE_READ_ERROR) Line 170
{
error (0, errno, "%s", quotef (infile)); Line 172
return false; Line 173
}
/* End of this file? */
if (n_read == 0) Line 178
return true; Line 179
/* Write this block out. */
{
/* The following is ok, since we know that 0 < n_read. */
size_t n = n_read; Line 185
if (full_write (STDOUT_FILENO, buf, n) != n) Line 186...!syscalls auto-comment...
die (EXIT_FAILURE, errno, _("write error")); Line 187
}
}
}
/* Write any pending output to STDOUT_FILENO.
Pending is defined to be the *BPOUT - OUTBUF bytes starting at OUTBUF.
Then set *BPOUT to OUTPUT if it's not already that value. */
static inline void Line 196
write_pending (char *outbuf, char **bpout) Line 197
{
size_t n_write = *bpout - outbuf; Line 199
if (0 < n_write) Line 200
{
if (full_write (STDOUT_FILENO, outbuf, n_write) != n_write) Line 202...!syscalls auto-comment...
die (EXIT_FAILURE, errno, _("write error")); Line 203
*bpout = outbuf; Line 204
}
} Block 5
/* Cat the file behind INPUT_DESC to the file behind OUTPUT_DESC.
Return true if successful.
Called if any option more than -u was specified.
A newline character is always put at the end of the buffer, to make
an explicit test for buffer end unnecessary. */
static bool Line 215
cat ( Line 216
/* Pointer to the beginning of the input buffer. */
char *inbuf, Line 218
/* Number of characters read in each read call. */
size_t insize, Line 221
/* Pointer to the beginning of the output buffer. */
char *outbuf, Line 224
/* Number of characters written by each write call. */
size_t outsize, Line 227
/* Variables that have values according to the specified options. */
bool show_nonprinting, Line 230
bool show_tabs, Line 231
bool number, Line 232
bool number_nonblank, Line 233
bool show_ends, Line 234
bool squeeze_blank) Line 235
{
/* Last character read from the input buffer. */
unsigned char ch; Line 238
/* Pointer to the next character in the input buffer. */
char *bpin; Line 241
/* Pointer to the first non-valid byte in the input buffer, i.e., the
current end of the buffer. */
char *eob; Line 245
/* Pointer to the position where the next character shall be written. */
char *bpout; Line 248
/* Number of characters read by the last read call. */
size_t n_read; Line 251
/* Determines how many consecutive newlines there have been in the
input. 0 newlines makes NEWLINES -1, 1 newline makes NEWLINES 1,
etc. Initially 0 to indicate that we are at the beginning of a
new line. The "state" of the procedure is determined by
NEWLINES. */
int newlines = newlines2; Line 258
#ifdef FIONREAD Line 260
/* If nonzero, use the FIONREAD ioctl, as an optimization.
(On Ultrix, it is not supported on NFS file systems.) */
bool use_fionread = true; Line 263
#endif Line 264
/* The inbuf pointers are initialized so that BPIN > EOB, and thereby input
is read immediately. */
eob = inbuf; Line 269
bpin = eob + 1; Line 270
bpout = outbuf; Line 272
while (true) Line 274
{
do
{
/* Write if there are at least OUTSIZE bytes in OUTBUF. */
if (outbuf + outsize <= bpout) Line 280
{
char *wp = outbuf; Line 282
size_t remaining_bytes; Line 283
do
{
if (full_write (STDOUT_FILENO, wp, outsize) != outsize) Line 286...!syscalls auto-comment...
die (EXIT_FAILURE, errno, _("write error")); Line 287
wp += outsize; Line 288
remaining_bytes = bpout - wp; Line 289
}
while (outsize <= remaining_bytes); Line 291
/* Move the remaining bytes to the beginning of the
buffer. */
memmove (outbuf, wp, remaining_bytes); Line 296
bpout = outbuf + remaining_bytes; Line 297
}
/* Is INBUF empty? */
if (bpin > eob) Line 302
{
bool input_pending = false; Line 304
#ifdef FIONREAD Line 305
int n_to_read = 0; Line 306
/* Is there any input to read immediately?
If not, we are about to wait,
so write all buffered output before waiting. */
if (use_fionread Line 312
&& ioctl (input_desc, FIONREAD, &n_to_read) < 0) Line 313...!syscalls auto-comment...
{
/* Ultrix returns EOPNOTSUPP on NFS;
HP-UX returns ENOTTY on pipes.
SunOS returns EINVAL and
More/BSD returns ENODEV on special files
like /dev/null.
Irix-5 returns ENOSYS on pipes. */
if (errno == EOPNOTSUPP || errno == ENOTTY Line 321
|| errno == EINVAL || errno == ENODEV Line 322
|| errno == ENOSYS) Line 323
use_fionread = false; Line 324
else Line 325
{
error (0, errno, _("cannot do ioctl on %s"), Line 327
quoteaf (infile)); Line 328
newlines2 = newlines; Line 329
return false; Line 330
}
}
if (n_to_read != 0) Line 333
input_pending = true; Line 334
#endif Line 335
if (!input_pending) Line 337
write_pending (outbuf, &bpout); Line 338
/* Read more input into INBUF. */
n_read = safe_read (input_desc, inbuf, insize); Line 342...!syscalls auto-comment...
if (n_read == SAFE_READ_ERROR) Line 343
{
error (0, errno, "%s", quotef (infile)); Line 345
write_pending (outbuf, &bpout); Line 346
newlines2 = newlines; Line 347
return false; Line 348
}
if (n_read == 0) Line 350
{
write_pending (outbuf, &bpout); Line 352
newlines2 = newlines; Line 353
return true; Line 354
}
/* Update the pointers and insert a sentinel at the buffer
end. */
bpin = inbuf; Line 360
eob = bpin + n_read; Line 361
*eob = '\n'; Line 362
}
else Line 364
{
/* It was a real (not a sentinel) newline. */
/* Was the last line empty?
(i.e., have two or more consecutive newlines been read?) */
if (++newlines > 0) Line 371
{
if (newlines >= 2) Line 373
{
/* Limit this to 2 here. Otherwise, with lots of
consecutive newlines, the counter could wrap
around at INT_MAX. */
newlines = 2; Line 378
/* Are multiple adjacent empty lines to be substituted
by single ditto (-s), and this was the second empty
line? */
if (squeeze_blank) Line 383
{
ch = *bpin++; Line 385
continue; Line 386
}
}
/* Are line numbers to be written at empty lines (-n)? */
if (number && !number_nonblank) Line 392
{
next_line_num (); Line 394
bpout = stpcpy (bpout, line_num_print); Line 395
}
}
/* Output a currency symbol if requested (-e). */
if (show_ends) Line 401
*bpout++ = '$'; Line 402
/* Output the newline. */
*bpout++ = '\n'; Line 406
}
ch = *bpin++; Line 408
}
while (ch == '\n'); Line 410
/* Are we at the beginning of a line, and line numbers are requested? */
if (newlines >= 0 && number) Line 414
{
next_line_num (); Line 416
bpout = stpcpy (bpout, line_num_print); Line 417
}
/* Here CH cannot contain a newline character. */
/* The loops below continue until a newline character is found,
which means that the buffer is empty or that a proper newline
has been found. */
/* If quoting, i.e., at least one of -v, -e, or -t specified,
scan for chars that need conversion. */
if (show_nonprinting) Line 428
{
while (true) Line 430
{
if (ch >= 32) Line 432
{
if (ch < 127) Line 434
*bpout++ = ch; Line 435
else if (ch == 127) Line 436
{
*bpout++ = '^'; Line 438
*bpout++ = '?'; Line 439
}
else Line 441
{
*bpout++ = 'M'; Line 443
*bpout++ = '-'; Line 444
if (ch >= 128 + 32) Line 445
{
if (ch < 128 + 127) Line 447
*bpout++ = ch - 128; Line 448
else Line 449
{
*bpout++ = '^'; Line 451
*bpout++ = '?'; Line 452
}
}
else Line 455
{
*bpout++ = '^'; Line 457
*bpout++ = ch - 128 + 64; Line 458
}
}
}
else if (ch == '\t' && !show_tabs) Line 462
*bpout++ = '\t'; Line 463
else if (ch == '\n') Line 464
{
newlines = -1; Line 466
break; Line 467
}
else Line 469
{
*bpout++ = '^'; Line 471
*bpout++ = ch + 64; Line 472
}
ch = *bpin++; Line 475
}
}
else Line 478
{
/* Not quoting, neither of -v, -e, or -t specified. */
while (true) Line 481
{
if (ch == '\t' && show_tabs) Line 483
{
*bpout++ = '^'; Line 485
*bpout++ = ch + 64; Line 486
}
else if (ch != '\n') Line 488
*bpout++ = ch; Line 489
else Line 490
{
newlines = -1; Line 492
break; Line 493
}
ch = *bpin++; Line 496
}
}
}
}
int
main (int argc, char **argv) Line 503
{
/* Optimal size of i/o operations of output. */
size_t outsize; Line 506
/* Optimal size of i/o operations of input. */
size_t insize; Line 509
size_t page_size = getpagesize (); Line 511
/* Pointer to the input buffer. */
char *inbuf; Line 514
/* Pointer to the output buffer. */
char *outbuf; Line 517
bool ok = true; Line 519
int c; Line 520
/* Index in argv to processed argument. */
int argind; Line 523
/* Device number of the output (file or whatever). */
dev_t out_dev; Line 526
/* I-node number of the output. */
ino_t out_ino; Line 529
/* True if the output is a regular file. */
bool out_isreg; Line 532
/* Nonzero if we have ever read standard input. */
bool have_read_stdin = false; Line 535
struct stat stat_buf; Line 537
/* Variables that are set according to the specified options. */
bool number = false; Line 540
bool number_nonblank = false; Line 541
bool squeeze_blank = false; Line 542
bool show_ends = false; Line 543
bool show_nonprinting = false; Line 544
bool show_tabs = false; Line 545
int file_open_mode = O_RDONLY; Line 546
static struct option const long_options[] = Line 548
{
{"number-nonblank", no_argument, NULL, 'b'}, Line 550
{"number", no_argument, NULL, 'n'}, Line 551
{"squeeze-blank", no_argument, NULL, 's'}, Line 552
{"show-nonprinting", no_argument, NULL, 'v'}, Line 553
{"show-ends", no_argument, NULL, 'E'}, Line 554
{"show-tabs", no_argument, NULL, 'T'}, Line 555
{"show-all", no_argument, NULL, 'A'}, Line 556
{GETOPT_HELP_OPTION_DECL}, Line 557
{GETOPT_VERSION_OPTION_DECL}, Line 558
{NULL, 0, NULL, 0} Line 559
};
initialize_main (&argc, &argv); VMS-specific entry point handling wildcard expansion
set_program_name (argv[0]); Retains program name and discards path
setlocale (LC_ALL, ""); Sets up internationalization (i18n)
bindtextdomain (PACKAGE, LOCALEDIR); Assigns i18n directorySets text domain for _() [gettext()] function
textdomain (PACKAGE); Sets text domain for _() [gettext()] function
/* Arrange to close stdout if we exit via the
case_GETOPT_HELP_CHAR or case_GETOPT_VERSION_CHAR code.
Normally STDOUT_FILENO is used rather than stdout, so
close_stdout does nothing. */
atexit (close_stdout); Close stdout on exit (see gnulib)
/* Parse command line options. */
while ((c = getopt_long (argc, argv, "benstuvAET", long_options, NULL)) Line 576
!= -1) Line 577
{
switch (c) Line 579
{
case 'b': Line 581
number = true; Line 582
number_nonblank = true; Line 583
break; Line 584
case 'e': Line 586
show_ends = true; Line 587
show_nonprinting = true; Line 588
break; Line 589
case 'n': Line 591
number = true; Line 592
break; Line 593
case 's': Line 595
squeeze_blank = true; Line 596
break; Line 597
case 't': Line 599
show_tabs = true; Line 600
show_nonprinting = true; Line 601
break; Line 602
case 'u': Line 604
/* We provide the -u feature unconditionally. */
break; Line 606
case 'v': Line 608
show_nonprinting = true; Line 609
break; Line 610
case 'A': Line 612
show_nonprinting = true; Line 613
show_ends = true; Line 614
show_tabs = true; Line 615
break; Line 616
case 'E': Line 618
show_ends = true; Line 619
break; Line 620
case 'T': Line 622
show_tabs = true; Line 623
break; Line 624
case_GETOPT_HELP_CHAR; Line 626
case_GETOPT_VERSION_CHAR (PROGRAM_NAME, AUTHORS); Line 628
default: Line 630
usage (EXIT_FAILURE); Line 631
}
}
/* Get device, i-node number, and optimal blocksize of output. */
if (fstat (STDOUT_FILENO, &stat_buf) < 0) Line 637...!syscalls auto-comment......!syscalls auto-comment...
die (EXIT_FAILURE, errno, _("standard output")); Line 638
outsize = io_blksize (stat_buf); Line 640
out_dev = stat_buf.st_dev; Line 641
out_ino = stat_buf.st_ino; Line 642
out_isreg = S_ISREG (stat_buf.st_mode) != 0; Line 643
if (! (number || show_ends || squeeze_blank)) Line 645
{
file_open_mode |= O_BINARY; Line 647
xset_binary_mode (STDOUT_FILENO, O_BINARY); Line 648
}
/* Check if any of the input files are the same as the output file. */
/* Main loop. */
infile = "-"; Line 655
argind = optind; Line 656
do
{
if (argind < argc) Line 660
infile = argv[argind]; Line 661
if (STREQ (infile, "-")) Line 663
{
have_read_stdin = true; Line 665
input_desc = STDIN_FILENO; Line 666
if (file_open_mode & O_BINARY) Line 667
xset_binary_mode (STDIN_FILENO, O_BINARY); Line 668
}
else Line 670
{
input_desc = open (infile, file_open_mode); Line 672...!syscalls auto-comment...
if (input_desc < 0) Line 673
{
error (0, errno, "%s", quotef (infile)); Line 675
ok = false; Line 676
continue; Line 677
}
}
if (fstat (input_desc, &stat_buf) < 0) Line 681...!syscalls auto-comment......!syscalls auto-comment...
{
error (0, errno, "%s", quotef (infile)); Line 683
ok = false; Line 684
goto contin; Line 685
}
insize = io_blksize (stat_buf); Line 687
fdadvise (input_desc, 0, 0, FADVISE_SEQUENTIAL); Line 689
/* Don't copy a nonempty regular file to itself, as that would
merely exhaust the output device. It's better to catch this
error earlier rather than later. */
if (out_isreg Line 695
&& stat_buf.st_dev == out_dev && stat_buf.st_ino == out_ino Line 696
&& lseek (input_desc, 0, SEEK_CUR) < stat_buf.st_size) Line 697
{
error (0, 0, _("%s: input file is output file"), quotef (infile)); Line 699
ok = false; Line 700
goto contin; Line 701
}
/* Select which version of 'cat' to use. If any format-oriented
options were given use 'cat'; otherwise use 'simple_cat'. */
if (! (number || show_ends || show_nonprinting Line 707
|| show_tabs || squeeze_blank)) Line 708
{
insize = MAX (insize, outsize); Line 710
inbuf = xmalloc (insize + page_size - 1); Line 711
ok &= simple_cat (ptr_align (inbuf, page_size), insize); Line 713
}
else Line 715
{
inbuf = xmalloc (insize + 1 + page_size - 1); Line 717
/* Why are
(OUTSIZE - 1 + INSIZE * 4 + LINE_COUNTER_BUF_LEN + PAGE_SIZE - 1)
bytes allocated for the output buffer?
A test whether output needs to be written is done when the input
buffer empties or when a newline appears in the input. After
output is written, at most (OUTSIZE - 1) bytes will remain in the
buffer. Now INSIZE bytes of input is read. Each input character
may grow by a factor of 4 (by the prepending of M-^). If all
characters do, and no newlines appear in this block of input, we
will have at most (OUTSIZE - 1 + INSIZE * 4) bytes in the buffer.
If the last character in the preceding block of input was a
newline, a line number may be written (according to the given
options) as the first thing in the output buffer. (Done after the
new input is read, but before processing of the input begins.)
A line number requires seldom more than LINE_COUNTER_BUF_LEN
positions.
Align the output buffer to a page size boundary, for efficiency
on some paging implementations, so add PAGE_SIZE - 1 bytes to the
request to make room for the alignment. */
outbuf = xmalloc (outsize - 1 + insize * 4 + LINE_COUNTER_BUF_LEN Line 741
+ page_size - 1); Line 742
ok &= cat (ptr_align (inbuf, page_size), insize, Line 744
ptr_align (outbuf, page_size), outsize, show_nonprinting, Line 745
show_tabs, number, number_nonblank, show_ends, Line 746
squeeze_blank); Line 747
free (outbuf); Line 749
}
free (inbuf); Line 752
contin: Line 754
if (!STREQ (infile, "-") && close (input_desc) < 0) Line 755...!syscalls auto-comment...
{
error (0, errno, "%s", quotef (infile)); Line 757
ok = false; Line 758
}
}
while (++argind < argc); Line 761
if (have_read_stdin && close (STDIN_FILENO) < 0) Line 763...!syscalls auto-comment...
die (EXIT_FAILURE, errno, _("closing standard input")); Line 764
return ok ? EXIT_SUCCESS : EXIT_FAILURE; Line 766
}