]>
Commit | Line | Data |
---|---|---|
974e3884 A |
1 | /* $NetBSD: unvis.c,v 1.41 2012/12/15 04:29:53 matt Exp $ */ |
2 | ||
9385eb3d | 3 | /*- |
e9ce8d39 A |
4 | * Copyright (c) 1989, 1993 |
5 | * The Regents of the University of California. All rights reserved. | |
6 | * | |
7 | * Redistribution and use in source and binary forms, with or without | |
8 | * modification, are permitted provided that the following conditions | |
9 | * are met: | |
10 | * 1. Redistributions of source code must retain the above copyright | |
11 | * notice, this list of conditions and the following disclaimer. | |
12 | * 2. Redistributions in binary form must reproduce the above copyright | |
13 | * notice, this list of conditions and the following disclaimer in the | |
14 | * documentation and/or other materials provided with the distribution. | |
974e3884 | 15 | * 3. Neither the name of the University nor the names of its contributors |
e9ce8d39 A |
16 | * may be used to endorse or promote products derived from this software |
17 | * without specific prior written permission. | |
18 | * | |
19 | * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND | |
20 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | |
21 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | |
22 | * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE | |
23 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | |
24 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | |
25 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | |
26 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | |
27 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | |
28 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | |
29 | * SUCH DAMAGE. | |
30 | */ | |
31 | ||
974e3884 | 32 | #include <sys/cdefs.h> |
9385eb3d | 33 | #if defined(LIBC_SCCS) && !defined(lint) |
974e3884 | 34 | #if 0 |
9385eb3d | 35 | static char sccsid[] = "@(#)unvis.c 8.1 (Berkeley) 6/4/93"; |
974e3884 A |
36 | #else |
37 | __RCSID("$NetBSD: unvis.c,v 1.41 2012/12/15 04:29:53 matt Exp $"); | |
38 | #endif | |
9385eb3d | 39 | #endif /* LIBC_SCCS and not lint */ |
ad3c9f2a A |
40 | #include "xlocale_private.h" |
41 | ||
e9ce8d39 | 42 | #include <sys/types.h> |
974e3884 A |
43 | |
44 | #include <assert.h> | |
e9ce8d39 | 45 | #include <ctype.h> |
974e3884 A |
46 | #include <stdint.h> |
47 | #include <stdio.h> | |
48 | #include <errno.h> | |
e9ce8d39 A |
49 | #include <vis.h> |
50 | ||
974e3884 A |
51 | #define _DIAGASSERT(x) assert(x) |
52 | ||
53 | /* | |
54 | * Return the number of elements in a statically-allocated array, | |
55 | * __x. | |
56 | */ | |
57 | #define __arraycount(__x) (sizeof(__x) / sizeof(__x[0])) | |
58 | ||
59 | #if !HAVE_VIS | |
e9ce8d39 A |
60 | /* |
61 | * decode driven by state machine | |
62 | */ | |
63 | #define S_GROUND 0 /* haven't seen escape char */ | |
64 | #define S_START 1 /* start decoding special sequence */ | |
65 | #define S_META 2 /* metachar started (M) */ | |
66 | #define S_META1 3 /* metachar more, regular char (-) */ | |
67 | #define S_CTRL 4 /* control char started (^) */ | |
68 | #define S_OCTAL2 5 /* octal digit 2 */ | |
69 | #define S_OCTAL3 6 /* octal digit 3 */ | |
974e3884 A |
70 | #define S_HEX 7 /* mandatory hex digit */ |
71 | #define S_HEX1 8 /* http hex digit */ | |
72 | #define S_HEX2 9 /* http hex digit 2 */ | |
73 | #define S_MIME1 10 /* mime hex digit 1 */ | |
74 | #define S_MIME2 11 /* mime hex digit 2 */ | |
75 | #define S_EATCRNL 12 /* mime eating CRNL */ | |
76 | #define S_AMP 13 /* seen & */ | |
77 | #define S_NUMBER 14 /* collecting number */ | |
78 | #define S_STRING 15 /* collecting string */ | |
e9ce8d39 A |
79 | |
80 | #define isoctal(c) (((u_char)(c)) >= '0' && ((u_char)(c)) <= '7') | |
974e3884 A |
81 | #define xtod(c) (isdigit(c) ? (c - '0') : ((tolower(c) - 'a') + 10)) |
82 | #define XTOD(c) (isdigit(c) ? (c - '0') : ((c - 'A') + 10)) | |
83 | ||
84 | /* | |
85 | * RFC 1866 | |
86 | */ | |
87 | static const struct nv { | |
88 | char name[7]; | |
89 | uint8_t value; | |
90 | } nv[] = { | |
91 | { "AElig", 198 }, /* capital AE diphthong (ligature) */ | |
92 | { "Aacute", 193 }, /* capital A, acute accent */ | |
93 | { "Acirc", 194 }, /* capital A, circumflex accent */ | |
94 | { "Agrave", 192 }, /* capital A, grave accent */ | |
95 | { "Aring", 197 }, /* capital A, ring */ | |
96 | { "Atilde", 195 }, /* capital A, tilde */ | |
97 | { "Auml", 196 }, /* capital A, dieresis or umlaut mark */ | |
98 | { "Ccedil", 199 }, /* capital C, cedilla */ | |
99 | { "ETH", 208 }, /* capital Eth, Icelandic */ | |
100 | { "Eacute", 201 }, /* capital E, acute accent */ | |
101 | { "Ecirc", 202 }, /* capital E, circumflex accent */ | |
102 | { "Egrave", 200 }, /* capital E, grave accent */ | |
103 | { "Euml", 203 }, /* capital E, dieresis or umlaut mark */ | |
104 | { "Iacute", 205 }, /* capital I, acute accent */ | |
105 | { "Icirc", 206 }, /* capital I, circumflex accent */ | |
106 | { "Igrave", 204 }, /* capital I, grave accent */ | |
107 | { "Iuml", 207 }, /* capital I, dieresis or umlaut mark */ | |
108 | { "Ntilde", 209 }, /* capital N, tilde */ | |
109 | { "Oacute", 211 }, /* capital O, acute accent */ | |
110 | { "Ocirc", 212 }, /* capital O, circumflex accent */ | |
111 | { "Ograve", 210 }, /* capital O, grave accent */ | |
112 | { "Oslash", 216 }, /* capital O, slash */ | |
113 | { "Otilde", 213 }, /* capital O, tilde */ | |
114 | { "Ouml", 214 }, /* capital O, dieresis or umlaut mark */ | |
115 | { "THORN", 222 }, /* capital THORN, Icelandic */ | |
116 | { "Uacute", 218 }, /* capital U, acute accent */ | |
117 | { "Ucirc", 219 }, /* capital U, circumflex accent */ | |
118 | { "Ugrave", 217 }, /* capital U, grave accent */ | |
119 | { "Uuml", 220 }, /* capital U, dieresis or umlaut mark */ | |
120 | { "Yacute", 221 }, /* capital Y, acute accent */ | |
121 | { "aacute", 225 }, /* small a, acute accent */ | |
122 | { "acirc", 226 }, /* small a, circumflex accent */ | |
123 | { "acute", 180 }, /* acute accent */ | |
124 | { "aelig", 230 }, /* small ae diphthong (ligature) */ | |
125 | { "agrave", 224 }, /* small a, grave accent */ | |
126 | { "amp", 38 }, /* ampersand */ | |
127 | { "aring", 229 }, /* small a, ring */ | |
128 | { "atilde", 227 }, /* small a, tilde */ | |
129 | { "auml", 228 }, /* small a, dieresis or umlaut mark */ | |
130 | { "brvbar", 166 }, /* broken (vertical) bar */ | |
131 | { "ccedil", 231 }, /* small c, cedilla */ | |
132 | { "cedil", 184 }, /* cedilla */ | |
133 | { "cent", 162 }, /* cent sign */ | |
134 | { "copy", 169 }, /* copyright sign */ | |
135 | { "curren", 164 }, /* general currency sign */ | |
136 | { "deg", 176 }, /* degree sign */ | |
137 | { "divide", 247 }, /* divide sign */ | |
138 | { "eacute", 233 }, /* small e, acute accent */ | |
139 | { "ecirc", 234 }, /* small e, circumflex accent */ | |
140 | { "egrave", 232 }, /* small e, grave accent */ | |
141 | { "eth", 240 }, /* small eth, Icelandic */ | |
142 | { "euml", 235 }, /* small e, dieresis or umlaut mark */ | |
143 | { "frac12", 189 }, /* fraction one-half */ | |
144 | { "frac14", 188 }, /* fraction one-quarter */ | |
145 | { "frac34", 190 }, /* fraction three-quarters */ | |
146 | { "gt", 62 }, /* greater than */ | |
147 | { "iacute", 237 }, /* small i, acute accent */ | |
148 | { "icirc", 238 }, /* small i, circumflex accent */ | |
149 | { "iexcl", 161 }, /* inverted exclamation mark */ | |
150 | { "igrave", 236 }, /* small i, grave accent */ | |
151 | { "iquest", 191 }, /* inverted question mark */ | |
152 | { "iuml", 239 }, /* small i, dieresis or umlaut mark */ | |
153 | { "laquo", 171 }, /* angle quotation mark, left */ | |
154 | { "lt", 60 }, /* less than */ | |
155 | { "macr", 175 }, /* macron */ | |
156 | { "micro", 181 }, /* micro sign */ | |
157 | { "middot", 183 }, /* middle dot */ | |
158 | { "nbsp", 160 }, /* no-break space */ | |
159 | { "not", 172 }, /* not sign */ | |
160 | { "ntilde", 241 }, /* small n, tilde */ | |
161 | { "oacute", 243 }, /* small o, acute accent */ | |
162 | { "ocirc", 244 }, /* small o, circumflex accent */ | |
163 | { "ograve", 242 }, /* small o, grave accent */ | |
164 | { "ordf", 170 }, /* ordinal indicator, feminine */ | |
165 | { "ordm", 186 }, /* ordinal indicator, masculine */ | |
166 | { "oslash", 248 }, /* small o, slash */ | |
167 | { "otilde", 245 }, /* small o, tilde */ | |
168 | { "ouml", 246 }, /* small o, dieresis or umlaut mark */ | |
169 | { "para", 182 }, /* pilcrow (paragraph sign) */ | |
170 | { "plusmn", 177 }, /* plus-or-minus sign */ | |
171 | { "pound", 163 }, /* pound sterling sign */ | |
172 | { "quot", 34 }, /* double quote */ | |
173 | { "raquo", 187 }, /* angle quotation mark, right */ | |
174 | { "reg", 174 }, /* registered sign */ | |
175 | { "sect", 167 }, /* section sign */ | |
176 | { "shy", 173 }, /* soft hyphen */ | |
177 | { "sup1", 185 }, /* superscript one */ | |
178 | { "sup2", 178 }, /* superscript two */ | |
179 | { "sup3", 179 }, /* superscript three */ | |
180 | { "szlig", 223 }, /* small sharp s, German (sz ligature) */ | |
181 | { "thorn", 254 }, /* small thorn, Icelandic */ | |
182 | { "times", 215 }, /* multiply sign */ | |
183 | { "uacute", 250 }, /* small u, acute accent */ | |
184 | { "ucirc", 251 }, /* small u, circumflex accent */ | |
185 | { "ugrave", 249 }, /* small u, grave accent */ | |
186 | { "uml", 168 }, /* umlaut (dieresis) */ | |
187 | { "uuml", 252 }, /* small u, dieresis or umlaut mark */ | |
188 | { "yacute", 253 }, /* small y, acute accent */ | |
189 | { "yen", 165 }, /* yen sign */ | |
190 | { "yuml", 255 }, /* small y, dieresis or umlaut mark */ | |
191 | }; | |
e9ce8d39 A |
192 | |
193 | /* | |
194 | * unvis - decode characters previously encoded by vis | |
195 | */ | |
196 | int | |
3d9156a7 | 197 | unvis(char *cp, int c, int *astate, int flag) |
e9ce8d39 | 198 | { |
974e3884 A |
199 | unsigned char uc = (unsigned char)c; |
200 | unsigned char st, ia, is, lc; | |
201 | ||
202 | /* | |
203 | * Bottom 8 bits of astate hold the state machine state. | |
204 | * Top 8 bits hold the current character in the http 1866 nv string decoding | |
205 | */ | |
206 | #define GS(a) ((a) & 0xff) | |
207 | #define SS(a, b) (((uint32_t)(a) << 24) | (b)) | |
208 | #define GI(a) ((uint32_t)(a) >> 24) | |
209 | ||
210 | _DIAGASSERT(cp != NULL); | |
211 | _DIAGASSERT(astate != NULL); | |
212 | st = GS(*astate); | |
e9ce8d39 A |
213 | |
214 | if (flag & UNVIS_END) { | |
974e3884 A |
215 | switch (st) { |
216 | case S_OCTAL2: | |
217 | case S_OCTAL3: | |
218 | case S_HEX2: | |
219 | *astate = SS(0, S_GROUND); | |
220 | return UNVIS_VALID; | |
221 | case S_GROUND: | |
222 | return UNVIS_NOCHAR; | |
223 | default: | |
224 | return UNVIS_SYNBAD; | |
9385eb3d | 225 | } |
e9ce8d39 A |
226 | } |
227 | ||
974e3884 | 228 | switch (st) { |
e9ce8d39 A |
229 | |
230 | case S_GROUND: | |
231 | *cp = 0; | |
974e3884 A |
232 | if ((flag & VIS_NOESCAPE) == 0 && c == '\\') { |
233 | *astate = SS(0, S_START); | |
234 | return UNVIS_NOCHAR; | |
235 | } | |
236 | if ((flag & VIS_HTTP1808) && c == '%') { | |
237 | *astate = SS(0, S_HEX1); | |
238 | return UNVIS_NOCHAR; | |
239 | } | |
240 | if ((flag & VIS_HTTP1866) && c == '&') { | |
241 | *astate = SS(0, S_AMP); | |
242 | return UNVIS_NOCHAR; | |
9385eb3d | 243 | } |
974e3884 A |
244 | if ((flag & VIS_MIMESTYLE) && c == '=') { |
245 | *astate = SS(0, S_MIME1); | |
246 | return UNVIS_NOCHAR; | |
9385eb3d | 247 | } |
e9ce8d39 | 248 | *cp = c; |
974e3884 | 249 | return UNVIS_VALID; |
e9ce8d39 A |
250 | |
251 | case S_START: | |
252 | switch(c) { | |
253 | case '\\': | |
254 | *cp = c; | |
974e3884 A |
255 | *astate = SS(0, S_GROUND); |
256 | return UNVIS_VALID; | |
e9ce8d39 A |
257 | case '0': case '1': case '2': case '3': |
258 | case '4': case '5': case '6': case '7': | |
259 | *cp = (c - '0'); | |
974e3884 A |
260 | *astate = SS(0, S_OCTAL2); |
261 | return UNVIS_NOCHAR; | |
e9ce8d39 | 262 | case 'M': |
974e3884 A |
263 | *cp = (char)0200; |
264 | *astate = SS(0, S_META); | |
265 | return UNVIS_NOCHAR; | |
e9ce8d39 | 266 | case '^': |
974e3884 A |
267 | *astate = SS(0, S_CTRL); |
268 | return UNVIS_NOCHAR; | |
e9ce8d39 A |
269 | case 'n': |
270 | *cp = '\n'; | |
974e3884 A |
271 | *astate = SS(0, S_GROUND); |
272 | return UNVIS_VALID; | |
e9ce8d39 A |
273 | case 'r': |
274 | *cp = '\r'; | |
974e3884 A |
275 | *astate = SS(0, S_GROUND); |
276 | return UNVIS_VALID; | |
e9ce8d39 A |
277 | case 'b': |
278 | *cp = '\b'; | |
974e3884 A |
279 | *astate = SS(0, S_GROUND); |
280 | return UNVIS_VALID; | |
e9ce8d39 A |
281 | case 'a': |
282 | *cp = '\007'; | |
974e3884 A |
283 | *astate = SS(0, S_GROUND); |
284 | return UNVIS_VALID; | |
e9ce8d39 A |
285 | case 'v': |
286 | *cp = '\v'; | |
974e3884 A |
287 | *astate = SS(0, S_GROUND); |
288 | return UNVIS_VALID; | |
e9ce8d39 A |
289 | case 't': |
290 | *cp = '\t'; | |
974e3884 A |
291 | *astate = SS(0, S_GROUND); |
292 | return UNVIS_VALID; | |
e9ce8d39 A |
293 | case 'f': |
294 | *cp = '\f'; | |
974e3884 A |
295 | *astate = SS(0, S_GROUND); |
296 | return UNVIS_VALID; | |
e9ce8d39 A |
297 | case 's': |
298 | *cp = ' '; | |
974e3884 A |
299 | *astate = SS(0, S_GROUND); |
300 | return UNVIS_VALID; | |
e9ce8d39 A |
301 | case 'E': |
302 | *cp = '\033'; | |
974e3884 A |
303 | *astate = SS(0, S_GROUND); |
304 | return UNVIS_VALID; | |
305 | case 'x': | |
306 | *astate = SS(0, S_HEX); | |
307 | return UNVIS_NOCHAR; | |
e9ce8d39 A |
308 | case '\n': |
309 | /* | |
310 | * hidden newline | |
311 | */ | |
974e3884 A |
312 | *astate = SS(0, S_GROUND); |
313 | return UNVIS_NOCHAR; | |
e9ce8d39 A |
314 | case '$': |
315 | /* | |
316 | * hidden marker | |
317 | */ | |
974e3884 A |
318 | *astate = SS(0, S_GROUND); |
319 | return UNVIS_NOCHAR; | |
e9ce8d39 | 320 | } |
974e3884 | 321 | goto bad; |
9385eb3d | 322 | |
e9ce8d39 A |
323 | case S_META: |
324 | if (c == '-') | |
974e3884 | 325 | *astate = SS(0, S_META1); |
e9ce8d39 | 326 | else if (c == '^') |
974e3884 A |
327 | *astate = SS(0, S_CTRL); |
328 | else | |
329 | goto bad; | |
330 | return UNVIS_NOCHAR; | |
9385eb3d | 331 | |
e9ce8d39 | 332 | case S_META1: |
974e3884 | 333 | *astate = SS(0, S_GROUND); |
e9ce8d39 | 334 | *cp |= c; |
974e3884 | 335 | return UNVIS_VALID; |
9385eb3d | 336 | |
e9ce8d39 A |
337 | case S_CTRL: |
338 | if (c == '?') | |
339 | *cp |= 0177; | |
340 | else | |
341 | *cp |= c & 037; | |
974e3884 A |
342 | *astate = SS(0, S_GROUND); |
343 | return UNVIS_VALID; | |
e9ce8d39 A |
344 | |
345 | case S_OCTAL2: /* second possible octal digit */ | |
974e3884 | 346 | if (isoctal(uc)) { |
9385eb3d A |
347 | /* |
348 | * yes - and maybe a third | |
e9ce8d39 A |
349 | */ |
350 | *cp = (*cp << 3) + (c - '0'); | |
974e3884 A |
351 | *astate = SS(0, S_OCTAL3); |
352 | return UNVIS_NOCHAR; | |
9385eb3d A |
353 | } |
354 | /* | |
355 | * no - done with current sequence, push back passed char | |
e9ce8d39 | 356 | */ |
974e3884 A |
357 | *astate = SS(0, S_GROUND); |
358 | return UNVIS_VALIDPUSH; | |
e9ce8d39 A |
359 | |
360 | case S_OCTAL3: /* third possible octal digit */ | |
974e3884 A |
361 | *astate = SS(0, S_GROUND); |
362 | if (isoctal(uc)) { | |
e9ce8d39 | 363 | *cp = (*cp << 3) + (c - '0'); |
974e3884 | 364 | return UNVIS_VALID; |
e9ce8d39 A |
365 | } |
366 | /* | |
367 | * we were done, push back passed char | |
368 | */ | |
974e3884 | 369 | return UNVIS_VALIDPUSH; |
9385eb3d | 370 | |
974e3884 A |
371 | case S_HEX: |
372 | if (!isxdigit(uc)) | |
373 | goto bad; | |
374 | /*FALLTHROUGH*/ | |
375 | case S_HEX1: | |
376 | if (isxdigit(uc)) { | |
377 | *cp = xtod(uc); | |
378 | *astate = SS(0, S_HEX2); | |
379 | return UNVIS_NOCHAR; | |
9385eb3d | 380 | } |
974e3884 A |
381 | /* |
382 | * no - done with current sequence, push back passed char | |
383 | */ | |
384 | *astate = SS(0, S_GROUND); | |
385 | return UNVIS_VALIDPUSH; | |
386 | ||
387 | case S_HEX2: | |
9385eb3d | 388 | *astate = S_GROUND; |
974e3884 A |
389 | if (isxdigit(uc)) { |
390 | *cp = xtod(uc) | (*cp << 4); | |
391 | return UNVIS_VALID; | |
392 | } | |
393 | return UNVIS_VALIDPUSH; | |
394 | ||
395 | case S_MIME1: | |
396 | if (uc == '\n' || uc == '\r') { | |
397 | *astate = SS(0, S_EATCRNL); | |
398 | return UNVIS_NOCHAR; | |
399 | } | |
400 | if (isxdigit(uc) && (isdigit(uc) || isupper(uc))) { | |
401 | *cp = XTOD(uc); | |
402 | *astate = SS(0, S_MIME2); | |
403 | return UNVIS_NOCHAR; | |
404 | } | |
405 | goto bad; | |
406 | ||
407 | case S_MIME2: | |
408 | if (isxdigit(uc) && (isdigit(uc) || isupper(uc))) { | |
409 | *astate = SS(0, S_GROUND); | |
410 | *cp = XTOD(uc) | (*cp << 4); | |
411 | return UNVIS_VALID; | |
412 | } | |
413 | goto bad; | |
414 | ||
415 | case S_EATCRNL: | |
416 | switch (uc) { | |
417 | case '\r': | |
418 | case '\n': | |
419 | return UNVIS_NOCHAR; | |
420 | case '=': | |
421 | *astate = SS(0, S_MIME1); | |
422 | return UNVIS_NOCHAR; | |
423 | default: | |
424 | *cp = uc; | |
425 | *astate = SS(0, S_GROUND); | |
426 | return UNVIS_VALID; | |
427 | } | |
428 | ||
429 | case S_AMP: | |
430 | *cp = 0; | |
431 | if (uc == '#') { | |
432 | *astate = SS(0, S_NUMBER); | |
433 | return UNVIS_NOCHAR; | |
434 | } | |
435 | *astate = SS(0, S_STRING); | |
436 | /*FALLTHROUGH*/ | |
437 | ||
438 | case S_STRING: | |
439 | ia = *cp; /* index in the array */ | |
440 | is = GI(*astate); /* index in the string */ | |
441 | lc = is == 0 ? 0 : nv[ia].name[is - 1]; /* last character */ | |
442 | ||
443 | if (uc == ';') | |
444 | uc = '\0'; | |
445 | ||
446 | for (; ia < __arraycount(nv); ia++) { | |
447 | if (is != 0 && nv[ia].name[is - 1] != lc) | |
448 | goto bad; | |
449 | if (nv[ia].name[is] == uc) | |
450 | break; | |
451 | } | |
452 | ||
453 | if (ia == __arraycount(nv)) | |
454 | goto bad; | |
455 | ||
456 | if (uc != 0) { | |
457 | *cp = ia; | |
458 | *astate = SS(is + 1, S_STRING); | |
459 | return UNVIS_NOCHAR; | |
460 | } | |
461 | ||
462 | *cp = nv[ia].value; | |
463 | *astate = SS(0, S_GROUND); | |
464 | return UNVIS_VALID; | |
465 | ||
466 | case S_NUMBER: | |
467 | if (uc == ';') | |
468 | return UNVIS_VALID; | |
469 | if (!isdigit(uc)) | |
470 | goto bad; | |
471 | *cp += (*cp * 10) + uc - '0'; | |
472 | return UNVIS_NOCHAR; | |
9385eb3d A |
473 | |
474 | default: | |
974e3884 | 475 | bad: |
9385eb3d A |
476 | /* |
477 | * decoder in unknown state - (probably uninitialized) | |
e9ce8d39 | 478 | */ |
974e3884 A |
479 | *astate = SS(0, S_GROUND); |
480 | return UNVIS_SYNBAD; | |
e9ce8d39 A |
481 | } |
482 | } | |
483 | ||
484 | /* | |
974e3884 | 485 | * strnunvisx - decode src into dst |
e9ce8d39 A |
486 | * |
487 | * Number of chars decoded into dst is returned, -1 on error. | |
488 | * Dst is null terminated. | |
489 | */ | |
490 | ||
491 | int | |
974e3884 | 492 | strnunvisx(char *dst, size_t dlen, const char *src, int flag) |
e9ce8d39 | 493 | { |
9385eb3d | 494 | char c; |
974e3884 | 495 | char t = '\0', *start = dst; |
e9ce8d39 A |
496 | int state = 0; |
497 | ||
974e3884 A |
498 | _DIAGASSERT(src != NULL); |
499 | _DIAGASSERT(dst != NULL); | |
500 | #define CHECKSPACE() \ | |
501 | do { \ | |
502 | if (dlen-- == 0) { \ | |
503 | errno = ENOSPC; \ | |
504 | return -1; \ | |
505 | } \ | |
506 | } while (/*CONSTCOND*/0) | |
507 | ||
508 | while ((c = *src++) != '\0') { | |
509 | again: | |
510 | switch (unvis(&t, c, &state, flag)) { | |
e9ce8d39 | 511 | case UNVIS_VALID: |
974e3884 A |
512 | CHECKSPACE(); |
513 | *dst++ = t; | |
e9ce8d39 A |
514 | break; |
515 | case UNVIS_VALIDPUSH: | |
974e3884 A |
516 | CHECKSPACE(); |
517 | *dst++ = t; | |
e9ce8d39 A |
518 | goto again; |
519 | case 0: | |
520 | case UNVIS_NOCHAR: | |
521 | break; | |
974e3884 A |
522 | case UNVIS_SYNBAD: |
523 | errno = EINVAL; | |
524 | return -1; | |
e9ce8d39 | 525 | default: |
974e3884 A |
526 | _DIAGASSERT(/*CONSTCOND*/0); |
527 | errno = EINVAL; | |
528 | return -1; | |
e9ce8d39 A |
529 | } |
530 | } | |
974e3884 A |
531 | if (unvis(&t, c, &state, UNVIS_END) == UNVIS_VALID) { |
532 | CHECKSPACE(); | |
533 | *dst++ = t; | |
534 | } | |
535 | CHECKSPACE(); | |
e9ce8d39 | 536 | *dst = '\0'; |
974e3884 | 537 | return (int)(dst - start); |
e9ce8d39 | 538 | } |
9385eb3d A |
539 | |
540 | int | |
3d9156a7 | 541 | strunvisx(char *dst, const char *src, int flag) |
9385eb3d | 542 | { |
974e3884 A |
543 | return strnunvisx(dst, (size_t)~0, src, flag); |
544 | } | |
545 | ||
546 | int | |
547 | strunvis(char *dst, const char *src) | |
548 | { | |
549 | return strnunvisx(dst, (size_t)~0, src, 0); | |
550 | } | |
551 | ||
552 | int | |
553 | strnunvis(char *dst, size_t dlen, const char *src) | |
554 | { | |
555 | return strnunvisx(dst, dlen, src, 0); | |
9385eb3d | 556 | } |
974e3884 | 557 | #endif |