Module Name:    src
Committed By:   christos
Date:           Sun Nov  1 22:27:15 UTC 2020

Modified Files:
        src/usr.bin/col: Makefile col.1 col.c

Log Message:
Replace col with the FreeBSD version that adds wide char support


To generate a diff of this commit:
cvs rdiff -u -r1.5 -r1.6 src/usr.bin/col/Makefile
cvs rdiff -u -r1.10 -r1.11 src/usr.bin/col/col.1
cvs rdiff -u -r1.18 -r1.19 src/usr.bin/col/col.c

Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.

Modified files:

Index: src/usr.bin/col/Makefile
diff -u src/usr.bin/col/Makefile:1.5 src/usr.bin/col/Makefile:1.6
--- src/usr.bin/col/Makefile:1.5	Tue Apr 14 18:15:18 2009
+++ src/usr.bin/col/Makefile	Sun Nov  1 17:27:15 2020
@@ -1,6 +1,7 @@
-#	$NetBSD: Makefile,v 1.5 2009/04/14 22:15:18 lukem Exp $
+#	$NetBSD: Makefile,v 1.6 2020/11/01 22:27:15 christos Exp $
 #	@(#)Makefile	8.1 (Berkeley) 6/6/93
 
+WARNS=6
 PROG=	col
 
 .include <bsd.prog.mk>

Index: src/usr.bin/col/col.1
diff -u src/usr.bin/col/col.1:1.10 src/usr.bin/col/col.1:1.11
--- src/usr.bin/col/col.1:1.10	Thu Mar 22 03:58:18 2012
+++ src/usr.bin/col/col.1	Sun Nov  1 17:27:15 2020
@@ -1,5 +1,4 @@
-.\"	$NetBSD: col.1,v 1.10 2012/03/22 07:58:18 wiz Exp $
-.\"
+.\" $NetBSD: col.1,v 1.11 2020/11/01 22:27:15 christos Exp $
 .\" Copyright (c) 1990, 1993
 .\"	The Regents of the University of California.  All rights reserved.
 .\"
@@ -31,8 +30,9 @@
 .\" SUCH DAMAGE.
 .\"
 .\"     @(#)col.1	8.1 (Berkeley) 6/29/93
+.\" $FreeBSD: head/usr.bin/col/col.1 366913 2020-10-21 16:30:34Z fernape $
 .\"
-.Dd February 22, 1999
+.Dd November 1, 2020
 .Dt COL 1
 .Os
 .Sh NAME
@@ -40,23 +40,21 @@
 .Nd filter reverse line feeds from input
 .Sh SYNOPSIS
 .Nm
-.Op Fl bfpx
+.Op Fl bfhpx
 .Op Fl l Ar num
 .Sh DESCRIPTION
+The
 .Nm
-filters out reverse (and half reverse) line feeds so that the output is
+utility filters out reverse (and half reverse) line feeds so that the output is
 in the correct order with only forward and half forward line
 feeds, and replaces white-space characters with tabs where possible.
-This can be useful in processing the output of
-.Xr nroff 1
-and
-.Xr tbl 1 .
 .Pp
+The
 .Nm
-reads from the standard input and writes to the standard output.
+utility reads from the standard input and writes to the standard output.
 .Pp
 The options are as follows:
-.Bl -tag -width "-l num  "
+.Bl -tag -width indent
 .It Fl b
 Do not output any backspaces, printing only the last character
 written to each column position.
@@ -64,6 +62,13 @@ written to each column position.
 Forward half line feeds are permitted (``fine'' mode).
 Normally characters printed on a half line boundary are printed
 on the following line.
+.It Fl h
+Do not output multiple spaces instead of tabs (default).
+.It Fl l Ar num
+Buffer at least
+.Ar num
+lines in memory.
+By default, 128 lines are buffered.
 .It Fl p
 Force unknown control sequences to be passed through unchanged.
 Normally,
@@ -72,25 +77,35 @@ will filter out any control sequences fr
 recognized and interpreted by itself, which are listed below.
 .It Fl x
 Output multiple spaces instead of tabs.
-.It Fl l Ar num
-Buffer at least
-.Ar num
-lines in memory.
-By default, 128 lines are buffered.
 .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
@@ -100,7 +115,7 @@ forward line feed (10); also does carria
 .It shift in
 shift to normal character set (15)
 .It shift out
-shift to alternative character set (14)
+shift to alternate character set (14)
 .It space
 moves forward one column (32)
 .It tab
@@ -112,27 +127,46 @@ reverse line feed (11)
 All unrecognized control characters and escape sequences are
 discarded.
 .Pp
+The
 .Nm
-keeps track of the character set as characters are read and makes
+utility keeps track of the character set as characters are read and makes
 sure the character set is correct when they are output.
 .Pp
 If the input attempts to back up to the last flushed line,
 .Nm
 will display a warning message.
