The branch main has been updated by bapt: URL: https://cgit.FreeBSD.org/src/commit/?id=d2cfdf4c12a76db3612c83575403150811f5aa9a
commit d2cfdf4c12a76db3612c83575403150811f5aa9a Author: Baptiste Daroussin <[email protected]> AuthorDate: 2026-08-21 14:41:54 +0000 Commit: Baptiste Daroussin <[email protected]> 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 <[email protected]> +# +# + +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 +}
