GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: usr.bin/colrm/colrm.c Lines: 54 64 84.4 %
Date: 2017-11-13 Branches: 77 102 75.5 %

Line Branch Exec Source
1
/*	$OpenBSD: colrm.c,v 1.13 2016/10/27 12:53:54 schwarze Exp $	*/
2
/*	$NetBSD: colrm.c,v 1.4 1995/09/02 05:51:37 jtc Exp $	*/
3
4
/*-
5
 * Copyright (c) 1991, 1993
6
 *	The Regents of the University of California.  All rights reserved.
7
 *
8
 * Redistribution and use in source and binary forms, with or without
9
 * modification, are permitted provided that the following conditions
10
 * are met:
11
 * 1. Redistributions of source code must retain the above copyright
12
 *    notice, this list of conditions and the following disclaimer.
13
 * 2. Redistributions in binary form must reproduce the above copyright
14
 *    notice, this list of conditions and the following disclaimer in the
15
 *    documentation and/or other materials provided with the distribution.
16
 * 3. Neither the name of the University nor the names of its contributors
17
 *    may be used to endorse or promote products derived from this software
18
 *    without specific prior written permission.
19
 *
20
 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
21
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
24
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30
 * SUCH DAMAGE.
31
 */
32
33
#include <sys/types.h>
34
35
#include <err.h>
36
#include <errno.h>
37
#include <limits.h>
38
#include <locale.h>
39
#include <stdio.h>
40
#include <stdlib.h>
41
#include <string.h>
42
#include <unistd.h>
43
#include <wchar.h>
44
45
#define	TAB	8
46
47
void usage(void);
48
49
int
50
main(int argc, char *argv[])
51
{
52
800
	char	 *line, *p;
53
400
	ssize_t	  linesz;
54
400
	wchar_t	  wc;
55
	u_long	  column, newcol, start, stop;
56
	int	  ch, len, width;
57
58
400
	setlocale(LC_CTYPE, "");
59
60
400
	if (pledge("stdio flock rpath cpath wpath", NULL) == -1)
61
		err(1, "pledge");
62
63
800
	while ((ch = getopt(argc, argv, "")) != -1)
64
		switch(ch) {
65
		case '?':
66
		default:
67
			usage();
68
		}
69
1060
	argc -= optind;
70
1060
	argv += optind;
71
72
	start = stop = 0;
73

1060
	switch(argc) {
74
	case 2:
75
300
		stop = strtol(argv[1], &p, 10);
76

600
		if (stop <= 0 || *p)
77
			errx(1, "illegal column -- %s", argv[1]);
78
		/* FALLTHROUGH */
79
	case 1:
80
360
		start = strtol(argv[0], &p, 10);
81

720
		if (start <= 0 || *p)
82
			errx(1, "illegal column -- %s", argv[0]);
83
		break;
84
	case 0:
85
		break;
86
	default:
87
		usage();
88
	}
89
90

700
	if (stop && start > stop)
91
		err(1, "illegal start and stop columns");
92
93
400
	line = NULL;
94
1580
	while (getline(&line, &linesz, stdin) != -1) {
95
		column = 0;
96
		width = 0;
97
5120
		for (p = line; *p != '\0'; p += len) {
98
			len = 1;
99

2170
			switch (*p) {
100
			case '\n':
101
20
				putchar('\n');
102
				continue;
103
			case '\b':
104
				/*
105
				 * Pass it through if the previous character
106
				 * was in scope, still represented by the
107
				 * current value of "column".
108
				 * Allow an optional second backspace
109
				 * after a double-width character.
110
				 */
111

555
				if (start == 0 || column < start ||
112
155
				    (stop > 0 &&
113
155
				     column > stop + (width > 1))) {
114
280
					putchar('\b');
115

160
					if (width > 1 && p[1] == '\b')
116
20
						putchar('\b');
117
				}
118

255
				if (width > 1 && p[1] == '\b')
119
25
					p++;
120
205
				column -= width;
121
205
				continue;
122
			case '\t':
123
70
				newcol = (column + TAB) & ~(TAB - 1);
124

130
				if (start == 0 || newcol < start) {
125
60
					putchar('\t');
126
					column = newcol;
127
30
				} else
128
					/*
129
					 * Expand tabs that intersect or
130
					 * follow deleted columns.
131
					 */
132
540
					while (column < newcol)
133

350
						if (++column < start ||
134
130
						    (stop > 0 &&
135
120
						     column > stop))
136
260
				 			putchar(' ');
137
				continue;
138
			default:
139
				break;
140
			}
141
142
			/*
143
			 * Handle the three cases of invalid bytes,
144
			 * non-printable, and printable characters.
145
			 */
146
147
1885
			if ((len = mbtowc(&wc, p, MB_CUR_MAX)) == -1) {
148
15
				(void)mbtowc(NULL, NULL, MB_CUR_MAX);
149
				len = 1;
150
				width = 1;
151
1885
			} else if ((width = wcwidth(wc)) == -1)
152
				width = 1;
153
154
			/*
155
			 * If the character completely fits before or
156
			 * after the cut, keep it; otherwise, skip it.
157
			 */
158
159

4840
			if ((start == 0 || column + width < start ||
160
2370
			    (stop > 0 && column + (width > 0) > stop)))
161
1410
			    	fwrite(p, 1, len, stdout);
162
163
			/*
164
			 * If the cut cuts the character in half
165
			 * and no backspace follows,
166
			 * print a blank for correct columnation.
167
			 */
168
169

530
			else if (width > 1 && p[len] != '\b' &&
170

30
			    (start == 0 || column + 1 < start ||
171
20
			    (stop > 0 && column + width > stop)))
172
20
				putchar(' ');
173
174
1885
			column += width;
175
1885
		}
176
	}
177

800
	if (ferror(stdin))
178
		err(1, "stdin");
179

800
	if (ferror(stdout))
180
		err(1, "stdout");
181
400
	return 0;
182
400
}
183
184
void
185
usage(void)
186
{
187
	(void)fprintf(stderr, "usage: colrm [start [stop]]\n");
188
	exit(1);
189
}