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