git: d2cfdf4c12a7 - main - cat: add -A, -E and -T flags
- Go to: [ bottom of page ] [ top of archives ] [ this month ]
Date: Mon, 31 Aug 2026 12:38:02 UTC
The branch main has been updated by bapt:
URL: https://cgit.FreeBSD.org/src/commit/?id=d2cfdf4c12a76db3612c83575403150811f5aa9a
commit d2cfdf4c12a76db3612c83575403150811f5aa9a
Author: Baptiste Daroussin <bapt@FreeBSD.org>
AuthorDate: 2026-08-21 14:41:54 +0000
Commit: Baptiste Daroussin <bapt@FreeBSD.org>
CommitDate: 2026-08-31 12:35:21 +0000
cat: add -A, -E and -T flags
Support cat -A, -E and -T, which are commonly used by Linux shell
scripts. -E prints a "$" at the end of each line, -T renders tabs
as ^I, and -A is equivalent to -vET.
MFC After: 1 week
Discussed with: jrtc27
Reviewed by: jrtc27, ziaee
Differential Revision: https://reviews.freebsd.org/D59250
---
bin/cat/cat.1 | 32 ++++++++++++++++------
bin/cat/cat.c | 25 +++++++++++------
bin/cat/tests/Makefile | 1 +
bin/cat/tests/cat_extra_test.sh | 59 +++++++++++++++++++++++++++++++++++++++++
4 files changed, 101 insertions(+), 16 deletions(-)
diff --git a/bin/cat/cat.1 b/bin/cat/cat.1
index 59e0dff80ed0..7112b8167eef 100644
--- a/bin/cat/cat.1
+++ b/bin/cat/cat.1
@@ -29,7 +29,7 @@
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
.\" SUCH DAMAGE.
.\"
-.Dd January 29, 2013
+.Dd August 21, 2026
.Dt CAT 1
.Os
.Sh NAME
@@ -37,7 +37,7 @@
.Nd concatenate and print files
.Sh SYNOPSIS
.Nm
-.Op Fl belnstuv
+.Op Fl AbeElnstTuv
.Op Ar
.Sh DESCRIPTION
The
@@ -68,12 +68,24 @@ domain binding capability available in
.Pp
The options are as follows:
.Bl -tag -width indent
+.It Fl A
+Equivalent to specifying the
+.Fl v
+,
+.Fl E
+and
+.Fl T
+options.
.It Fl b
Number the non-blank output lines, starting at 1.
.It Fl e
-Display non-printing characters (see the
+Equivalent to specifying the
+.Fl E
+and
.Fl v
-option), and display a dollar sign
+options.
+.It Fl E
+Display a dollar sign
.Pq Ql \&$
at the end of each line.
.It Fl l
@@ -91,11 +103,15 @@ Number the output lines, starting at 1.
.It Fl s
Squeeze multiple adjacent empty lines, causing the output to be
single spaced.
+.It Fl T
+Display tab characters as
+.Ql ^I .
.It Fl t
-Display non-printing characters (see the
+Equivalent to specifying the
+.Fl T
+and
.Fl v
-option), and display tab characters as
-.Ql ^I .
+options.
.It Fl u
Disable output buffering.
.It Fl v
@@ -183,7 +199,7 @@ utility is compliant with the
specification.
.Pp
The flags
-.Op Fl belnstv
+.Op Fl AbeElnstTv
are extensions to the specification.
.Sh HISTORY
A
diff --git a/bin/cat/cat.c b/bin/cat/cat.c
index 8c10faf7cff9..20a20b44d9f7 100644
--- a/bin/cat/cat.c
+++ b/bin/cat/cat.c
@@ -58,7 +58,7 @@
#include <casper/cap_fileargs.h>
#include <casper/cap_net.h>
-static int bflag, eflag, lflag, nflag, sflag, tflag, vflag;
+static int bflag, Eflag, lflag, nflag, sflag, Tflag, vflag;
static int rval;
static const char *filename;
static fileargs_t *fa;
@@ -103,7 +103,7 @@ static int udom_open(const char *path, int flags);
#ifdef BOOTSTRAP_CAT
#define SUPPORTED_FLAGS "lu"
#else
-#define SUPPORTED_FLAGS "belnstuv"
+#define SUPPORTED_FLAGS "belnstuvAET"
#endif
#ifndef NO_UDOM_SUPPORT
@@ -166,8 +166,14 @@ main(int argc, char *argv[])
case 'b':
bflag = nflag = 1; /* -b implies -n */
break;
+ case 'A':
+ Eflag = Tflag = vflag = 1; /* -A implies -v -E -T */
+ break;
case 'e':
- eflag = vflag = 1; /* -e implies -v */
+ Eflag = vflag = 1; /* -e implies -v */
+ break;
+ case 'E':
+ Eflag = 1;
break;
case 'l':
lflag = 1;
@@ -179,7 +185,10 @@ main(int argc, char *argv[])
sflag = 1;
break;
case 't':
- tflag = vflag = 1; /* -t implies -v */
+ Tflag = vflag = 1; /* -t implies -v */
+ break;
+ case 'T':
+ Tflag = 1;
break;
case 'u':
setbuf(stdout, NULL);
@@ -209,7 +218,7 @@ main(int argc, char *argv[])
if (caph_enter_casper() != 0)
err(EXIT_FAILURE, "capsicum");
- if (bflag || eflag || nflag || sflag || tflag || vflag)
+ if (bflag || Eflag || nflag || sflag || Tflag || vflag)
scanfiles(argv, 1);
else
scanfiles(argv, 0);
@@ -313,7 +322,7 @@ cook_cat(FILE *fp)
(void)fprintf(stdout, "%6d\t", ++line);
if (ferror(stdout))
break;
- } else if (eflag) {
+ } else if (Eflag) {
(void)fprintf(stdout, "%6s\t", "");
if (ferror(stdout))
break;
@@ -321,10 +330,10 @@ cook_cat(FILE *fp)
}
}
if (ch == '\n') {
- if (eflag && putchar('$') == EOF)
+ if (Eflag && putchar('$') == EOF)
break;
} else if (ch == '\t') {
- if (tflag) {
+ if (Tflag) {
if (putchar('^') == EOF || putchar('I') == EOF)
break;
continue;
diff --git a/bin/cat/tests/Makefile b/bin/cat/tests/Makefile
index 347f4826ba4d..38fcff5eaf36 100644
--- a/bin/cat/tests/Makefile
+++ b/bin/cat/tests/Makefile
@@ -1,5 +1,6 @@
PACKAGE= tests
+ATF_TESTS_SH= cat_extra_test
NETBSD_ATF_TESTS_SH= cat_test
${PACKAGE}FILES+= d_align.in
diff --git a/bin/cat/tests/cat_extra_test.sh b/bin/cat/tests/cat_extra_test.sh
new file mode 100644
index 000000000000..87d617122abf
--- /dev/null
+++ b/bin/cat/tests/cat_extra_test.sh
@@ -0,0 +1,59 @@
+#
+# SPDX-License-Identifier: BSD-2-Clause
+#
+# Copyright (c) 2026 Baptiste Daroussin <bapt@FreeBSD.org>
+#
+#
+
+atf_test_case E_output
+E_output_body()
+{
+ printf 'a\tb\n\001c\n\177\n' > input
+ atf_check -o 'inline:a\tb$\n\001c$\n\0177$\n' cat -E input
+}
+
+atf_test_case T_output
+T_output_body()
+{
+ printf 'a\tb\n\001c\n\177\n' > input
+ atf_check -o 'inline:a^Ib\n\001c\n\0177\n' cat -T input
+}
+
+atf_test_case A_output
+A_output_body()
+{
+ printf 'a\tb\n\001c\n\177\n' > input
+
+ # -A implies -v, -E and -T.
+ expected='a^Ib$\n^Ac$\n^?$\n'
+ atf_check -o "inline:${expected}" cat -A input
+ atf_check -o "inline:${expected}" cat -vET input
+ atf_check -o "inline:${expected}" cat -AET input
+}
+
+atf_test_case e_implies_v
+e_implies_v_body()
+{
+ printf 'a\tb\n\001c\n\177\n' > input
+
+ atf_check -o 'inline:a\tb$\n^Ac$\n^?$\n' cat -e input
+ atf_check -o 'inline:a\tb$\n^Ac$\n^?$\n' cat -Ev input
+}
+
+atf_test_case t_implies_v
+t_implies_v_body()
+{
+ printf 'a\tb\n\001c\n\177\n' > input
+
+ atf_check -o 'inline:a^Ib\n^Ac\n^?\n' cat -t input
+ atf_check -o 'inline:a^Ib\n^Ac\n^?\n' cat -Tv input
+}
+
+atf_init_test_cases()
+{
+ atf_add_test_case E_output
+ atf_add_test_case T_output
+ atf_add_test_case A_output
+ atf_add_test_case e_implies_v
+ atf_add_test_case t_implies_v
+}