1 /*        $NetBSD: unescape.c,v 1.2 2017/02/14 01:16:49 christos 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 
unescape(VSTRING * result,const char * data)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 
escape(VSTRING * result,const char * data,ssize_t len)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           vstring_sprintf_append(result, "\\%03o", ch);
172     }
173     VSTRING_TERMINATE(result);
174     return (result);
175 }
176 
177 #ifdef TEST
178 
179 #include <stdlib.h>
180 #include <string.h>
181 #include <msg.h>
182 #include <vstring_vstream.h>
183 
main(int argc,char ** argv)184 int     main(int argc, char **argv)
185 {
186     VSTRING *in = vstring_alloc(10);
187     VSTRING *out = vstring_alloc(10);
188     int     un_escape = 1;
189 
190     if (argc > 2 || (argc > 1 && (un_escape = strcmp(argv[1], "-e"))) != 0)
191           msg_fatal("usage: %s [-e (escape)]", argv[0]);
192 
193     if (un_escape) {
194           while (vstring_fgets_nonl(in, VSTREAM_IN)) {
195               unescape(out, vstring_str(in));
196               vstream_fwrite(VSTREAM_OUT, vstring_str(out), VSTRING_LEN(out));
197               VSTREAM_PUTC('\n', VSTREAM_OUT);
198           }
199     } else {
200           while (vstring_fgets_nonl(in, VSTREAM_IN)) {
201               escape(out, vstring_str(in), VSTRING_LEN(in));
202               vstream_fwrite(VSTREAM_OUT, vstring_str(out), VSTRING_LEN(out));
203               VSTREAM_PUTC('\n', VSTREAM_OUT);
204           }
205     }
206     vstream_fflush(VSTREAM_OUT);
207     exit(0);
208 }
209 
210 #endif
211