[git commit] nl: new applet; also implement cat -nb (similar functionality to nl)

Denys Vlasenko vda.linux at googlemail.com
Wed Apr 5 16:17:17 UTC 2017


commit: https://git.busybox.net/busybox/commit/?id=d88f94a5df3a2edb8ba56fab5c13674b452f87ab
branch: https://git.busybox.net/busybox/commit/?id=refs/heads/master

function                                             old     new   delta
nl_main                                                -     201    +201
print_numbered_lines                                   -     115    +115
cat_main                                              36     149    +113
static.nl_longopts                                     -     106    +106
packed_usage                                       31081   31182    +101
applet_main                                         1488    1492      +4
applet_names                                        2575    2578      +3
applet_suid                                           93      94      +1
applet_install_loc                                   186     187      +1
------------------------------------------------------------------------------
(add/remove: 4/0 grow/shrink: 6/0 up/down: 645/0)             Total: 645 bytes

Signed-off-by: Denys Vlasenko <vda.linux at googlemail.com>
---
 coreutils/cat.c |  43 +++++++++++++++++++++---
 coreutils/nl.c  | 100 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 include/libbb.h |  10 ++++++
 3 files changed, 149 insertions(+), 4 deletions(-)

diff --git a/coreutils/cat.c b/coreutils/cat.c
index 6597888..4169d95 100644
--- a/coreutils/cat.c
+++ b/coreutils/cat.c
@@ -15,15 +15,31 @@
 
 //applet:IF_CAT(APPLET_NOFORK(cat, cat, BB_DIR_BIN, BB_SUID_DROP, cat))
 
-//kbuild:lib-$(CONFIG_CAT)     += cat.o
+//kbuild:lib-$(CONFIG_CAT) += cat.o
+// For -n:
+//kbuild:lib-$(CONFIG_CAT) += nl.o
 
 /* BB_AUDIT SUSv3 compliant */
 /* http://www.opengroup.org/onlinepubs/007904975/utilities/cat.html */
 
 //usage:#define cat_trivial_usage
-//usage:       "[FILE]..."
+//usage:       "[-n] [FILE]..."
 //usage:#define cat_full_usage "\n\n"
 //usage:       "Concatenate FILEs and print them to stdout"
+//usage:     "\n	-n	Number output lines"
+/*
+  Longopts not implemented yet:
+     --number-nonblank    number nonempty output lines, overrides -n
+     --number             number all output lines
+  Not implemented yet:
+  -A, --show-all           equivalent to -vET
+  -e                       equivalent to -vE
+  -E, --show-ends          display $ at end of each line
+  -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
 //usage:       "$ cat /proc/uptime\n"
@@ -61,7 +77,26 @@ int bb_cat(char **argv)
 int cat_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
 int cat_main(int argc UNUSED_PARAM, char **argv)
 {
-	getopt32(argv, "u");
+	struct number_state ns;
+	unsigned opt;
+
+	/* -u is ignored */
+	opt = getopt32(argv, "nbu");
 	argv += optind;
-	return bb_cat(argv);
+	if (!(opt & 3)) /* no -n or -b */
+		return bb_cat(argv);
+
+	if (!*argv)
+		*--argv = (char*)"-";
+	ns.width = 6;
+	ns.start = 1;
+	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) */
+	do {
+		print_numbered_lines(&ns, *argv);
+	} while (*++argv);
+	fflush_stdout_and_exit(EXIT_SUCCESS);
 }
