nrf_fprintf_format.c 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510
  1. /*********************************************************************
  2. * SEGGER Microcontroller GmbH & Co. KG *
  3. * The Embedded Experts *
  4. **********************************************************************
  5. * *
  6. * (c) 2014 - 2017 SEGGER Microcontroller GmbH & Co. KG *
  7. * *
  8. * www.segger.com Support: support@segger.com *
  9. * *
  10. **********************************************************************
  11. * *
  12. * SEGGER RTT * Real Time Transfer for embedded targets *
  13. * *
  14. **********************************************************************
  15. * *
  16. * All rights reserved. *
  17. * *
  18. * SEGGER strongly recommends to not make any changes *
  19. * to or modify the source code of this software in order to stay *
  20. * compatible with the RTT protocol and J-Link. *
  21. * *
  22. * Redistribution and use in source and binary forms, with or *
  23. * without modification, are permitted provided that the following *
  24. * conditions are met: *
  25. * *
  26. * o Redistributions of source code must retain the above copyright *
  27. * notice, this list of conditions and the following disclaimer. *
  28. * *
  29. * o Redistributions in binary form must reproduce the above *
  30. * copyright notice, this list of conditions and the following *
  31. * disclaimer in the documentation and/or other materials provided *
  32. * with the distribution. *
  33. * *
  34. * o Neither the name of SEGGER Microcontroller GmbH & Co. KG *
  35. * nor the names of its contributors may be used to endorse or *
  36. * promote products derived from this software without specific *
  37. * prior written permission. *
  38. * *
  39. * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND *
  40. * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, *
  41. * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF *
  42. * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE *
  43. * DISCLAIMED. IN NO EVENT SHALL SEGGER Microcontroller BE LIABLE FOR *
  44. * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR *
  45. * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT *
  46. * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; *
  47. * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF *
  48. * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT *
  49. * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE *
  50. * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH *
  51. * DAMAGE. *
  52. * *
  53. **********************************************************************
  54. * *
  55. * RTT version: 6.14d *
  56. * *
  57. *********************************************************************/
  58. #include "sdk_common.h"
  59. #if NRF_MODULE_ENABLED(NRF_FPRINTF)
  60. #include <stdarg.h>
  61. #include "nrf_assert.h"
  62. #include "nrf_fprintf.h"
  63. #include "nrf_fprintf_format.h"
  64. #define NRF_CLI_FORMAT_FLAG_LEFT_JUSTIFY (1u << 0)
  65. #define NRF_CLI_FORMAT_FLAG_PAD_ZERO (1u << 1)
  66. #define NRF_CLI_FORMAT_FLAG_PRINT_SIGN (1u << 2)
  67. static void buffer_add(nrf_fprintf_ctx_t * const p_ctx, char c)
  68. {
  69. p_ctx->p_io_buffer[p_ctx->io_buffer_cnt++] = c;
  70. if (p_ctx->io_buffer_cnt >= p_ctx->io_buffer_size)
  71. {
  72. nrf_fprintf_buffer_flush(p_ctx);
  73. }
  74. }
  75. static void string_print(nrf_fprintf_ctx_t * const p_ctx,
  76. char const * p_str,
  77. uint32_t FieldWidth,
  78. uint32_t FormatFlags)
  79. {
  80. uint32_t Width = 0;
  81. char c;
  82. if ((FormatFlags & NRF_CLI_FORMAT_FLAG_LEFT_JUSTIFY) == NRF_CLI_FORMAT_FLAG_LEFT_JUSTIFY)
  83. {
  84. while ((c = *p_str) != '\0')
  85. {
  86. p_str++;
  87. Width++;
  88. buffer_add(p_ctx, c);
  89. }
  90. while ((FieldWidth > Width) && (FieldWidth > 0))
  91. {
  92. FieldWidth--;
  93. buffer_add(p_ctx, ' ');
  94. }
  95. }
  96. else
  97. {
  98. if (p_str != 0)
  99. {
  100. Width = strlen(p_str);
  101. }
  102. while ((FieldWidth > Width) && (FieldWidth > 0))
  103. {
  104. FieldWidth--;
  105. buffer_add(p_ctx, ' ');
  106. }
  107. while ((c = *p_str) != '\0')
  108. {
  109. p_str++;
  110. Width++;
  111. buffer_add(p_ctx, c);
  112. }
  113. }
  114. }
  115. static void unsigned_print(nrf_fprintf_ctx_t * const p_ctx,
  116. uint32_t v,
  117. uint32_t Base,
  118. uint32_t NumDigits,
  119. uint32_t FieldWidth,
  120. uint32_t FormatFlags)
  121. {
  122. static const char _aV2C[16] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
  123. 'A', 'B', 'C', 'D', 'E', 'F' };
  124. uint32_t Div;
  125. uint32_t Value;
  126. uint32_t Width;
  127. char c;
  128. Value = v;
  129. //
  130. // Get actual field width
  131. //
  132. Width = 1u;
  133. while (Value >= Base)
  134. {
  135. Value = (Value / Base);
  136. Width++;
  137. }
  138. if (NumDigits > Width)
  139. {
  140. Width = NumDigits;
  141. }
  142. //
  143. // Print leading chars if necessary
  144. //
  145. if ((FormatFlags & NRF_CLI_FORMAT_FLAG_LEFT_JUSTIFY) == 0u)
  146. {
  147. if (FieldWidth != 0u)
  148. {
  149. if (((FormatFlags & NRF_CLI_FORMAT_FLAG_PAD_ZERO) == NRF_CLI_FORMAT_FLAG_PAD_ZERO) &&
  150. (NumDigits == 0u))
  151. {
  152. c = '0';
  153. }
  154. else
  155. {
  156. c = ' ';
  157. }
  158. while ((FieldWidth != 0u) && (Width < FieldWidth))
  159. {
  160. FieldWidth--;
  161. buffer_add(p_ctx, c);
  162. }
  163. }
  164. }
  165. Value = 1;
  166. /*
  167. * Compute Digit.
  168. * Loop until Digit has the value of the highest digit required.
  169. * Example: If the output is 345 (Base 10), loop 2 times until Digit is 100.
  170. */
  171. while (1)
  172. {
  173. /* User specified a min number of digits to print? => Make sure we loop at least that
  174. * often, before checking anything else (> 1 check avoids problems with NumDigits
  175. * being signed / unsigned)
  176. */
  177. if (NumDigits > 1u)
  178. {
  179. NumDigits--;
  180. }
  181. else
  182. {
  183. Div = v / Value;
  184. // Is our divider big enough to extract the highest digit from value? => Done
  185. if (Div < Base)
  186. {
  187. break;
  188. }
  189. }
  190. Value *= Base;
  191. }
  192. //
  193. // Output digits
  194. //
  195. do
  196. {
  197. Div = v / Value;
  198. v -= Div * Value;
  199. buffer_add(p_ctx, _aV2C[Div]);
  200. Value /= Base;
  201. } while (Value);
  202. //
  203. // Print trailing spaces if necessary
  204. //
  205. if ((FormatFlags & NRF_CLI_FORMAT_FLAG_LEFT_JUSTIFY) == NRF_CLI_FORMAT_FLAG_LEFT_JUSTIFY)
  206. {
  207. if (FieldWidth != 0u)
  208. {
  209. while ((FieldWidth != 0u) && (Width < FieldWidth))
  210. {
  211. FieldWidth--;
  212. buffer_add(p_ctx, ' ');
  213. }
  214. }
  215. }
  216. }
  217. static void int_print(nrf_fprintf_ctx_t * const p_ctx,
  218. int32_t v,
  219. uint32_t Base,
  220. uint32_t NumDigits,
  221. uint32_t FieldWidth,
  222. uint32_t FormatFlags)
  223. {
  224. uint32_t Width;
  225. int32_t Number;
  226. Number = (v < 0) ? -v : v;
  227. //
  228. // Get actual field width
  229. //
  230. Width = 1u;
  231. while (Number >= (int32_t)Base)
  232. {
  233. Number = (Number / (int32_t)Base);
  234. Width++;
  235. }
  236. if (NumDigits > Width)
  237. {
  238. Width = NumDigits;
  239. }
  240. if ((FieldWidth > 0u) && ((v < 0) ||
  241. ((FormatFlags & NRF_CLI_FORMAT_FLAG_PRINT_SIGN) == NRF_CLI_FORMAT_FLAG_PRINT_SIGN)))
  242. {
  243. FieldWidth--;
  244. }
  245. //
  246. // Print leading spaces if necessary
  247. //
  248. if ((((FormatFlags & NRF_CLI_FORMAT_FLAG_PAD_ZERO) == 0u) || (NumDigits != 0u)) &&
  249. ((FormatFlags & NRF_CLI_FORMAT_FLAG_LEFT_JUSTIFY) == 0u))
  250. {
  251. if (FieldWidth != 0u)
  252. {
  253. while ((FieldWidth != 0u) && (Width < FieldWidth))
  254. {
  255. FieldWidth--;
  256. buffer_add(p_ctx, ' ');
  257. }
  258. }
  259. }
  260. //
  261. // Print sign if necessary
  262. //
  263. if (v < 0)
  264. {
  265. v = -v;
  266. buffer_add(p_ctx, '-');
  267. }
  268. else if ((FormatFlags & NRF_CLI_FORMAT_FLAG_PRINT_SIGN) == NRF_CLI_FORMAT_FLAG_PRINT_SIGN)
  269. {
  270. buffer_add(p_ctx, '+');
  271. }
  272. else
  273. {
  274. /* do nothing */
  275. }
  276. //
  277. // Print leading zeros if necessary
  278. //
  279. if (((FormatFlags & NRF_CLI_FORMAT_FLAG_PAD_ZERO) == NRF_CLI_FORMAT_FLAG_PAD_ZERO) &&
  280. ((FormatFlags & NRF_CLI_FORMAT_FLAG_LEFT_JUSTIFY) == 0u) && (NumDigits == 0u))
  281. {
  282. if (FieldWidth != 0u)
  283. {
  284. while ((FieldWidth != 0u) && (Width < FieldWidth))
  285. {
  286. FieldWidth--;
  287. buffer_add(p_ctx, '0');
  288. }
  289. }
  290. }
  291. //
  292. // Print number without sign
  293. //
  294. unsigned_print(p_ctx, (uint32_t)v, Base, NumDigits, FieldWidth, FormatFlags);
  295. }
  296. void nrf_fprintf_fmt(nrf_fprintf_ctx_t * const p_ctx,
  297. char const * p_fmt,
  298. va_list * p_args)
  299. {
  300. ASSERT(p_ctx != NULL);
  301. ASSERT(p_ctx->fwrite != NULL);
  302. ASSERT(p_ctx->p_io_buffer != NULL);
  303. ASSERT(p_ctx->io_buffer_size > 0);
  304. if (p_fmt == NULL)
  305. {
  306. return;
  307. }
  308. char c;
  309. int32_t v;
  310. uint32_t NumDigits;
  311. uint32_t FormatFlags;
  312. uint32_t FieldWidth;
  313. do
  314. {
  315. c = *p_fmt;
  316. p_fmt++;
  317. if (c == 0u)
  318. {
  319. break;
  320. }
  321. if (c == '%')
  322. {
  323. //
  324. // Filter out flags
  325. //
  326. FormatFlags = 0u;
  327. v = 1;
  328. do
  329. {
  330. c = *p_fmt;
  331. switch (c)
  332. {
  333. case '-':
  334. FormatFlags |= NRF_CLI_FORMAT_FLAG_LEFT_JUSTIFY;
  335. p_fmt++;
  336. break;
  337. case '0':
  338. FormatFlags |= NRF_CLI_FORMAT_FLAG_PAD_ZERO;
  339. p_fmt++;
  340. break;
  341. case '+':
  342. FormatFlags |= NRF_CLI_FORMAT_FLAG_PRINT_SIGN;
  343. p_fmt++;
  344. break;
  345. default:
  346. v = 0;
  347. break;
  348. }
  349. } while (v);
  350. //
  351. // filter out field width
  352. //
  353. FieldWidth = 0u;
  354. do
  355. {
  356. if (c == '*')
  357. {
  358. /*lint -save -e64 -e56*/
  359. FieldWidth += va_arg(*p_args, unsigned);
  360. /*lint -restore*/
  361. p_fmt++;
  362. break;
  363. }
  364. c = *p_fmt;
  365. if ((c < '0') || (c > '9'))
  366. {
  367. break;
  368. }
  369. p_fmt++;
  370. FieldWidth = (FieldWidth * 10u) + (c - '0');
  371. } while (1);
  372. //
  373. // Filter out precision (number of digits to display)
  374. //
  375. NumDigits = 0u;
  376. c = *p_fmt;
  377. if (c == '.')
  378. {
  379. p_fmt++;
  380. do
  381. {
  382. c = *p_fmt;
  383. if ((c < '0') || (c > '9'))
  384. {
  385. break;
  386. }
  387. p_fmt++;
  388. NumDigits = NumDigits * 10u + (c - '0');
  389. } while (1);
  390. }
  391. //
  392. // Filter out length modifier
  393. //
  394. c = *p_fmt;
  395. do
  396. {
  397. if ((c == 'l') || (c == 'h'))
  398. {
  399. p_fmt++;
  400. c = *p_fmt;
  401. }
  402. else
  403. {
  404. break;
  405. }
  406. } while (1);
  407. //
  408. // Handle specifiers
  409. //
  410. /*lint -save -e64*/
  411. switch (c)
  412. {
  413. case 'c':
  414. {
  415. char c0;
  416. v = va_arg(*p_args, int32_t);
  417. c0 = (char)v;
  418. buffer_add(p_ctx, c0);
  419. break;
  420. }
  421. case 'd':
  422. case 'i':
  423. v = va_arg(*p_args, int32_t);
  424. int_print(p_ctx,
  425. v,
  426. 10u,
  427. NumDigits,
  428. FieldWidth,
  429. FormatFlags);
  430. break;
  431. case 'u':
  432. v = va_arg(*p_args, int32_t);
  433. unsigned_print(p_ctx,
  434. (uint32_t)v,
  435. 10u,
  436. NumDigits,
  437. FieldWidth,
  438. FormatFlags);
  439. break;
  440. case 'x':
  441. case 'X':
  442. v = va_arg(*p_args, int32_t);
  443. unsigned_print(p_ctx,
  444. (uint32_t)v,
  445. 16u,
  446. NumDigits,
  447. FieldWidth,
  448. FormatFlags);
  449. break;
  450. case 's':
  451. {
  452. char const * p_s = va_arg(*p_args, const char *);
  453. string_print(p_ctx, p_s, FieldWidth, FormatFlags);
  454. break;
  455. }
  456. case 'p':
  457. v = va_arg(*p_args, int32_t);
  458. buffer_add(p_ctx, '0');
  459. buffer_add(p_ctx, 'x');
  460. unsigned_print(p_ctx, (uint32_t)v, 16u, 8u, 8u, 0);
  461. break;
  462. case '%':
  463. buffer_add(p_ctx, '%');
  464. break;
  465. default:
  466. break;
  467. }
  468. /*lint -restore*/
  469. p_fmt++;
  470. }
  471. else
  472. {
  473. buffer_add(p_ctx, c);
  474. }
  475. } while (*p_fmt != '\0');
  476. if (p_ctx->auto_flush)
  477. {
  478. nrf_fprintf_buffer_flush(p_ctx);
  479. }
  480. }
  481. #endif // NRF_MODULE_ENABLED(NRF_FPRINTF)