vis.c 9.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297
  1. /*
  2. * Copyright (C) 2013 by egnite GmbH
  3. * Copyright (c) 1989, 1993 The Regents of the University of California
  4. *
  5. * 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. *
  11. * 1. Redistributions of source code must retain the above copyright
  12. * notice, this list of conditions and the following disclaimer.
  13. * 2. Redistributions in binary form must reproduce the above copyright
  14. * notice, this list of conditions and the following disclaimer in the
  15. * documentation and/or other materials provided with the distribution.
  16. * 3. Neither the name of the copyright holders nor the names of
  17. * contributors may be used to endorse or promote products derived
  18. * from this software without specific prior written permission.
  19. *
  20. * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  21. * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  22. * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
  23. * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
  24. * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
  25. * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
  26. * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
  27. * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
  28. * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
  29. * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
  30. * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  31. * SUCH DAMAGE.
  32. *
  33. * For additional information see http://www.ethernut.de/
  34. */
  35. #include <sys/types.h>
  36. #include <limits.h>
  37. #include <ctype.h>
  38. #include <string.h>
  39. #include <vis.h>
  40. #define isoctal(c) (((u_char)(c)) >= '0' && ((u_char)(c)) <= '7')
  41. #define isvisible(c) \
  42. (((u_int)(c) <= UCHAR_MAX && isascii((u_char)(c)) && \
  43. (((c) != '*' && (c) != '?' && (c) != '[' && (c) != '#') || \
  44. (flag & VIS_GLOB) == 0) && isgraph((u_char)(c))) || \
  45. ((flag & VIS_SP) == 0 && (c) == ' ') || \
  46. ((flag & VIS_TAB) == 0 && (c) == '\t') || \
  47. ((flag & VIS_NL) == 0 && (c) == '\n') || \
  48. ((flag & VIS_SAFE) && ((c) == '\b' || \
  49. (c) == '\007' || (c) == '\r' || \
  50. isgraph((u_char)(c)))))
  51. /*!
  52. * \brief Visually encode a single character.
  53. *
  54. * This function copies into dst a string which represents the character c.
  55. * If c needs no encoding, it is copied in unaltered. The string is null
  56. * terminated and the maximum length of any encoding is four characters.
  57. *
  58. * \param dst Pointer to a buffer that receives the encoded string.
  59. * At least 5 bytes of buffer space should be available.
  60. * \param c The character to be encoded.
  61. * \param flag Used for altering the default range of characters considered
  62. * for encoding and for altering the visual representation.
  63. * The following range flags are supported:
  64. *
  65. * - VIS_GLOB Also encodes '*', '?', '[' and '#'.
  66. * - VIS_SP Also encodes space.
  67. * - VIS_TAB Also encodes tab.
  68. * - VIS_NL Also encodes newline.
  69. * - VIS_WHITE Same as VIS_SP | VIS_TAB | VIS_NL.
  70. * - VIS_SAFE Only encodes "unsafe" characters, which may
  71. * cause unexpected functions in terminal emulators.
  72. *
  73. * The following flags specify the visual format:
  74. *
  75. * - VIS_CSTYLE Use C-style backslash sequences.
  76. * - VIS_HTTPSTYLE Use URI encoding as described in RFC1808.
  77. * - VIS_OCTAL Use 3 digit octal sequences.
  78. *
  79. * In addition, the flag VIS_NOSLASH can be used to inhibit
  80. * the doubling of backslashes.
  81. * \param nextc Only used when selecting the VIS_CSTYLE encoding format.
  82. *
  83. * \return Pointer to the end of the destination string.
  84. */
  85. char *vis(char *dst, int c, int flag, int nextc)
  86. {
  87. static char *hex = "0123456789abcdef";
  88. if (flag & VIS_HTTPSTYLE) {
  89. /* Described in RFC 1808 */
  90. if (!(isalnum(c) /* alpha-numeric */
  91. /* safe */
  92. || c == '$' || c == '-' || c == '_' || c == '.' || c == '+'
  93. /* extra */
  94. || c == '!' || c == '*' || c == '\'' || c == '('
  95. || c == ')' || c == ',')) {
  96. *dst++ = '%';
  97. *dst++ = hex[((unsigned int) c >> 4) & 0xf];
  98. *dst++ = hex[(unsigned int) c & 0xf];
  99. goto done;
  100. }
  101. }
  102. if (isvisible(c)) {
  103. *dst++ = c;
  104. if (c == '\\' && (flag & VIS_NOSLASH) == 0)
  105. *dst++ = '\\';
  106. *dst = '\0';
  107. return dst;
  108. }
  109. if (flag & VIS_CSTYLE) {
  110. switch (c) {
  111. case '\n':
  112. *dst++ = '\\';
  113. *dst++ = 'n';
  114. goto done;
  115. case '\r':
  116. *dst++ = '\\';
  117. *dst++ = 'r';
  118. goto done;
  119. case '\b':
  120. *dst++ = '\\';
  121. *dst++ = 'b';
  122. goto done;
  123. case '\a':
  124. *dst++ = '\\';
  125. *dst++ = 'a';
  126. goto done;
  127. case '\v':
  128. *dst++ = '\\';
  129. *dst++ = 'v';
  130. goto done;
  131. case '\t':
  132. *dst++ = '\\';
  133. *dst++ = 't';
  134. goto done;
  135. case '\f':
  136. *dst++ = '\\';
  137. *dst++ = 'f';
  138. goto done;
  139. case ' ':
  140. *dst++ = '\\';
  141. *dst++ = 's';
  142. goto done;
  143. case '\0':
  144. *dst++ = '\\';
  145. *dst++ = '0';
  146. if (isoctal(nextc)) {
  147. *dst++ = '0';
  148. *dst++ = '0';
  149. }
  150. goto done;
  151. }
  152. }
  153. if (((c & 0177) == ' ') || (flag & VIS_OCTAL) ||
  154. ((flag & VIS_GLOB)
  155. && (c == '*' || c == '?' || c == '[' || c == '#'))) {
  156. *dst++ = '\\';
  157. *dst++ = ((u_char) c >> 6 & 07) + '0';
  158. *dst++ = ((u_char) c >> 3 & 07) + '0';
  159. *dst++ = ((u_char) c & 07) + '0';
  160. goto done;
  161. }
  162. if ((flag & VIS_NOSLASH) == 0)
  163. *dst++ = '\\';
  164. if (c & 0200) {
  165. c &= 0177;
  166. *dst++ = 'M';
  167. }
  168. if (iscntrl((u_char) c)) {
  169. *dst++ = '^';
  170. if (c == 0177)
  171. *dst++ = '?';
  172. else
  173. *dst++ = c + '@';
  174. } else {
  175. *dst++ = '-';
  176. *dst++ = c;
  177. }
  178. done:
  179. *dst = '\0';
  180. return dst;
  181. }
  182. /*!
  183. * \brief Visually encode a string.
  184. *
  185. * \param dst Pointer to a buffer that receives the encoded string.
  186. * The size of this buffer must be at least four times the
  187. * number of characters encoded, plus one for the string
  188. * terminator.
  189. * \param src The string to be encoded.
  190. * \param flag Used for altering the range of characters and the visual
  191. * representation, see vis().
  192. *
  193. * \return The length of the resulting string.
  194. */
  195. int strvis(char *dst, const char *src, int flag)
  196. {
  197. char c;
  198. char *start;
  199. for (start = dst; (c = *src);)
  200. dst = vis(dst, c, flag, *++src);
  201. *dst = '\0';
  202. return dst - start;
  203. }
  204. /*!
  205. * \brief Visually encode a string up to a maximum number of characters.
  206. *
  207. * \param dst Pointer to a buffer that receives the encoded string.
  208. * \param src Pointer to the buffer to be encoded.
  209. * \param siz The size of the destination buffer.
  210. * \param flag Used for altering the range of characters and the visual
  211. * representation, see vis().
  212. *
  213. * \return The length of the resulting string.
  214. */
  215. int strnvis(char *dst, const char *src, size_t siz, int flag)
  216. {
  217. char *start, *end;
  218. char tbuf[5];
  219. int c, i;
  220. i = 0;
  221. for (start = dst, end = start + siz - 1; (c = *src) && dst < end;) {
  222. if (isvisible(c)) {
  223. i = 1;
  224. *dst++ = c;
  225. if (c == '\\' && (flag & VIS_NOSLASH) == 0) {
  226. /* need space for the extra '\\' */
  227. if (dst < end)
  228. *dst++ = '\\';
  229. else {
  230. dst--;
  231. i = 2;
  232. break;
  233. }
  234. }
  235. src++;
  236. } else {
  237. i = vis(tbuf, c, flag, *++src) - tbuf;
  238. if (dst + i <= end) {
  239. memcpy(dst, tbuf, i);
  240. dst += i;
  241. } else {
  242. src--;
  243. break;
  244. }
  245. }
  246. }
  247. if (siz > 0)
  248. *dst = '\0';
  249. if (dst + i > end) {
  250. /* adjust return value for truncation */
  251. while ((c = *src))
  252. dst += vis(tbuf, c, flag, *++src) - tbuf;
  253. }
  254. return dst - start;
  255. }
  256. /*!
  257. * \brief Visually encode a buffer.
  258. *
  259. * This function is useful for encoding a block of data that may contain
  260. * NULs.
  261. *
  262. * \param dst Pointer to a buffer that receives the encoded string.
  263. * The size of this buffer must be at least four times the
  264. * number of characters encoded, plus one for the string
  265. * terminator.
  266. * \param src The buffer to encode.
  267. * \param len The number of characters to encode.
  268. * \param flag Used for altering the range of characters and the visual
  269. * representation, see vis().
  270. *
  271. * \return The length of the resulting string.
  272. */
  273. int strvisx(char *dst, const char *src, size_t len, int flag)
  274. {
  275. char c;
  276. char *start;
  277. for (start = dst; len > 1; len--) {
  278. c = *src;
  279. dst = vis(dst, c, flag, *++src);
  280. }
  281. if (len)
  282. dst = vis(dst, *src, flag, '\0');
  283. *dst = '\0';
  284. return dst - start;
  285. }