summaryrefslogtreecommitdiff
path: root/usr.bin/col
diff options
context:
space:
mode:
authorSimon J. Gerraty <sjg@FreeBSD.org>2015-05-27 01:19:58 +0000
committerSimon J. Gerraty <sjg@FreeBSD.org>2015-05-27 01:19:58 +0000
commit98e0ffaefb0f241cda3a72395d3be04192ae0d47 (patch)
tree55c065b6730aaac2afb6c29933ee6ec5fa4c4249 /usr.bin/col
parentb17ff922d4072ae132ece458f5b5d74a236880ac (diff)
parente81032ad243db32b8fd615b2d55ee94b9f6a5b6a (diff)
downloadsrc-test-98e0ffaefb0f241cda3a72395d3be04192ae0d47.tar.gz
src-test-98e0ffaefb0f241cda3a72395d3be04192ae0d47.zip
Merge sync of head
Notes
Notes: svn path=/projects/bmake/; revision=283595
Diffstat (limited to 'usr.bin/col')
-rw-r--r--usr.bin/col/Makefile6
-rw-r--r--usr.bin/col/col.129
-rw-r--r--usr.bin/col/col.c171
-rw-r--r--usr.bin/col/tests/Makefile11
-rwxr-xr-xusr.bin/col/tests/col.sh33
-rw-r--r--usr.bin/col/tests/rlf.in2
-rw-r--r--usr.bin/col/tests/rlf2.in2
7 files changed, 187 insertions, 67 deletions
diff --git a/usr.bin/col/Makefile b/usr.bin/col/Makefile
index 8e3a95948f3f6..a162866119022 100644
--- a/usr.bin/col/Makefile
+++ b/usr.bin/col/Makefile
@@ -1,6 +1,12 @@
# @(#)Makefile 8.1 (Berkeley) 6/6/93
# $FreeBSD$
+.include <src.opts.mk>
+
PROG= col
+.if ${MK_TESTS} != "no"
+SUBDIR+= tests
+.endif
+
.include <bsd.prog.mk>
diff --git a/usr.bin/col/col.1 b/usr.bin/col/col.1
index 9419fe326cb3e..fc02ca4b54f73 100644
--- a/usr.bin/col/col.1
+++ b/usr.bin/col/col.1
@@ -31,7 +31,7 @@
.\" @(#)col.1 8.1 (Berkeley) 6/29/93
.\" $FreeBSD$
.\"
-.Dd August 4, 2004
+.Dd May 10, 2015
.Dt COL 1
.Os
.Sh NAME
@@ -82,18 +82,33 @@ recognized and interpreted by itself, which are listed below.
Output multiple spaces instead of tabs.
.El
.Pp
-The control sequences for carriage motion that
+In the input stream,
.Nm
-understands and their decimal values are listed in the following
-table:
+understands both the escape sequences of the form escape-digit
+mandated by
+.St -susv2
+and the traditional
+.Bx
+format escape-control-character.
+The control sequences for carriage motion and their ASCII values
+are as follows:
.Pp
.Bl -tag -width "carriage return" -compact
+.It ESC\-BELL
+reverse line feed (escape then bell).
.It ESC\-7
-reverse line feed (escape then 7)
+reverse line feed (escape then 7).
+.It ESC\-BACKSPACE
+half reverse line feed (escape then backspace).
.It ESC\-8
-half reverse line feed (escape then 8)
+half reverse line feed (escape then 8).
+.It ESC\-TAB
+half forward line feed (escape than tab).
.It ESC\-9
-half forward line feed (escape then 9)
+half forward line feed (escape then 9).
+In
+.Fl f
+mode, this sequence may also occur in the output stream.
.It backspace
moves back one column (8); ignored in the first column
.It carriage return
diff --git a/usr.bin/col/col.c b/usr.bin/col/col.c
index 5221485748c6b..13df126e00ba3 100644
--- a/usr.bin/col/col.c
+++ b/usr.bin/col/col.c
@@ -45,11 +45,15 @@ static char sccsid[] = "@(#)col.c 8.5 (Berkeley) 5/4/95";
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
+#include <sys/capsicum.h>
+
#include <err.h>
+#include <errno.h>
#include <locale.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
+#include <termios.h>
#include <unistd.h>
#include <wchar.h>
#include <wctype.h>
@@ -63,9 +67,9 @@ __FBSDID("$FreeBSD$");
#define SI '\017' /* shift in to normal character set */
#define SO '\016' /* shift out to alternate character set */
#define VT '\013' /* vertical tab (aka reverse line feed) */
-#define RLF '\007' /* ESC-07 reverse line feed */
-#define RHLF '\010' /* ESC-010 reverse half-line feed */
-#define FHLF '\011' /* ESC-011 forward half-line feed */
+#define RLF '7' /* ESC-7 reverse line feed */
+#define RHLF '8' /* ESC-8 reverse half-line feed */
+#define FHLF '9' /* ESC-9 forward half-line feed */
/* build up at least this many lines before flushing them out */
#define BUFFER_MARGIN 32
@@ -92,6 +96,7 @@ struct line_str {
int l_max_col; /* max column in the line */
};
+static void addto_lineno(int *, int);
static LINE *alloc_line(void);
static void dowarn(int);
static void flush_line(LINE *);
@@ -104,7 +109,7 @@ static CSET last_set; /* char_set of last char printed */
static LINE *lines;
static int compress_spaces; /* if doing space -> tab conversion */
static int fine; /* if `fine' resolution (half lines) */
-static int max_bufd_lines; /* max # lines to keep in memory */
+static int max_bufd_lines; /* max # of half lines to keep in memory */
static int nblank_lines; /* # blanks after last flushed line */
static int no_backspaces; /* if not to output any backspaces */
static int pass_unknown_seqs; /* pass unknown control sequences */
@@ -129,10 +134,26 @@ main(int argc, char **argv)
int this_line; /* line l points to */
int nflushd_lines; /* number of lines that were flushed */
int adjust, opt, warned, width;
+ const char *errstr;
+ cap_rights_t rights;
+ unsigned long cmd;
(void)setlocale(LC_CTYPE, "");
- max_bufd_lines = 128;
+ cap_rights_init(&rights, CAP_FSTAT, CAP_READ);
+ if (cap_rights_limit(STDIN_FILENO, &rights) < 0 && errno != ENOSYS)
+ err(1, "unable to limit rights for stdin");
+ cap_rights_init(&rights, CAP_FSTAT, CAP_WRITE, CAP_IOCTL);
+ if (cap_rights_limit(STDOUT_FILENO, &rights) < 0 && errno != ENOSYS)
+ err(1, "unable to limit rights for stdout");
+ cmd = TIOCGETA; /* required by isatty(3) in printf(3) */
+ if (cap_ioctls_limit(STDOUT_FILENO, &cmd, 1) < 0 && errno != ENOSYS)
+ err(1, "unable to limit ioctls for stdout");
+
+ if (cap_enter() < 0 && errno != ENOSYS)
+ err(1, "unable to enter capability mode");
+
+ max_bufd_lines = 256;
compress_spaces = 1; /* compress spaces into tabs */
while ((opt = getopt(argc, argv, "bfhl:px")) != -1)
switch (opt) {
@@ -146,8 +167,11 @@ main(int argc, char **argv)
compress_spaces = 1;
break;
case 'l': /* buffered line count */
- if ((max_bufd_lines = atoi(optarg)) <= 0)
- errx(1, "bad -l argument %s", optarg);
+ max_bufd_lines = strtonum(optarg, 1,
+ (INT_MAX - BUFFER_MARGIN) / 2, &errstr) * 2;
+ if (errstr != NULL)
+ errx(1, "bad -l argument, %s: %s", errstr,
+ optarg);
break;
case 'p': /* pass unknown control sequences */
pass_unknown_seqs = 1;
@@ -163,9 +187,6 @@ main(int argc, char **argv)
if (optind != argc)
usage();
- /* this value is in half lines */
- max_bufd_lines *= 2;
-
adjust = cur_col = extra_lines = warned = 0;
cur_line = max_line = nflushd_lines = this_line = 0;
cur_set = last_set = CS_NORMAL;
@@ -184,20 +205,31 @@ main(int argc, char **argv)
continue;
case ESC: /* just ignore EOF */
switch(getwchar()) {
+ /*
+ * In the input stream, accept both the
+ * XPG5 sequences ESC-digit and the
+ * traditional BSD sequences ESC-ctrl.
+ */
+ case '\007':
+ /* FALLTHROUGH */
case RLF:
- cur_line -= 2;
+ addto_lineno(&cur_line, -2);
break;
+ case '\010':
+ /* FALLTHROUGH */
case RHLF:
- cur_line--;
+ addto_lineno(&cur_line, -1);
break;
+ case '\011':
+ /* FALLTHROUGH */
case FHLF:
- cur_line++;
+ addto_lineno(&cur_line, 1);
if (cur_line > max_line)
max_line = cur_line;
}
continue;
case NL:
- cur_line += 2;
+ addto_lineno(&cur_line, 2);
if (cur_line > max_line)
max_line = cur_line;
cur_col = 0;
@@ -216,7 +248,7 @@ main(int argc, char **argv)
++cur_col;
continue;
case VT:
- cur_line -= 2;
+ addto_lineno(&cur_line, -2);
continue;
}
if (iswspace(ch)) {
@@ -229,58 +261,61 @@ main(int argc, char **argv)
}
/* Must stuff ch in a line - are we at the right one? */
- if (cur_line != this_line - adjust) {
+ if (cur_line + adjust != this_line) {
LINE *lnew;
- int nmove;
-
- adjust = 0;
- nmove = cur_line - this_line;
- if (!fine) {
- /* round up to next line */
- if (cur_line & 1) {
- adjust = 1;
- nmove++;
- }
- }
- if (nmove < 0) {
- for (; nmove < 0 && l->l_prev; nmove++)
+
+ /* round up to next line */
+ adjust = !fine && (cur_line & 1);
+
+ if (cur_line + adjust < this_line) {
+ while (cur_line + adjust < this_line &&
+ l->l_prev != NULL) {
l = l->l_prev;
- if (nmove) {
+ this_line--;
+ }
+ if (cur_line + adjust < this_line) {
if (nflushd_lines == 0) {
/*
* Allow backup past first
* line if nothing has been
* flushed yet.
*/
- for (; nmove < 0; nmove++) {
+ while (cur_line + adjust
+ < this_line) {
lnew = alloc_line();
l->l_prev = lnew;
lnew->l_next = l;
l = lines = lnew;
extra_lines++;
+ this_line--;
}
} else {
if (!warned++)
dowarn(cur_line);
- cur_line -= nmove;
+ cur_line = this_line - adjust;
}
}
} else {
/* may need to allocate here */
- for (; nmove > 0 && l->l_next; nmove--)
+ while (cur_line + adjust > this_line) {
+ if (l->l_next == NULL) {
+ l->l_next = alloc_line();
+ l->l_next->l_prev = l;
+ }
l = l->l_next;
- for (; nmove > 0; nmove--) {
- lnew = alloc_line();
- lnew->l_prev = l;
- l->l_next = lnew;
- l = lnew;
+ this_line++;
}
}
- this_line = cur_line + adjust;
- nmove = this_line - nflushd_lines;
- if (nmove >= max_bufd_lines + BUFFER_MARGIN) {
- nflushd_lines += nmove - max_bufd_lines;
- flush_lines(nmove - max_bufd_lines);
+ if (this_line > nflushd_lines &&
+ this_line - nflushd_lines >=
+ max_bufd_lines + BUFFER_MARGIN) {
+ if (extra_lines) {
+ flush_lines(extra_lines);
+ extra_lines = 0;
+ }
+ flush_lines(this_line - nflushd_lines -
+ max_bufd_lines);
+ nflushd_lines = this_line - max_bufd_lines;
}
}
/* grow line's buffer? */
@@ -290,7 +325,7 @@ main(int argc, char **argv)
need = l->l_lsize ? l->l_lsize * 2 : 90;
if ((l->l_line = realloc(l->l_line,
(unsigned)need * sizeof(CHAR))) == NULL)
- err(1, (char *)NULL);
+ err(1, NULL);
l->l_lsize = need;
}
c = &l->l_line[l->l_line_len++];
@@ -311,25 +346,23 @@ main(int argc, char **argv)
}
if (ferror(stdin))
err(1, NULL);
- if (max_line == 0)
- exit(0); /* no lines, so just exit */
+ if (extra_lines)
+ flush_lines(extra_lines);
/* goto the last line that had a character on it */
for (; l->l_next; l = l->l_next)
this_line++;
- flush_lines(this_line - nflushd_lines + extra_lines + 1);
+ flush_lines(this_line - nflushd_lines + 1);
/* make sure we leave things in a sane state */
if (last_set != CS_NORMAL)
- PUTC('\017');
+ PUTC(SI);
/* flush out the last few blank lines */
- nblank_lines = max_line - this_line;
+ if (max_line > this_line)
+ nblank_lines = max_line - this_line;
if (max_line & 1)
nblank_lines++;
- else if (!nblank_lines)
- /* missing a \n on the last line? */
- nblank_lines = 2;
flush_blanks();
exit(0);
}
@@ -346,7 +379,8 @@ flush_lines(int nflush)
flush_blanks();
flush_line(l);
}
- nblank_lines++;
+ if (l->l_line || l->l_next)
+ nblank_lines++;
if (l->l_line)
(void)free(l->l_line);
free_line(l);
@@ -377,8 +411,8 @@ flush_blanks(void)
for (i = nb; --i >= 0;)
PUTC('\n');
if (half) {
- PUTC('\033');
- PUTC('\011');
+ PUTC(ESC);
+ PUTC(FHLF);
if (!nb)
PUTC('\r');
}
@@ -410,13 +444,13 @@ flush_line(LINE *l)
sorted_size = l->l_lsize;
if ((sorted = realloc(sorted,
(unsigned)sizeof(CHAR) * sorted_size)) == NULL)
- err(1, (char *)NULL);
+ err(1, NULL);
}
if (l->l_max_col >= count_size) {
count_size = l->l_max_col + 1;
if ((count = realloc(count,
(unsigned)sizeof(int) * count_size)) == NULL)
- err(1, (char *)NULL);
+ err(1, NULL);
}
memset(count, 0, sizeof(int) * l->l_max_col + 1);
for (i = nchars, c = l->l_line; --i >= 0; c++)
@@ -480,10 +514,10 @@ flush_line(LINE *l)
if (c->c_set != last_set) {
switch (c->c_set) {
case CS_NORMAL:
- PUTC('\017');
+ PUTC(SI);
break;
case CS_ALTERNATE:
- PUTC('\016');
+ PUTC(SO);
}
last_set = c->c_set;
}
@@ -498,6 +532,23 @@ flush_line(LINE *l)
}
}
+/*
+ * Increment or decrement a line number, checking for overflow.
+ * Stop one below INT_MAX such that the adjust variable is safe.
+ */
+void
+addto_lineno(int *lno, int offset)
+{
+ if (offset > 0) {
+ if (*lno >= INT_MAX - offset)
+ errx(1, "too many lines");
+ } else {
+ if (*lno < INT_MIN - offset)
+ errx(1, "too many reverse line feeds");
+ }
+ *lno += offset;
+}
+
#define NALLOC 64
static LINE *line_freelist;
@@ -510,7 +561,7 @@ alloc_line(void)
if (!line_freelist) {
if ((l = realloc(NULL, sizeof(LINE) * NALLOC)) == NULL)
- err(1, (char *)NULL);
+ err(1, NULL);
line_freelist = l;
for (i = 1; i < NALLOC; i++, l++)
l->l_next = l + 1;
diff --git a/usr.bin/col/tests/Makefile b/usr.bin/col/tests/Makefile
new file mode 100644
index 0000000000000..43838e9c5eab7
--- /dev/null
+++ b/usr.bin/col/tests/Makefile
@@ -0,0 +1,11 @@
+# $FreeBSD$
+
+TESTSDIR= ${TESTSBASE}/usr.bin/col
+
+ATF_TESTS_SH= col
+
+FILES= rlf.in \
+ rlf2.in
+FILESDIR= ${TESTSDIR}
+
+.include <bsd.test.mk>
diff --git a/usr.bin/col/tests/col.sh b/usr.bin/col/tests/col.sh
new file mode 100755
index 0000000000000..c072aab929cdf
--- /dev/null
+++ b/usr.bin/col/tests/col.sh
@@ -0,0 +1,33 @@
+# $FreeBSD$
+
+atf_test_case rlf
+
+rlf_head()
+{
+ atf_set "descr" "testing reverse line feed"
+}
+rlf_body()
+{
+ atf_check \
+ -o inline:"a b\n" \
+ -e empty \
+ -s exit:0 \
+ col < $(atf_get_srcdir)/rlf.in
+
+ atf_check \
+ -o inline:"a b\n" \
+ -e empty \
+ -s exit:0 \
+ col < $(atf_get_srcdir)/rlf2.in
+
+ atf_check \
+ -o inline:"a b\n" \
+ -e empty \
+ -s exit:0 \
+ col -x < $(atf_get_srcdir)/rlf2.in
+}
+
+atf_init_test_cases()
+{
+ atf_add_test_case rlf
+}
diff --git a/usr.bin/col/tests/rlf.in b/usr.bin/col/tests/rlf.in
new file mode 100644
index 0000000000000..57a14e5771b72
--- /dev/null
+++ b/usr.bin/col/tests/rlf.in
@@ -0,0 +1,2 @@
+a
+ 7b
diff --git a/usr.bin/col/tests/rlf2.in b/usr.bin/col/tests/rlf2.in
new file mode 100644
index 0000000000000..dd4685174dd74
--- /dev/null
+++ b/usr.bin/col/tests/rlf2.in
@@ -0,0 +1,2 @@
+a
+ 7b