diff options
author | sjg <sjg@FreeBSD.org> | 2015-05-27 01:19:58 +0000 |
---|---|---|
committer | sjg <sjg@FreeBSD.org> | 2015-05-27 01:19:58 +0000 |
commit | 65145fa4c81da358fcbc3b650156dab705dfa34e (patch) | |
tree | 55c065b6730aaac2afb6c29933ee6ec5fa4c4249 /usr.bin/col | |
parent | 60ff4eb0dff94a04d75d0d52a3957aaaf5f8c693 (diff) | |
parent | e6b664c390af88d4a87208bc042ce503da664c3b (diff) | |
download | FreeBSD-src-65145fa4c81da358fcbc3b650156dab705dfa34e.zip FreeBSD-src-65145fa4c81da358fcbc3b650156dab705dfa34e.tar.gz |
Merge sync of head
Diffstat (limited to 'usr.bin/col')
-rw-r--r-- | usr.bin/col/Makefile | 6 | ||||
-rw-r--r-- | usr.bin/col/col.1 | 29 | ||||
-rw-r--r-- | usr.bin/col/col.c | 171 | ||||
-rw-r--r-- | usr.bin/col/tests/Makefile | 11 | ||||
-rwxr-xr-x | usr.bin/col/tests/col.sh | 33 | ||||
-rw-r--r-- | usr.bin/col/tests/rlf.in | 2 | ||||
-rw-r--r-- | usr.bin/col/tests/rlf2.in | 2 |
7 files changed, 187 insertions, 67 deletions
diff --git a/usr.bin/col/Makefile b/usr.bin/col/Makefile index 8e3a959..a162866 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 9419fe3..fc02ca4 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 52214857..13df126 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 0000000..43838e9 --- /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 0000000..c072aab --- /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 0000000..57a14e5 --- /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 0000000..dd46851 --- /dev/null +++ b/usr.bin/col/tests/rlf2.in @@ -0,0 +1,2 @@ +a + 7b |