+.Sh ENVIRONMENT
+The
+.Ev LANG , LC_ALL
+and
+.Ev LC_CTYPE
+environment variables affect the execution of
+.Nm
+as described in
+.Xr environ 7 .
+.Sh EXIT STATUS
+.Ex -std
+.Sh EXAMPLES
+We can use
+.Nm
+to filter the output of
+.Xr man 1
+and remove the backspace characters (
+.Em ^H
+) before searching for some text:
+.Bd -literal -offset indent
+man ls | col -b | grep HISTORY
+.Ed
 .Sh SEE ALSO
-.Xr expand 1 ,
-.Xr nroff 1 ,
-.Xr tbl 1
+.Xr expand 1
 .Sh STANDARDS
 The
 .Nm
 utility conforms to
-.St -xpg4.2 .
-The
-.Fl l
-option is an extension to the standard.
+.St -susv2 .
 .Sh HISTORY
 A
 .Nm
-command appeared in
+command
+appeared in
 .At v6 .

Index: src/usr.bin/col/col.c
diff -u src/usr.bin/col/col.c:1.18 src/usr.bin/col/col.c:1.19
--- src/usr.bin/col/col.c:1.18	Sat Oct 18 10:56:14 2014
+++ src/usr.bin/col/col.c	Sun Nov  1 17:27:15 2020
@@ -1,6 +1,8 @@
-/*	$NetBSD: col.c,v 1.18 2014/10/18 14:56:14 christos Exp $	*/
+/*	$NetBSD: col.c,v 1.19 2020/11/01 22:27:15 christos Exp $	*/
 
 /*-
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
  * Copyright (c) 1990, 1993, 1994
  *	The Regents of the University of California.  All rights reserved.
  *
@@ -37,20 +39,29 @@
 __COPYRIGHT("@(#) Copyright (c) 1990, 1993, 1994\
  The Regents of the University of California.  All rights reserved.");
 #endif /* not lint */
-
+ 
 #ifndef lint
 #if 0
 static char sccsid[] = "@(#)col.c	8.5 (Berkeley) 5/4/95";
+__FBSDID("$FreeBSD: head/usr.bin/col/col.c 366577 2020-10-09 15:27:37Z markj $")
+;
+
 #endif
-__RCSID("$NetBSD: col.c,v 1.18 2014/10/18 14:56:14 christos Exp $");
+__RCSID("$NetBSD: col.c,v 1.19 2020/11/01 22:27:15 christos Exp $");
 #endif /* not lint */
 
-#include <ctype.h>
 #include <err.h>
-#include <string.h>
+#include <errno.h>
+#include <inttypes.h>
+#include <limits.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>
 
 #define	BS	'\b'		/* backspace */
 #define	TAB	'\t'		/* tab */
