diff --git a/coreutils/cat.c b/coreutils/cat.c index 96970b19d..4d9147f8a 100644 --- a/coreutils/cat.c +++ b/coreutils/cat.c @@ -12,8 +12,15 @@ //config: help //config: cat is used to concatenate files and print them to the standard //config: output. Enable this option if you wish to enable the 'cat' utility. +//config: +//config:config FEATURE_CATV +//config: bool "cat -v[etA]" +//config: default y +//config: depends on CAT +//config: help +//config: Display nonprinting characters as escape sequences -//applet:IF_CAT(APPLET_NOFORK(cat, cat, BB_DIR_BIN, BB_SUID_DROP, cat)) +//applet:IF_CAT(APPLET(cat, BB_DIR_BIN, BB_SUID_DROP)) //kbuild:lib-$(CONFIG_CAT) += cat.o @@ -21,22 +28,27 @@ /* http://www.opengroup.org/onlinepubs/007904975/utilities/cat.html */ //usage:#define cat_trivial_usage -//usage: "[-n] [FILE]..." +//usage: "[-nb"IF_FEATURE_CATV("vteA")"] [FILE]..." //usage:#define cat_full_usage "\n\n" -//usage: "Concatenate FILEs and print them to stdout" +//usage: "Print FILEs to stdout\n" //usage: "\n -n Number output lines" +//usage: "\n -b Number nonempty lines" +//usage: IF_FEATURE_CATV( +//usage: "\n -v Show nonprinting characters as ^x or M-x" +//usage: "\n -t ...and tabs as ^I" +//usage: "\n -e ...and end lines with $" +//usage: "\n -A Same as -vte" +//usage: ) /* Longopts not implemented yet: - --number-nonblank number nonempty output lines, overrides -n - --number number all output lines + --number-nonblank number nonempty output lines, overrides -n + --number number all output lines + --show-nonprinting use ^ and M- notation, except for LFD and TAB + --show-all equivalent to -vet Not implemented yet: - -A, --show-all equivalent to -vET - -e equivalent to -vE - -E, --show-ends display $ at end of each line + -E, --show-ends display $ at end of each line (-e sans -v) + -T, --show-tabs display TAB characters as ^I (-t sans -v) -s, --squeeze-blank suppress repeated empty output lines - -t equivalent to -vT - -T, --show-tabs display TAB characters as ^I - -v, --show-nonprinting use ^ and M- notation, except for LFD and TAB */ //usage: //usage:#define cat_example_usage @@ -44,19 +56,111 @@ //usage: "110716.72 17.67" #include "libbb.h" +#include "common_bufsiz.h" -/* This is a NOFORK applet. Be very careful! */ +#if ENABLE_FEATURE_CATV +/* + * cat -v implementation for busybox + * + * Copyright (C) 2006 Rob Landley + * + * Licensed under GPLv2 or later, see file LICENSE in this source tree. + */ +/* Rob had "cat -v" implemented as a separate applet, catv. + * See "cat -v considered harmful" at + * http://cm.bell-labs.com/cm/cs/doc/84/kp.ps.gz + * From USENIX Summer Conference Proceedings, 1983 + * """ + * The talk reviews reasons for UNIX's popularity and shows, using UCB cat + * as a primary example, how UNIX has grown fat. cat isn't for printing + * files with line numbers, it isn't for compressing multiple blank lines, + * it's not for looking at non-printing ASCII characters, it's for + * concatenating files. + * We are reminded that ls isn't the place for code to break a single column + * into multiple ones, and that mailnews shouldn't have its own more + * processing or joke encryption code. + * """ + * + * I agree with the argument. Unfortunately, this ship has sailed (1983...). + * There are dozens of Linux distros and each of them has "cat" which supports -v. + * It's unrealistic for us to "reeducate" them to use our, incompatible way + * to achieve "cat -v" effect. The actuall effect would be "users pissed off + * by gratuitous incompatibility". + */ +#define CATV_OPT_e (1<<0) +#define CATV_OPT_t (1<<1) +#define CATV_OPT_v (1<<2) +static int catv(unsigned opts, char **argv) +{ + int retval = EXIT_SUCCESS; + int fd; + + BUILD_BUG_ON(CATV_OPT_e != VISIBLE_ENDLINE); + BUILD_BUG_ON(CATV_OPT_t != VISIBLE_SHOW_TABS); +#if 0 /* These consts match, we can just pass "opts" to visible() */ + if (opts & CATV_OPT_e) + flags |= VISIBLE_ENDLINE; + if (opts & CATV_OPT_t) + flags |= VISIBLE_SHOW_TABS; +#endif + + /* Read from stdin if there's nothing else to do. */ + if (!argv[0]) + *--argv = (char*)"-"; + +#define read_buf bb_common_bufsiz1 + setup_common_bufsiz(); + do { + fd = open_or_warn_stdin(*argv); + if (fd < 0) { + retval = EXIT_FAILURE; + continue; + } + for (;;) { + int i, res; + + res = read(fd, read_buf, COMMON_BUFSIZE); + if (res < 0) + retval = EXIT_FAILURE; + if (res <= 0) + break; + for (i = 0; i < res; i++) { + unsigned char c = read_buf[i]; + char buf[sizeof("M-^c")]; + visible(c, buf, opts); + fputs(buf, stdout); + } + } + if (ENABLE_FEATURE_CLEAN_UP && fd) + close(fd); + } while (*++argv); + + fflush_stdout_and_exit(retval); +} +#endif int cat_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; int cat_main(int argc UNUSED_PARAM, char **argv) { struct number_state ns; - unsigned opt; + unsigned opts; - /* -u is ignored */ - opt = getopt32(argv, "nbu"); + IF_FEATURE_CATV(opt_complementary = "Aetv"; /* -A == -vet */) + /* -u is ignored ("unbuffered") */ + opts = getopt32(argv, IF_FEATURE_CATV("etvA")"nbu"); argv += optind; - if (!(opt & 3)) /* no -n or -b */ + +#if ENABLE_FEATURE_CATV + if (opts & 7) + return catv(opts, argv); +//BUG: -v,-e,-t,-A ignore -nb + opts >>= 4; +#endif + +#define CAT_OPT_n (1<<0) +#define CAT_OPT_b (1<<1) +#define CAT_OPT_u (1<<2) + if (!(opts & (CAT_OPT_n|CAT_OPT_b))) /* no -n or -b */ return bb_cat(argv); if (!*argv) @@ -66,8 +170,8 @@ int cat_main(int argc UNUSED_PARAM, char **argv) ns.inc = 1; ns.sep = "\t"; ns.empty_str = "\n"; - ns.all = !(opt & 2); /* -n without -b */ - ns.nonempty = (opt & 2); /* -b (with or without -n) */ + ns.all = !(opts & CAT_OPT_b); /* -n without -b */ + ns.nonempty = (opts & CAT_OPT_b); /* -b (with or without -n) */ do { print_numbered_lines(&ns, *argv); } while (*++argv); diff --git a/coreutils/catv.c b/coreutils/catv.c deleted file mode 100644 index 1aeebe1d9..000000000 --- a/coreutils/catv.c +++ /dev/null @@ -1,96 +0,0 @@ -/* vi: set sw=4 ts=4: */ -/* - * cat -v implementation for busybox - * - * Copyright (C) 2006 Rob Landley - * - * Licensed under GPLv2 or later, see file LICENSE in this source tree. - */ - -/* See "Cat -v considered harmful" at - * http://cm.bell-labs.com/cm/cs/doc/84/kp.ps.gz */ - -//config:config CATV -//config: bool "catv" -//config: default y -//config: help -//config: Display nonprinting characters as escape sequences (like some -//config: implementations' cat -v option). - -//applet:IF_CATV(APPLET(catv, BB_DIR_BIN, BB_SUID_DROP)) - -//kbuild:lib-$(CONFIG_CATV) += catv.o - -//usage:#define catv_trivial_usage -//usage: "[-etv] [FILE]..." -//usage:#define catv_full_usage "\n\n" -//usage: "Display nonprinting characters as ^x or M-x\n" -//usage: "\n -e End each line with $" -//usage: "\n -t Show tabs as ^I" -//usage: "\n -v Don't use ^x or M-x escapes" - -#include "libbb.h" -#include "common_bufsiz.h" - -#define CATV_OPT_e (1<<0) -#define CATV_OPT_t (1<<1) -#define CATV_OPT_v (1<<2) -struct BUG_const_mismatch { - char BUG_const_mismatch[ - CATV_OPT_e == VISIBLE_ENDLINE && CATV_OPT_t == VISIBLE_SHOW_TABS - ? 1 : -1 - ]; -}; - -int catv_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; -int catv_main(int argc UNUSED_PARAM, char **argv) -{ - int retval = EXIT_SUCCESS; - int fd; - unsigned opts; - opts = getopt32(argv, "etv"); - argv += optind; -#if 0 /* These consts match, we can just pass "opts" to visible() */ - if (opts & CATV_OPT_e) - flags |= VISIBLE_ENDLINE; - if (opts & CATV_OPT_t) - flags |= VISIBLE_SHOW_TABS; -#endif - - /* Read from stdin if there's nothing else to do. */ - if (!argv[0]) - *--argv = (char*)"-"; - -#define read_buf bb_common_bufsiz1 - setup_common_bufsiz(); - do { - fd = open_or_warn_stdin(*argv); - if (fd < 0) { - retval = EXIT_FAILURE; - continue; - } - for (;;) { - int i, res; - - res = read(fd, read_buf, COMMON_BUFSIZE); - if (res < 0) - retval = EXIT_FAILURE; - if (res <= 0) - break; - for (i = 0; i < res; i++) { - unsigned char c = read_buf[i]; - if (opts & CATV_OPT_v) { - putchar(c); - } else { - char buf[sizeof("M-^c")]; - visible(c, buf, opts); - fputs(buf, stdout); - } - } - } - if (ENABLE_FEATURE_CLEAN_UP && fd) - close(fd); - } while (*++argv); - - fflush_stdout_and_exit(retval); -}