1/*++
2/* NAME
3/*	unescape 3
4/* SUMMARY
5/*	translate C-like escape sequences
6/* SYNOPSIS
7/*	#include <stringops.h>
8/*
9/*	VSTRING	*unescape(result, input)
10/*	VSTRING	*result;
11/*	const char *input;
12/*
13/*	VSTRING	*escape(result, input, len)
14/*	VSTRING	*result;
15/*	const char *input;
16/*	ssize_t len;
17/* DESCRIPTION
18/*	unescape() translates C-like escape sequences in the null-terminated
19/*	string \fIinput\fR and places the result in \fIresult\fR. The result
20/*	is null-terminated, and is the function result value.
21/*
22/*	escape() does the reverse transformation.
23/*
24/*	Escape sequences and their translations:
25/* .IP \ea
26/*	Bell character.
27/* .IP \eb
28/*	Backspace character.
29/* .IP \ef
30/*	formfeed character.
31/* .IP \en
32/*	newline character
33/* .IP \er
34/*	Carriage-return character.
35/* .IP \et
36/*	Horizontal tab character.
37/* .IP \ev
38/*	Vertical tab character.
39/* .IP \e\e
40/*	Backslash character.
41/* .IP \e\fInum\fR
42/*	8-bit character whose ASCII value is the 1..3 digit
43/*	octal number \fInum\fR.
44/* .IP \e\fIother\fR
45/*	The backslash character is discarded.
46/* LICENSE
47/* .ad
48/* .fi
49/*	The Secure Mailer license must be distributed with this software.
50/* AUTHOR(S)
51/*	Wietse Venema
52/*	IBM T.J. Watson Research
53/*	P.O. Box 704
54/*	Yorktown Heights, NY 10598, USA
55/*--*/
56
57/* System library. */
58
59#include <sys_defs.h>
60#include <ctype.h>
61
62/* Utility library. */
63
64#include <vstring.h>
65#include <stringops.h>
66
67/* unescape - process escape sequences */
68
69VSTRING *unescape(VSTRING *result, const char *data)
70{
71    int     ch;
72    int     oval;
73    int     i;
74
75#define UCHAR(cp)	((unsigned char *) (cp))
76#define ISOCTAL(ch)	(ISDIGIT(ch) && (ch) != '8' && (ch) != '9')
77
78    VSTRING_RESET(result);
79
80    while ((ch = *UCHAR(data++)) != 0) {
81	if (ch == '\\') {
82	    if ((ch = *UCHAR(data++)) == 0)
83		break;
84	    switch (ch) {
85	    case 'a':				/* \a -> audible bell */
86		ch = '\a';
87		break;
88	    case 'b':				/* \b -> backspace */
89		ch = '\b';
90		break;
91	    case 'f':				/* \f -> formfeed */
92		ch = '\f';
93		break;
94	    case 'n':				/* \n -> newline */
95		ch = '\n';
96		break;
97	    case 'r':				/* \r -> carriagereturn */
98		ch = '\r';
99		break;
100	    case 't':				/* \t -> horizontal tab */
101		ch = '\t';
102		break;
103	    case 'v':				/* \v -> vertical tab */
104		ch = '\v';
105		break;
106	    case '0':				/* \nnn -> ASCII value */
107	    case '1':
108	    case '2':
109	    case '3':
110	    case '4':
111	    case '5':
112	    case '6':
113	    case '7':
114		for (oval = ch - '0', i = 0;
115		     i < 2 && (ch = *UCHAR(data)) != 0 && ISOCTAL(ch);
116		     i++, data++) {
117		    oval = (oval << 3) | (ch - '0');
118		}
119		ch = oval;
120		break;
121	    default:				/* \any -> any */
122		break;
123	    }
124	}
125	VSTRING_ADDCH(result, ch);
126    }
127    VSTRING_TERMINATE(result);
128    return (result);
129}
130
131/* escape - reverse transformation */
132
133VSTRING *escape(VSTRING *result, const char *data, ssize_t len)
134{
135    int     ch;
136
137    VSTRING_RESET(result);
138    while (len-- > 0) {
139	ch = *UCHAR(data++);
140	if (ISASCII(ch)) {
141	    if (ISPRINT(ch)) {
142		if (ch == '\\')
143		    VSTRING_ADDCH(result, ch);
144		VSTRING_ADDCH(result, ch);
145		continue;
146	    } else if (ch == '\a') {		/* \a -> audible bell */
147		vstring_strcat(result, "\\a");
148		continue;
149	    } else if (ch == '\b') {		/* \b -> backspace */
150		vstring_strcat(result, "\\b");
151		continue;
152	    } else if (ch == '\f') {		/* \f -> formfeed */
153		vstring_strcat(result, "\\f");
154		continue;
155	    } else if (ch == '\n') {		/* \n -> newline */
156		vstring_strcat(result, "\\n");
157		continue;
158	    } else if (ch == '\r') {		/* \r -> carriagereturn */
159		vstring_strcat(result, "\\r");
160		continue;
161	    } else if (ch == '\t') {		/* \t -> horizontal tab */
162		vstring_strcat(result, "\\t");
163		continue;
164	    } else if (ch == '\v') {		/* \v -> vertical tab */
165		vstring_strcat(result, "\\v");
166		continue;
167	    }
168	}
169	if (ISDIGIT(*UCHAR(data)))
170	    vstring_sprintf_append(result, "\\%03d", ch);
171	else
172	    vstring_sprintf_append(result, "\\%d", ch);
173    }
174    VSTRING_TERMINATE(result);
175    return (result);
176}
177
178#ifdef TEST
179
180#include <stdlib.h>
181#include <string.h>
182#include <msg.h>
183#include <vstring_vstream.h>
184
185int     main(int argc, char **argv)
186{
187    VSTRING *in = vstring_alloc(10);
188    VSTRING *out = vstring_alloc(10);
189    int     un_escape = 1;
190
191    if (argc > 2 || (argc > 1 && (un_escape = strcmp(argv[1], "-e"))) != 0)
192	msg_fatal("usage: %s [-e (escape)]", argv[0]);
193
194    if (un_escape) {
195	while (vstring_fgets_nonl(in, VSTREAM_IN)) {
196	    unescape(out, vstring_str(in));
197	    vstream_fwrite(VSTREAM_OUT, vstring_str(out), VSTRING_LEN(out));
198	}
199    } else {
200	while (vstring_fgets(in, VSTREAM_IN)) {
201	    escape(out, vstring_str(in), VSTRING_LEN(in));
202	    vstream_fwrite(VSTREAM_OUT, vstring_str(out), VSTRING_LEN(out));
203	}
204    }
205    vstream_fflush(VSTREAM_OUT);
206    exit(0);
207}
208
209#endif
210