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