xref: /csrg-svn/lib/libc/gen/unvis.c (revision 61111)
144303Smarc /*-
2*61111Sbostic  * Copyright (c) 1989, 1993
3*61111Sbostic  *	The Regents of the University of California.  All rights reserved.
441932Smarc  *
544303Smarc  * %sccs.include.redist.c%
641932Smarc  */
741932Smarc 
841932Smarc #if defined(LIBC_SCCS) && !defined(lint)
9*61111Sbostic static char sccsid[] = "@(#)unvis.c	8.1 (Berkeley) 06/04/93";
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  */
3246597Sdonn int
unvis(cp,c,astate,flag)3341932Smarc unvis(cp, c, astate, flag)
3452364Sbostic 	char *cp;
3552364Sbostic 	int c, *astate, flag;
3641932Smarc {
3741932Smarc 
3841932Smarc 	if (flag & UNVIS_END) {
3941932Smarc 		if (*astate == S_OCTAL2 || *astate == S_OCTAL3) {
4041932Smarc 			*astate = S_GROUND;
4141932Smarc 			return (UNVIS_VALID);
4241932Smarc 		}
4341932Smarc 		return (*astate == S_GROUND ? UNVIS_NOCHAR : UNVIS_SYNBAD);
4441932Smarc 	}
4541932Smarc 
4641932Smarc 	switch (*astate) {
4741932Smarc 
4841932Smarc 	case S_GROUND:
4941932Smarc 		*cp = 0;
5041932Smarc 		if (c == '\\') {
5141932Smarc 			*astate = S_START;
5241932Smarc 			return (0);
5341932Smarc 		}
5441932Smarc 		*cp = c;
5541932Smarc 		return (UNVIS_VALID);
5641932Smarc 
5741932Smarc 	case S_START:
5841932Smarc 		switch(c) {
5941932Smarc 		case '\\':
6041932Smarc 			*cp = c;
6141932Smarc 			*astate = S_GROUND;
6241932Smarc 			return (UNVIS_VALID);
6341932Smarc 		case '0': case '1': case '2': case '3':
6441932Smarc 		case '4': case '5': case '6': case '7':
6541932Smarc 			*cp = (c - '0');
6641932Smarc 			*astate = S_OCTAL2;
6741932Smarc 			return (0);
6841932Smarc 		case 'M':
6941932Smarc 			*cp = 0200;
7041932Smarc 			*astate = S_META;
7141932Smarc 			return (0);
7241932Smarc 		case '^':
7341932Smarc 			*astate = S_CTRL;
7441932Smarc 			return (0);
7541932Smarc 		case 'n':
7641932Smarc 			*cp = '\n';
7741932Smarc 			*astate = S_GROUND;
7841932Smarc 			return (UNVIS_VALID);
7941932Smarc 		case 'r':
8041932Smarc 			*cp = '\r';
8141932Smarc 			*astate = S_GROUND;
8241932Smarc 			return (UNVIS_VALID);
8341932Smarc 		case 'b':
8441932Smarc 			*cp = '\b';
8541932Smarc 			*astate = S_GROUND;
8641932Smarc 			return (UNVIS_VALID);
8741932Smarc 		case 'a':
8841932Smarc 			*cp = '\007';
8941932Smarc 			*astate = S_GROUND;
9041932Smarc 			return (UNVIS_VALID);
9141932Smarc 		case 'v':
9241932Smarc 			*cp = '\v';
9341932Smarc 			*astate = S_GROUND;
9441932Smarc 			return (UNVIS_VALID);
9541932Smarc 		case 't':
9641932Smarc 			*cp = '\t';
9741932Smarc 			*astate = S_GROUND;
9841932Smarc 			return (UNVIS_VALID);
9941932Smarc 		case 'f':
10041932Smarc 			*cp = '\f';
10141932Smarc 			*astate = S_GROUND;
10241932Smarc 			return (UNVIS_VALID);
10341932Smarc 		case 's':
10441932Smarc 			*cp = ' ';
10541932Smarc 			*astate = S_GROUND;
10641932Smarc 			return (UNVIS_VALID);
10741932Smarc 		case 'E':
10841932Smarc 			*cp = '\033';
10941932Smarc 			*astate = S_GROUND;
11041932Smarc 			return (UNVIS_VALID);
11141932Smarc 		case '\n':
11241932Smarc 			/*
11341932Smarc 			 * hidden newline
11441932Smarc 			 */
11541932Smarc 			*astate = S_GROUND;
11641932Smarc 			return (UNVIS_NOCHAR);
11744303Smarc 		case '$':
11844303Smarc 			/*
11944303Smarc 			 * hidden marker
12044303Smarc 			 */
12144303Smarc 			*astate = S_GROUND;
12244303Smarc 			return (UNVIS_NOCHAR);
12341932Smarc 		}
12441932Smarc 		*astate = S_GROUND;
12541932Smarc 		return (UNVIS_SYNBAD);
12641932Smarc 
12741932Smarc 	case S_META:
12841932Smarc 		if (c == '-')
12941932Smarc 			*astate = S_META1;
13041932Smarc 		else if (c == '^')
13141932Smarc 			*astate = S_CTRL;
13241932Smarc 		else {
13341932Smarc 			*astate = S_GROUND;
13441932Smarc 			return (UNVIS_SYNBAD);
13541932Smarc 		}
13641932Smarc 		return (0);
13741932Smarc 
13841932Smarc 	case S_META1:
13941932Smarc 		*astate = S_GROUND;
14041932Smarc 		*cp |= c;
14141932Smarc 		return (UNVIS_VALID);
14241932Smarc 
14341932Smarc 	case S_CTRL:
14441932Smarc 		if (c == '?')
14541932Smarc 			*cp |= 0177;
14641932Smarc 		else
14741932Smarc 			*cp |= c & 037;
14841932Smarc 		*astate = S_GROUND;
14941932Smarc 		return (UNVIS_VALID);
15041932Smarc 
15141932Smarc 	case S_OCTAL2:	/* second possible octal digit */
15241932Smarc 		if (isoctal(c)) {
15341932Smarc 			/*
15441932Smarc 			 * yes - and maybe a third
15541932Smarc 			 */
15641932Smarc 			*cp = (*cp << 3) + (c - '0');
15741932Smarc 			*astate = S_OCTAL3;
15841932Smarc 			return (0);
15941932Smarc 		}
16041932Smarc 		/*
16141932Smarc 		 * no - done with current sequence, push back passed char
16241932Smarc 		 */
16341932Smarc 		*astate = S_GROUND;
16441932Smarc 		return (UNVIS_VALIDPUSH);
16541932Smarc 
16641932Smarc 	case S_OCTAL3:	/* third possible octal digit */
16741932Smarc 		*astate = S_GROUND;
16841932Smarc 		if (isoctal(c)) {
16941932Smarc 			*cp = (*cp << 3) + (c - '0');
17041932Smarc 			return (UNVIS_VALID);
17141932Smarc 		}
17241932Smarc 		/*
17341932Smarc 		 * we were done, push back passed char
17441932Smarc 		 */
17541932Smarc 		return (UNVIS_VALIDPUSH);
17641932Smarc 
17741932Smarc 	default:
17841932Smarc 		/*
17941932Smarc 		 * decoder in unknown state - (probably uninitialized)
18041932Smarc 		 */
18144333Smarc 		*astate = S_GROUND;
18244333Smarc 		return (UNVIS_SYNBAD);
18341932Smarc 	}
18441932Smarc }
18541932Smarc 
18641932Smarc /*
18744303Smarc  * strunvis - decode src into dst
18841932Smarc  *
18944303Smarc  *	Number of chars decoded into dst is returned, -1 on error.
19044303Smarc  *	Dst is null terminated.
19141932Smarc  */
19244303Smarc 
19346597Sdonn int
strunvis(dst,src)19444303Smarc strunvis(dst, src)
19546597Sdonn 	register char *dst;
19646597Sdonn 	register const char *src;
19741932Smarc {
19844303Smarc 	register char c;
19941932Smarc 	char *start = dst;
20044333Smarc 	int state = 0;
20141932Smarc 
20244303Smarc 	while (c = *src++) {
20344303Smarc 	again:
20444303Smarc 		switch (unvis(dst, c, &state, 0)) {
20544303Smarc 		case UNVIS_VALID:
20644303Smarc 			dst++;
20741932Smarc 			break;
20844303Smarc 		case UNVIS_VALIDPUSH:
20944303Smarc 			dst++;
21044303Smarc 			goto again;
21144303Smarc 		case 0:
21244303Smarc 		case UNVIS_NOCHAR:
21344303Smarc 			break;
21444303Smarc 		default:
21544303Smarc 			return (-1);
21644303Smarc 		}
21741932Smarc 	}
21844333Smarc 	if (unvis(dst, c, &state, UNVIS_END) == UNVIS_VALID)
21944333Smarc 		dst++;
22044303Smarc 	*dst = '\0';
22141932Smarc 	return (dst - start);
22241932Smarc }
223