GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: lib/libc/gen/unvis.c Lines: 0 126 0.0 %
Date: 2017-11-07 Branches: 0 85 0.0 %

Line Branch Exec Source
1
/*	$OpenBSD: unvis.c,v 1.17 2015/09/13 11:32:51 guenther Exp $ */
2
/*-
3
 * Copyright (c) 1989, 1993
4
 *	The Regents of the University of California.  All rights reserved.
5
 *
6
 * Redistribution and use in source and binary forms, with or without
7
 * modification, are permitted provided that the following conditions
8
 * are met:
9
 * 1. Redistributions of source code must retain the above copyright
10
 *    notice, this list of conditions and the following disclaimer.
11
 * 2. Redistributions in binary form must reproduce the above copyright
12
 *    notice, this list of conditions and the following disclaimer in the
13
 *    documentation and/or other materials provided with the distribution.
14
 * 3. Neither the name of the University nor the names of its contributors
15
 *    may be used to endorse or promote products derived from this software
16
 *    without specific prior written permission.
17
 *
18
 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
19
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
22
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
24
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
26
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
27
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28
 * SUCH DAMAGE.
29
 */
30
31
#include <sys/types.h>
32
#include <ctype.h>
33
#include <vis.h>
34
35
/*
36
 * decode driven by state machine
37
 */
38
#define	S_GROUND	0	/* haven't seen escape char */
39
#define	S_START		1	/* start decoding special sequence */
40
#define	S_META		2	/* metachar started (M) */
41
#define	S_META1		3	/* metachar more, regular char (-) */
42
#define	S_CTRL		4	/* control char started (^) */
43
#define	S_OCTAL2	5	/* octal digit 2 */
44
#define	S_OCTAL3	6	/* octal digit 3 */
45
46
#define	isoctal(c)	(((u_char)(c)) >= '0' && ((u_char)(c)) <= '7')
47
48
/*
49
 * unvis - decode characters previously encoded by vis
50
 */
