xref: /original-bsd/lib/libc/gen/unvis.c (revision 3415274a)
1 
2 /*
3  * Copyright (c) 1989 The Regents of the University of California.
4  * All rights reserved.
5  *
6  * Redistribution and use in source and binary forms are permitted
7  * provided that the above copyright notice and this paragraph are
8  * duplicated in all such forms and that any documentation,
9  * advertising materials, and other materials related to such
10  * distribution and use acknowledge that the software was developed
11  * by the University of California, Berkeley.  The name of the
12  * University may not be used to endorse or promote products derived
13  * from this software without specific prior written permission.
14  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
15  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
16  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
17  */
18 
19 #if defined(LIBC_SCCS) && !defined(lint)
20 static char sccsid[] = "@(#)unvis.c	1.1 (Berkeley) 05/15/90";
21 #endif /* LIBC_SCCS and not lint */
22 
23 #include <sys/types.h>
24 #include <ctype.h>
25 #include <vis.h>
26 
27 /*
28  * decode driven by state machine
29  */
30 #define	S_GROUND	0	/* haven't seen escape char */
31 #define	S_START		1	/* start decoding special sequence */
32 #define	S_META		2	/* metachar started (M) */
33 #define	S_META1		3	/* metachar more, regular char (-) */
34 #define	S_CTRL		4	/* control char started (^) */
35 #define	S_OCTAL2	5	/* octal digit 2 */
36 #define	S_OCTAL3	6	/* octal digit 3 */
37 
38 /*
39  * unvis - decode characters previously encoded by vis
40  */
41 unvis(cp, c, astate, flag)
42 	u_char *cp, c;
43 	int *astate, flag;
44 {
45 
46 	if (flag & UNVIS_END) {
47 		if (*astate == S_OCTAL2 || *astate == S_OCTAL3) {
48 			*astate = S_GROUND;
49 			return (UNVIS_VALID);
50 		}
51 		return (*astate == S_GROUND ? UNVIS_NOCHAR : UNVIS_SYNBAD);
52 	}
53 
54 	switch (*astate) {
55 
56 	case S_GROUND:
57 		*cp = 0;
58 		if (c == '\\') {
59 			*astate = S_START;
60 			return (0);
61 		}
62 		*cp = c;
63 		return (UNVIS_VALID);
64 
65 	case S_START:
66 		switch(c) {
67 		case '\\':
68 			*cp = c;
69 			*astate = S_GROUND;
70 			return (UNVIS_VALID);
71 		case '0': case '1': case '2': case '3':
72 		case '4': case '5': case '6': case '7':
73 			*cp = (c - '0');
74 			*astate = S_OCTAL2;
75 			return (0);
76 		case 'M':
77 			*cp = 0200;
78 			*astate = S_META;
79 			return (0);
80 		case '^':
81 			*astate = S_CTRL;
82 			return (0);
83 		case 'n':
84 			*cp = '\n';
85 			*astate = S_GROUND;
86 			return (UNVIS_VALID);
87 		case 'r':
88 			*cp = '\r';
89 			*astate = S_GROUND;
90 			return (UNVIS_VALID);
91 		case 'b':
92 			*cp = '\b';
93 			*astate = S_GROUND;
94 			return (UNVIS_VALID);
95 		case 'a':
96 			*cp = '\007';
97 			*astate = S_GROUND;
98 			return (UNVIS_VALID);
99 		case 'v':
100 			*cp = '\v';
101 			*astate = S_GROUND;
102 			return (UNVIS_VALID);
103 		case 't':
104 			*cp = '\t';
105 			*astate = S_GROUND;
106 			return (UNVIS_VALID);
107 		case 'f':
108 			*cp = '\f';
109 			*astate = S_GROUND;
110 			return (UNVIS_VALID);
111 		case 's':
112 			*cp = ' ';
113 			*astate = S_GROUND;
114 			return (UNVIS_VALID);
115 		case 'E':
116 			*cp = '\033';
117 			*astate = S_GROUND;
118 			return (UNVIS_VALID);
119 		case '\n':
120 			/*
121 			 * hidden newline
122 			 */
123 			*astate = S_GROUND;
124 			return (UNVIS_NOCHAR);
125 		}
126 		*astate = S_GROUND;
127 		return (UNVIS_SYNBAD);
128 
129 	case S_META:
130 		if (c == '-')
131 			*astate = S_META1;
132 		else if (c == '^')
133 			*astate = S_CTRL;
134 		else {
135 			*astate = S_GROUND;
136 			return (UNVIS_SYNBAD);
137 		}
138 		return (0);
139 
140 	case S_META1:
141 		*astate = S_GROUND;
142 		*cp |= c;
143 		return (UNVIS_VALID);
144 
145 	case S_CTRL:
146 		if (c == '?')
147 			*cp |= 0177;
148 		else
149 			*cp |= c & 037;
150 		*astate = S_GROUND;
151 		return (UNVIS_VALID);
152 
153 	case S_OCTAL2:	/* second possible octal digit */
154 		if (isoctal(c)) {
155 			/*
156 			 * yes - and maybe a third
157 			 */
158 			*cp = (*cp << 3) + (c - '0');
159 			*astate = S_OCTAL3;
160 			return (0);
161 		}
162 		/*
163 		 * no - done with current sequence, push back passed char
164 		 */
165 		*astate = S_GROUND;
166 		return (UNVIS_VALIDPUSH);
167 
168 	case S_OCTAL3:	/* third possible octal digit */
169 		*astate = S_GROUND;
170 		if (isoctal(c)) {
171 			*cp = (*cp << 3) + (c - '0');
172 			return (UNVIS_VALID);
173 		}
174 		/*
175 		 * we were done, push back passed char
176 		 */
177 		return (UNVIS_VALIDPUSH);
178 
179 	default:
180 		/*
181 		 * decoder in unknown state - (probably uninitialized)
182 		 */
183 		return (UNVIS_ERROR);
184 	}
185 }
186 
187 /*
188  * strvis - visually encode characters from src into dst
189  *
190  *	If len >= 0, encodes exactly len chars from src (including NULL's).
191  *	Otherwise, stops before first NULL in src.  In all cases, dst is
192  *	NULL terminated.
193  *
194  *	Dst must be 4 times the size of src to account for possible
195  *	expansion.  The length of dst, not including the trailing NULL,
196  *	is returned.
197  */
198 strvis(dst, src, len, flag)
199 	register char *dst, *src;
200 	register int len;
201 {
202 	char *start = dst;
203 
204 	for (;;) {
205 		if (len > 0) {
206 			if (len-- == 0)
207 				break;
208 		} else if (!*src)
209 			break;
210 		dst = vis(dst, *src, flag, *(src+1));
211 		src++;
212 	}
213 
214 	return (dst - start);
215 }
216