col(1): Fix a couple of bugs

- When flushing extra lines after all input has been processed, make
  sure that local state is reinitialized correctly.
- When -f is specified, make sure to end output with a full newline.
- Fix some style issues and update comments.
- Add some regression tests.

PR:		249308
Submitted by:	Yang Zhong <yzhong@freebsdfoundation.org>
MFC after:	3 weeks
Sponsored by:	The FreeBSD Foundation
Differential Revision:  https://reviews.freebsd.org/D26536
This commit is contained in:
Mark Johnston 2020-10-09 15:27:37 +00:00
parent b0eefff78b
commit 6b43126f81
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=366577
9 changed files with 127 additions and 15 deletions

View File

@ -100,7 +100,7 @@ struct line_str {
};
static void addto_lineno(int *, int);
static LINE *alloc_line(void);
static LINE *alloc_line(void);
static void dowarn(int);
static void flush_line(LINE *);
static void flush_lines(int);
@ -109,7 +109,7 @@ static void free_line(LINE *);
static void usage(void);
static CSET last_set; /* char_set of last char printed */
static LINE *lines;
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 # of half lines to keep in memory */
@ -340,8 +340,16 @@ main(int argc, char **argv)
}
if (ferror(stdin))
err(1, NULL);
if (extra_lines)
if (extra_lines) {
/*
* Extra lines only exist if no lines have been flushed
* yet. This means that 'lines' must point to line zero
* after we flush the extra lines.
*/
flush_lines(extra_lines);
l = lines;
this_line = 0;
}
/* goto the last line that had a character on it */
for (; l->l_next; l = l->l_next)
@ -353,14 +361,22 @@ main(int argc, char **argv)
PUTC(SI);
/* flush out the last few blank lines */
if (max_line > this_line)
nblank_lines = max_line - this_line;
if (max_line & 1)
nblank_lines++;
if (max_line >= this_line)
nblank_lines = max_line - this_line + (max_line & 1);
if (nblank_lines == 0)
/* end with a newline even if the source doesn't */
nblank_lines = 2;
flush_blanks();
exit(0);
}
/*
* Prints the first 'nflush' lines. Printed lines are freed.
* After this function returns, 'lines' points to the first
* of the remaining lines, and 'nblank_lines' will have the
* number of half line feeds between the final flushed line
* and the first remaining line.
*/
static void
flush_lines(int nflush)
{
@ -372,11 +388,10 @@ flush_lines(int nflush)
if (l->l_line) {
flush_blanks();
flush_line(l);
free(l->l_line);
}
if (l->l_line || l->l_next)
if (l->l_next)
nblank_lines++;
if (l->l_line)
(void)free(l->l_line);
free_line(l);
}
if (lines)
@ -384,9 +399,8 @@ flush_lines(int nflush)
}
/*
* Print a number of newline/half newlines. If fine flag is set, nblank_lines
* is the number of half line feeds, otherwise it is the number of whole line
* feeds.
* Print a number of newline/half newlines.
* nblank_lines is the number of half line feeds.
*/
static void
flush_blanks(void)

View File

@ -4,8 +4,14 @@ PACKAGE= tests
ATF_TESTS_SH= col_test
${PACKAGE}FILES+= \
${PACKAGE}FILES+= \
hlf.in \
hlf2.in \
nl.in \
nl2.in \
nl3.in \
rlf.in \
rlf2.in
rlf2.in \
rlf3.in
.include <bsd.test.mk>

View File

@ -1,5 +1,44 @@
# $FreeBSD$
atf_test_case nl
nl_head()
{
atf_set "descr" "testing just newlines"
}
nl_body()
{
atf_check \
-o inline:"a\nb\n" \
-e empty \
-s exit:0 \
col < $(atf_get_srcdir)/nl.in
atf_check \
-o inline:"a\nb\n" \
-e empty \
-s exit:0 \
col -f < $(atf_get_srcdir)/nl.in
atf_check \
-o inline:"a\nb\n" \
-e empty \
-s exit:0 \
col < $(atf_get_srcdir)/nl2.in
atf_check \
-o inline:"a\nb\n" \
-e empty \
-s exit:0 \
col -f < $(atf_get_srcdir)/nl2.in
atf_check \
-o inline:"a\n\nb\n\n" \
-e empty \
-s exit:0 \
col < $(atf_get_srcdir)/nl3.in
}
atf_test_case rlf
rlf_head()
@ -25,9 +64,50 @@ rlf_body()
-e empty \
-s exit:0 \
col -x < $(atf_get_srcdir)/rlf2.in
atf_check \
-o inline:" b\na\n" \
-e empty \
-s exit:0 \
col < $(atf_get_srcdir)/rlf3.in
}
atf_test_case hlf
hlf_head()
{
atf_set "descr" "testing half line feed"
}
hlf_body()
{
atf_check \
-o inline:"a f\naf\n" \
-e empty \
-s exit:0 \
col < $(atf_get_srcdir)/hlf.in
atf_check \
-o inline:"a f9 f9 a\n" \
-e empty \
-s exit:0 \
col -f < $(atf_get_srcdir)/hlf.in
atf_check \
-o inline:"a\n f\n" \
-e empty \
-s exit:0 \
col < $(atf_get_srcdir)/hlf2.in
atf_check \
-o inline:"a9 f\n9" \
-e empty \
-s exit:0 \
col -f < $(atf_get_srcdir)/hlf2.in
}
atf_init_test_cases()
{
atf_add_test_case nl
atf_add_test_case rlf
atf_add_test_case hlf
}

2
usr.bin/col/tests/hlf.in Normal file
View File

@ -0,0 +1,2 @@
a
a8f8f

View File

@ -0,0 +1 @@
a9f

2
usr.bin/col/tests/nl.in Normal file
View File

@ -0,0 +1,2 @@
a
b

2
usr.bin/col/tests/nl2.in Normal file
View File

@ -0,0 +1,2 @@
a
b

4
usr.bin/col/tests/nl3.in Normal file
View File

@ -0,0 +1,4 @@
a
b

View File

@ -0,0 +1 @@
a b