51
int
52
unvis(char *cp, char c, int *astate, int flag)
53
{
54
55
	if (flag & UNVIS_END) {
56
		if (*astate == S_OCTAL2 || *astate == S_OCTAL3) {
57
			*astate = S_GROUND;
58
			return (UNVIS_VALID);
59
		}
60
		return (*astate == S_GROUND ? UNVIS_NOCHAR : UNVIS_SYNBAD);
61
	}
62
63
	switch (*astate) {
64
65
	case S_GROUND:
66
		*cp = 0;
67
		if (c == '\\') {
68
			*astate = S_START;
69
			return (0);
70
		}
71
		*cp = c;
72
		return (UNVIS_VALID);
73
74
	case S_START:
75
		switch(c) {
76
		case '-':
77
			*cp = 0;
78
			*astate = S_GROUND;
79
			return (0);
80
		case '\\':
81
		case '"':
82
			*cp = c;
83
			*astate = S_GROUND;
84
			return (UNVIS_VALID);
85
		case '0': case '1': case '2': case '3':
86
		case '4': case '5': case '6': case '7':
87
			*cp = (c - '0');
88
			*astate = S_OCTAL2;
89
			return (0);
90
		case 'M':
91
			*cp = (char) 0200;
92
			*astate = S_META;
93
			return (0);
94
		case '^':
95
			*astate = S_CTRL;
96
			return (0);
97
		case 'n':
98
			*cp = '\n';
99
			*astate = S_GROUND;
100
			return (UNVIS_VALID);
101
		case 'r':
102
			*cp = '\r';
103
			*astate = S_GROUND;
104
			return (UNVIS_VALID);
105
		case 'b':
106
			*cp = '\b';
107
			*astate = S_GROUND;
108
			return (UNVIS_VALID);
109
		case 'a':
110
			*cp = '\007';
111
			*astate = S_GROUND;
112
			return (UNVIS_VALID);
113
		case 'v':
114
			*cp = '\v';
115
			*astate = S_GROUND;
116
			return (UNVIS_VALID);
117
		case 't':
118
			*cp = '\t';
119
			*astate = S_GROUND;
120
			return (UNVIS_VALID);
121
		case 'f':
122
			*cp = '\f';
123
			*astate = S_GROUND;
124
			return (UNVIS_VALID);
125
		case 's':
126
			*cp = ' ';
127
			*astate = S_GROUND;
128
			return (UNVIS_VALID);
129
		case 'E':
130
			*cp = '\033';
131
			*astate = S_GROUND;
132
			return (UNVIS_VALID);
133
		case '\n':
134
			/*
135
			 * hidden newline
136
			 */
137
			*astate = S_GROUND;
138
			return (UNVIS_NOCHAR);
139
		case '$':
140
			/*
141
			 * hidden marker
142
			 */
143
			*astate = S_GROUND;
144
			return (UNVIS_NOCHAR);
145
		}
146
		*astate = S_GROUND;
147
		return (UNVIS_SYNBAD);
148
149
	case S_META:
150
		if (c == '-')
151
			*astate = S_META1;
152
		else if (c == '^')
153
			*astate = S_CTRL;
154
		else {
155
			*astate = S_GROUND;
156
			return (UNVIS_SYNBAD);
157
		}
158
		return (0);
159
160
	case S_META1:
161
		*astate = S_GROUND;
162
		*cp |= c;
163
		return (UNVIS_VALID);
164
165
	case S_CTRL:
166
		if (c == '?')
167
			*cp |= 0177;
168
		else
169
			*cp |= c & 037;
170
		*astate = S_GROUND;
171
		return (UNVIS_VALID);
172
173
	case S_OCTAL2:	/* second possible octal digit */
174
		if (isoctal(c)) {
175
			/*
176
			 * yes - and maybe a third
177
			 */
178
			*cp = (*cp << 3) + (c - '0');
179
			*astate = S_OCTAL3;
180
			return (0);
181
		}
182
		/*
183
		 * no - done with current sequence, push back passed char
184
		 */
185
		*astate = S_GROUND;
186
		return (UNVIS_VALIDPUSH);
187
188
	case S_OCTAL3:	/* third possible octal digit */
189
		*astate = S_GROUND;
190
		if (isoctal(c)) {
191
			*cp = (*cp << 3) + (c - '0');
192
			return (UNVIS_VALID);
193
		}
194
		/*
195
		 * we were done, push back passed char
196
		 */
197
		return (UNVIS_VALIDPUSH);
198
199
	default:
200
		/*
201
		 * decoder in unknown state - (probably uninitialized)
202
		 */
203
		*astate = S_GROUND;
204
		return (UNVIS_SYNBAD);
205
	}
206
}
207
DEF_WEAK(unvis);
208
209
/*
210
 * strunvis - decode src into dst
211
 *
212
 *	Number of chars decoded into dst is returned, -1 on error.
213
 *	Dst is null terminated.
214
 */
215
216
int
217
strunvis(char *dst, const char *src)
218
{
219
	char c;
220
	char *start = dst;
221
	int state = 0;
222
223
	while ((c = *src++)) {
224
	again:
225
		switch (unvis(dst, c, &state, 0)) {
226
		case UNVIS_VALID:
227
			dst++;
228
			break;
229
		case UNVIS_VALIDPUSH:
230
			dst++;
231
			goto again;
232
		case 0:
233
		case UNVIS_NOCHAR:
234
			break;
235
		default:
236
			*dst = '\0';
237
			return (-1);
238
		}
239
	}
240
	if (unvis(dst, c, &state, UNVIS_END) == UNVIS_VALID)
241
		dst++;
242
	*dst = '\0';
243
	return (dst - start);
244
}
245
246
ssize_t
247
strnunvis(char *dst, const char *src, size_t sz)
248
{
249
	char c, p;
250
	char *start = dst, *end = dst + sz - 1;
251
	int state = 0;
252
253
	if (sz > 0)
254
		*end = '\0';
255
	while ((c = *src++)) {
256
	again:
257
		switch (unvis(&p, c, &state, 0)) {
258
		case UNVIS_VALID:
259
			if (dst < end)
260
				*dst = p;
261
			dst++;
262
			break;
263
		case UNVIS_VALIDPUSH:
264
			if (dst < end)
265
				*dst = p;
266
			dst++;
267
			goto again;
268
		case 0:
269
		case UNVIS_NOCHAR:
270
			break;
271
		default:
272
			if (dst <= end)
273
				*dst = '\0';
274
			return (-1);
275
		}
276
	}
277
	if (unvis(&p, c, &state, UNVIS_END) == UNVIS_VALID) {
278
		if (dst < end)
279
			*dst = p;
280
		dst++;
281
	}
282
	if (dst <= end)
283
		*dst = '\0';
284
	return (dst - start);
285
}
286