unvis.c revision 178825
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#ifdef HAVE_CONFIG_H
3472445Sassar#include <config.h>
35178825SdfrRCSID("$Id: unvis.c 21005 2007-06-08 01:54:35Z lha $");
3672445Sassar#endif
37178825Sdfr#include "roken.h"
3872445Sassar#ifndef _DIAGASSERT
3972445Sassar#define _DIAGASSERT(X)
4072445Sassar#endif
4172445Sassar#else
4272445Sassar#include <sys/cdefs.h>
4372445Sassar#if defined(LIBC_SCCS) && !defined(lint)
4472445Sassar#if 0
4572445Sassarstatic char sccsid[] = "@(#)unvis.c	8.1 (Berkeley) 6/4/93";
4672445Sassar#else
4772445Sassar__RCSID("$NetBSD: unvis.c,v 1.19 2000/01/22 22:19:13 mycroft Exp $");
4872445Sassar#endif
4972445Sassar#endif /* LIBC_SCCS and not lint */
5072445Sassar
5172445Sassar#define __LIBC12_SOURCE__
5272445Sassar
5372445Sassar#include "namespace.h"
5472445Sassar#endif
5572445Sassar#include <sys/types.h>
5672445Sassar
5772445Sassar#include <assert.h>
5872445Sassar#include <ctype.h>
5972445Sassar#include <stdio.h>
6072445Sassar#include <vis.h>
6172445Sassar
6272445Sassar#if 0
6372445Sassar#ifdef __weak_alias
6472445Sassar__weak_alias(strunvis,_strunvis)
6572445Sassar__weak_alias(unvis,_unvis)
6672445Sassar#endif
6772445Sassar
6872445Sassar__warn_references(unvis,
6972445Sassar    "warning: reference to compatibility unvis(); include <vis.h> for correct reference")
7072445Sassar#endif
7172445Sassar
7272445Sassar/*
7372445Sassar * decode driven by state machine
7472445Sassar */
7572445Sassar#define	S_GROUND	0	/* haven't seen escape char */
7672445Sassar#define	S_START		1	/* start decoding special sequence */
7772445Sassar#define	S_META		2	/* metachar started (M) */
7872445Sassar#define	S_META1		3	/* metachar more, regular char (-) */
7972445Sassar#define	S_CTRL		4	/* control char started (^) */
8072445Sassar#define	S_OCTAL2	5	/* octal digit 2 */
8172445Sassar#define	S_OCTAL3	6	/* octal digit 3 */
8272445Sassar
8372445Sassar#define	isoctal(c)	(((u_char)(c)) >= '0' && ((u_char)(c)) <= '7')
8472445Sassar
85178825Sdfrint ROKEN_LIB_FUNCTION
86178825Sdfr	rk_strunvis (char *, const char *);
87178825Sdfrint ROKEN_LIB_FUNCTION
88178825Sdfr	rk_unvis (char *, int, int *, int);
89178825Sdfr
9072445Sassar/*
9172445Sassar * unvis - decode characters previously encoded by vis
9272445Sassar */
93178825Sdfr
94178825Sdfrint ROKEN_LIB_FUNCTION
95178825Sdfrrk_unvis(char *cp, int c, int *astate, int flag)
9672445Sassar{
9772445Sassar
9872445Sassar	_DIAGASSERT(cp != NULL);
9972445Sassar	_DIAGASSERT(astate != NULL);
10072445Sassar
10172445Sassar	if (flag & UNVIS_END) {
10272445Sassar		if (*astate == S_OCTAL2 || *astate == S_OCTAL3) {
10372445Sassar			*astate = S_GROUND;
10472445Sassar			return (UNVIS_VALID);
10572445Sassar		}
10672445Sassar		return (*astate == S_GROUND ? UNVIS_NOCHAR : UNVIS_SYNBAD);
10772445Sassar	}
10872445Sassar
10972445Sassar	switch (*astate) {
11072445Sassar
11172445Sassar	case S_GROUND:
11272445Sassar		*cp = 0;
11372445Sassar		if (c == '\\') {
11472445Sassar			*astate = S_START;
11572445Sassar			return (0);
11672445Sassar		}
11772445Sassar		*cp = c;
11872445Sassar		return (UNVIS_VALID);
11972445Sassar
12072445Sassar	case S_START:
12172445Sassar		switch(c) {
12272445Sassar		case '\\':
12372445Sassar			*cp = c;
12472445Sassar			*astate = S_GROUND;
12572445Sassar			return (UNVIS_VALID);
12672445Sassar		case '0': case '1': case '2': case '3':
12772445Sassar		case '4': case '5': case '6': case '7':
12872445Sassar			*cp = (c - '0');
12972445Sassar			*astate = S_OCTAL2;
13072445Sassar			return (0);
13172445Sassar		case 'M':
13272445Sassar			*cp = (char)0200;
13372445Sassar			*astate = S_META;
13472445Sassar			return (0);
13572445Sassar		case '^':
13672445Sassar			*astate = S_CTRL;
13772445Sassar			return (0);
13872445Sassar		case 'n':
13972445Sassar			*cp = '\n';
14072445Sassar			*astate = S_GROUND;
14172445Sassar			return (UNVIS_VALID);
14272445Sassar		case 'r':
14372445Sassar			*cp = '\r';
14472445Sassar			*astate = S_GROUND;
14572445Sassar			return (UNVIS_VALID);
14672445Sassar		case 'b':
14772445Sassar			*cp = '\b';
14872445Sassar			*astate = S_GROUND;
14972445Sassar			return (UNVIS_VALID);
15072445Sassar		case 'a':
15172445Sassar			*cp = '\007';
15272445Sassar			*astate = S_GROUND;
15372445Sassar			return (UNVIS_VALID);
15472445Sassar		case 'v':
15572445Sassar			*cp = '\v';
15672445Sassar			*astate = S_GROUND;
15772445Sassar			return (UNVIS_VALID);
15872445Sassar		case 't':
15972445Sassar			*cp = '\t';
16072445Sassar			*astate = S_GROUND;
16172445Sassar			return (UNVIS_VALID);
16272445Sassar		case 'f':
16372445Sassar			*cp = '\f';
16472445Sassar			*astate = S_GROUND;
16572445Sassar			return (UNVIS_VALID);
16672445Sassar		case 's':
16772445Sassar			*cp = ' ';
16872445Sassar			*astate = S_GROUND;
16972445Sassar			return (UNVIS_VALID);
17072445Sassar		case 'E':
17172445Sassar			*cp = '\033';
17272445Sassar			*astate = S_GROUND;
17372445Sassar			return (UNVIS_VALID);
17472445Sassar		case '\n':
17572445Sassar			/*
17672445Sassar			 * hidden newline
17772445Sassar			 */
17872445Sassar			*astate = S_GROUND;
17972445Sassar			return (UNVIS_NOCHAR);
18072445Sassar		case '$':
18172445Sassar			/*
18272445Sassar			 * hidden marker
18372445Sassar			 */
18472445Sassar			*astate = S_GROUND;
18572445Sassar			return (UNVIS_NOCHAR);
18672445Sassar		}
18772445Sassar		*astate = S_GROUND;
18872445Sassar		return (UNVIS_SYNBAD);
18972445Sassar
19072445Sassar	case S_META:
19172445Sassar		if (c == '-')
19272445Sassar			*astate = S_META1;
19372445Sassar		else if (c == '^')
19472445Sassar			*astate = S_CTRL;
19572445Sassar		else {
19672445Sassar			*astate = S_GROUND;
19772445Sassar			return (UNVIS_SYNBAD);
19872445Sassar		}
19972445Sassar		return (0);
20072445Sassar
20172445Sassar	case S_META1:
20272445Sassar		*astate = S_GROUND;
20372445Sassar		*cp |= c;
20472445Sassar		return (UNVIS_VALID);
20572445Sassar
20672445Sassar	case S_CTRL:
20772445Sassar		if (c == '?')
20872445Sassar			*cp |= 0177;
20972445Sassar		else
21072445Sassar			*cp |= c & 037;
21172445Sassar		*astate = S_GROUND;
21272445Sassar		return (UNVIS_VALID);
21372445Sassar
21472445Sassar	case S_OCTAL2:	/* second possible octal digit */
21572445Sassar		if (isoctal(c)) {
21672445Sassar			/*
21772445Sassar			 * yes - and maybe a third
21872445Sassar			 */
21972445Sassar			*cp = (*cp << 3) + (c - '0');
22072445Sassar			*astate = S_OCTAL3;
22172445Sassar			return (0);
22272445Sassar		}
22372445Sassar		/*
22472445Sassar		 * no - done with current sequence, push back passed char
22572445Sassar		 */
22672445Sassar		*astate = S_GROUND;
22772445Sassar		return (UNVIS_VALIDPUSH);
22872445Sassar
22972445Sassar	case S_OCTAL3:	/* third possible octal digit */
23072445Sassar		*astate = S_GROUND;
23172445Sassar		if (isoctal(c)) {
23272445Sassar			*cp = (*cp << 3) + (c - '0');
23372445Sassar			return (UNVIS_VALID);
23472445Sassar		}
23572445Sassar		/*
23672445Sassar		 * we were done, push back passed char
23772445Sassar		 */
23872445Sassar		return (UNVIS_VALIDPUSH);
23972445Sassar
24072445Sassar	default:
24172445Sassar		/*
24272445Sassar		 * decoder in unknown state - (probably uninitialized)
24372445Sassar		 */
24472445Sassar		*astate = S_GROUND;
24572445Sassar		return (UNVIS_SYNBAD);
24672445Sassar	}
24772445Sassar}
24872445Sassar
24972445Sassar/*
25072445Sassar * strunvis - decode src into dst
25172445Sassar *
25272445Sassar *	Number of chars decoded into dst is returned, -1 on error.
25372445Sassar *	Dst is null terminated.
25472445Sassar */
25572445Sassar
256178825Sdfrint ROKEN_LIB_FUNCTION
257178825Sdfrrk_strunvis(char *dst, const char *src)
25872445Sassar{
25972445Sassar	char c;
26072445Sassar	char *start = dst;
26172445Sassar	int state = 0;
26272445Sassar
26372445Sassar	_DIAGASSERT(src != NULL);
26472445Sassar	_DIAGASSERT(dst != NULL);
26572445Sassar
26672445Sassar	while ((c = *src++) != '\0') {
26772445Sassar	again:
268178825Sdfr		switch (rk_unvis(dst, (unsigned char)c, &state, 0)) {
26972445Sassar		case UNVIS_VALID:
27072445Sassar			dst++;
27172445Sassar			break;
27272445Sassar		case UNVIS_VALIDPUSH:
27372445Sassar			dst++;
27472445Sassar			goto again;
27572445Sassar		case 0:
27672445Sassar		case UNVIS_NOCHAR:
27772445Sassar			break;
27872445Sassar		default:
27972445Sassar			return (-1);
28072445Sassar		}
28172445Sassar	}
282178825Sdfr	if (unvis(dst, (unsigned char)c, &state, UNVIS_END) == UNVIS_VALID)
28372445Sassar		dst++;
28472445Sassar	*dst = '\0';
28572445Sassar	return (dst - start);
28672445Sassar}
287