xref: /csrg-svn/lib/libc/gen/vis.c (revision 39284)
1 /*
2  * Copyright (c) 1989 The Regents of the University of California.
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms are permitted
6  * provided that the above copyright notice and this paragraph are
7  * duplicated in all such forms and that any documentation,
8  * advertising materials, and other materials related to such
9  * distribution and use acknowledge that the software was developed
10  * by the University of California, Berkeley.  The name of the
11  * University may not be used to endorse or promote products derived
12  * from this software without specific prior written permission.
13  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
14  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
15  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
16  */
17 
18 #if defined(LIBC_SCCS) && !defined(lint)
19 static char sccsid[] = "@(#)vis.c	5.1 (Berkeley) 10/13/89";
20 #endif /* LIBC_SCCS and not lint */
21 
22 #include <sys/types.h>
23 #include <ctype.h>
24 #include <cencode.h>
25 
26 #define	iswhite(c)	((c)==' '||(c)=='\t'||(c)=='\n')
27 #define	isoctal(c)	(((u_char)(c)) >= '0' && ((u_char)(c)) <= '7')
28 
29 /*
30  * cencode
31  */
32 
33 /*VARARGS2*/
34 char *
35 cencode(sc, flags, rachar)
36 	char sc, rachar;
37 {
38 	static char buff[5];
39 	register char *s = buff;
40 	register u_char c = sc;
41 
42 	if (isgraph(c) || (!(flags&CENC_WHITE) && iswhite(c))) {
43 		if (c == '\\')
44 			*s++ = '\\';
45 		*s++ = c;
46 		goto done;
47 	}
48 	*s++ = '\\';
49 	if (flags&CENC_CSTYLE) {
50 		switch(c) {
51 		case '\n':
52 			*s++ = 'n';
53 			goto done;
54 		case '\r':
55 			*s++ = 'r';
56 			goto done;
57 		case '\b':
58 			*s++ = 'b';
59 			goto done;
60 		case '\007':
61 			*s++ = 'a';
62 			goto done;
63 		case '\v':
64 			*s++ = 'v';
65 			goto done;
66 		case '\t':
67 			*s++ = 't';
68 			goto done;
69 		case '\f':
70 			*s++ = 'f';
71 			goto done;
72 		case ' ':
73 			*s++ = 's';
74 			goto done;
75 		case '\0':
76 			*s++ = '0';
77 			if (!(flags&CENC_RACHAR) || isoctal(rachar)) {
78 				*s++ = '0';
79 				*s++ = '0';
80 			}
81 			goto done;
82 		}
83 	}
84 	if ((flags&CENC_GRAPH) && (c&0177) != ' ') {
85 		if (c & 0200) {
86 			c &= 0177;
87 			*s++ = 'M';
88 		}
89 		if (iscntrl(c)) {
90 			*s++ = '^';
91 			if (c == 0177)
92 				*s++ = '?';
93 			else
94 				*s++ = c + '@';
95 		} else {
96 			*s++ = '-';
97 			*s++ = c;
98 		}
99 		goto done;
100 	}
101 	if (flags&CENC_OCTAL) {
102 		if (flags&CENC_RACHAR && !isoctal(rachar))
103 			(void)sprintf(s, "%o", (int)c);
104 		else
105 			(void)sprintf(s, "%03o", (int)c);
106 		while (*s++)
107 			;
108 		goto done;
109 	}
110 	/*
111 	 * Couldn't encode.
112 	 */
113 	s--;
114 	*s = c;
115 done:
116 	*s = '\0';
117 	return(buff);
118 }
119 
120 /*
121  * decode driven by state machine
122  */
123 #define	S_NORMAL	1	/* haven't seen escape char */
124 #define	S_START		2	/* start decoding special sequence */
125 #define	S_META		3	/* metachar started (M) */
126 #define	S_META1		4	/* metachar more, regular char (-) */
127 #define	S_CTRL		5	/* control char started (^) */
128 #define	S_OCTAL		6	/* octal number */
129 
130 /*
131  *
132  */
133 cdecode(c, cp, flags)
134 	char c;
135 	char *cp;
136 {
137 	static int state = S_NORMAL;
138 	u_char buildchar;
139 	int octal;
140 
141 	if (flags&CDEC_END) {
142 		int ostate = state;
143 		state = S_NORMAL;
144 		if (ostate == S_OCTAL) {
145 			*cp = buildchar;
146 			return(CDEC_OK);
147 		} else if (ostate == S_META1) {
148 			/* slightly forgiving, if not wrong */
149 			*cp = ' ' | 0200;
150 			return(CDEC_OK);
151 		} else
152 			return(ostate == S_NORMAL ? CDEC_NOCHAR : CDEC_SYNBAD);
153 	}
154 
155 	switch (state) {
156 	case S_NORMAL:
157 		buildchar = 0;
158 		if (c == '\\') {
159 			state = S_START;
160 			return(CDEC_NEEDMORE);
161 		} else if (flags&CDEC_HAT && c == '^') {
162 			state = S_CTRL;
163 			return(CDEC_NEEDMORE);
164 		} else {
165 			*cp = c;
166 			return(CDEC_OK);
167 		}
168 		break;
169 	case S_START:
170 		state = S_NORMAL;
171 		if (c == '\\') {
172 			*cp = c;
173 			return(CDEC_OK);
174 		}
175 		if (isoctal(c)) {
176 			buildchar = (c-'0');
177 			octal = 1;
178 			state = S_OCTAL;
179 			return(CDEC_NEEDMORE);
180 		}
181 		switch(c) {
182 		case 'M':
183 			buildchar |= 0200;
184 			state = S_META;
185 			return(CDEC_NEEDMORE);
186 		case '^':
187 			state = S_CTRL;
188 			return(CDEC_NEEDMORE);
189 		case 'n':
190 			*cp = '\n';
191 			return(CDEC_OK);
192 		case 'r':
193 			*cp = '\r';
194 			return(CDEC_OK);
195 		case 'b':
196 			*cp = '\b';
197 			return(CDEC_OK);
198 		case 'a':
199 			*cp = '\007';
200 			return(CDEC_OK);
201 		case 'v':
202 			*cp = '\v';
203 			return(CDEC_OK);
204 		case 't':
205 			*cp = '\t';
206 			return(CDEC_OK);
207 		case 'f':
208 			*cp = '\f';
209 			return(CDEC_OK);
210 		case 's':			/* does anyone use this ? */
211 			*cp = ' ';
212 			return(CDEC_OK);
213 		case 'E':
214 			*cp = '\033';
215 			return(CDEC_OK);
216 		case '\n':
217 			return(CDEC_NOCHAR);	/* hidden newline */
218 		}
219 		state = S_NORMAL;
220 		return(CDEC_SYNBAD);
221 	case S_META:
222 		if (c == '-')
223 			state = S_META1;
224 		else if (c == '^')
225 			state = S_CTRL;
226 		else {
227 			state = S_NORMAL;
228 			return(CDEC_SYNBAD);
229 		}
230 		return(CDEC_NEEDMORE);
231 	case S_META1:
232 		state = S_NORMAL;
233 		*cp = c | buildchar;
234 		return(CDEC_OK);
235 	case S_CTRL:
236 		if (c == '?')
237 			buildchar |= 0177;
238 		else
239 			buildchar |= c&037;
240 		state = S_NORMAL;
241 		*cp = buildchar;
242 		return(CDEC_OK);
243 	case S_OCTAL:
244 		if (isoctal(c)) {
245 			buildchar = (buildchar<<3) + (c-'0');
246 			if (++octal == 3) {
247 				state = S_NORMAL;
248 				*cp = buildchar;
249 				return(CDEC_OK);
250 			} else
251 				return(CDEC_NEEDMORE);
252 		} else {
253 			state = S_NORMAL;
254 			*cp = buildchar;
255 			return(CDEC_OKPUSH);
256 		}
257 	}
258 }
259