unvis.c 7.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322
  1. /* $NetBSD: unvis.c,v 1.22 2002/03/23 17:38:27 christos Exp $ */
  2. /*-
  3. * Copyright (c) 1989, 1993
  4. * The Regents of the University of California. All rights reserved.
  5. *
  6. * Redistribution and use in source and binary forms, with or without
  7. * modification, are permitted provided that the following conditions
  8. * are met:
  9. * 1. Redistributions of source code must retain the above copyright
  10. * notice, this list of conditions and the following disclaimer.
  11. * 2. Redistributions in binary form must reproduce the above copyright
  12. * notice, this list of conditions and the following disclaimer in the
  13. * documentation and/or other materials provided with the distribution.
  14. * 3. All advertising materials mentioning features or use of this software
  15. * must display the following acknowledgement:
  16. * This product includes software developed by the University of
  17. * California, Berkeley and its contributors.
  18. * 4. Neither the name of the University nor the names of its contributors
  19. * may be used to endorse or promote products derived from this software
  20. * without specific prior written permission.
  21. *
  22. * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
  23. * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  24. * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  25. * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
  26. * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  27. * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  28. * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  29. * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  30. * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  31. * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  32. * SUCH DAMAGE.
  33. */
  34. #include <sys/cdefs.h>
  35. #if defined(LIBC_SCCS) && !defined(lint)
  36. #if 0
  37. static char sccsid[] = "@(#)unvis.c 8.1 (Berkeley) 6/4/93";
  38. #else
  39. __RCSID("$NetBSD: unvis.c,v 1.22 2002/03/23 17:38:27 christos Exp $");
  40. #endif
  41. #endif /* LIBC_SCCS and not lint */
  42. #define __LIBC12_SOURCE__
  43. #include <sys/types.h>
  44. #include <assert.h>
  45. #include <ctype.h>
  46. #include <stdio.h>
  47. #include "np/vis.h"
  48. #ifdef __weak_alias
  49. __weak_alias(strunvis,_strunvis)
  50. __weak_alias(unvis,_unvis)
  51. #endif
  52. #ifdef __warn_references
  53. __warn_references(unvis,
  54. "warning: reference to compatibility unvis(); include <vis.h> for correct reference")
  55. #endif
  56. #ifndef HAVE_VIS_H
  57. /*
  58. * decode driven by state machine
  59. */
  60. #define S_GROUND 0 /* haven't seen escape char */
  61. #define S_START 1 /* start decoding special sequence */
  62. #define S_META 2 /* metachar started (M) */
  63. #define S_META1 3 /* metachar more, regular char (-) */
  64. #define S_CTRL 4 /* control char started (^) */
  65. #define S_OCTAL2 5 /* octal digit 2 */
  66. #define S_OCTAL3 6 /* octal digit 3 */
  67. #define S_HEX1 7 /* hex digit */
  68. #define S_HEX2 8 /* hex digit 2 */
  69. #define isoctal(c) (((u_char)(c)) >= '0' && ((u_char)(c)) <= '7')
  70. #define xtod(c) (isdigit(c) ? (c - '0') : ((tolower(c) - 'a') + 10))
  71. int
  72. unvis(cp, c, astate, flag)
  73. char *cp;
  74. int c;
  75. int *astate, flag;
  76. {
  77. return __unvis13(cp, (int)c, astate, flag);
  78. }
  79. /*
  80. * unvis - decode characters previously encoded by vis
  81. */
  82. int
  83. __unvis13(cp, c, astate, flag)
  84. char *cp;
  85. int c;
  86. int *astate, flag;
  87. {
  88. _DIAGASSERT(cp != NULL);
  89. _DIAGASSERT(astate != NULL);
  90. if (flag & UNVIS_END) {
  91. if (*astate == S_OCTAL2 || *astate == S_OCTAL3
  92. || *astate == S_HEX2) {
  93. *astate = S_GROUND;
  94. return (UNVIS_VALID);
  95. }
  96. return (*astate == S_GROUND ? UNVIS_NOCHAR : UNVIS_SYNBAD);
  97. }
  98. switch (*astate) {
  99. case S_GROUND:
  100. *cp = 0;
  101. if (c == '\\') {
  102. *astate = S_START;
  103. return (0);
  104. }
  105. if ((flag & VIS_HTTPSTYLE) && c == '%') {
  106. *astate = S_HEX1;
  107. return (0);
  108. }
  109. *cp = c;
  110. return (UNVIS_VALID);
  111. case S_START:
  112. switch(c) {
  113. case '\\':
  114. *cp = c;
  115. *astate = S_GROUND;
  116. return (UNVIS_VALID);
  117. case '0': case '1': case '2': case '3':
  118. case '4': case '5': case '6': case '7':
  119. *cp = (c - '0');
  120. *astate = S_OCTAL2;
  121. return (0);
  122. case 'M':
  123. *cp = (char)0200;
  124. *astate = S_META;
  125. return (0);
  126. case '^':
  127. *astate = S_CTRL;
  128. return (0);
  129. case 'n':
  130. *cp = '\n';
  131. *astate = S_GROUND;
  132. return (UNVIS_VALID);
  133. case 'r':
  134. *cp = '\r';
  135. *astate = S_GROUND;
  136. return (UNVIS_VALID);
  137. case 'b':
  138. *cp = '\b';
  139. *astate = S_GROUND;
  140. return (UNVIS_VALID);
  141. case 'a':
  142. *cp = '\007';
  143. *astate = S_GROUND;
  144. return (UNVIS_VALID);
  145. case 'v':
  146. *cp = '\v';
  147. *astate = S_GROUND;
  148. return (UNVIS_VALID);
  149. case 't':
  150. *cp = '\t';
  151. *astate = S_GROUND;
  152. return (UNVIS_VALID);
  153. case 'f':
  154. *cp = '\f';
  155. *astate = S_GROUND;
  156. return (UNVIS_VALID);
  157. case 's':
  158. *cp = ' ';
  159. *astate = S_GROUND;
  160. return (UNVIS_VALID);
  161. case 'E':
  162. *cp = '\033';
  163. *astate = S_GROUND;
  164. return (UNVIS_VALID);
  165. case '\n':
  166. /*
  167. * hidden newline
  168. */
  169. *astate = S_GROUND;
  170. return (UNVIS_NOCHAR);
  171. case '$':
  172. /*
  173. * hidden marker
  174. */
  175. *astate = S_GROUND;
  176. return (UNVIS_NOCHAR);
  177. }
  178. *astate = S_GROUND;
  179. return (UNVIS_SYNBAD);
  180. case S_META:
  181. if (c == '-')
  182. *astate = S_META1;
  183. else if (c == '^')
  184. *astate = S_CTRL;
  185. else {
  186. *astate = S_GROUND;
  187. return (UNVIS_SYNBAD);
  188. }
  189. return (0);
  190. case S_META1:
  191. *astate = S_GROUND;
  192. *cp |= c;
  193. return (UNVIS_VALID);
  194. case S_CTRL:
  195. if (c == '?')
  196. *cp |= 0177;
  197. else
  198. *cp |= c & 037;
  199. *astate = S_GROUND;
  200. return (UNVIS_VALID);
  201. case S_OCTAL2: /* second possible octal digit */
  202. if (isoctal(c)) {
  203. /*
  204. * yes - and maybe a third
  205. */
  206. *cp = (*cp << 3) + (c - '0');
  207. *astate = S_OCTAL3;
  208. return (0);
  209. }
  210. /*
  211. * no - done with current sequence, push back passed char
  212. */
  213. *astate = S_GROUND;
  214. return (UNVIS_VALIDPUSH);
  215. case S_OCTAL3: /* third possible octal digit */
  216. *astate = S_GROUND;
  217. if (isoctal(c)) {
  218. *cp = (*cp << 3) + (c - '0');
  219. return (UNVIS_VALID);
  220. }
  221. /*
  222. * we were done, push back passed char
  223. */
  224. return (UNVIS_VALIDPUSH);
  225. case S_HEX1:
  226. if (isxdigit(c)) {
  227. *cp = xtod(c);
  228. *astate = S_HEX2;
  229. return (0);
  230. }
  231. /*
  232. * no - done with current sequence, push back passed char
  233. */
  234. *astate = S_GROUND;
  235. return (UNVIS_VALIDPUSH);
  236. case S_HEX2:
  237. *astate = S_GROUND;
  238. if (isxdigit(c)) {
  239. *cp = xtod(c) | (*cp << 4);
  240. return (UNVIS_VALID);
  241. }
  242. return (UNVIS_VALIDPUSH);
  243. default:
  244. /*
  245. * decoder in unknown state - (probably uninitialized)
  246. */
  247. *astate = S_GROUND;
  248. return (UNVIS_SYNBAD);
  249. }
  250. }
  251. /*
  252. * strunvis - decode src into dst
  253. *
  254. * Number of chars decoded into dst is returned, -1 on error.
  255. * Dst is null terminated.
  256. */
  257. int
  258. strunvisx(dst, src, flag)
  259. char *dst;
  260. const char *src;
  261. int flag;
  262. {
  263. char c;
  264. char *start = dst;
  265. int state = 0;
  266. _DIAGASSERT(src != NULL);
  267. _DIAGASSERT(dst != NULL);
  268. while ((c = *src++) != '\0') {
  269. again:
  270. switch (__unvis13(dst, c, &state, flag)) {
  271. case UNVIS_VALID:
  272. dst++;
  273. break;
  274. case UNVIS_VALIDPUSH:
  275. dst++;
  276. goto again;
  277. case 0:
  278. case UNVIS_NOCHAR:
  279. break;
  280. default:
  281. return (-1);
  282. }
  283. }
  284. if (__unvis13(dst, c, &state, UNVIS_END) == UNVIS_VALID)
  285. dst++;
  286. *dst = '\0';
  287. return (dst - start);
  288. }
  289. int
  290. strunvis(dst, src)
  291. char *dst;
  292. const char *src;
  293. {
  294. return strunvisx(dst, src, 0);
  295. }
  296. #endif