PrintTemplates.h 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500
  1. /**
  2. * Copyright (c) 2011-2020 Bill Greiman
  3. * This file is part of the SdFat library for SD memory cards.
  4. *
  5. * MIT License
  6. *
  7. * Permission is hereby granted, free of charge, to any person obtaining a
  8. * copy of this software and associated documentation files (the "Software"),
  9. * to deal in the Software without restriction, including without limitation
  10. * the rights to use, copy, modify, merge, publish, distribute, sublicense,
  11. * and/or sell copies of the Software, and to permit persons to whom the
  12. * Software is furnished to do so, subject to the following conditions:
  13. *
  14. * The above copyright notice and this permission notice shall be included
  15. * in all copies or substantial portions of the Software.
  16. *
  17. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
  18. * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  19. * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  20. * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  21. * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
  22. * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
  23. * DEALINGS IN THE SOFTWARE.
  24. */
  25. #ifndef PrintTemplates_h
  26. #define PrintTemplates_h
  27. /**
  28. * \file
  29. * \brief templates for printf
  30. */
  31. #include <stdarg.h>
  32. #include "FmtNumber.h"
  33. /** test for digit */
  34. #define isDigit(d) ('0' <= (d) && (d) <= '9')
  35. /** control for supported floating formats */
  36. #define PRINTF_USE_FLOAT 2
  37. //-----------------------------------------------------------------------------
  38. /** Formatted print.
  39. *
  40. * \param[in] file destination file or device.
  41. * \param[in] fmt format string.
  42. * \param[in] ap argument list.
  43. *
  44. * \return number of character printed for success else a negative value.
  45. */
  46. template<typename F>
  47. int vfprintf(F* file, const char *fmt, va_list ap) {
  48. #if PRINTF_USE_FLOAT
  49. char buf[30];
  50. double f;
  51. #else // PRINTF_USE_FLOAT
  52. char buf[15];
  53. #endif // PRINTF_USE_FLOAT
  54. char prefix[3];
  55. unsigned base;
  56. int n;
  57. int nc = 0;
  58. int nf;
  59. int nz;
  60. int prec;
  61. int width;
  62. size_t np;
  63. size_t ns;
  64. size_t nw;
  65. long ln;
  66. char c;
  67. char plusSign;
  68. char* ptr; // end of string
  69. char* str; // start of string
  70. bool altForm;
  71. bool leftAdjust;
  72. bool isLong;
  73. bool zeroPad;
  74. while (true) {
  75. const char* bgn = fmt;
  76. while ((c = *fmt++) && c!= '%') {}
  77. nw = fmt - bgn - 1;
  78. if (nw) {
  79. nc += nw;
  80. if (nw != file->write(bgn, nw)) {
  81. goto fail;
  82. }
  83. }
  84. if (!c) break;
  85. altForm = false;
  86. leftAdjust = false;
  87. np = 0;
  88. nz = 0;
  89. zeroPad = false;
  90. plusSign = 0;
  91. c = *fmt++;
  92. while (true) {
  93. if (c == '-') {
  94. leftAdjust = true;
  95. } else if (c == '+') {
  96. plusSign = '+';
  97. } else if (c == ' ') {
  98. if (plusSign == 0) {
  99. plusSign = ' ';
  100. }
  101. } else if (c == '0') {
  102. zeroPad = true;
  103. } else if (c == '#') {
  104. altForm = true;
  105. } else {
  106. break;
  107. }
  108. c = *fmt++;
  109. }
  110. width = 0;
  111. if (isDigit(c)) {
  112. while(isDigit(c)) {
  113. width = 10 * width + c - '0';
  114. c = *fmt++;
  115. }
  116. } else if (c == '*') {
  117. width = va_arg(ap, int);
  118. c = *fmt++;
  119. if (width < 0) {
  120. leftAdjust = true;
  121. width = -width;
  122. }
  123. }
  124. if (leftAdjust) {
  125. zeroPad = false;
  126. }
  127. prec = -1;
  128. if (c == '.') {
  129. zeroPad = false;
  130. prec = 0;
  131. c = *fmt++;
  132. if (isDigit(c)) {
  133. while(isDigit(c)) {
  134. prec = 10 * prec + c - '0';
  135. c = *fmt++;
  136. }
  137. } else if (c == '*') {
  138. prec = va_arg(ap, int);
  139. c = *fmt++;
  140. }
  141. }
  142. isLong = false;
  143. if (c == 'l' || c =='L') {
  144. isLong = true;
  145. c = *fmt++;
  146. }
  147. if (!c) break;
  148. str = buf + sizeof(buf);
  149. ptr = str;
  150. switch(c) {
  151. case 'c':
  152. *--str = va_arg(ap, int);
  153. break;
  154. case 's':
  155. str = va_arg(ap, char *);
  156. if (!str) {
  157. str = (char*)"(null)";
  158. }
  159. ns = strlen(str);
  160. ptr = str + (prec >= 0 && (size_t)prec < ns ? prec : ns);
  161. break;
  162. case 'd':
  163. case 'i':
  164. ln = isLong ? va_arg(ap, long) : va_arg(ap, int);
  165. if (prec || ln) {
  166. if (ln < 0) {
  167. prefix[np++] = '-';
  168. ln = -ln;
  169. } else if (plusSign) {
  170. prefix[np++] = plusSign;
  171. }
  172. str = fmtUnsigned(str, ln, 10, true);
  173. nz = prec + str - ptr;
  174. }
  175. break;
  176. #if PRINTF_USE_FLOAT > 1
  177. case 'e':
  178. case 'E':
  179. case 'f':
  180. case 'F':
  181. f = va_arg(ap, double);
  182. if (f < 0) {
  183. f = -f;
  184. prefix[np++] = '-';
  185. } else if (plusSign) {
  186. prefix[np++] = plusSign;
  187. }
  188. str = fmtDouble(str, f, prec < 0 ? 6 : prec, altForm, c);
  189. break;
  190. #elif PRINTF_USE_FLOAT > 0
  191. case 'f':
  192. case 'F':
  193. f = va_arg(ap, double);
  194. if (f < 0) {
  195. f = -f;
  196. prefix[np++] = '-';
  197. } else if (plusSign) {
  198. prefix[np++] = plusSign;
  199. }
  200. str = fmtDouble(str, f, prec < 0 ? 6 : prec, altForm);
  201. break;
  202. #endif // PRINTF_USE_FLOAT
  203. case 'o':
  204. base = 8;
  205. goto printUnsigned;
  206. case 'u':
  207. base = 10;
  208. altForm = false;
  209. goto printUnsigned;
  210. case 'x':
  211. case 'X':
  212. base = 16;
  213. goto printUnsigned;
  214. printUnsigned:
  215. ln = isLong ? va_arg(ap, long) : va_arg(ap, int);
  216. if (prec || ln) {
  217. str = fmtUnsigned(str, ln, base, c == 'X');
  218. nz = prec + str - ptr;
  219. }
  220. if (altForm && ln) {
  221. if (c == 'o') {
  222. *--str = '0';
  223. } else {
  224. prefix[np++] = '0';
  225. prefix[np++] = c;
  226. }
  227. }
  228. break;
  229. default:
  230. *--str = c;
  231. break;
  232. }
  233. ns = (ptr - str);
  234. if (nz < 0) nz = 0;
  235. n = ns + np + nz;
  236. if (width < n) {
  237. nc += n;
  238. nf = 0;
  239. } else {
  240. nc += width;
  241. if (zeroPad) {
  242. nz += width - n;
  243. nf = 0;
  244. } else {
  245. nf = width - n;
  246. }
  247. }
  248. // Do right blank padding.
  249. if (!leftAdjust) {
  250. for (; nf > 0; nf--) {
  251. if (1 != file->write(' ')) {
  252. goto fail;
  253. }
  254. }
  255. }
  256. // Don't call write if no prefix.
  257. if (np && np != file->write(prefix, np)) {
  258. goto fail;
  259. }
  260. // Do zero padding.
  261. for (; nz > 0; nz--) {
  262. if (1 != file->write('0')) {
  263. goto fail;
  264. }
  265. }
  266. // Main item.
  267. if (ns != file->write(str, ns)) {
  268. goto fail;
  269. }
  270. // Right blank padding.
  271. for (; nf > 0; nf--) {
  272. if (1 != file->write(' ')) {
  273. goto fail;
  274. }
  275. }
  276. }
  277. return nc;
  278. fail:
  279. return -1;
  280. }
  281. //-----------------------------------------------------------------------------
  282. /** Formatted print.
  283. *
  284. * \param[in] file destination file or device.
  285. * \param[in] fmt format string.
  286. *
  287. * \return number of character printed for success else a negative value.
  288. */
  289. template<typename T>
  290. int fprintf(T *file, const char* fmt, ...) {
  291. va_list ap;
  292. va_start(ap, fmt);
  293. int rtn = vfprintf(file, fmt, ap);
  294. va_end(ap);
  295. return rtn;
  296. }
  297. //-----------------------------------------------------------------------------
  298. /** Minimal formatted print.
  299. *
  300. * \param[in] file destination file or device.
  301. * \param[in] fmt format string.
  302. * \param[in] ap argument list.
  303. *
  304. * \return number of character printed for success else a negative value.
  305. */
  306. template<typename F>
  307. int vmprintf(F* file, const char *fmt, va_list ap) {
  308. char buf[15];
  309. char* ptr;
  310. char* str;
  311. bool isLong;
  312. char c;
  313. int nc = 0;
  314. size_t ns;
  315. long n;
  316. while (true) {
  317. const char* bgn = fmt;
  318. while ((c = *fmt++) && c!= '%') {}
  319. ns = fmt - bgn - 1;
  320. if (ns) {
  321. nc += file->write(bgn, ns);
  322. }
  323. if (!c) {
  324. break;
  325. }
  326. c = *fmt++;
  327. if (c == 'l') {
  328. isLong = true;
  329. c = *fmt++;
  330. } else {
  331. isLong = false;
  332. }
  333. if (!c) {
  334. break;
  335. }
  336. ptr = str = buf + sizeof(buf);
  337. switch (c) {
  338. case 'c':
  339. *--str = va_arg(ap, int);
  340. break;
  341. case 's':
  342. str = va_arg(ap, char*);
  343. ptr = str ? str + strlen(str) : nullptr;
  344. break;
  345. case 'd':
  346. n = isLong ? va_arg(ap, long) : va_arg(ap, int);
  347. str = fmtSigned(str, n, 10, true);
  348. break;
  349. case 'u':
  350. n = isLong ? va_arg(ap, long) : va_arg(ap, int);
  351. str = fmtUnsigned(str, n, 10, true);
  352. break;
  353. case 'x':
  354. case 'X':
  355. n = isLong ? va_arg(ap, long) : va_arg(ap, int);
  356. str = fmtUnsigned(str, n, 16, c == 'X');
  357. break;
  358. default:
  359. *--str = c;
  360. break;
  361. }
  362. ns = ptr - str;
  363. nc += file->write(str, ns);
  364. }
  365. return nc;
  366. }
  367. //-----------------------------------------------------------------------------
  368. /** Minimal formatted print.
  369. *
  370. * \param[in] file destination file or device.
  371. * \param[in] fmt format string.
  372. *
  373. * \return number of character printed for success else a negative value.
  374. */
  375. template<typename T>
  376. int mprintf(T *file, const char* fmt, ...) {
  377. va_list ap;
  378. va_start(ap, fmt);
  379. int rtn = vmprintf(file, fmt, ap);
  380. va_end(ap);
  381. return rtn;
  382. }
  383. //------------------------------------------------------------------------------
  384. #ifdef __AVR__
  385. /** Minimal formatted print.
  386. *
  387. * \param[in] file destination file or device.
  388. * \param[in] ifsh format string using F() macro.
  389. * \param[in] ap argument list.
  390. *
  391. * \return number of character printed for success else a negative value.
  392. */
  393. template<typename F>
  394. int vmprintf(F file, const __FlashStringHelper *ifsh, va_list ap) {
  395. bool isLong;
  396. char buf[15];
  397. char c;
  398. char* ptr;
  399. char* str;
  400. size_t ns;
  401. int nc = 0;
  402. long n;
  403. PGM_P fmt = reinterpret_cast<PGM_P>(ifsh);
  404. while (true) {
  405. while ((c = pgm_read_byte(fmt++)) && c != '%') {
  406. nc += file->write(c);
  407. }
  408. if (!c) {
  409. break;
  410. }
  411. c = pgm_read_byte(fmt++);
  412. if (c == 'l') {
  413. isLong = true;
  414. c = pgm_read_byte(fmt++);
  415. } else {
  416. isLong = false;
  417. }
  418. if (!c) {
  419. break;
  420. }
  421. ptr = str = buf + sizeof(buf);
  422. switch (c) {
  423. case 'c':
  424. *--str = va_arg(ap, int);
  425. break;
  426. case 's':
  427. str = va_arg(ap, char*);
  428. ptr = str ? str + strlen(str) : nullptr;
  429. break;
  430. case 'd':
  431. n = isLong ? va_arg(ap, long) : va_arg(ap, int);
  432. str = fmtSigned(str, n, 10, true);
  433. break;
  434. case 'u':
  435. n = isLong ? va_arg(ap, long) : va_arg(ap, int);
  436. str = fmtUnsigned(str, n, 10, true);
  437. break;
  438. case 'x':
  439. case 'X':
  440. n = isLong ? va_arg(ap, long) : va_arg(ap, int);
  441. str = fmtUnsigned(str, n, 16, c == 'X');
  442. break;
  443. default:
  444. *--str = c;
  445. break;
  446. }
  447. ns = ptr - str;
  448. nc += file->write(str, ns);
  449. }
  450. return nc;
  451. }
  452. #endif // __AVR__
  453. //-----------------------------------------------------------------------------
  454. /** Minimal formatted print.
  455. *
  456. * \param[in] file destination file or device.
  457. * \param[in] ifsh format string using F() macro.
  458. *
  459. * \return number of character printed for success else a negative value.
  460. */
  461. template<typename F>
  462. int mprintf(F* file, const __FlashStringHelper *ifsh, ...) {
  463. va_list ap;
  464. va_start(ap, ifsh);
  465. #ifdef __AVR__
  466. int rtn = vmprintf(file, ifsh, ap);
  467. #else // __AVR__
  468. int rtn = vmprintf(file, (const char*)ifsh, ap);
  469. #endif // __AVR__
  470. va_end(ap);
  471. return rtn;
  472. }
  473. #endif // PrintTemplates_h