172445Sassar/*	$NetBSD: unvis.c,v 1.19 2000/01/22 22:19:13 mycroft Exp $	*/
272445Sassar
372445Sassar/*-
472445Sassar * Copyright (c) 1989, 1993
572445Sassar *	The Regents of the University of California.  All rights reserved.
672445Sassar *
772445Sassar * Redistribution and use in source and binary forms, with or without
872445Sassar * modification, are permitted provided that the following conditions
972445Sassar * are met:
1072445Sassar * 1. Redistributions of source code must retain the above copyright
1172445Sassar *    notice, this list of conditions and the following disclaimer.
1272445Sassar * 2. Redistributions in binary form must reproduce the above copyright
1372445Sassar *    notice, this list of conditions and the following disclaimer in the
1472445Sassar *    documentation and/or other materials provided with the distribution.
15178825Sdfr * 3. Neither the name of the University nor the names of its contributors
1672445Sassar *    may be used to endorse or promote products derived from this software
1772445Sassar *    without specific prior written permission.
1872445Sassar *
1972445Sassar * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
2072445Sassar * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2172445Sassar * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2272445Sassar * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
2372445Sassar * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2472445Sassar * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2572445Sassar * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2672445Sassar * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2772445Sassar * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2872445Sassar * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2972445Sassar * SUCH DAMAGE.
3072445Sassar */
3172445Sassar
3272445Sassar#if 1
3372445Sassar#include <config.h>
34178825Sdfr#include "roken.h"
3572445Sassar#ifndef _DIAGASSERT
3672445Sassar#define _DIAGASSERT(X)
3772445Sassar#endif
3872445Sassar#else
3972445Sassar#include <sys/cdefs.h>
4072445Sassar#if defined(LIBC_SCCS) && !defined(lint)
4172445Sassar#if 0
4272445Sassarstatic char sccsid[] = "@(#)unvis.c	8.1 (Berkeley) 6/4/93";
4372445Sassar#else
4472445Sassar__RCSID("$NetBSD: unvis.c,v 1.19 2000/01/22 22:19:13 mycroft Exp $");
4572445Sassar#endif
4672445Sassar#endif /* LIBC_SCCS and not lint */
4772445Sassar
4872445Sassar#define __LIBC12_SOURCE__
4972445Sassar
5072445Sassar#include "namespace.h"
5172445Sassar#endif
5272445Sassar#include <sys/types.h>
5372445Sassar
5472445Sassar#include <assert.h>
5572445Sassar#include <ctype.h>
5672445Sassar#include <stdio.h>
5772445Sassar#include <vis.h>
5872445Sassar
5972445Sassar#if 0
6072445Sassar#ifdef __weak_alias
6172445Sassar__weak_alias(strunvis,_strunvis)
6272445Sassar__weak_alias(unvis,_unvis)
6372445Sassar#endif
6472445Sassar
6572445Sassar__warn_references(unvis,
6672445Sassar    "warning: reference to compatibility unvis(); include <vis.h> for correct reference")
6772445Sassar#endif
6872445Sassar
6972445Sassar/*
7072445Sassar * decode driven by state machine
7172445Sassar */
7272445Sassar#define	S_GROUND	0	/* haven't seen escape char */
7372445Sassar#define	S_START		1	/* start decoding special sequence */
7472445Sassar#define	S_META		2	/* metachar started (M) */
7572445Sassar#define	S_META1		3	/* metachar more, regular char (-) */
7672445Sassar#define	S_CTRL		4	/* control char started (^) */
7772445Sassar#define	S_OCTAL2	5	/* octal digit 2 */
7872445Sassar#define	S_OCTAL3	6	/* octal digit 3 */
7972445Sassar
8072445Sassar#define	isoctal(c)	(((u_char)(c)) >= '0' && ((u_char)(c)) <= '7')
8172445Sassar
82233294SstasROKEN_LIB_FUNCTION int ROKEN_LIB_CALL
83178825Sdfr	rk_strunvis (char *, const char *);
84233294SstasROKEN_LIB_FUNCTION int ROKEN_LIB_CALL
85178825Sdfr	rk_unvis (char *, int, int *, int);
86178825Sdfr
8772445Sassar/*
8872445Sassar * unvis - decode characters previously encoded by vis
8972445Sassar */
90178825Sdfr
91233294SstasROKEN_LIB_FUNCTION int ROKEN_LIB_CALL
92178825Sdfrrk_unvis(char *cp, int c, int *astate, int flag)
9372445Sassar{
9472445Sassar
9572445Sassar	_DIAGASSERT(cp != NULL);
9672445Sassar	_DIAGASSERT(astate != NULL);
9772445Sassar
9872445Sassar	if (flag & UNVIS_END) {
9972445Sassar		if (*astate == S_OCTAL2 || *astate == S_OCTAL3) {
10072445Sassar			*astate = S_GROUND;
10172445Sassar			return (UNVIS_VALID);
102233294Sstas		}
10372445Sassar		return (*astate == S_GROUND ? UNVIS_NOCHAR : UNVIS_SYNBAD);
10472445Sassar	}
10572445Sassar
10672445Sassar	switch (*astate) {
10772445Sassar
10872445Sassar	case S_GROUND:
10972445Sassar		*cp = 0;
11072445Sassar		if (c == '\\') {
11172445Sassar			*astate = S_START;
11272445Sassar			return (0);
113233294Sstas		}
11472445Sassar		*cp = c;
11572445Sassar		return (UNVIS_VALID);
11672445Sassar
11772445Sassar	case S_START:
11872445Sassar		switch(c) {
11972445Sassar		case '\\':
12072445Sassar			*cp = c;
12172445Sassar			*astate = S_GROUND;
12272445Sassar			return (UNVIS_VALID);
12372445Sassar		case '0': case '1': case '2': case '3':
12472445Sassar		case '4': case '5': case '6': case '7':
12572445Sassar			*cp = (c - '0');
12672445Sassar			*astate = S_OCTAL2;
12772445Sassar			return (0);
12872445Sassar		case 'M':
129233294Sstas			*cp = (u_char)0200;
13072445Sassar			*astate = S_META;
13172445Sassar			return (0);
13272445Sassar		case '^':
13372445Sassar			*astate = S_CTRL;
13472445Sassar			return (0);
13572445Sassar		case 'n':
13672445Sassar			*cp = '\n';
13772445Sassar			*astate = S_GROUND;
13872445Sassar			return (UNVIS_VALID);
13972445Sassar		case 'r':
14072445Sassar			*cp = '\r';
14172445Sassar			*astate = S_GROUND;
14272445Sassar			return (UNVIS_VALID);
14372445Sassar		case 'b':
14472445Sassar			*cp = '\b';
14572445Sassar			*astate = S_GROUND;
14672445Sassar			return (UNVIS_VALID);
14772445Sassar		case 'a':
14872445Sassar			*cp = '\007';
14972445Sassar			*astate = S_GROUND;
15072445Sassar			return (UNVIS_VALID);
15172445Sassar		case 'v':
15272445Sassar			*cp = '\v';
15372445Sassar			*astate = S_GROUND;
15472445Sassar			return (UNVIS_VALID);
15572445Sassar		case 't':
15672445Sassar			*cp = '\t';
15772445Sassar			*astate = S_GROUND;
15872445Sassar			return (UNVIS_VALID);
15972445Sassar		case 'f':
16072445Sassar			*cp = '\f';
16172445Sassar			*astate = S_GROUND;
16272445Sassar			return (UNVIS_VALID);
16372445Sassar		case 's':
16472445Sassar			*cp = ' ';
16572445Sassar			*astate = S_GROUND;
16672445Sassar			return (UNVIS_VALID);
16772445Sassar		case 'E':
16872445Sassar			*cp = '\033';
16972445Sassar			*astate = S_GROUND;
17072445Sassar			return (UNVIS_VALID);
17172445Sassar		case '\n':
17272445Sassar			/*
17372445Sassar			 * hidden newline
17472445Sassar			 */
17572445Sassar			*astate = S_GROUND;
17672445Sassar			return (UNVIS_NOCHAR);
17772445Sassar		case '$':
17872445Sassar			/*
17972445Sassar			 * hidden marker
18072445Sassar			 */
18172445Sassar			*astate = S_GROUND;
18272445Sassar			return (UNVIS_NOCHAR);
18372445Sassar		}
18472445Sassar		*astate = S_GROUND;
18572445Sassar		return (UNVIS_SYNBAD);
186233294Sstas
18772445Sassar	case S_META:
18872445Sassar		if (c == '-')
18972445Sassar			*astate = S_META1;
19072445Sassar		else if (c == '^')
19172445Sassar			*astate = S_CTRL;
19272445Sassar		else {
19372445Sassar			*astate = S_GROUND;
19472445Sassar			return (UNVIS_SYNBAD);
19572445Sassar		}
19672445Sassar		return (0);
197233294Sstas
19872445Sassar	case S_META1:
19972445Sassar		*astate = S_GROUND;
20072445Sassar		*cp |= c;
20172445Sassar		return (UNVIS_VALID);
202233294Sstas
20372445Sassar	case S_CTRL:
20472445Sassar		if (c == '?')
20572445Sassar			*cp |= 0177;
20672445Sassar		else
20772445Sassar			*cp |= c & 037;
20872445Sassar		*astate = S_GROUND;
20972445Sassar		return (UNVIS_VALID);
21072445Sassar
21172445Sassar	case S_OCTAL2:	/* second possible octal digit */
21272445Sassar		if (isoctal(c)) {
213233294Sstas			/*
214233294Sstas			 * yes - and maybe a third
21572445Sassar			 */
21672445Sassar			*cp = (*cp << 3) + (c - '0');
217233294Sstas			*astate = S_OCTAL3;
21872445Sassar			return (0);
219233294Sstas		}
220233294Sstas		/*
221233294Sstas		 * no - done with current sequence, push back passed char
22272445Sassar		 */
22372445Sassar		*astate = S_GROUND;
22472445Sassar		return (UNVIS_VALIDPUSH);
22572445Sassar
22672445Sassar	case S_OCTAL3:	/* third possible octal digit */
22772445Sassar		*astate = S_GROUND;
22872445Sassar		if (isoctal(c)) {
22972445Sassar			*cp = (*cp << 3) + (c - '0');
23072445Sassar			return (UNVIS_VALID);
23172445Sassar		}
23272445Sassar		/*
23372445Sassar		 * we were done, push back passed char
23472445Sassar		 */
23572445Sassar		return (UNVIS_VALIDPUSH);
236233294Sstas
237233294Sstas	default:
238233294Sstas		/*
239233294Sstas		 * decoder in unknown state - (probably uninitialized)
24072445Sassar		 */
24172445Sassar		*astate = S_GROUND;
24272445Sassar		return (UNVIS_SYNBAD);
24372445Sassar	}
24472445Sassar}
24572445Sassar
24672445Sassar/*
247233294Sstas * strunvis - decode src into dst
24872445Sassar *
24972445Sassar *	Number of chars decoded into dst is returned, -1 on error.
25072445Sassar *	Dst is null terminated.
25172445Sassar */
25272445Sassar
253233294SstasROKEN_LIB_FUNCTION int ROKEN_LIB_CALL
254178825Sdfrrk_strunvis(char *dst, const char *src)
25572445Sassar{
25672445Sassar	char c;
25772445Sassar	char *start = dst;
25872445Sassar	int state = 0;
25972445Sassar
26072445Sassar	_DIAGASSERT(src != NULL);
26172445Sassar	_DIAGASSERT(dst != NULL);
26272445Sassar
26372445Sassar	while ((c = *src++) != '\0') {
26472445Sassar	again:
265178825Sdfr		switch (rk_unvis(dst, (unsigned char)c, &state, 0)) {
26672445Sassar		case UNVIS_VALID:
26772445Sassar			dst++;
26872445Sassar			break;
26972445Sassar		case UNVIS_VALIDPUSH:
27072445Sassar			dst++;
27172445Sassar			goto again;
27272445Sassar		case 0:
27372445Sassar		case UNVIS_NOCHAR:
27472445Sassar			break;
27572445Sassar		default:
27672445Sassar			return (-1);
27772445Sassar		}
27872445Sassar	}
279178825Sdfr	if (unvis(dst, (unsigned char)c, &state, UNVIS_END) == UNVIS_VALID)
28072445Sassar		dst++;
28172445Sassar	*dst = '\0';
28272445Sassar	return (dst - start);
28372445Sassar}
284