unvis.c 6.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281
  1. /* $OpenBSD: unvis.c,v 1.12 2005/08/08 08:05:34 espie 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. Neither the name of the University nor the names of its contributors
  15. * may be used to endorse or promote products derived from this software
  16. * without specific prior written permission.
  17. *
  18. * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
  19. * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  20. * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  21. * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
  22. * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  23. * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  24. * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  25. * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  26. * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  27. * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  28. * SUCH DAMAGE.
  29. */
  30. #include <sys/types.h>
  31. #include <ctype.h>
  32. #include "tmux.h"
  33. /*
  34. * decode driven by state machine
  35. */
  36. #define S_GROUND 0 /* haven't seen escape char */
  37. #define S_START 1 /* start decoding special sequence */
  38. #define S_META 2 /* metachar started (M) */
  39. #define S_META1 3 /* metachar more, regular char (-) */
  40. #define S_CTRL 4 /* control char started (^) */
  41. #define S_OCTAL2 5 /* octal digit 2 */
  42. #define S_OCTAL3 6 /* octal digit 3 */
  43. #define isoctal(c) (((u_char)(c)) >= '0' && ((u_char)(c)) <= '7')
  44. /*
  45. * unvis - decode characters previously encoded by vis
  46. */
  47. int
  48. unvis(char *cp, char c, int *astate, int flag)
  49. {
  50. if (flag & UNVIS_END) {
  51. if (*astate == S_OCTAL2 || *astate == S_OCTAL3) {
  52. *astate = S_GROUND;
  53. return (UNVIS_VALID);
  54. }
  55. return (*astate == S_GROUND ? UNVIS_NOCHAR : UNVIS_SYNBAD);
  56. }
  57. switch (*astate) {
  58. case S_GROUND:
  59. *cp = 0;
  60. if (c == '\\') {
  61. *astate = S_START;
  62. return (0);
  63. }
  64. *cp = c;
  65. return (UNVIS_VALID);
  66. case S_START:
  67. switch(c) {
  68. case '\\':
  69. *cp = c;
  70. *astate = S_GROUND;
  71. return (UNVIS_VALID);
  72. case '0': case '1': case '2': case '3':
  73. case '4': case '5': case '6': case '7':
  74. *cp = (c - '0');
  75. *astate = S_OCTAL2;
  76. return (0);
  77. case 'M':
  78. *cp = (char) 0200;
  79. *astate = S_META;
  80. return (0);
  81. case '^':
  82. *astate = S_CTRL;
  83. return (0);
  84. case 'n':
  85. *cp = '\n';
  86. *astate = S_GROUND;
  87. return (UNVIS_VALID);
  88. case 'r':
  89. *cp = '\r';
  90. *astate = S_GROUND;
  91. return (UNVIS_VALID);
  92. case 'b':
  93. *cp = '\b';
  94. *astate = S_GROUND;
  95. return (UNVIS_VALID);
  96. case 'a':
  97. *cp = '\007';
  98. *astate = S_GROUND;
  99. return (UNVIS_VALID);
  100. case 'v':
  101. *cp = '\v';
  102. *astate = S_GROUND;
  103. return (UNVIS_VALID);
  104. case 't':
  105. *cp = '\t';
  106. *astate = S_GROUND;
  107. return (UNVIS_VALID);
  108. case 'f':
  109. *cp = '\f';
  110. *astate = S_GROUND;
  111. return (UNVIS_VALID);
  112. case 's':
  113. *cp = ' ';
  114. *astate = S_GROUND;
  115. return (UNVIS_VALID);
  116. case 'E':
  117. *cp = '\033';
  118. *astate = S_GROUND;
  119. return (UNVIS_VALID);
  120. case '\n':
  121. /*
  122. * hidden newline
  123. */
  124. *astate = S_GROUND;
  125. return (UNVIS_NOCHAR);
  126. case '$':
  127. /*
  128. * hidden marker
  129. */
  130. *astate = S_GROUND;
  131. return (UNVIS_NOCHAR);
  132. }
  133. *astate = S_GROUND;
  134. return (UNVIS_SYNBAD);
  135. case S_META:
  136. if (c == '-')
  137. *astate = S_META1;
  138. else if (c == '^')
  139. *astate = S_CTRL;
  140. else {
  141. *astate = S_GROUND;
  142. return (UNVIS_SYNBAD);
  143. }
  144. return (0);
  145. case S_META1:
  146. *astate = S_GROUND;
  147. *cp |= c;
  148. return (UNVIS_VALID);
  149. case S_CTRL:
  150. if (c == '?')
  151. *cp |= 0177;
  152. else
  153. *cp |= c & 037;
  154. *astate = S_GROUND;
  155. return (UNVIS_VALID);
  156. case S_OCTAL2: /* second possible octal digit */
  157. if (isoctal(c)) {
  158. /*
  159. * yes - and maybe a third
  160. */
  161. *cp = (*cp << 3) + (c - '0');
  162. *astate = S_OCTAL3;
  163. return (0);
  164. }
  165. /*
  166. * no - done with current sequence, push back passed char
  167. */
  168. *astate = S_GROUND;
  169. return (UNVIS_VALIDPUSH);
  170. case S_OCTAL3: /* third possible octal digit */
  171. *astate = S_GROUND;
  172. if (isoctal(c)) {
  173. *cp = (*cp << 3) + (c - '0');
  174. return (UNVIS_VALID);
  175. }
  176. /*
  177. * we were done, push back passed char
  178. */
  179. return (UNVIS_VALIDPUSH);
  180. default:
  181. /*
  182. * decoder in unknown state - (probably uninitialized)
  183. */
  184. *astate = S_GROUND;
  185. return (UNVIS_SYNBAD);
  186. }
  187. }
  188. /*
  189. * strunvis - decode src into dst
  190. *
  191. * Number of chars decoded into dst is returned, -1 on error.
  192. * Dst is null terminated.
  193. */
  194. int
  195. strunvis(char *dst, const char *src)
  196. {
  197. char c;
  198. char *start = dst;
  199. int state = 0;
  200. while ((c = *src++)) {
  201. again:
  202. switch (unvis(dst, c, &state, 0)) {
  203. case UNVIS_VALID:
  204. dst++;
  205. break;
  206. case UNVIS_VALIDPUSH:
  207. dst++;
  208. goto again;
  209. case 0:
  210. case UNVIS_NOCHAR:
  211. break;
  212. default:
  213. *dst = '\0';
  214. return (-1);
  215. }
  216. }
  217. if (unvis(dst, c, &state, UNVIS_END) == UNVIS_VALID)
  218. dst++;
  219. *dst = '\0';
  220. return (dst - start);
  221. }
  222. ssize_t
  223. strnunvis(char *dst, const char *src, size_t sz)
  224. {
  225. char c, p;
  226. char *start = dst, *end = dst + sz - 1;
  227. int state = 0;
  228. if (sz > 0)
  229. *end = '\0';
  230. while ((c = *src++)) {
  231. again:
  232. switch (unvis(&p, c, &state, 0)) {
  233. case UNVIS_VALID:
  234. if (dst < end)
  235. *dst = p;
  236. dst++;
  237. break;
  238. case UNVIS_VALIDPUSH:
  239. if (dst < end)
  240. *dst = p;
  241. dst++;
  242. goto again;
  243. case 0:
  244. case UNVIS_NOCHAR:
  245. break;
  246. default:
  247. if (dst <= end)
  248. *dst = '\0';
  249. return (-1);
  250. }
  251. }
  252. if (unvis(&p, c, &state, UNVIS_END) == UNVIS_VALID) {
  253. if (dst < end)
  254. *dst = p;
  255. dst++;
  256. }
  257. if (dst <= end)
  258. *dst = '\0';
  259. return (dst - start);
  260. }