xref: /csrg-svn/lib/libc/gen/vis.c (revision 41757)
139284Smarc /*
239284Smarc  * Copyright (c) 1989 The Regents of the University of California.
339284Smarc  * All rights reserved.
439284Smarc  *
539284Smarc  * Redistribution and use in source and binary forms are permitted
639284Smarc  * provided that the above copyright notice and this paragraph are
739284Smarc  * duplicated in all such forms and that any documentation,
839284Smarc  * advertising materials, and other materials related to such
939284Smarc  * distribution and use acknowledge that the software was developed
1039284Smarc  * by the University of California, Berkeley.  The name of the
1139284Smarc  * University may not be used to endorse or promote products derived
1239284Smarc  * from this software without specific prior written permission.
1339284Smarc  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
1439284Smarc  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
1539284Smarc  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
1639284Smarc  */
1739284Smarc 
1839284Smarc #if defined(LIBC_SCCS) && !defined(lint)
19*41757Smarc static char sccsid[] = "@(#)vis.c	5.2 (Berkeley) 05/11/90";
2039284Smarc #endif /* LIBC_SCCS and not lint */
2139284Smarc 
2239284Smarc #include <sys/types.h>
2339284Smarc #include <ctype.h>
2439284Smarc #include <cencode.h>
2539284Smarc 
2639284Smarc #define	isoctal(c)	(((u_char)(c)) >= '0' && ((u_char)(c)) <= '7')
2739284Smarc 
2839284Smarc /*
29*41757Smarc  * vis - visually encode characters
3039284Smarc  */
3139284Smarc char *
32*41757Smarc vis(dst, c, flag, nextc)
33*41757Smarc 	register char *dst, c;
34*41757Smarc 	char nextc;
35*41757Smarc 	register int flag;
3639284Smarc {
37*41757Smarc 	if (isascii(c) && isgraph(c) ||
38*41757Smarc 	   ((flag & VIS_WHITE) == 0 &&
39*41757Smarc 		(c == ' ' || c == '\n' || (flag & VIS_TAB) == 0 && c == '\t')) ||
40*41757Smarc 	   ((flag & VIS_SAFE) && (c == '\b' || c == '\007' || c == '\r'))) {
41*41757Smarc 		*dst++ = c;
42*41757Smarc 		if (c == '\\' && (flag & VIS_NOSLASH) == 0)
43*41757Smarc 			*dst++ = '\\';
44*41757Smarc 		*dst = '\0';
45*41757Smarc 		return (dst);
46*41757Smarc 	}
4739284Smarc 
48*41757Smarc 	if ((flag & VIS_NOSLASH) == 0)
49*41757Smarc 		*dst++ = '\\';
50*41757Smarc 	if (flag & VIS_CSTYLE) {
5139284Smarc 		switch(c) {
5239284Smarc 		case '\n':
53*41757Smarc 			*dst++ = 'n';
5439284Smarc 			goto done;
5539284Smarc 		case '\r':
56*41757Smarc 			*dst++ = 'r';
5739284Smarc 			goto done;
5839284Smarc 		case '\b':
59*41757Smarc 			*dst++ = 'b';
6039284Smarc 			goto done;
61*41757Smarc 		case '\007':	/* waiting for ansi compiler */
62*41757Smarc 			*dst++ = 'a';
6339284Smarc 			goto done;
6439284Smarc 		case '\v':
65*41757Smarc 			*dst++ = 'v';
6639284Smarc 			goto done;
6739284Smarc 		case '\t':
68*41757Smarc 			*dst++ = 't';
6939284Smarc 			goto done;
7039284Smarc 		case '\f':
71*41757Smarc 			*dst++ = 'f';
7239284Smarc 			goto done;
7339284Smarc 		case ' ':
74*41757Smarc 			*dst++ = 's';
7539284Smarc 			goto done;
7639284Smarc 		case '\0':
77*41757Smarc 			*dst++ = '0';
78*41757Smarc 			if ((flag & VIS_NEXTC) == 0 || isoctal(nextc)) {
79*41757Smarc 				*dst++ = '0';
80*41757Smarc 				*dst++ = '0';
8139284Smarc 			}
8239284Smarc 			goto done;
8339284Smarc 		}
8439284Smarc 	}
85*41757Smarc 	if (((c & 0177) == ' ') || (flag & VIS_OCTAL)) {
86*41757Smarc 		*dst++ = ((u_char)c >> 6 & 07) + '0';
87*41757Smarc 		*dst++ = ((u_char)c >> 3 & 07) + '0';
88*41757Smarc 		*dst++ = ((u_char)c & 07) + '0';
8939284Smarc 		goto done;
9039284Smarc 	}
91*41757Smarc 	if (c & 0200) {
92*41757Smarc 		c &= 0177;
93*41757Smarc 		*dst++ = 'M';
94*41757Smarc 	}
95*41757Smarc 	if (iscntrl(c)) {
96*41757Smarc 		*dst++ = '^';
97*41757Smarc 		if (c == 0177)
98*41757Smarc 			*dst++ = '?';
9939284Smarc 		else
100*41757Smarc 			*dst++ = c + '@';
101*41757Smarc 	} else {
102*41757Smarc 		*dst++ = '-';
103*41757Smarc 		*dst++ = c;
10439284Smarc 	}
10539284Smarc done:
106*41757Smarc 	*dst = '\0';
107*41757Smarc 	return (dst);
10839284Smarc }
10939284Smarc 
110*41757Smarc 
11139284Smarc /*
11239284Smarc  * decode driven by state machine
11339284Smarc  */
11439284Smarc #define	S_NORMAL	1	/* haven't seen escape char */
11539284Smarc #define	S_START		2	/* start decoding special sequence */
11639284Smarc #define	S_META		3	/* metachar started (M) */
11739284Smarc #define	S_META1		4	/* metachar more, regular char (-) */
11839284Smarc #define	S_CTRL		5	/* control char started (^) */
11939284Smarc #define	S_OCTAL		6	/* octal number */
12039284Smarc 
12139284Smarc /*
12239284Smarc  *
12339284Smarc  */
124*41757Smarc cunvis(c, cp, flags)
12539284Smarc 	char c;
12639284Smarc 	char *cp;
12739284Smarc {
12839284Smarc 	static int state = S_NORMAL;
129*41757Smarc 	static u_char buildchar;
130*41757Smarc 	static int octal;
13139284Smarc 
132*41757Smarc 	if (flags&UNVIS_END) {
13339284Smarc 		int ostate = state;
13439284Smarc 		state = S_NORMAL;
13539284Smarc 		if (ostate == S_OCTAL) {
13639284Smarc 			*cp = buildchar;
137*41757Smarc 			return(UNVIS_OK);
13839284Smarc 		} else if (ostate == S_META1) {
13939284Smarc 			/* slightly forgiving, if not wrong */
14039284Smarc 			*cp = ' ' | 0200;
141*41757Smarc 			return(UNVIS_OK);
14239284Smarc 		} else
143*41757Smarc 			return(ostate == S_NORMAL ? UNVIS_NOCHAR : CDEC_SYNBAD);
14439284Smarc 	}
14539284Smarc 
14639284Smarc 	switch (state) {
14739284Smarc 	case S_NORMAL:
14839284Smarc 		buildchar = 0;
14939284Smarc 		if (c == '\\') {
15039284Smarc 			state = S_START;
151*41757Smarc 			return(UNVIS_NEEDMORE);
152*41757Smarc 		} else if (flags&UNVIS_HAT && c == '^') {
15339284Smarc 			state = S_CTRL;
154*41757Smarc 			return(UNVIS_NEEDMORE);
15539284Smarc 		} else {
15639284Smarc 			*cp = c;
157*41757Smarc 			return(UNVIS_OK);
15839284Smarc 		}
15939284Smarc 		break;
16039284Smarc 	case S_START:
16139284Smarc 		state = S_NORMAL;
16239284Smarc 		if (c == '\\') {
16339284Smarc 			*cp = c;
164*41757Smarc 			return(UNVIS_OK);
16539284Smarc 		}
16639284Smarc 		if (isoctal(c)) {
16739284Smarc 			buildchar = (c-'0');
16839284Smarc 			octal = 1;
16939284Smarc 			state = S_OCTAL;
170*41757Smarc 			return(UNVIS_NEEDMORE);
17139284Smarc 		}
17239284Smarc 		switch(c) {
17339284Smarc 		case 'M':
17439284Smarc 			buildchar |= 0200;
17539284Smarc 			state = S_META;
176*41757Smarc 			return(UNVIS_NEEDMORE);
17739284Smarc 		case '^':
17839284Smarc 			state = S_CTRL;
179*41757Smarc 			return(UNVIS_NEEDMORE);
18039284Smarc 		case 'n':
18139284Smarc 			*cp = '\n';
182*41757Smarc 			return(UNVIS_OK);
18339284Smarc 		case 'r':
18439284Smarc 			*cp = '\r';
185*41757Smarc 			return(UNVIS_OK);
18639284Smarc 		case 'b':
18739284Smarc 			*cp = '\b';
188*41757Smarc 			return(UNVIS_OK);
18939284Smarc 		case 'a':
19039284Smarc 			*cp = '\007';
191*41757Smarc 			return(UNVIS_OK);
19239284Smarc 		case 'v':
19339284Smarc 			*cp = '\v';
194*41757Smarc 			return(UNVIS_OK);
19539284Smarc 		case 't':
19639284Smarc 			*cp = '\t';
197*41757Smarc 			return(UNVIS_OK);
19839284Smarc 		case 'f':
19939284Smarc 			*cp = '\f';
200*41757Smarc 			return(UNVIS_OK);
20139284Smarc 		case 's':			/* does anyone use this ? */
20239284Smarc 			*cp = ' ';
203*41757Smarc 			return(UNVIS_OK);
20439284Smarc 		case 'E':
20539284Smarc 			*cp = '\033';
206*41757Smarc 			return(UNVIS_OK);
20739284Smarc 		case '\n':
208*41757Smarc 			return(UNVIS_NOCHAR);	/* hidden newline */
20939284Smarc 		}
21039284Smarc 		state = S_NORMAL;
211*41757Smarc 		return(UNVIS_SYNBAD);
21239284Smarc 	case S_META:
21339284Smarc 		if (c == '-')
21439284Smarc 			state = S_META1;
21539284Smarc 		else if (c == '^')
21639284Smarc 			state = S_CTRL;
21739284Smarc 		else {
21839284Smarc 			state = S_NORMAL;
219*41757Smarc 			return(UNVIS_SYNBAD);
22039284Smarc 		}
221*41757Smarc 		return(UNVIS_NEEDMORE);
22239284Smarc 	case S_META1:
22339284Smarc 		state = S_NORMAL;
22439284Smarc 		*cp = c | buildchar;
225*41757Smarc 		return(UNVIS_OK);
22639284Smarc 	case S_CTRL:
22739284Smarc 		if (c == '?')
22839284Smarc 			buildchar |= 0177;
22939284Smarc 		else
23039284Smarc 			buildchar |= c&037;
23139284Smarc 		state = S_NORMAL;
23239284Smarc 		*cp = buildchar;
233*41757Smarc 		return(UNVIS_OK);
23439284Smarc 	case S_OCTAL:
23539284Smarc 		if (isoctal(c)) {
23639284Smarc 			buildchar = (buildchar<<3) + (c-'0');
23739284Smarc 			if (++octal == 3) {
23839284Smarc 				state = S_NORMAL;
23939284Smarc 				*cp = buildchar;
240*41757Smarc 				return(UNVIS_OK);
24139284Smarc 			} else
242*41757Smarc 				return(UNVIS_NEEDMORE);
24339284Smarc 		} else {
24439284Smarc 			state = S_NORMAL;
24539284Smarc 			*cp = buildchar;
246*41757Smarc 			return(UNVIS_OKPUSH);
24739284Smarc 		}
24839284Smarc 	}
24939284Smarc }
250*41757Smarc 
251*41757Smarc /*
252*41757Smarc  * strvis - visually encode characters from src into dst
253*41757Smarc  *
254*41757Smarc  *	If len >= 0, encodes exactly len chars from src (including NULL's).
255*41757Smarc  *	Otherwise, stops before first NULL in src.  In all cases, dst is
256*41757Smarc  *	NULL terminated.
257*41757Smarc  *
258*41757Smarc  *	Dst must be 4 times the size of src to account for possible
259*41757Smarc  *	expansion.  The length of dst, not including the trailing NULL,
260*41757Smarc  *	is returned.
261*41757Smarc  */
262*41757Smarc strvis(dst, src, len, flag)
263*41757Smarc 	register char *dst, *src;
264*41757Smarc 	register int len;
265*41757Smarc {
266*41757Smarc 	char *start = dst;
267*41757Smarc 
268*41757Smarc 	for (;;) {
269*41757Smarc 		if (len > 0) {
270*41757Smarc 			if (len-- == 0)
271*41757Smarc 				break;
272*41757Smarc 		} else if (!*src)
273*41757Smarc 			break;
274*41757Smarc 		dst = vis(dst, *src, flag | VIS_NEXTC, *(src+1));
275*41757Smarc 		src++;
276*41757Smarc 	}
277*41757Smarc 
278*41757Smarc 	return (dst - start);
279*41757Smarc }
280