oksh-noxz

[fork] Portable OpenBSD ksh, based on the Public Domain Korn Shell (pdksh).
git clone https://noxz.tech/git/oksh-noxz.git
Log | Files | Tags

unvis.c
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 "pconfig.h"
32
33#ifndef HAVE_STRUNVIS
34
35#include <sys/types.h>
36#include <ctype.h>
37
38#include "vis.h"
39
40/*
41 * decode driven by state machine
42 */
43#define	S_GROUND	0	/* haven't seen escape char */
44#define	S_START		1	/* start decoding special sequence */
45#define	S_META		2	/* metachar started (M) */
46#define	S_META1		3	/* metachar more, regular char (-) */
47#define	S_CTRL		4	/* control char started (^) */
48#define	S_OCTAL2	5	/* octal digit 2 */
49#define	S_OCTAL3	6	/* octal digit 3 */
50
51#define	isoctal(c)	(((u_char)(c)) >= '0' && ((u_char)(c)) <= '7')
52
53/*
54 * unvis - decode characters previously encoded by vis
55 */
56static int
57eunvis(char *cp, char c, int *astate, int flag)
58{
59
60	if (flag & UNVIS_END) {
61		if (*astate == S_OCTAL2 || *astate == S_OCTAL3) {
62			*astate = S_GROUND;
63			return (UNVIS_VALID);
64		} 
65		return (*astate == S_GROUND ? UNVIS_NOCHAR : UNVIS_SYNBAD);
66	}
67
68	switch (*astate) {
69
70	case S_GROUND:
71		*cp = 0;
72		if (c == '\\') {
73			*astate = S_START;
74			return (0);
75		} 
76		*cp = c;
77		return (UNVIS_VALID);
78
79	case S_START:
80		switch(c) {
81		case '-':
82			*cp = 0;
83			*astate = S_GROUND;
84			return (0);
85		case '\\':
86		case '"':
87			*cp = c;
88			*astate = S_GROUND;
89			return (UNVIS_VALID);
90		case '0': case '1': case '2': case '3':
91		case '4': case '5': case '6': case '7':
92			*cp = (c - '0');
93			*astate = S_OCTAL2;
94			return (0);
95		case 'M':
96			*cp = (char) 0200;
97			*astate = S_META;
98			return (0);
99		case '^':
100			*astate = S_CTRL;
101			return (0);
102		case 'n':
103			*cp = '\n';
104			*astate = S_GROUND;
105			return (UNVIS_VALID);
106		case 'r':
107			*cp = '\r';
108			*astate = S_GROUND;
109			return (UNVIS_VALID);
110		case 'b':
111			*cp = '\b';
112			*astate = S_GROUND;
113			return (UNVIS_VALID);
114		case 'a':
115			*cp = '\007';
116			*astate = S_GROUND;
117			return (UNVIS_VALID);
118		case 'v':
119			*cp = '\v';
120			*astate = S_GROUND;
121			return (UNVIS_VALID);
122		case 't':
123			*cp = '\t';
124			*astate = S_GROUND;
125			return (UNVIS_VALID);
126		case 'f':
127			*cp = '\f';
128			*astate = S_GROUND;
129			return (UNVIS_VALID);
130		case 's':
131			*cp = ' ';
132			*astate = S_GROUND;
133			return (UNVIS_VALID);
134		case 'E':
135			*cp = '\033';
136			*astate = S_GROUND;
137			return (UNVIS_VALID);
138		case '\n':
139			/*
140			 * hidden newline
141			 */
142			*astate = S_GROUND;
143			return (UNVIS_NOCHAR);
144		case '$':
145			/*
146			 * hidden marker
147			 */
148			*astate = S_GROUND;
149			return (UNVIS_NOCHAR);
150		}
151		*astate = S_GROUND;
152		return (UNVIS_SYNBAD);
153		 
154	case S_META:
155		if (c == '-')
156			*astate = S_META1;
157		else if (c == '^')
158			*astate = S_CTRL;
159		else {
160			*astate = S_GROUND;
161			return (UNVIS_SYNBAD);
162		}
163		return (0);
164		 
165	case S_META1:
166		*astate = S_GROUND;
167		*cp |= c;
168		return (UNVIS_VALID);
169		 
170	case S_CTRL:
171		if (c == '?')
172			*cp |= 0177;
173		else
174			*cp |= c & 037;
175		*astate = S_GROUND;
176		return (UNVIS_VALID);
177
178	case S_OCTAL2:	/* second possible octal digit */
179		if (isoctal(c)) {
180			/* 
181			 * yes - and maybe a third 
182			 */
183			*cp = (*cp << 3) + (c - '0');
184			*astate = S_OCTAL3;	
185			return (0);
186		} 
187		/* 
188		 * no - done with current sequence, push back passed char 
189		 */
190		*astate = S_GROUND;
191		return (UNVIS_VALIDPUSH);
192
193	case S_OCTAL3:	/* third possible octal digit */
194		*astate = S_GROUND;
195		if (isoctal(c)) {
196			*cp = (*cp << 3) + (c - '0');
197			return (UNVIS_VALID);
198		}
199		/*
200		 * we were done, push back passed char
201		 */
202		return (UNVIS_VALIDPUSH);
203
204	default:	
205		/* 
206		 * decoder in unknown state - (probably uninitialized) 
207		 */
208		*astate = S_GROUND;
209		return (UNVIS_SYNBAD);
210	}
211}
212
213/*
214 * strunvis - decode src into dst 
215 *
216 *	Number of chars decoded into dst is returned, -1 on error.
217 *	Dst is null terminated.
218 */
219
220int
221strunvis(char *dst, const char *src)
222{
223	char c;
224	char *start = dst;
225	int state = 0;
226
227	while ((c = *src++)) {
228	again:
229		switch (eunvis(dst, c, &state, 0)) {
230		case UNVIS_VALID:
231			dst++;
232			break;
233		case UNVIS_VALIDPUSH:
234			dst++;
235			goto again;
236		case 0:
237		case UNVIS_NOCHAR:
238			break;
239		default:
240			*dst = '\0';
241			return (-1);
242		}
243	}
244	if (eunvis(dst, c, &state, UNVIS_END) == UNVIS_VALID)
245		dst++;
246	*dst = '\0';
247	return (dst - start);
248}
249
250#endif /* !HAVE_STRUNVIS */