mpprint.c 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576
  1. /*
  2. * This file is part of the MicroPython project, http://micropython.org/
  3. *
  4. * The MIT License (MIT)
  5. *
  6. * Copyright (c) 2013-2015 Damien P. George
  7. *
  8. * Permission is hereby granted, free of charge, to any person obtaining a copy
  9. * of this software and associated documentation files (the "Software"), to deal
  10. * in the Software without restriction, including without limitation the rights
  11. * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  12. * copies of the Software, and to permit persons to whom the Software is
  13. * furnished to do so, subject to the following conditions:
  14. *
  15. * The above copyright notice and this permission notice shall be included in
  16. * all copies or substantial portions of the Software.
  17. *
  18. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  19. * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  20. * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  21. * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  22. * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  23. * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  24. * THE SOFTWARE.
  25. */
  26. #include <assert.h>
  27. #include <stdarg.h>
  28. #include <stdint.h>
  29. #include <stdio.h>
  30. #include <string.h>
  31. #include "py/mphal.h"
  32. #include "py/mpprint.h"
  33. #include "py/obj.h"
  34. #include "py/objint.h"
  35. #include "py/runtime.h"
  36. #if MICROPY_PY_BUILTINS_FLOAT
  37. #include "py/formatfloat.h"
  38. #endif
  39. static const char pad_spaces[] = " ";
  40. static const char pad_zeroes[] = "0000000000000000";
  41. static void plat_print_strn(void *env, const char *str, size_t len) {
  42. (void)env;
  43. MP_PLAT_PRINT_STRN(str, len);
  44. }
  45. const mp_print_t mp_plat_print = {NULL, plat_print_strn};
  46. int mp_print_str(const mp_print_t *print, const char *str) {
  47. size_t len = strlen(str);
  48. if (len) {
  49. print->print_strn(print->data, str, len);
  50. }
  51. return len;
  52. }
  53. int mp_print_strn(const mp_print_t *print, const char *str, size_t len, int flags, char fill, int width) {
  54. int left_pad = 0;
  55. int right_pad = 0;
  56. int pad = width - len;
  57. int pad_size;
  58. int total_chars_printed = 0;
  59. const char *pad_chars;
  60. if (!fill || fill == ' ') {
  61. pad_chars = pad_spaces;
  62. pad_size = sizeof(pad_spaces) - 1;
  63. } else if (fill == '0') {
  64. pad_chars = pad_zeroes;
  65. pad_size = sizeof(pad_zeroes) - 1;
  66. } else {
  67. // Other pad characters are fairly unusual, so we'll take the hit
  68. // and output them 1 at a time.
  69. pad_chars = &fill;
  70. pad_size = 1;
  71. }
  72. if (flags & PF_FLAG_CENTER_ADJUST) {
  73. left_pad = pad / 2;
  74. right_pad = pad - left_pad;
  75. } else if (flags & PF_FLAG_LEFT_ADJUST) {
  76. right_pad = pad;
  77. } else {
  78. left_pad = pad;
  79. }
  80. if (left_pad > 0) {
  81. total_chars_printed += left_pad;
  82. while (left_pad > 0) {
  83. int p = left_pad;
  84. if (p > pad_size) {
  85. p = pad_size;
  86. }
  87. print->print_strn(print->data, pad_chars, p);
  88. left_pad -= p;
  89. }
  90. }
  91. if (len) {
  92. print->print_strn(print->data, str, len);
  93. total_chars_printed += len;
  94. }
  95. if (right_pad > 0) {
  96. total_chars_printed += right_pad;
  97. while (right_pad > 0) {
  98. int p = right_pad;
  99. if (p > pad_size) {
  100. p = pad_size;
  101. }
  102. print->print_strn(print->data, pad_chars, p);
  103. right_pad -= p;
  104. }
  105. }
  106. return total_chars_printed;
  107. }
  108. // 32-bits is 10 digits, add 3 for commas, 1 for sign, 1 for terminating null
  109. // We can use 16 characters for 32-bit and 32 characters for 64-bit
  110. #define INT_BUF_SIZE (sizeof(mp_int_t) * 4)
  111. // Our mp_vprintf function below does not support the '#' format modifier to
  112. // print the prefix of a non-base-10 number, so we don't need code for this.
  113. #define SUPPORT_INT_BASE_PREFIX (0)
  114. // This function is used exclusively by mp_vprintf to format ints.
  115. // It needs to be a separate function to mp_print_mp_int, since converting to a mp_int looses the MSB.
  116. static int mp_print_int(const mp_print_t *print, mp_uint_t x, int sgn, int base, int base_char, int flags, char fill, int width) {
  117. char sign = 0;
  118. if (sgn) {
  119. if ((mp_int_t)x < 0) {
  120. sign = '-';
  121. x = -x;
  122. } else if (flags & PF_FLAG_SHOW_SIGN) {
  123. sign = '+';
  124. } else if (flags & PF_FLAG_SPACE_SIGN) {
  125. sign = ' ';
  126. }
  127. }
  128. char buf[INT_BUF_SIZE];
  129. char *b = buf + INT_BUF_SIZE;
  130. if (x == 0) {
  131. *(--b) = '0';
  132. } else {
  133. do {
  134. int c = x % base;
  135. x /= base;
  136. if (c >= 10) {
  137. c += base_char - 10;
  138. } else {
  139. c += '0';
  140. }
  141. *(--b) = c;
  142. } while (b > buf && x != 0);
  143. }
  144. #if SUPPORT_INT_BASE_PREFIX
  145. char prefix_char = '\0';
  146. if (flags & PF_FLAG_SHOW_PREFIX) {
  147. if (base == 2) {
  148. prefix_char = base_char + 'b' - 'a';
  149. } else if (base == 8) {
  150. prefix_char = base_char + 'o' - 'a';
  151. } else if (base == 16) {
  152. prefix_char = base_char + 'x' - 'a';
  153. }
  154. }
  155. #endif
  156. int len = 0;
  157. if (flags & PF_FLAG_PAD_AFTER_SIGN) {
  158. if (sign) {
  159. len += mp_print_strn(print, &sign, 1, flags, fill, 1);
  160. width--;
  161. }
  162. #if SUPPORT_INT_BASE_PREFIX
  163. if (prefix_char) {
  164. len += mp_print_strn(print, "0", 1, flags, fill, 1);
  165. len += mp_print_strn(print, &prefix_char, 1, flags, fill, 1);
  166. width -= 2;
  167. }
  168. #endif
  169. } else {
  170. #if SUPPORT_INT_BASE_PREFIX
  171. if (prefix_char && b > &buf[1]) {
  172. *(--b) = prefix_char;
  173. *(--b) = '0';
  174. }
  175. #endif
  176. if (sign && b > buf) {
  177. *(--b) = sign;
  178. }
  179. }
  180. len += mp_print_strn(print, b, buf + INT_BUF_SIZE - b, flags, fill, width);
  181. return len;
  182. }
  183. int mp_print_mp_int(const mp_print_t *print, mp_obj_t x, int base, int base_char, int flags, char fill, int width, int prec) {
  184. // These are the only values for "base" that are required to be supported by this
  185. // function, since Python only allows the user to format integers in these bases.
  186. // If needed this function could be generalised to handle other values.
  187. assert(base == 2 || base == 8 || base == 10 || base == 16);
  188. if (!mp_obj_is_int(x)) {
  189. // This will convert booleans to int, or raise an error for
  190. // non-integer types.
  191. x = MP_OBJ_NEW_SMALL_INT(mp_obj_get_int(x));
  192. }
  193. if ((flags & (PF_FLAG_LEFT_ADJUST | PF_FLAG_CENTER_ADJUST)) == 0 && fill == '0') {
  194. if (prec > width) {
  195. width = prec;
  196. }
  197. prec = 0;
  198. }
  199. char prefix_buf[4];
  200. char *prefix = prefix_buf;
  201. if (mp_obj_int_sign(x) >= 0) {
  202. if (flags & PF_FLAG_SHOW_SIGN) {
  203. *prefix++ = '+';
  204. } else if (flags & PF_FLAG_SPACE_SIGN) {
  205. *prefix++ = ' ';
  206. }
  207. }
  208. if (flags & PF_FLAG_SHOW_PREFIX) {
  209. if (base == 2) {
  210. *prefix++ = '0';
  211. *prefix++ = base_char + 'b' - 'a';
  212. } else if (base == 8) {
  213. *prefix++ = '0';
  214. if (flags & PF_FLAG_SHOW_OCTAL_LETTER) {
  215. *prefix++ = base_char + 'o' - 'a';
  216. }
  217. } else if (base == 16) {
  218. *prefix++ = '0';
  219. *prefix++ = base_char + 'x' - 'a';
  220. }
  221. }
  222. *prefix = '\0';
  223. int prefix_len = prefix - prefix_buf;
  224. prefix = prefix_buf;
  225. char comma = '\0';
  226. if (flags & PF_FLAG_SHOW_COMMA) {
  227. comma = ',';
  228. }
  229. // The size of this buffer is rather arbitrary. If it's not large
  230. // enough, a dynamic one will be allocated.
  231. char stack_buf[sizeof(mp_int_t) * 4];
  232. char *buf = stack_buf;
  233. size_t buf_size = sizeof(stack_buf);
  234. size_t fmt_size = 0;
  235. char *str;
  236. if (prec > 1) {
  237. flags |= PF_FLAG_PAD_AFTER_SIGN;
  238. }
  239. char sign = '\0';
  240. if (flags & PF_FLAG_PAD_AFTER_SIGN) {
  241. // We add the pad in this function, so since the pad goes after
  242. // the sign & prefix, we format without a prefix
  243. str = mp_obj_int_formatted(&buf, &buf_size, &fmt_size,
  244. x, base, NULL, base_char, comma);
  245. if (*str == '-') {
  246. sign = *str++;
  247. fmt_size--;
  248. }
  249. } else {
  250. str = mp_obj_int_formatted(&buf, &buf_size, &fmt_size,
  251. x, base, prefix, base_char, comma);
  252. }
  253. int spaces_before = 0;
  254. int spaces_after = 0;
  255. if (prec > 1) {
  256. // If prec was specified, then prec specifies the width to zero-pad the
  257. // the number to. This zero-padded number then gets left or right
  258. // aligned in width characters.
  259. int prec_width = fmt_size; // The digits
  260. if (prec_width < prec) {
  261. prec_width = prec;
  262. }
  263. if (flags & PF_FLAG_PAD_AFTER_SIGN) {
  264. if (sign) {
  265. prec_width++;
  266. }
  267. prec_width += prefix_len;
  268. }
  269. if (prec_width < width) {
  270. if (flags & PF_FLAG_LEFT_ADJUST) {
  271. spaces_after = width - prec_width;
  272. } else {
  273. spaces_before = width - prec_width;
  274. }
  275. }
  276. fill = '0';
  277. flags &= ~PF_FLAG_LEFT_ADJUST;
  278. }
  279. int len = 0;
  280. if (spaces_before) {
  281. len += mp_print_strn(print, "", 0, 0, ' ', spaces_before);
  282. }
  283. if (flags & PF_FLAG_PAD_AFTER_SIGN) {
  284. // pad after sign implies pad after prefix as well.
  285. if (sign) {
  286. len += mp_print_strn(print, &sign, 1, 0, 0, 1);
  287. width--;
  288. }
  289. if (prefix_len) {
  290. len += mp_print_strn(print, prefix, prefix_len, 0, 0, 1);
  291. width -= prefix_len;
  292. }
  293. }
  294. if (prec > 1) {
  295. width = prec;
  296. }
  297. len += mp_print_strn(print, str, fmt_size, flags, fill, width);
  298. if (spaces_after) {
  299. len += mp_print_strn(print, "", 0, 0, ' ', spaces_after);
  300. }
  301. if (buf != stack_buf) {
  302. m_del(char, buf, buf_size);
  303. }
  304. return len;
  305. }
  306. #if MICROPY_PY_BUILTINS_FLOAT
  307. int mp_print_float(const mp_print_t *print, mp_float_t f, char fmt, int flags, char fill, int width, int prec) {
  308. char buf[32];
  309. char sign = '\0';
  310. int chrs = 0;
  311. if (flags & PF_FLAG_SHOW_SIGN) {
  312. sign = '+';
  313. } else
  314. if (flags & PF_FLAG_SPACE_SIGN) {
  315. sign = ' ';
  316. }
  317. int len = mp_format_float(f, buf, sizeof(buf), fmt, prec, sign);
  318. char *s = buf;
  319. if ((flags & PF_FLAG_ADD_PERCENT) && (size_t)(len + 1) < sizeof(buf)) {
  320. buf[len++] = '%';
  321. buf[len] = '\0';
  322. }
  323. // buf[0] < '0' returns true if the first character is space, + or -
  324. if ((flags & PF_FLAG_PAD_AFTER_SIGN) && buf[0] < '0') {
  325. // We have a sign character
  326. s++;
  327. chrs += mp_print_strn(print, &buf[0], 1, 0, 0, 1);
  328. width--;
  329. len--;
  330. }
  331. chrs += mp_print_strn(print, s, len, flags, fill, width);
  332. return chrs;
  333. }
  334. #endif
  335. int mp_printf(const mp_print_t *print, const char *fmt, ...) {
  336. va_list ap;
  337. va_start(ap, fmt);
  338. int ret = mp_vprintf(print, fmt, ap);
  339. va_end(ap);
  340. return ret;
  341. }
  342. int mp_vprintf(const mp_print_t *print, const char *fmt, va_list args) {
  343. int chrs = 0;
  344. for (;;) {
  345. {
  346. const char *f = fmt;
  347. while (*f != '\0' && *f != '%') {
  348. ++f; // XXX UTF8 advance char
  349. }
  350. if (f > fmt) {
  351. print->print_strn(print->data, fmt, f - fmt);
  352. chrs += f - fmt;
  353. fmt = f;
  354. }
  355. }
  356. if (*fmt == '\0') {
  357. break;
  358. }
  359. // move past % character
  360. ++fmt;
  361. // parse flags, if they exist
  362. int flags = 0;
  363. char fill = ' ';
  364. while (*fmt != '\0') {
  365. if (*fmt == '-') {
  366. flags |= PF_FLAG_LEFT_ADJUST;
  367. } else if (*fmt == '+') {
  368. flags |= PF_FLAG_SHOW_SIGN;
  369. } else if (*fmt == ' ') {
  370. flags |= PF_FLAG_SPACE_SIGN;
  371. } else if (*fmt == '!') {
  372. flags |= PF_FLAG_NO_TRAILZ;
  373. } else if (*fmt == '0') {
  374. flags |= PF_FLAG_PAD_AFTER_SIGN;
  375. fill = '0';
  376. } else {
  377. break;
  378. }
  379. ++fmt;
  380. }
  381. // parse width, if it exists
  382. int width = 0;
  383. for (; '0' <= *fmt && *fmt <= '9'; ++fmt) {
  384. width = width * 10 + *fmt - '0';
  385. }
  386. // parse precision, if it exists
  387. int prec = -1;
  388. if (*fmt == '.') {
  389. ++fmt;
  390. if (*fmt == '*') {
  391. ++fmt;
  392. prec = va_arg(args, int);
  393. } else {
  394. prec = 0;
  395. for (; '0' <= *fmt && *fmt <= '9'; ++fmt) {
  396. prec = prec * 10 + *fmt - '0';
  397. }
  398. }
  399. if (prec < 0) {
  400. prec = 0;
  401. }
  402. }
  403. // parse long specifiers (only for LP64 model where they make a difference)
  404. #ifndef __LP64__
  405. const
  406. #endif
  407. bool long_arg = false;
  408. if (*fmt == 'l') {
  409. ++fmt;
  410. #ifdef __LP64__
  411. long_arg = true;
  412. #endif
  413. }
  414. if (*fmt == '\0') {
  415. break;
  416. }
  417. switch (*fmt) {
  418. case 'b':
  419. if (va_arg(args, int)) {
  420. chrs += mp_print_strn(print, "true", 4, flags, fill, width);
  421. } else {
  422. chrs += mp_print_strn(print, "false", 5, flags, fill, width);
  423. }
  424. break;
  425. case 'c': {
  426. char str = va_arg(args, int);
  427. chrs += mp_print_strn(print, &str, 1, flags, fill, width);
  428. break;
  429. }
  430. case 'q': {
  431. qstr qst = va_arg(args, qstr);
  432. size_t len;
  433. const char *str = (const char *)qstr_data(qst, &len);
  434. if (prec >= 0 && (size_t)prec < len) {
  435. len = prec;
  436. }
  437. chrs += mp_print_strn(print, str, len, flags, fill, width);
  438. break;
  439. }
  440. case 's': {
  441. const char *str = va_arg(args, const char *);
  442. #ifndef NDEBUG
  443. // With debugging enabled, catch printing of null string pointers
  444. if (prec != 0 && str == NULL) {
  445. chrs += mp_print_strn(print, "(null)", 6, flags, fill, width);
  446. break;
  447. }
  448. #endif
  449. size_t len = strlen(str);
  450. if (prec >= 0 && (size_t)prec < len) {
  451. len = prec;
  452. }
  453. chrs += mp_print_strn(print, str, len, flags, fill, width);
  454. break;
  455. }
  456. case 'd': {
  457. mp_int_t val;
  458. if (long_arg) {
  459. val = va_arg(args, long int);
  460. } else {
  461. val = va_arg(args, int);
  462. }
  463. chrs += mp_print_int(print, val, 1, 10, 'a', flags, fill, width);
  464. break;
  465. }
  466. case 'u':
  467. case 'x':
  468. case 'X': {
  469. int base = 16 - ((*fmt + 1) & 6); // maps char u/x/X to base 10/16/16
  470. char fmt_c = (*fmt & 0xf0) - 'P' + 'A'; // maps char u/x/X to char a/a/A
  471. mp_uint_t val;
  472. if (long_arg) {
  473. val = va_arg(args, unsigned long int);
  474. } else {
  475. val = va_arg(args, unsigned int);
  476. }
  477. chrs += mp_print_int(print, val, 0, base, fmt_c, flags, fill, width);
  478. break;
  479. }
  480. case 'p':
  481. case 'P': // don't bother to handle upcase for 'P'
  482. // Use unsigned long int to work on both ILP32 and LP64 systems
  483. chrs += mp_print_int(print, va_arg(args, unsigned long int), 0, 16, 'a', flags, fill, width);
  484. break;
  485. #if MICROPY_PY_BUILTINS_FLOAT
  486. case 'e':
  487. case 'E':
  488. case 'f':
  489. case 'F':
  490. case 'g':
  491. case 'G': {
  492. #if ((MICROPY_FLOAT_IMPL == MICROPY_FLOAT_IMPL_FLOAT) || (MICROPY_FLOAT_IMPL == MICROPY_FLOAT_IMPL_DOUBLE))
  493. mp_float_t f = (mp_float_t)va_arg(args, double);
  494. chrs += mp_print_float(print, f, *fmt, flags, fill, width, prec);
  495. #else
  496. #error Unknown MICROPY FLOAT IMPL
  497. #endif
  498. break;
  499. }
  500. #endif
  501. // Because 'l' is eaten above, another 'l' means %ll. We need to support
  502. // this length specifier for OBJ_REPR_D (64-bit NaN boxing).
  503. // TODO Either enable this unconditionally, or provide a specific config var.
  504. #if (MICROPY_OBJ_REPR == MICROPY_OBJ_REPR_D) || defined(_WIN64)
  505. case 'l': {
  506. unsigned long long int arg_value = va_arg(args, unsigned long long int);
  507. ++fmt;
  508. assert(*fmt == 'u' || *fmt == 'd' || !"unsupported fmt char");
  509. chrs += mp_print_int(print, arg_value, *fmt == 'd', 10, 'a', flags, fill, width);
  510. break;
  511. }
  512. #endif
  513. default:
  514. // if it's not %% then it's an unsupported format character
  515. assert(*fmt == '%' || !"unsupported fmt char");
  516. print->print_strn(print->data, fmt, 1);
  517. chrs += 1;
  518. break;
  519. }
  520. ++fmt;
  521. }
  522. return chrs;
  523. }