guest_sprintf.c 6.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314
  1. // SPDX-License-Identifier: GPL-2.0-only
  2. #include "test_util.h"
  3. #include "kvm_util.h"
  4. #include "ucall_common.h"
  5. #define APPEND_BUFFER_SAFE(str, end, v) \
  6. do { \
  7. GUEST_ASSERT(str < end); \
  8. *str++ = (v); \
  9. } while (0)
  10. static int isdigit(int ch)
  11. {
  12. return (ch >= '0') && (ch <= '9');
  13. }
  14. static int skip_atoi(const char **s)
  15. {
  16. int i = 0;
  17. while (isdigit(**s))
  18. i = i * 10 + *((*s)++) - '0';
  19. return i;
  20. }
  21. #define ZEROPAD 1 /* pad with zero */
  22. #define SIGN 2 /* unsigned/signed long */
  23. #define PLUS 4 /* show plus */
  24. #define SPACE 8 /* space if plus */
  25. #define LEFT 16 /* left justified */
  26. #define SMALL 32 /* Must be 32 == 0x20 */
  27. #define SPECIAL 64 /* 0x */
  28. #define __do_div(n, base) \
  29. ({ \
  30. int __res; \
  31. \
  32. __res = ((uint64_t) n) % (uint32_t) base; \
  33. n = ((uint64_t) n) / (uint32_t) base; \
  34. __res; \
  35. })
  36. static char *number(char *str, const char *end, long num, int base, int size,
  37. int precision, int type)
  38. {
  39. /* we are called with base 8, 10 or 16, only, thus don't need "G..." */
  40. static const char digits[16] = "0123456789ABCDEF"; /* "GHIJKLMNOPQRSTUVWXYZ"; */
  41. char tmp[66];
  42. char c, sign, locase;
  43. int i;
  44. /*
  45. * locase = 0 or 0x20. ORing digits or letters with 'locase'
  46. * produces same digits or (maybe lowercased) letters
  47. */
  48. locase = (type & SMALL);
  49. if (type & LEFT)
  50. type &= ~ZEROPAD;
  51. if (base < 2 || base > 16)
  52. return NULL;
  53. c = (type & ZEROPAD) ? '0' : ' ';
  54. sign = 0;
  55. if (type & SIGN) {
  56. if (num < 0) {
  57. sign = '-';
  58. num = -num;
  59. size--;
  60. } else if (type & PLUS) {
  61. sign = '+';
  62. size--;
  63. } else if (type & SPACE) {
  64. sign = ' ';
  65. size--;
  66. }
  67. }
  68. if (type & SPECIAL) {
  69. if (base == 16)
  70. size -= 2;
  71. else if (base == 8)
  72. size--;
  73. }
  74. i = 0;
  75. if (num == 0)
  76. tmp[i++] = '0';
  77. else
  78. while (num != 0)
  79. tmp[i++] = (digits[__do_div(num, base)] | locase);
  80. if (i > precision)
  81. precision = i;
  82. size -= precision;
  83. if (!(type & (ZEROPAD + LEFT)))
  84. while (size-- > 0)
  85. APPEND_BUFFER_SAFE(str, end, ' ');
  86. if (sign)
  87. APPEND_BUFFER_SAFE(str, end, sign);
  88. if (type & SPECIAL) {
  89. if (base == 8)
  90. APPEND_BUFFER_SAFE(str, end, '0');
  91. else if (base == 16) {
  92. APPEND_BUFFER_SAFE(str, end, '0');
  93. APPEND_BUFFER_SAFE(str, end, 'x');
  94. }
  95. }
  96. if (!(type & LEFT))
  97. while (size-- > 0)
  98. APPEND_BUFFER_SAFE(str, end, c);
  99. while (i < precision--)
  100. APPEND_BUFFER_SAFE(str, end, '0');
  101. while (i-- > 0)
  102. APPEND_BUFFER_SAFE(str, end, tmp[i]);
  103. while (size-- > 0)
  104. APPEND_BUFFER_SAFE(str, end, ' ');
  105. return str;
  106. }
  107. int guest_vsnprintf(char *buf, int n, const char *fmt, va_list args)
  108. {
  109. char *str, *end;
  110. const char *s;
  111. uint64_t num;
  112. int i, base;
  113. int len;
  114. int flags; /* flags to number() */
  115. int field_width; /* width of output field */
  116. int precision; /*
  117. * min. # of digits for integers; max
  118. * number of chars for from string
  119. */
  120. int qualifier; /* 'h', 'l', or 'L' for integer fields */
  121. end = buf + n;
  122. GUEST_ASSERT(buf < end);
  123. GUEST_ASSERT(n > 0);
  124. for (str = buf; *fmt; ++fmt) {
  125. if (*fmt != '%') {
  126. APPEND_BUFFER_SAFE(str, end, *fmt);
  127. continue;
  128. }
  129. /* process flags */
  130. flags = 0;
  131. repeat:
  132. ++fmt; /* this also skips first '%' */
  133. switch (*fmt) {
  134. case '-':
  135. flags |= LEFT;
  136. goto repeat;
  137. case '+':
  138. flags |= PLUS;
  139. goto repeat;
  140. case ' ':
  141. flags |= SPACE;
  142. goto repeat;
  143. case '#':
  144. flags |= SPECIAL;
  145. goto repeat;
  146. case '0':
  147. flags |= ZEROPAD;
  148. goto repeat;
  149. }
  150. /* get field width */
  151. field_width = -1;
  152. if (isdigit(*fmt))
  153. field_width = skip_atoi(&fmt);
  154. else if (*fmt == '*') {
  155. ++fmt;
  156. /* it's the next argument */
  157. field_width = va_arg(args, int);
  158. if (field_width < 0) {
  159. field_width = -field_width;
  160. flags |= LEFT;
  161. }
  162. }
  163. /* get the precision */
  164. precision = -1;
  165. if (*fmt == '.') {
  166. ++fmt;
  167. if (isdigit(*fmt))
  168. precision = skip_atoi(&fmt);
  169. else if (*fmt == '*') {
  170. ++fmt;
  171. /* it's the next argument */
  172. precision = va_arg(args, int);
  173. }
  174. if (precision < 0)
  175. precision = 0;
  176. }
  177. /* get the conversion qualifier */
  178. qualifier = -1;
  179. if (*fmt == 'h' || *fmt == 'l' || *fmt == 'L') {
  180. qualifier = *fmt;
  181. ++fmt;
  182. }
  183. /*
  184. * Play nice with %llu, %llx, etc. KVM selftests only support
  185. * 64-bit builds, so just treat %ll* the same as %l*.
  186. */
  187. if (qualifier == 'l' && *fmt == 'l')
  188. ++fmt;
  189. /* default base */
  190. base = 10;
  191. switch (*fmt) {
  192. case 'c':
  193. if (!(flags & LEFT))
  194. while (--field_width > 0)
  195. APPEND_BUFFER_SAFE(str, end, ' ');
  196. APPEND_BUFFER_SAFE(str, end,
  197. (uint8_t)va_arg(args, int));
  198. while (--field_width > 0)
  199. APPEND_BUFFER_SAFE(str, end, ' ');
  200. continue;
  201. case 's':
  202. s = va_arg(args, char *);
  203. len = strnlen(s, precision);
  204. if (!(flags & LEFT))
  205. while (len < field_width--)
  206. APPEND_BUFFER_SAFE(str, end, ' ');
  207. for (i = 0; i < len; ++i)
  208. APPEND_BUFFER_SAFE(str, end, *s++);
  209. while (len < field_width--)
  210. APPEND_BUFFER_SAFE(str, end, ' ');
  211. continue;
  212. case 'p':
  213. if (field_width == -1) {
  214. field_width = 2 * sizeof(void *);
  215. flags |= SPECIAL | SMALL | ZEROPAD;
  216. }
  217. str = number(str, end,
  218. (uint64_t)va_arg(args, void *), 16,
  219. field_width, precision, flags);
  220. continue;
  221. case 'n':
  222. if (qualifier == 'l') {
  223. long *ip = va_arg(args, long *);
  224. *ip = (str - buf);
  225. } else {
  226. int *ip = va_arg(args, int *);
  227. *ip = (str - buf);
  228. }
  229. continue;
  230. case '%':
  231. APPEND_BUFFER_SAFE(str, end, '%');
  232. continue;
  233. /* integer number formats - set up the flags and "break" */
  234. case 'o':
  235. base = 8;
  236. break;
  237. case 'x':
  238. flags |= SMALL;
  239. case 'X':
  240. base = 16;
  241. break;
  242. case 'd':
  243. case 'i':
  244. flags |= SIGN;
  245. case 'u':
  246. break;
  247. default:
  248. APPEND_BUFFER_SAFE(str, end, '%');
  249. if (*fmt)
  250. APPEND_BUFFER_SAFE(str, end, *fmt);
  251. else
  252. --fmt;
  253. continue;
  254. }
  255. if (qualifier == 'l')
  256. num = va_arg(args, uint64_t);
  257. else if (qualifier == 'h') {
  258. num = (uint16_t)va_arg(args, int);
  259. if (flags & SIGN)
  260. num = (int16_t)num;
  261. } else if (flags & SIGN)
  262. num = va_arg(args, int);
  263. else
  264. num = va_arg(args, uint32_t);
  265. str = number(str, end, num, base, field_width, precision, flags);
  266. }
  267. GUEST_ASSERT(str < end);
  268. *str = '\0';
  269. return str - buf;
  270. }
  271. int guest_snprintf(char *buf, int n, const char *fmt, ...)
  272. {
  273. va_list va;
  274. int len;
  275. va_start(va, fmt);
  276. len = guest_vsnprintf(buf, n, fmt, va);
  277. va_end(va);
  278. return len;
  279. }