diff --git a/coreutils/nl.c b/coreutils/nl.c
new file mode 100644
index 0000000..97931f3
--- /dev/null
+++ b/coreutils/nl.c
@@ -0,0 +1,100 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Licensed under GPLv2 or later, see file LICENSE in this source tree.
+ */
+//config:config NL
+//config:	bool "nl"
+//config:	default y
+//config:	help
+//config:	  nl is used to number lines of files.
+
+//applet:IF_UNIQ(APPLET(nl, BB_DIR_USR_BIN, BB_SUID_DROP))
+
+//kbuild:lib-$(CONFIG_UNIQ) += nl.o
+
+//usage:#define nl_trivial_usage
+//usage:       "[OPTIONS] [FILE]..."
+//usage:#define nl_full_usage "\n\n"
+//usage:       "Write FILEs to standard output with line numbers added\n"
+//usage:     "\n	-b STYLE	Which lines to number - a: all, t: nonempty, n: none"
+//^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^TODO: support "pBRE": number only lines thatmatch regexp BRE"
+////usage:     "\n	-f STYLE	footer lines"
+////usage:     "\n	-h STYLE	header lines"
+////usage:     "\n	-d CC		use CC for separating logical pages"
+//usage:     "\n	-i N		Line number increment"
+////usage:     "\n	-l NUMBER	group of NUMBER empty lines counted as one"
+////usage:     "\n	-n FORMAT	lneft justified, no leading zeros; rn or rz"
+////usage:     "\n	-p 		do not reset line numbers at logical pages (huh?)"
+//usage:     "\n	-s STRING	Use STRING as line number separator"
+//usage:     "\n	-v N		Start from N"
+//usage:     "\n	-w N		Width of line numbers"
+
+/* By default, selects -v1 -i1 -l1 -sTAB -w6 -nrn -hn -bt -fn */
+
+#include "libbb.h"
+
+void FAST_FUNC print_numbered_lines(struct number_state *ns, const char *filename)
+{
+	FILE *fp = fopen_or_warn_stdin(filename);
+	unsigned N = ns->start;
+	char *line;
+
+	while ((line = xmalloc_fgetline(fp)) != NULL) {
+		if (ns->all
+		 || (ns->nonempty && line[0])
+		) {
+			printf("%*u%s%s\n", ns->width, N, ns->sep, line);
+			N += ns->inc;
+		} else if (ns->empty_str)
+			fputs(ns->empty_str, stdout);
+		free(line);
+	}
+
+	fclose(fp);
+}
+
+int nl_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
+int nl_main(int argc UNUSED_PARAM, char **argv)
+{
+	unsigned opt;
+	struct number_state ns;
+	const char *opt_b = "t";
+	enum {
+		OPT_p = (1 << 0),
+	};
+#if ENABLE_LONG_OPTS
+	static const char nl_longopts[] ALIGN1 =
+		"body-numbering\0"	Required_argument "b"
+	//	"footer-numbering\0"	Required_argument "f" - not implemented yet
+	//	"header-numbering\0"	Required_argument "h" - not implemented yet
+	//	"section-delimiter\0"	Required_argument "d" - not implemented yet
+		"line-increment\0"	Required_argument "i"
+	//	"join-blank-lines\0"	Required_argument "l" - not implemented yet
+	//	"number-format\0"	Required_argument "n" - not implemented yet
+		"no-renumber\0"		No_argument       "p" // no-op so far
+		"number-separator\0"	Required_argument "s"
+		"starting-line-number\0"Required_argument "v"
+		"number-width\0"	Required_argument "w"
+	;
+
+	applet_long_options = nl_longopts;
+#endif
+	ns.width = 6;
+	ns.start = 1;
+	ns.inc = 1;
+	ns.sep = "\t";
+	opt = getopt32(argv, "pw:+s:v:+i:+b:", &ns.width, &ns.sep, &ns.start, &ns.inc, &opt_b);
+	ns.all = (opt_b[0] == 'a');
+	ns.nonempty = (opt_b[0] == 't');
+	ns.empty_str = xasprintf("%*s\n", ns.width + strlen(ns.sep), "");
+
+	argv += optind;
+	if (!*argv)
+		*--argv = (char*)"-";
+
+	do {
+		print_numbered_lines(&ns, *argv);
+	} while (*++argv);
+
+	fflush_stdout_and_exit(EXIT_SUCCESS);
+}
diff --git a/include/libbb.h b/include/libbb.h
index e97efcb..a2c699b 100644
--- a/include/libbb.h
+++ b/include/libbb.h
@@ -1271,6 +1271,16 @@ int bunzip2_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
 void bb_displayroutes(int noresolve, int netstatfmt) FAST_FUNC;
 #endif
 
+struct number_state {
+	unsigned width;
+	unsigned start;
+	unsigned inc;
+	const char *sep;
+	const char *empty_str;
+	smallint all, nonempty;
+};
+void print_numbered_lines(struct number_state *ns, const char *filename) FAST_FUNC;
+
 
 /* Networking */
 /* This structure defines protocol families and their handlers. */


More information about the busybox-cvs mailing list