blob: 4b3414941e87a47bd639bc481ab9f3fa0045ea80 [file] [log] [blame]
Erik Andersene49d5ec2000-02-08 19:58:47 +00001/* vi: set sw=4 ts=4: */
Eric Andersencc8ed391999-10-05 16:24:54 +00002/*
Manuel Novoa III cad53642003-03-19 09:13:01 +00003 * cat implementation for busybox
Eric Andersencc8ed391999-10-05 16:24:54 +00004 *
Manuel Novoa III cad53642003-03-19 09:13:01 +00005 * Copyright (C) 2003 Manuel Novoa III <mjn3@codepoet.org>
Eric Andersencc8ed391999-10-05 16:24:54 +00006 *
Denys Vlasenko0ef64bd2010-08-16 20:14:46 +02007 * Licensed under GPLv2, see file LICENSE in this source tree.
Eric Andersencc8ed391999-10-05 16:24:54 +00008 */
Denys Vlasenkoe4070cb2010-06-04 19:59:49 +02009//config:config CAT
Denys Vlasenko4eed2c62017-07-18 22:01:24 +020010//config: bool "cat (5.6 kb)"
Denys Vlasenko2f32bf82010-06-06 04:14:28 +020011//config: default y
Denys Vlasenkoe4070cb2010-06-04 19:59:49 +020012//config: help
Denys Vlasenko72089cf2017-07-21 09:50:55 +020013//config: cat is used to concatenate files and print them to the standard
14//config: output. Enable this option if you wish to enable the 'cat' utility.
Denys Vlasenkoe31ca2e2017-04-12 17:17:29 +020015//config:
Kang-Che Sunga2bdc5c2017-07-14 09:56:13 +020016//config:config FEATURE_CATN
17//config: bool "Enable -n and -b options"
18//config: default y
19//config: depends on CAT
20//config: help
Denys Vlasenko72089cf2017-07-21 09:50:55 +020021//config: -n numbers all output lines while -b numbers nonempty output lines.
Kang-Che Sunga2bdc5c2017-07-14 09:56:13 +020022//config:
Denys Vlasenkoe31ca2e2017-04-12 17:17:29 +020023//config:config FEATURE_CATV
24//config: bool "cat -v[etA]"
25//config: default y
26//config: depends on CAT
27//config: help
Denys Vlasenko72089cf2017-07-21 09:50:55 +020028//config: Display nonprinting characters as escape sequences
Denys Vlasenkoe4070cb2010-06-04 19:59:49 +020029
Denys Vlasenkoe31ca2e2017-04-12 17:17:29 +020030//applet:IF_CAT(APPLET(cat, BB_DIR_BIN, BB_SUID_DROP))
Denys Vlasenkoaf3f4202016-11-23 14:46:56 +010031
Denys Vlasenkod88f94a2017-04-05 18:17:17 +020032//kbuild:lib-$(CONFIG_CAT) += cat.o
Denys Vlasenkoaf3f4202016-11-23 14:46:56 +010033
34/* BB_AUDIT SUSv3 compliant */
35/* http://www.opengroup.org/onlinepubs/007904975/utilities/cat.html */
36
Kang-Che Sunga2bdc5c2017-07-14 09:56:13 +020037//usage:#if ENABLE_FEATURE_CATN || ENABLE_FEATURE_CATV
Pere Orga34425382011-03-31 14:43:25 +020038//usage:#define cat_trivial_usage
Kang-Che Sunga2bdc5c2017-07-14 09:56:13 +020039//usage: "[-" IF_FEATURE_CATN("nb") IF_FEATURE_CATV("vteA") "] [FILE]..."
40//usage:#else
41//usage:#define cat_trivial_usage
42//usage: "[FILE]..."
43//usage:#endif
Pere Orga34425382011-03-31 14:43:25 +020044//usage:#define cat_full_usage "\n\n"
Denys Vlasenkoe31ca2e2017-04-12 17:17:29 +020045//usage: "Print FILEs to stdout\n"
Kang-Che Sunga2bdc5c2017-07-14 09:56:13 +020046//usage: IF_FEATURE_CATN(
Denys Vlasenkod88f94a2017-04-05 18:17:17 +020047//usage: "\n -n Number output lines"
Denys Vlasenkoe31ca2e2017-04-12 17:17:29 +020048//usage: "\n -b Number nonempty lines"
Kang-Che Sunga2bdc5c2017-07-14 09:56:13 +020049//usage: )
Denys Vlasenkoe31ca2e2017-04-12 17:17:29 +020050//usage: IF_FEATURE_CATV(
51//usage: "\n -v Show nonprinting characters as ^x or M-x"
52//usage: "\n -t ...and tabs as ^I"
53//usage: "\n -e ...and end lines with $"
54//usage: "\n -A Same as -vte"
55//usage: )
Denys Vlasenkod88f94a2017-04-05 18:17:17 +020056/*
57 Longopts not implemented yet:
Denys Vlasenkoe31ca2e2017-04-12 17:17:29 +020058 --number-nonblank number nonempty output lines, overrides -n
59 --number number all output lines
60 --show-nonprinting use ^ and M- notation, except for LFD and TAB
61 --show-all equivalent to -vet
Denys Vlasenkod88f94a2017-04-05 18:17:17 +020062 Not implemented yet:
Denys Vlasenkoe31ca2e2017-04-12 17:17:29 +020063 -E, --show-ends display $ at end of each line (-e sans -v)
64 -T, --show-tabs display TAB characters as ^I (-t sans -v)
Denys Vlasenkod88f94a2017-04-05 18:17:17 +020065 -s, --squeeze-blank suppress repeated empty output lines
Denys Vlasenkod88f94a2017-04-05 18:17:17 +020066*/
Pere Orga34425382011-03-31 14:43:25 +020067//usage:
68//usage:#define cat_example_usage
69//usage: "$ cat /proc/uptime\n"
70//usage: "110716.72 17.67"
71
Denis Vlasenkob6adbf12007-05-26 19:00:18 +000072#include "libbb.h"
Denys Vlasenkoe31ca2e2017-04-12 17:17:29 +020073#include "common_bufsiz.h"
Eric Andersencc8ed391999-10-05 16:24:54 +000074
Denys Vlasenkoe31ca2e2017-04-12 17:17:29 +020075#if ENABLE_FEATURE_CATV
76/*
77 * cat -v implementation for busybox
78 *
79 * Copyright (C) 2006 Rob Landley <rob@landley.net>
80 *
81 * Licensed under GPLv2 or later, see file LICENSE in this source tree.
82 */
83/* Rob had "cat -v" implemented as a separate applet, catv.
84 * See "cat -v considered harmful" at
85 * http://cm.bell-labs.com/cm/cs/doc/84/kp.ps.gz
86 * From USENIX Summer Conference Proceedings, 1983
87 * """
88 * The talk reviews reasons for UNIX's popularity and shows, using UCB cat
89 * as a primary example, how UNIX has grown fat. cat isn't for printing
90 * files with line numbers, it isn't for compressing multiple blank lines,
91 * it's not for looking at non-printing ASCII characters, it's for
92 * concatenating files.
93 * We are reminded that ls isn't the place for code to break a single column
94 * into multiple ones, and that mailnews shouldn't have its own more
95 * processing or joke encryption code.
96 * """
97 *
98 * I agree with the argument. Unfortunately, this ship has sailed (1983...).
99 * There are dozens of Linux distros and each of them has "cat" which supports -v.
100 * It's unrealistic for us to "reeducate" them to use our, incompatible way
Kang-Che Sunga2bdc5c2017-07-14 09:56:13 +0200101 * to achieve "cat -v" effect. The actual effect would be "users pissed off
Denys Vlasenkoe31ca2e2017-04-12 17:17:29 +0200102 * by gratuitous incompatibility".
103 */
Denys Vlasenko75e90b12017-07-14 10:47:18 +0200104#define CAT_OPT_e (1<<0)
105#define CAT_OPT_t (1<<1)
106#define CAT_OPT_v (1<<2)
107/* -A occupies bit (1<<3) */
108#define CAT_OPT_n ((1<<4) * ENABLE_FEATURE_CATN)
109#define CAT_OPT_b ((1<<5) * ENABLE_FEATURE_CATN)
Denys Vlasenkoe31ca2e2017-04-12 17:17:29 +0200110static int catv(unsigned opts, char **argv)
111{
112 int retval = EXIT_SUCCESS;
113 int fd;
Denys Vlasenko75e90b12017-07-14 10:47:18 +0200114#if ENABLE_FEATURE_CATN
Denys Vlasenkod80eecb2018-04-29 14:05:43 +0200115 bool eol_seen = (opts & (CAT_OPT_n|CAT_OPT_b));
116 unsigned eol_char = (eol_seen ? '\n' : 0x100);
Denys Vlasenko75e90b12017-07-14 10:47:18 +0200117 unsigned skip_num_on = (opts & CAT_OPT_b) ? '\n' : 0x100;
Denys Vlasenkod80eecb2018-04-29 14:05:43 +0200118 unsigned lineno = 0;
Denys Vlasenkoe31ca2e2017-04-12 17:17:29 +0200119#endif
120
Denys Vlasenko75e90b12017-07-14 10:47:18 +0200121 BUILD_BUG_ON(CAT_OPT_e != VISIBLE_ENDLINE);
122 BUILD_BUG_ON(CAT_OPT_t != VISIBLE_SHOW_TABS);
123#if 0 /* These consts match, we can just pass "opts" to visible() */
124 if (opts & CAT_OPT_e)
125 flags |= VISIBLE_ENDLINE;
126 if (opts & CAT_OPT_t)
127 flags |= VISIBLE_SHOW_TABS;
128#endif
Denys Vlasenkoe31ca2e2017-04-12 17:17:29 +0200129
130#define read_buf bb_common_bufsiz1
131 setup_common_bufsiz();
132 do {
133 fd = open_or_warn_stdin(*argv);
134 if (fd < 0) {
135 retval = EXIT_FAILURE;
136 continue;
137 }
138 for (;;) {
139 int i, res;
140
141 res = read(fd, read_buf, COMMON_BUFSIZE);
142 if (res < 0)
143 retval = EXIT_FAILURE;
144 if (res <= 0)
145 break;
146 for (i = 0; i < res; i++) {
147 unsigned char c = read_buf[i];
148 char buf[sizeof("M-^c")];
Denys Vlasenko75e90b12017-07-14 10:47:18 +0200149#if ENABLE_FEATURE_CATN
150 if (eol_seen && c != skip_num_on)
151 printf("%6u ", ++lineno);
152 eol_seen = (c == eol_char);
153#endif
Denys Vlasenkoe31ca2e2017-04-12 17:17:29 +0200154 visible(c, buf, opts);
Ron Yorstoncad3fc72021-02-03 20:47:14 +0100155 fputs_stdout(buf);
Denys Vlasenkoe31ca2e2017-04-12 17:17:29 +0200156 }
157 }
158 if (ENABLE_FEATURE_CLEAN_UP && fd)
159 close(fd);
160 } while (*++argv);
161
162 fflush_stdout_and_exit(retval);
163}
Denys Vlasenko75e90b12017-07-14 10:47:18 +0200164#undef CAT_OPT_n
165#undef CAT_OPT_b
Denys Vlasenkoe31ca2e2017-04-12 17:17:29 +0200166#endif
Denis Vlasenko99912ca2007-04-10 15:43:37 +0000167
Denis Vlasenko9b49a5e2007-10-11 10:05:36 +0000168int cat_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +0000169int cat_main(int argc UNUSED_PARAM, char **argv)
Denis Vlasenkobf66fbc2006-12-21 13:23:14 +0000170{
Denys Vlasenko82d1c1f2017-12-31 17:30:02 +0100171#if ENABLE_FEATURE_CATV || ENABLE_FEATURE_CATN
Denys Vlasenkoe31ca2e2017-04-12 17:17:29 +0200172 unsigned opts;
Denys Vlasenkod88f94a2017-04-05 18:17:17 +0200173
Denys Vlasenko82d1c1f2017-12-31 17:30:02 +0100174 opts =
175#endif
176 getopt32(argv, IF_FEATURE_CATV("^")
Denys Vlasenko22542ec2017-08-08 21:55:02 +0200177 /* -u is ignored ("unbuffered") */
178 IF_FEATURE_CATV("etvA")IF_FEATURE_CATN("nb")"u"
179 IF_FEATURE_CATV("\0" "Aetv" /* -A == -vet */)
180 );
Denis Vlasenkobf66fbc2006-12-21 13:23:14 +0000181 argv += optind;
Denys Vlasenkoe31ca2e2017-04-12 17:17:29 +0200182
Denys Vlasenko75e90b12017-07-14 10:47:18 +0200183 /* Read from stdin if there's nothing else to do. */
184 if (!argv[0])
185 *--argv = (char*)"-";
186
Denys Vlasenkoe31ca2e2017-04-12 17:17:29 +0200187#if ENABLE_FEATURE_CATV
188 if (opts & 7)
189 return catv(opts, argv);
Denys Vlasenkoe31ca2e2017-04-12 17:17:29 +0200190 opts >>= 4;
191#endif
192
Kang-Che Sunga2bdc5c2017-07-14 09:56:13 +0200193#if ENABLE_FEATURE_CATN
194# define CAT_OPT_n (1<<0)
195# define CAT_OPT_b (1<<1)
196 if (opts & (CAT_OPT_n|CAT_OPT_b)) { /* -n or -b */
Denys Vlasenko75e90b12017-07-14 10:47:18 +0200197 struct number_state ns;
Denys Vlasenkoc1005352018-11-29 11:44:10 +0100198 int exitcode;
Denys Vlasenko75e90b12017-07-14 10:47:18 +0200199
Kang-Che Sunga2bdc5c2017-07-14 09:56:13 +0200200 ns.width = 6;
201 ns.start = 1;
202 ns.inc = 1;
203 ns.sep = "\t";
Ron Yorstonc849e722021-01-21 08:40:54 +0000204 ns.empty_str = NULL;
Kang-Che Sunga2bdc5c2017-07-14 09:56:13 +0200205 ns.all = !(opts & CAT_OPT_b); /* -n without -b */
206 ns.nonempty = (opts & CAT_OPT_b); /* -b (with or without -n) */
Denys Vlasenkoc1005352018-11-29 11:44:10 +0100207 exitcode = EXIT_SUCCESS;
Kang-Che Sunga2bdc5c2017-07-14 09:56:13 +0200208 do {
Denys Vlasenkoc1005352018-11-29 11:44:10 +0100209 exitcode |= print_numbered_lines(&ns, *argv);
Kang-Che Sunga2bdc5c2017-07-14 09:56:13 +0200210 } while (*++argv);
Denys Vlasenkoc1005352018-11-29 11:44:10 +0100211 fflush_stdout_and_exit(exitcode);
Kang-Che Sunga2bdc5c2017-07-14 09:56:13 +0200212 }
213 /*opts >>= 2;*/
214#endif
Denys Vlasenkod88f94a2017-04-05 18:17:17 +0200215
Kang-Che Sunga2bdc5c2017-07-14 09:56:13 +0200216 return bb_cat(argv);
Denis Vlasenkobf66fbc2006-12-21 13:23:14 +0000217}