xref: /csrg-svn/lib/libc/gen/unvis.c (revision 44303)
1*44303Smarc /*-
241932Smarc  * Copyright (c) 1989 The Regents of the University of California.
341932Smarc  * All rights reserved.
441932Smarc  *
5*44303Smarc  * %sccs.include.redist.c%
641932Smarc  */
741932Smarc 
841932Smarc #if defined(LIBC_SCCS) && !defined(lint)
9*44303Smarc static char sccsid[] = "@(#)unvis.c	1.2 (Berkeley) 06/26/90";
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 
27*44303Smarc #define	isoctal(c)	(((u_char)(c)) >= '0' && ((u_char)(c)) <= '7')
28*44303Smarc 
2941932Smarc /*
3041932Smarc  * unvis - decode characters previously encoded by vis
3141932Smarc  */
3241932Smarc unvis(cp, c, astate, flag)
3341932Smarc 	u_char *cp, c;
3441932Smarc 	int *astate, flag;
3541932Smarc {
3641932Smarc 
3741932Smarc 	if (flag & UNVIS_END) {
3841932Smarc 		if (*astate == S_OCTAL2 || *astate == S_OCTAL3) {
3941932Smarc 			*astate = S_GROUND;
4041932Smarc 			return (UNVIS_VALID);
4141932Smarc 		}
4241932Smarc 		return (*astate == S_GROUND ? UNVIS_NOCHAR : UNVIS_SYNBAD);
4341932Smarc 	}
4441932Smarc 
4541932Smarc 	switch (*astate) {
4641932Smarc 
4741932Smarc 	case S_GROUND:
4841932Smarc 		*cp = 0;
4941932Smarc 		if (c == '\\') {
5041932Smarc 			*astate = S_START;
5141932Smarc 			return (0);
5241932Smarc 		}
5341932Smarc 		*cp = c;
5441932Smarc 		return (UNVIS_VALID);
5541932Smarc 
5641932Smarc 	case S_START:
5741932Smarc 		switch(c) {
5841932Smarc 		case '\\':
5941932Smarc 			*cp = c;
6041932Smarc 			*astate = S_GROUND;
6141932Smarc 			return (UNVIS_VALID);
6241932Smarc 		case '0': case '1': case '2': case '3':
6341932Smarc 		case '4': case '5': case '6': case '7':
6441932Smarc 			*cp = (c - '0');
6541932Smarc 			*astate = S_OCTAL2;
6641932Smarc 			return (0);
6741932Smarc 		case 'M':
6841932Smarc 			*cp = 0200;
6941932Smarc 			*astate = S_META;
7041932Smarc 			return (0);
7141932Smarc 		case '^':
7241932Smarc 			*astate = S_CTRL;
7341932Smarc 			return (0);
7441932Smarc 		case 'n':
7541932Smarc 			*cp = '\n';
7641932Smarc 			*astate = S_GROUND;
7741932Smarc 			return (UNVIS_VALID);
7841932Smarc 		case 'r':
7941932Smarc 			*cp = '\r';
8041932Smarc 			*astate = S_GROUND;
8141932Smarc 			return (UNVIS_VALID);
8241932Smarc 		case 'b':
8341932Smarc 			*cp = '\b';
8441932Smarc 			*astate = S_GROUND;
8541932Smarc 			return (UNVIS_VALID);
8641932Smarc 		case 'a':
8741932Smarc 			*cp = '\007';
8841932Smarc 			*astate = S_GROUND;
8941932Smarc 			return (UNVIS_VALID);
9041932Smarc 		case 'v':
9141932Smarc 			*cp = '\v';
9241932Smarc 			*astate = S_GROUND;
9341932Smarc 			return (UNVIS_VALID);
9441932Smarc 		case 't':
9541932Smarc 			*cp = '\t';
9641932Smarc 			*astate = S_GROUND;
9741932Smarc 			return (UNVIS_VALID);
9841932Smarc 		case 'f':
9941932Smarc 			*cp = '\f';
10041932Smarc 			*astate = S_GROUND;
10141932Smarc 			return (UNVIS_VALID);
10241932Smarc 		case 's':
10341932Smarc 			*cp = ' ';
10441932Smarc 			*astate = S_GROUND;
10541932Smarc 			return (UNVIS_VALID);
10641932Smarc 		case 'E':
10741932Smarc 			*cp = '\033';
10841932Smarc 			*astate = S_GROUND;
10941932Smarc 			return (UNVIS_VALID);
11041932Smarc 		case '\n':
11141932Smarc 			/*
11241932Smarc 			 * hidden newline
11341932Smarc 			 */
11441932Smarc 			*astate = S_GROUND;
11541932Smarc 			return (UNVIS_NOCHAR);
116*44303Smarc 		case '$':
117*44303Smarc 			/*
118*44303Smarc 			 * hidden marker
119*44303Smarc 			 */
120*44303Smarc 			*astate = S_GROUND;
121*44303Smarc 			return (UNVIS_NOCHAR);
12241932Smarc 		}
12341932Smarc 		*astate = S_GROUND;
12441932Smarc 		return (UNVIS_SYNBAD);
12541932Smarc 
12641932Smarc 	case S_META:
12741932Smarc 		if (c == '-')
12841932Smarc 			*astate = S_META1;
12941932Smarc 		else if (c == '^')
13041932Smarc 			*astate = S_CTRL;
13141932Smarc 		else {
13241932Smarc 			*astate = S_GROUND;
13341932Smarc 			return (UNVIS_SYNBAD);
13441932Smarc 		}
13541932Smarc 		return (0);
13641932Smarc 
13741932Smarc 	case S_META1:
13841932Smarc 		*astate = S_GROUND;
13941932Smarc 		*cp |= c;
14041932Smarc 		return (UNVIS_VALID);
14141932Smarc 
14241932Smarc 	case S_CTRL:
14341932Smarc 		if (c == '?')
14441932Smarc 			*cp |= 0177;
14541932Smarc 		else
14641932Smarc 			*cp |= c & 037;
14741932Smarc 		*astate = S_GROUND;
14841932Smarc 		return (UNVIS_VALID);
14941932Smarc 
15041932Smarc 	case S_OCTAL2:	/* second possible octal digit */
15141932Smarc 		if (isoctal(c)) {
15241932Smarc 			/*
15341932Smarc 			 * yes - and maybe a third
15441932Smarc 			 */
15541932Smarc 			*cp = (*cp << 3) + (c - '0');
15641932Smarc 			*astate = S_OCTAL3;
15741932Smarc 			return (0);
15841932Smarc 		}
15941932Smarc 		/*
16041932Smarc 		 * no - done with current sequence, push back passed char
16141932Smarc 		 */
16241932Smarc 		*astate = S_GROUND;
16341932Smarc 		return (UNVIS_VALIDPUSH);
16441932Smarc 
16541932Smarc 	case S_OCTAL3:	/* third possible octal digit */
16641932Smarc 		*astate = S_GROUND;
16741932Smarc 		if (isoctal(c)) {
16841932Smarc 			*cp = (*cp << 3) + (c - '0');
16941932Smarc 			return (UNVIS_VALID);
17041932Smarc 		}
17141932Smarc 		/*
17241932Smarc 		 * we were done, push back passed char
17341932Smarc 		 */
17441932Smarc 		return (UNVIS_VALIDPUSH);
17541932Smarc 
17641932Smarc 	default:
17741932Smarc 		/*
17841932Smarc 		 * decoder in unknown state - (probably uninitialized)
17941932Smarc 		 */
18041932Smarc 		return (UNVIS_ERROR);
18141932Smarc 	}
18241932Smarc }
18341932Smarc 
18441932Smarc /*
185*44303Smarc  * strunvis - decode src into dst
18641932Smarc  *
187*44303Smarc  *	Number of chars decoded into dst is returned, -1 on error.
188*44303Smarc  *	Dst is null terminated.
18941932Smarc  */
190*44303Smarc 
191*44303Smarc strunvis(dst, src)
19241932Smarc 	register char *dst, *src;
19341932Smarc {
194*44303Smarc 	register char c;
19541932Smarc 	char *start = dst;
196*44303Smarc 	int state;
19741932Smarc 
198*44303Smarc 	while (c = *src++) {
199*44303Smarc 	again:
200*44303Smarc 		switch (unvis(dst, c, &state, 0)) {
201*44303Smarc 		case UNVIS_VALID:
202*44303Smarc 			dst++;
20341932Smarc 			break;
204*44303Smarc 		case UNVIS_VALIDPUSH:
205*44303Smarc 			dst++;
206*44303Smarc 			goto again;
207*44303Smarc 		case 0:
208*44303Smarc 		case UNVIS_NOCHAR:
209*44303Smarc 			break;
210*44303Smarc 		default:
211*44303Smarc 			return (-1);
212*44303Smarc 		}
21341932Smarc 	}
214*44303Smarc 	*dst = '\0';
21541932Smarc 	return (dst - start);
21641932Smarc }
217