1/* vi: set sw=4 ts=4: */ 2/* 3 * cat implementation for busybox 4 * 5 * Copyright (C) 2003 Manuel Novoa III <mjn3@codepoet.org> 6 * 7 * Licensed under GPLv2, see file LICENSE in this source tree. 8 */ 9//config:config CAT 10//config: bool "cat (5.6 kb)" 11//config: default y 12//config: help 13//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. 15//config: 16//config:config FEATURE_CATN 17//config: bool "Enable -n and -b options" 18//config: default y 19//config: depends on CAT 20//config: help 21//config: -n numbers all output lines while -b numbers nonempty output lines. 22//config: 23//config:config FEATURE_CATV 24//config: bool "cat -v[etA]" 25//config: default y 26//config: depends on CAT 27//config: help 28//config: Display nonprinting characters as escape sequences 29 30//applet:IF_CAT(APPLET(cat, BB_DIR_BIN, BB_SUID_DROP)) 31 32//kbuild:lib-$(CONFIG_CAT) += cat.o 33 34/* BB_AUDIT SUSv3 compliant */ 35/* http://www.opengroup.org/onlinepubs/007904975/utilities/cat.html */ 36 37//usage:#if ENABLE_FEATURE_CATN || ENABLE_FEATURE_CATV 38//usage:#define cat_trivial_usage 39//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 44//usage:#define cat_full_usage "\n\n" 45//usage: "Print FILEs to stdout\n" 46//usage: IF_FEATURE_CATN( 47//usage: "\n -n Number output lines" 48//usage: "\n -b Number nonempty lines" 49//usage: ) 50//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: ) 56/* 57 Longopts not implemented yet: 58 --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 62 Not implemented yet: 63 -E, --show-ends display $ at end of each line (-e sans -v) 64 -T, --show-tabs display TAB characters as ^I (-t sans -v) 65 -s, --squeeze-blank suppress repeated empty output lines 66*/ 67//usage: 68//usage:#define cat_example_usage 69//usage: "$ cat /proc/uptime\n" 70//usage: "110716.72 17.67" 71 72#include "libbb.h" 73#include "common_bufsiz.h" 74 75#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 101 * to achieve "cat -v" effect. The actual effect would be "users pissed off 102 * by gratuitous incompatibility". 103 */ 104#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) 110static int catv(unsigned opts, char **argv) 111{ 112 int retval = EXIT_SUCCESS; 113 int fd; 114#if ENABLE_FEATURE_CATN 115 bool eol_seen = (opts & (CAT_OPT_n|CAT_OPT_b)); 116 unsigned eol_char = (eol_seen ? '\n' : 0x100); 117 unsigned skip_num_on = (opts & CAT_OPT_b) ? '\n' : 0x100; 118 unsigned lineno = 0; 119#endif 120 121 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 129 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")]; 149#if ENABLE_FEATURE_CATN 150 if (eol_seen && c != skip_num_on) 151 printf("%6u ", ++lineno); 152 eol_seen = (c == eol_char); 153#endif 154 visible(c, buf, opts); 155 fputs_stdout(buf); 156 } 157 } 158 if (ENABLE_FEATURE_CLEAN_UP && fd) 159 close(fd); 160 } while (*++argv); 161 162 fflush_stdout_and_exit(retval); 163} 164#undef CAT_OPT_n 165#undef CAT_OPT_b 166#endif 167 168int cat_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; 169int cat_main(int argc UNUSED_PARAM, char **argv) 170{ 171#if ENABLE_FEATURE_CATV || ENABLE_FEATURE_CATN 172 unsigned opts; 173 174 opts = 175#endif 176 getopt32(argv, IF_FEATURE_CATV("^") 177 /* -u is ignored ("unbuffered") */ 178 IF_FEATURE_CATV("etvA")IF_FEATURE_CATN("nb")"u" 179 IF_FEATURE_CATV("\0" "Aetv" /* -A == -vet */) 180 ); 181 argv += optind; 182 183 /* Read from stdin if there's nothing else to do. */ 184 if (!argv[0]) 185 *--argv = (char*)"-"; 186 187#if ENABLE_FEATURE_CATV 188 if (opts & 7) 189 return catv(opts, argv); 190 opts >>= 4; 191#endif 192 193#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 */ 197 struct number_state ns; 198 int exitcode; 199 200 ns.width = 6; 201 ns.start = 1; 202 ns.inc = 1; 203 ns.sep = "\t"; 204 ns.empty_str = NULL; 205 ns.all = !(opts & CAT_OPT_b); /* -n without -b */ 206 ns.nonempty = (opts & CAT_OPT_b); /* -b (with or without -n) */ 207 exitcode = EXIT_SUCCESS; 208 do { 209 exitcode |= print_numbered_lines(&ns, *argv); 210 } while (*++argv); 211 fflush_stdout_and_exit(exitcode); 212 } 213 /*opts >>= 2;*/ 214#endif 215 216 return bb_cat(argv); 217} 218