@@ -61,9 +72,9 @@ __RCSID("$NetBSD: col.c,v 1.18 2014/10/1
 #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
@@ -73,9 +84,10 @@ typedef char CSET;
 typedef struct char_str {
 #define	CS_NORMAL	1
 #define	CS_ALTERNATE	2
-	short		c_column;	/* column character is in */
+	int		c_column;	/* column character is in */
 	CSET		c_set;		/* character set (currently only 2) */
-	char		c_char;		/* character in question */
+	wchar_t		c_char;		/* character in question */
+	int		c_width;	/* character width */
 } CHAR;
 
 typedef struct line_str LINE;
@@ -89,33 +101,34 @@ struct line_str {
 	int	l_max_col;		/* max column in the line */
 };
 
-static LINE   *alloc_line(void);
+static void	addto_lineno(int *, int);
+static LINE	*alloc_line(void);
 static void	dowarn(int);
 static void	flush_line(LINE *);
 static void	flush_lines(int);
 static void	flush_blanks(void);
 static void	free_line(LINE *);
 __dead static void	usage(void);
-__dead static void	wrerr(void);
-static void   *xmalloc(void *, size_t);
 
 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 # 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;	/* whether to pass unknown control sequences */
+static int	pass_unknown_seqs;	/* pass unknown control sequences */
 
 #define	PUTC(ch) \
-	if (putchar(ch) == EOF) \
-		wrerr();
+	do {					\
+		if (putwchar(ch) == WEOF)	\
+			errx(EXIT_FAILURE, "write error");	\
+	} while (/*CONSTCOND*/0)
 
 int
 main(int argc, char **argv)
 {
-	int ch;
+	wint_t ch;
 	CHAR *c;
 	CSET cur_set;			/* current character set */
 	LINE *l;			/* current line */
@@ -125,11 +138,13 @@ main(int argc, char **argv)
 	int max_line;			/* max value of cur_line */
 	int this_line;			/* line l points to */
 	int nflushd_lines;		/* number of lines that were flushed */
-	int adjust, opt, warned;
+	int adjust, opt, warned, width;
+	int e;
 
-	max_bufd_lines = 128;
+	(void)setlocale(LC_CTYPE, "");
+
+	max_bufd_lines = 256;
 	compress_spaces = 1;		/* compress spaces into tabs */
-	pass_unknown_seqs = 0;		/* remove unknown escape sequences */
 	while ((opt = getopt(argc, argv, "bfhl:px")) != -1)
 		switch (opt) {
 		case 'b':		/* do not output backspaces */
@@ -142,11 +157,11 @@ main(int argc, char **argv)
 			compress_spaces = 1;
 			break;
 		case 'l':		/* buffered line count */
-			if ((max_bufd_lines = atoi(optarg)) <= 0) {
-				(void)fprintf(stderr,
-				    "col: bad -l argument %s.\n", optarg);
-				exit(EXIT_FAILURE);
-			}
+			max_bufd_lines = (int)strtoi(optarg, NULL, 0, 1,
+			    (INT_MAX - BUFFER_MARGIN) / 2, &e) * 2;
+			if (e)
+				errc(EXIT_FAILURE, e, "bad -l argument `%s'",
+				    optarg);
 			break;
 		case 'p':		/* pass unknown control sequences */
 			pass_unknown_seqs = 1;
@@ -162,16 +177,13 @@ 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;
 	lines = l = alloc_line();
 
-	while ((ch = getchar()) != EOF) {
-		if (!isgraph(ch)) {
+	while ((ch = getwchar()) != WEOF) {
+		if (!iswgraph(ch)) {
 			switch (ch) {
 			case BS:		/* can't go back further */
 				if (cur_col == 0)
@@ -182,21 +194,32 @@ main(int argc, char **argv)
 				cur_col = 0;
 				continue;
 			case ESC:		/* just ignore EOF */
-				switch(getchar()) {
+				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;
@@ -215,7 +238,12 @@ main(int argc, char **argv)
 				++cur_col;
 				continue;
 			case VT:
-				cur_line -= 2;
+				addto_lineno(&cur_line, -2);
+				continue;
+			}
+			if (iswspace(ch)) {
+				if ((width = wcwidth(ch)) > 0)
+					cur_col += width;
 				continue;
 			}
 			if (!pass_unknown_seqs)
@@ -223,58 +251,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? */
@@ -282,14 +313,16 @@ main(int argc, char **argv)
 			int need;
 
 			need = l->l_lsize ? l->l_lsize * 2 : 90;
-			l->l_line = (CHAR *)xmalloc((void *) l->l_line,
-			    (unsigned) need * sizeof(CHAR));
+			if ((l->l_line = realloc(l->l_line,
+			    (unsigned)need * sizeof(CHAR))) == NULL)
+				err(EXIT_FAILURE, NULL);
 			l->l_lsize = need;
 		}
 		c = &l->l_line[l->l_line_len++];
 		c->c_char = ch;
 		c->c_set = cur_set;
 		c->c_column = cur_col;
+		c->c_width = wcwidth(ch);
 		/*
 		 * If things are put in out of order, they will need sorting
 		 * when it is flushed.
@@ -298,32 +331,48 @@ main(int argc, char **argv)
 			l->l_needs_sort = 1;
 		else
 			l->l_max_col = cur_col;
-		cur_col++;
+		if (c->c_width > 0)
+			cur_col += c->c_width;
+	}
+	if (ferror(stdin))
+		err(EXIT_FAILURE, NULL);
+	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;
 	}
-	if (max_line == 0)
-		exit(EXIT_SUCCESS);	/* no lines, so just exit */
 
 	/* 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 & 1)
-		nblank_lines++;
-	else if (!nblank_lines)
-		/* missing a \n on the last line? */
+	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(EXIT_SUCCESS);
-	/* NOTREACHED */
 }
 
+/*
+ * 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)
 {
@@ -335,10 +384,10 @@ flush_lines(int nflush)
 		if (l->l_line) {
 			flush_blanks();
 			flush_line(l);
+			free(l->l_line);
 		}
-		nblank_lines++;
-		if (l->l_line)
-			(void)free((void *)l->l_line);
+		if (l->l_next)
+			nblank_lines++;
 		free_line(l);
 	}
 	if (lines)
@@ -346,9 +395,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)
@@ -367,8 +415,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');
 	}
@@ -383,14 +431,14 @@ static void
 flush_line(LINE *l)
 {
 	CHAR *c, *endc;
-	int nchars, last_col, this_col;
+	int i, j, nchars, last_col, save, this_col, tot;
 
 	last_col = 0;
 	nchars = l->l_line_len;
 
 	if (l->l_needs_sort) {
 		static CHAR *sorted;
-		static int count_size, *count, i, save, sorted_size, tot;
+		static int count_size, *count, sorted_size;
 
 		/*
 		 * Do an O(n) sort on l->l_line by column being careful to
@@ -398,15 +446,17 @@ flush_line(LINE *l)
 		 */
 		if (l->l_lsize > sorted_size) {
 			sorted_size = l->l_lsize;
-			sorted = (CHAR *)xmalloc((void *)sorted,
-			    (unsigned)sizeof(CHAR) * sorted_size);
+			if ((sorted = realloc(sorted,
+			    sizeof(CHAR) * (size_t)sorted_size)) == NULL)
+				err(EXIT_FAILURE, NULL);
 		}
 		if (l->l_max_col >= count_size) {
 			count_size = l->l_max_col + 1;
-			count = (int *)xmalloc((void *)count,
-			    (unsigned)sizeof(int) * count_size);
+			if ((count = realloc(count,
+			    sizeof(int) * (size_t)count_size)) == NULL)
+				err(EXIT_FAILURE, NULL);
 		}
-		(void)memset(count, 0, sizeof(int) * l->l_max_col + 1);
+		memset(count, 0, sizeof(int) * (size_t)l->l_max_col + 1);
 		for (i = nchars, c = l->l_line; --i >= 0; c++)
 			count[c->c_column]++;
 
@@ -433,45 +483,74 @@ flush_line(LINE *l)
 		} while (--nchars > 0 && this_col == endc->c_column);
 
 		/* if -b only print last character */
-		if (no_backspaces)
+		if (no_backspaces) {
 			c = endc - 1;
+			if (nchars > 0 &&
+			    this_col + c->c_width > endc->c_column)
+				continue;
+		}
 
 		if (this_col > last_col) {
 			int nspace = this_col - last_col;
 
 			if (compress_spaces && nspace > 1) {
-				int ntabs;
+				while (1) {
+					int tab_col, tab_size;
 
-				ntabs = ((last_col % 8) + nspace) / 8;
-				if (ntabs) {
-					nspace -= (ntabs * 8) - (last_col % 8);
-					while (--ntabs >= 0)
+					tab_col = (last_col + 8) & ~7;
+					if (tab_col > this_col)
+						break;
+					tab_size = tab_col - last_col;
+					if (tab_size == 1)
+						PUTC(' ');
+					else
 						PUTC('\t');
+					nspace -= tab_size;
+					last_col = tab_col;
 				}
 			}
 			while (--nspace >= 0)
 				PUTC(' ');
 			last_col = this_col;
 		}
-		last_col++;
 
 		for (;;) {
 			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;
 			}
 			PUTC(c->c_char);
+			if ((c + 1) < endc)
+				for (j = 0; j < c->c_width; j++)
+					PUTC('\b');
 			if (++c >= endc)
 				break;
-			PUTC('\b');
 		}
+		last_col += (c - 1)->c_width;
+	}
+}
+
+/*
+ * 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(EXIT_FAILURE, "too many lines");
+	} else {
+		if (*lno < INT_MIN - offset)
+			errx(EXIT_FAILURE, "too many reverse line feeds");
 	}
+	*lno += offset;
 }
 
 #define	NALLOC 64
@@ -485,7 +564,8 @@ alloc_line(void)
 	int i;
 
 	if (!line_freelist) {
-		l = (LINE *)xmalloc(NULL, sizeof(LINE) * NALLOC);
+		if ((l = realloc(NULL, sizeof(LINE) * NALLOC)) == NULL)
+			err(EXIT_FAILURE, NULL);
 		line_freelist = l;
 		for (i = 1; i < NALLOC; i++, l++)
 			l->l_next = l + 1;
@@ -494,7 +574,7 @@ alloc_line(void)
 	l = line_freelist;
 	line_freelist = l->l_next;
 
-	(void)memset(l, 0, sizeof(LINE));
+	memset(l, 0, sizeof(LINE));
 	return (l);
 }
 
@@ -506,30 +586,11 @@ free_line(LINE *l)
 	line_freelist = l;
 }
 
-static void *
-xmalloc(void *p, size_t size)
-{
-	void *q;
-
-	if (!(q = (void *)realloc(p, size)))
-		err(EXIT_FAILURE, "realloc");
-	p = q;
-	return (p);
-}
-
 static void
 usage(void)
 {
 
-	(void)fprintf(stderr, "usage: col [-bfpx] [-l nline]\n");
-	exit(EXIT_FAILURE);
-}
-
-static void
-wrerr(void)
-{
-
-	(void)fprintf(stderr, "col: write error.\n");
+	(void)fprintf(stderr, "Usage: %s [-bfhpx] [-l nline]\n", getprogname());
 	exit(EXIT_FAILURE);
 }
 

Reply via email to