xref: /csrg-svn/lib/libc/gen/unvis.c (revision 46597)
144303Smarc /*-
241932Smarc  * Copyright (c) 1989 The Regents of the University of California.
341932Smarc  * All rights reserved.
441932Smarc  *
544303Smarc  * %sccs.include.redist.c%
641932Smarc  */
741932Smarc 
841932Smarc #if defined(LIBC_SCCS) && !defined(lint)
9*46597Sdonn static char sccsid[] = "@(#)unvis.c	1.4 (Berkeley) 02/23/91";
1041932Smarc #endif /* LIBC_SCCS and not lint */
1141932Smarc 
1241932Smarc #include <sys/types.h>
1341932Smarc #include <ctype.h>
1441932Smarc #include <vis.h>
1541932Smarc 
1641932Smarc /*
1741932Smarc  * decode driven by state machine
1841932Smarc  */
1941932Smarc #define	S_GROUND	0	/* haven't seen escape char */
2041932Smarc #define	S_START		1	/* start decoding special sequence */
2141932Smarc #define	S_META		2	/* metachar started (M) */
2241932Smarc #define	S_META1		3	/* metachar more, regular char (-) */
2341932Smarc #define	S_CTRL		4	/* control char started (^) */
2441932Smarc #define	S_OCTAL2	5	/* octal digit 2 */
2541932Smarc #define	S_OCTAL3	6	/* octal digit 3 */
2641932Smarc 
2744303Smarc #define	isoctal(c)	(((u_char)(c)) >= '0' && ((u_char)(c)) <= '7')
2844303Smarc 
2941932Smarc /*
3041932Smarc  * unvis - decode characters previously encoded by vis
3141932Smarc  */
32*46597Sdonn int
33*46597Sdonn #if __STDC__
34*46597Sdonn unvis(char *cp, char c, int *astate, int flag)
35*46597Sdonn #else
3641932Smarc unvis(cp, c, astate, flag)
37*46597Sdonn 	char *cp, c;
3841932Smarc 	int *astate, flag;
39*46597Sdonn #endif
4041932Smarc {
4141932Smarc 
4241932Smarc 	if (flag & UNVIS_END) {
4341932Smarc 		if (*astate == S_OCTAL2 || *astate == S_OCTAL3) {
4441932Smarc 			*astate = S_GROUND;
4541932Smarc 			return (UNVIS_VALID);
4641932Smarc 		}
4741932Smarc 		return (*astate == S_GROUND ? UNVIS_NOCHAR : UNVIS_SYNBAD);
4841932Smarc 	}
4941932Smarc 
5041932Smarc 	switch (*astate) {
5141932Smarc 
5241932Smarc 	case S_GROUND:
5341932Smarc 		*cp = 0;
5441932Smarc 		if (c == '\\') {
5541932Smarc 			*astate = S_START;
5641932Smarc 			return (0);
5741932Smarc 		}
5841932Smarc 		*cp = c;
5941932Smarc 		return (UNVIS_VALID);
6041932Smarc 
6141932Smarc 	case S_START:
6241932Smarc 		switch(c) {
6341932Smarc 		case '\\':
6441932Smarc 			*cp = c;
6541932Smarc 			*astate = S_GROUND;
6641932Smarc 			return (UNVIS_VALID);
6741932Smarc 		case '0': case '1': case '2': case '3':
6841932Smarc 		case '4': case '5': case '6': case '7':
6941932Smarc 			*cp = (c - '0');
7041932Smarc 			*astate = S_OCTAL2;
7141932Smarc 			return (0);
7241932Smarc 		case 'M':
7341932Smarc 			*cp = 0200;
7441932Smarc 			*astate = S_META;
7541932Smarc 			return (0);
7641932Smarc 		case '^':
7741932Smarc 			*astate = S_CTRL;
7841932Smarc 			return (0);
7941932Smarc 		case 'n':
8041932Smarc 			*cp = '\n';
8141932Smarc 			*astate = S_GROUND;
8241932Smarc 			return (UNVIS_VALID);
8341932Smarc 		case 'r':
8441932Smarc 			*cp = '\r';
8541932Smarc 			*astate = S_GROUND;
8641932Smarc 			return (UNVIS_VALID);
8741932Smarc 		case 'b':
8841932Smarc 			*cp = '\b';
8941932Smarc 			*astate = S_GROUND;
9041932Smarc 			return (UNVIS_VALID);
9141932Smarc 		case 'a':
9241932Smarc 			*cp = '\007';
9341932Smarc 			*astate = S_GROUND;
9441932Smarc 			return (UNVIS_VALID);
9541932Smarc 		case 'v':
9641932Smarc 			*cp = '\v';
9741932Smarc 			*astate = S_GROUND;
9841932Smarc 			return (UNVIS_VALID);
9941932Smarc 		case 't':
10041932Smarc 			*cp = '\t';
10141932Smarc 			*astate = S_GROUND;
10241932Smarc 			return (UNVIS_VALID);
10341932Smarc 		case 'f':
10441932Smarc 			*cp = '\f';
10541932Smarc 			*astate = S_GROUND;
10641932Smarc 			return (UNVIS_VALID);
10741932Smarc 		case 's':
10841932Smarc 			*cp = ' ';
10941932Smarc 			*astate = S_GROUND;
11041932Smarc 			return (UNVIS_VALID);
11141932Smarc 		case 'E':
11241932Smarc 			*cp = '\033';
11341932Smarc 			*astate = S_GROUND;
11441932Smarc 			return (UNVIS_VALID);
11541932Smarc 		case '\n':
11641932Smarc 			/*
11741932Smarc 			 * hidden newline
11841932Smarc 			 */
11941932Smarc 			*astate = S_GROUND;
12041932Smarc 			return (UNVIS_NOCHAR);
12144303Smarc 		case '$':
12244303Smarc 			/*
12344303Smarc 			 * hidden marker
12444303Smarc 			 */
12544303Smarc 			*astate = S_GROUND;
12644303Smarc 			return (UNVIS_NOCHAR);
12741932Smarc 		}
12841932Smarc 		*astate = S_GROUND;
12941932Smarc 		return (UNVIS_SYNBAD);
13041932Smarc 
13141932Smarc 	case S_META:
13241932Smarc 		if (c == '-')
13341932Smarc 			*astate = S_META1;
13441932Smarc 		else if (c == '^')
13541932Smarc 			*astate = S_CTRL;
13641932Smarc 		else {
13741932Smarc 			*astate = S_GROUND;
13841932Smarc 			return (UNVIS_SYNBAD);
13941932Smarc 		}
14041932Smarc 		return (0);
14141932Smarc 
14241932Smarc 	case S_META1:
14341932Smarc 		*astate = S_GROUND;
14441932Smarc 		*cp |= c;
14541932Smarc 		return (UNVIS_VALID);
14641932Smarc 
14741932Smarc 	case S_CTRL:
14841932Smarc 		if (c == '?')
14941932Smarc 			*cp |= 0177;
15041932Smarc 		else
15141932Smarc 			*cp |= c & 037;
15241932Smarc 		*astate = S_GROUND;
15341932Smarc 		return (UNVIS_VALID);
15441932Smarc 
15541932Smarc 	case S_OCTAL2:	/* second possible octal digit */
15641932Smarc 		if (isoctal(c)) {
15741932Smarc 			/*
15841932Smarc 			 * yes - and maybe a third
15941932Smarc 			 */
16041932Smarc 			*cp = (*cp << 3) + (c - '0');
16141932Smarc 			*astate = S_OCTAL3;
16241932Smarc 			return (0);
16341932Smarc 		}
16441932Smarc 		/*
16541932Smarc 		 * no - done with current sequence, push back passed char
16641932Smarc 		 */
16741932Smarc 		*astate = S_GROUND;
16841932Smarc 		return (UNVIS_VALIDPUSH);
16941932Smarc 
17041932Smarc 	case S_OCTAL3:	/* third possible octal digit */
17141932Smarc 		*astate = S_GROUND;
17241932Smarc 		if (isoctal(c)) {
17341932Smarc 			*cp = (*cp << 3) + (c - '0');
17441932Smarc 			return (UNVIS_VALID);
17541932Smarc 		}
17641932Smarc 		/*
17741932Smarc 		 * we were done, push back passed char
17841932Smarc 		 */
17941932Smarc 		return (UNVIS_VALIDPUSH);
18041932Smarc 
18141932Smarc 	default:
18241932Smarc 		/*
18341932Smarc 		 * decoder in unknown state - (probably uninitialized)
18441932Smarc 		 */
18544333Smarc 		*astate = S_GROUND;
18644333Smarc 		return (UNVIS_SYNBAD);
18741932Smarc 	}
18841932Smarc }
18941932Smarc 
19041932Smarc /*
19144303Smarc  * strunvis - decode src into dst
19241932Smarc  *
19344303Smarc  *	Number of chars decoded into dst is returned, -1 on error.
19444303Smarc  *	Dst is null terminated.
19541932Smarc  */
19644303Smarc 
197*46597Sdonn int
19844303Smarc strunvis(dst, src)
199*46597Sdonn 	register char *dst;
200*46597Sdonn 	register const char *src;
20141932Smarc {
20244303Smarc 	register char c;
20341932Smarc 	char *start = dst;
20444333Smarc 	int state = 0;
20541932Smarc 
20644303Smarc 	while (c = *src++) {
20744303Smarc 	again:
20844303Smarc 		switch (unvis(dst, c, &state, 0)) {
20944303Smarc 		case UNVIS_VALID:
21044303Smarc 			dst++;
21141932Smarc 			break;
21244303Smarc 		case UNVIS_VALIDPUSH:
21344303Smarc 			dst++;
21444303Smarc 			goto again;
21544303Smarc 		case 0:
21644303Smarc 		case UNVIS_NOCHAR:
21744303Smarc 			break;
21844303Smarc 		default:
21944303Smarc 			return (-1);
22044303Smarc 		}
22141932Smarc 	}
22244333Smarc 	if (unvis(dst, c, &state, UNVIS_END) == UNVIS_VALID)
22344333Smarc 		dst++;
22444303Smarc 	*dst = '\0';
22541932Smarc 	return (dst - start);
22641932Smarc }
227