Commit | Line | Data |
---|---|---|
9c260c06 MT |
1 | /* |
2 | * Copyright (c) 1989 The Regents of the University of California. | |
3 | * All rights reserved. | |
4 | * | |
5 | * Redistribution and use in source and binary forms are permitted | |
6 | * provided that the above copyright notice and this paragraph are | |
7 | * duplicated in all such forms and that any documentation, | |
8 | * advertising materials, and other materials related to such | |
9 | * distribution and use acknowledge that the software was developed | |
10 | * by the University of California, Berkeley. The name of the | |
11 | * University may not be used to endorse or promote products derived | |
12 | * from this software without specific prior written permission. | |
13 | * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR | |
14 | * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED | |
15 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. | |
16 | */ | |
17 | ||
18 | #if defined(LIBC_SCCS) && !defined(lint) | |
a11b735c | 19 | static char sccsid[] = "@(#)vis.c 5.2 (Berkeley) %G%"; |
9c260c06 MT |
20 | #endif /* LIBC_SCCS and not lint */ |
21 | ||
22 | #include <sys/types.h> | |
23 | #include <ctype.h> | |
24 | #include <cencode.h> | |
25 | ||
9c260c06 MT |
26 | #define isoctal(c) (((u_char)(c)) >= '0' && ((u_char)(c)) <= '7') |
27 | ||
28 | /* | |
a11b735c | 29 | * vis - visually encode characters |
9c260c06 | 30 | */ |
9c260c06 | 31 | char * |
a11b735c MT |
32 | vis(dst, c, flag, nextc) |
33 | register char *dst, c; | |
34 | char nextc; | |
35 | register int flag; | |
9c260c06 | 36 | { |
a11b735c MT |
37 | if (isascii(c) && isgraph(c) || |
38 | ((flag & VIS_WHITE) == 0 && | |
39 | (c == ' ' || c == '\n' || (flag & VIS_TAB) == 0 && c == '\t')) || | |
40 | ((flag & VIS_SAFE) && (c == '\b' || c == '\007' || c == '\r'))) { | |
41 | *dst++ = c; | |
42 | if (c == '\\' && (flag & VIS_NOSLASH) == 0) | |
43 | *dst++ = '\\'; | |
44 | *dst = '\0'; | |
45 | return (dst); | |
9c260c06 | 46 | } |
a11b735c MT |
47 | |
48 | if ((flag & VIS_NOSLASH) == 0) | |
49 | *dst++ = '\\'; | |
50 | if (flag & VIS_CSTYLE) { | |
9c260c06 MT |
51 | switch(c) { |
52 | case '\n': | |
a11b735c | 53 | *dst++ = 'n'; |
9c260c06 MT |
54 | goto done; |
55 | case '\r': | |
a11b735c | 56 | *dst++ = 'r'; |
9c260c06 MT |
57 | goto done; |
58 | case '\b': | |
a11b735c | 59 | *dst++ = 'b'; |
9c260c06 | 60 | goto done; |
a11b735c MT |
61 | case '\007': /* waiting for ansi compiler */ |
62 | *dst++ = 'a'; | |
9c260c06 MT |
63 | goto done; |
64 | case '\v': | |
a11b735c | 65 | *dst++ = 'v'; |
9c260c06 MT |
66 | goto done; |
67 | case '\t': | |
a11b735c | 68 | *dst++ = 't'; |
9c260c06 MT |
69 | goto done; |
70 | case '\f': | |
a11b735c | 71 | *dst++ = 'f'; |
9c260c06 MT |
72 | goto done; |
73 | case ' ': | |
a11b735c | 74 | *dst++ = 's'; |
9c260c06 MT |
75 | goto done; |
76 | case '\0': | |
a11b735c MT |
77 | *dst++ = '0'; |
78 | if ((flag & VIS_NEXTC) == 0 || isoctal(nextc)) { | |
79 | *dst++ = '0'; | |
80 | *dst++ = '0'; | |
9c260c06 MT |
81 | } |
82 | goto done; | |
83 | } | |
84 | } | |
a11b735c MT |
85 | if (((c & 0177) == ' ') || (flag & VIS_OCTAL)) { |
86 | *dst++ = ((u_char)c >> 6 & 07) + '0'; | |
87 | *dst++ = ((u_char)c >> 3 & 07) + '0'; | |
88 | *dst++ = ((u_char)c & 07) + '0'; | |
9c260c06 MT |
89 | goto done; |
90 | } | |
a11b735c MT |
91 | if (c & 0200) { |
92 | c &= 0177; | |
93 | *dst++ = 'M'; | |
94 | } | |
95 | if (iscntrl(c)) { | |
96 | *dst++ = '^'; | |
97 | if (c == 0177) | |
98 | *dst++ = '?'; | |
9c260c06 | 99 | else |
a11b735c MT |
100 | *dst++ = c + '@'; |
101 | } else { | |
102 | *dst++ = '-'; | |
103 | *dst++ = c; | |
9c260c06 | 104 | } |
9c260c06 | 105 | done: |
a11b735c MT |
106 | *dst = '\0'; |
107 | return (dst); | |
9c260c06 MT |
108 | } |
109 | ||
a11b735c | 110 | |
9c260c06 MT |
111 | /* |
112 | * decode driven by state machine | |
113 | */ | |
114 | #define S_NORMAL 1 /* haven't seen escape char */ | |
115 | #define S_START 2 /* start decoding special sequence */ | |
116 | #define S_META 3 /* metachar started (M) */ | |
117 | #define S_META1 4 /* metachar more, regular char (-) */ | |
118 | #define S_CTRL 5 /* control char started (^) */ | |
119 | #define S_OCTAL 6 /* octal number */ | |
120 | ||
121 | /* | |
122 | * | |
123 | */ | |
a11b735c | 124 | cunvis(c, cp, flags) |
9c260c06 MT |
125 | char c; |
126 | char *cp; | |
127 | { | |
128 | static int state = S_NORMAL; | |
a11b735c MT |
129 | static u_char buildchar; |
130 | static int octal; | |
9c260c06 | 131 | |
a11b735c | 132 | if (flags&UNVIS_END) { |
9c260c06 MT |
133 | int ostate = state; |
134 | state = S_NORMAL; | |
135 | if (ostate == S_OCTAL) { | |
136 | *cp = buildchar; | |
a11b735c | 137 | return(UNVIS_OK); |
9c260c06 MT |
138 | } else if (ostate == S_META1) { |
139 | /* slightly forgiving, if not wrong */ | |
140 | *cp = ' ' | 0200; | |
a11b735c | 141 | return(UNVIS_OK); |
9c260c06 | 142 | } else |
a11b735c | 143 | return(ostate == S_NORMAL ? UNVIS_NOCHAR : CDEC_SYNBAD); |
9c260c06 MT |
144 | } |
145 | ||
146 | switch (state) { | |
147 | case S_NORMAL: | |
148 | buildchar = 0; | |
149 | if (c == '\\') { | |
150 | state = S_START; | |
a11b735c MT |
151 | return(UNVIS_NEEDMORE); |
152 | } else if (flags&UNVIS_HAT && c == '^') { | |
9c260c06 | 153 | state = S_CTRL; |
a11b735c | 154 | return(UNVIS_NEEDMORE); |
9c260c06 MT |
155 | } else { |
156 | *cp = c; | |
a11b735c | 157 | return(UNVIS_OK); |
9c260c06 MT |
158 | } |
159 | break; | |
160 | case S_START: | |
161 | state = S_NORMAL; | |
162 | if (c == '\\') { | |
163 | *cp = c; | |
a11b735c | 164 | return(UNVIS_OK); |
9c260c06 MT |
165 | } |
166 | if (isoctal(c)) { | |
167 | buildchar = (c-'0'); | |
168 | octal = 1; | |
169 | state = S_OCTAL; | |
a11b735c | 170 | return(UNVIS_NEEDMORE); |
9c260c06 MT |
171 | } |
172 | switch(c) { | |
173 | case 'M': | |
174 | buildchar |= 0200; | |
175 | state = S_META; | |
a11b735c | 176 | return(UNVIS_NEEDMORE); |
9c260c06 MT |
177 | case '^': |
178 | state = S_CTRL; | |
a11b735c | 179 | return(UNVIS_NEEDMORE); |
9c260c06 MT |
180 | case 'n': |
181 | *cp = '\n'; | |
a11b735c | 182 | return(UNVIS_OK); |
9c260c06 MT |
183 | case 'r': |
184 | *cp = '\r'; | |
a11b735c | 185 | return(UNVIS_OK); |
9c260c06 MT |
186 | case 'b': |
187 | *cp = '\b'; | |
a11b735c | 188 | return(UNVIS_OK); |
9c260c06 MT |
189 | case 'a': |
190 | *cp = '\007'; | |
a11b735c | 191 | return(UNVIS_OK); |
9c260c06 MT |
192 | case 'v': |
193 | *cp = '\v'; | |
a11b735c | 194 | return(UNVIS_OK); |
9c260c06 MT |
195 | case 't': |
196 | *cp = '\t'; | |
a11b735c | 197 | return(UNVIS_OK); |
9c260c06 MT |
198 | case 'f': |
199 | *cp = '\f'; | |
a11b735c | 200 | return(UNVIS_OK); |
9c260c06 MT |
201 | case 's': /* does anyone use this ? */ |
202 | *cp = ' '; | |
a11b735c | 203 | return(UNVIS_OK); |
9c260c06 MT |
204 | case 'E': |
205 | *cp = '\033'; | |
a11b735c | 206 | return(UNVIS_OK); |
9c260c06 | 207 | case '\n': |
a11b735c | 208 | return(UNVIS_NOCHAR); /* hidden newline */ |
9c260c06 MT |
209 | } |
210 | state = S_NORMAL; | |
a11b735c | 211 | return(UNVIS_SYNBAD); |
9c260c06 MT |
212 | case S_META: |
213 | if (c == '-') | |
214 | state = S_META1; | |
215 | else if (c == '^') | |
216 | state = S_CTRL; | |
217 | else { | |
218 | state = S_NORMAL; | |
a11b735c | 219 | return(UNVIS_SYNBAD); |
9c260c06 | 220 | } |
a11b735c | 221 | return(UNVIS_NEEDMORE); |
9c260c06 MT |
222 | case S_META1: |
223 | state = S_NORMAL; | |
224 | *cp = c | buildchar; | |
a11b735c | 225 | return(UNVIS_OK); |
9c260c06 MT |
226 | case S_CTRL: |
227 | if (c == '?') | |
228 | buildchar |= 0177; | |
229 | else | |
230 | buildchar |= c&037; | |
231 | state = S_NORMAL; | |
232 | *cp = buildchar; | |
a11b735c | 233 | return(UNVIS_OK); |
9c260c06 MT |
234 | case S_OCTAL: |
235 | if (isoctal(c)) { | |
236 | buildchar = (buildchar<<3) + (c-'0'); | |
237 | if (++octal == 3) { | |
238 | state = S_NORMAL; | |
239 | *cp = buildchar; | |
a11b735c | 240 | return(UNVIS_OK); |
9c260c06 | 241 | } else |
a11b735c | 242 | return(UNVIS_NEEDMORE); |
9c260c06 MT |
243 | } else { |
244 | state = S_NORMAL; | |
245 | *cp = buildchar; | |
a11b735c | 246 | return(UNVIS_OKPUSH); |
9c260c06 MT |
247 | } |
248 | } | |
249 | } | |
a11b735c MT |
250 | |
251 | /* | |
252 | * strvis - visually encode characters from src into dst | |
253 | * | |
254 | * If len >= 0, encodes exactly len chars from src (including NULL's). | |
255 | * Otherwise, stops before first NULL in src. In all cases, dst is | |
256 | * NULL terminated. | |
257 | * | |
258 | * Dst must be 4 times the size of src to account for possible | |
259 | * expansion. The length of dst, not including the trailing NULL, | |
260 | * is returned. | |
261 | */ | |
262 | strvis(dst, src, len, flag) | |
263 | register char *dst, *src; | |
264 | register int len; | |
265 | { | |
266 | char *start = dst; | |
267 | ||
268 | for (;;) { | |
269 | if (len > 0) { | |
270 | if (len-- == 0) | |
271 | break; | |
272 | } else if (!*src) | |
273 | break; | |
274 | dst = vis(dst, *src, flag | VIS_NEXTC, *(src+1)); | |
275 | src++; | |
276 | } | |
277 | ||
278 | return (dst - start); | |
279 | } |