PageRenderTime 51ms CodeModel.GetById 17ms RepoModel.GetById 1ms app.codeStats 0ms

/erts/lib_src/common/erl_printf_format.c

https://github.com/bsmr-erlang/otp
C | 961 lines | 841 code | 75 blank | 45 comment | 145 complexity | 99bfb7417c35d354dec55eafe4333a97 MD5 | raw file
Possible License(s): BSD-3-Clause, LGPL-2.1, MPL-2.0-no-copyleft-exception, Apache-2.0
  1. /*
  2. * %CopyrightBegin%
  3. *
  4. * Copyright Ericsson AB 2005-2018. All Rights Reserved.
  5. *
  6. * Licensed under the Apache License, Version 2.0 (the "License");
  7. * you may not use this file except in compliance with the License.
  8. * You may obtain a copy of the License at
  9. *
  10. * http://www.apache.org/licenses/LICENSE-2.0
  11. *
  12. * Unless required by applicable law or agreed to in writing, software
  13. * distributed under the License is distributed on an "AS IS" BASIS,
  14. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  15. * See the License for the specific language governing permissions and
  16. * limitations under the License.
  17. *
  18. * %CopyrightEnd%
  19. */
  20. /*
  21. * fmt:
  22. * '%' <flag>* [ <width> [.<precision>]][<length>]<conversion>
  23. *
  24. * flag: # | O | - | <sp> | + | ' | I
  25. * width: [0-9]+ | '*'
  26. * precision: [0-9]+ | '*'
  27. * length: hh | h | l | ll | L | j | t | b<sz>
  28. * conversion: d,i | o,u,x,X | e,E | f,F | g,G | a,A | c | s | T | R |
  29. * p | n | %
  30. * sz: 8 | 16 | 32 | 64 | p | e
  31. */
  32. /* Without this, variable argument lists break on VxWorks */
  33. #ifdef VXWORKS
  34. #include <vxWorks.h>
  35. #endif
  36. #ifdef HAVE_CONFIG_H
  37. #include "config.h"
  38. #endif
  39. #ifdef __WIN32__
  40. #undef WIN32_LEAN_AND_MEAN
  41. #define WIN32_LEAN_AND_MEAN
  42. #include <windows.h>
  43. #endif
  44. #include <ctype.h>
  45. #include <string.h>
  46. #include <math.h>
  47. #include <stdio.h>
  48. #include <stdlib.h>
  49. #include "erl_errno.h"
  50. #include <limits.h>
  51. #include "erl_printf.h"
  52. #include "erl_printf_format.h"
  53. #ifdef DEBUG
  54. #include <assert.h>
  55. #define ASSERT(X) assert(X)
  56. #else
  57. #define ASSERT(X)
  58. #endif
  59. #ifdef __WIN32__
  60. #define long_long LONGLONG
  61. #define signed_long_long LONGLONG
  62. #define unsigned_long_long ULONGLONG
  63. #undef SIZEOF_LONG_LONG
  64. #define SIZEOF_LONG_LONG 8
  65. #else
  66. #if SIZEOF_LONG_LONG
  67. #define long_long long long
  68. #define signed_long_long signed long long
  69. #define unsigned_long_long unsigned long long
  70. #endif
  71. #endif
  72. #ifndef ERTS_SIZEOF_ETERM
  73. #define ERTS_SIZEOF_ETERM SIZEOF_VOID_P
  74. #endif
  75. #if defined(__GNUC__)
  76. # undef inline
  77. # define inline __inline__
  78. #elif defined(__WIN32__)
  79. # undef inline
  80. # define inline __forceinline
  81. #else
  82. # ifndef inline
  83. # define inline
  84. # endif
  85. #endif
  86. #define FMTC_d 0x0000
  87. /*empty 0x0001 was RELATIVE */
  88. #define FMTC_o 0x0002
  89. #define FMTC_u 0x0003
  90. #define FMTC_x 0x0004
  91. #define FMTC_X 0x0005
  92. #define FMTC_e 0x0006
  93. #define FMTC_E 0x0007
  94. #define FMTC_f 0x0008
  95. #define FMTC_T 0x0009
  96. #define FMTC_g 0x000a
  97. #define FMTC_G 0x000b
  98. #define FMTC_c 0x000c
  99. #define FMTC_s 0x000d
  100. #define FMTC_p 0x000e
  101. #define FMTC_n 0x000f
  102. #define FMTC_MASK 0x000f
  103. #define FMTL_no 0x0000
  104. #define FMTL_hh 0x0010
  105. #define FMTL_h 0x0020
  106. #define FMTL_l 0x0030
  107. #define FMTL_ll 0x0040
  108. #define FMTL_L 0x0050
  109. #define FMTL_j 0x0060
  110. #define FMTL_t 0x0070
  111. #define FMTL_MASK 0x00f0
  112. #define FMTF_alt 0x0100 /* # alterlate form ie 0x */
  113. #define FMTF_pad 0x0200 /* 0 zero pad */
  114. #define FMTF_adj 0x0400 /* left adjust */
  115. #define FMTF_blk 0x0800 /* add blank */
  116. #define FMTF_sgn 0x1000 /* add sign */
  117. #define FMTF_cnv 0x2000 /* decimal conversion */
  118. #define FMTF_cnV 0x4000 /* alternate decimal conversion */
  119. #define FMTF_MASK 0x7f00
  120. static char zeros[] = "00000000000000000000000000000000";
  121. static char blanks[] = " ";
  122. static char hex[] = "0123456789abcdef";
  123. static char heX[] = "0123456789ABCDEF";
  124. #define FMT(fn,arg,buf,len,count) do { \
  125. int res__ = (fn)((arg),(buf),(len)); \
  126. if (res__ < 0) \
  127. return res__; \
  128. (count) += (len); \
  129. } while(0)
  130. #define FILL(fn,arg,cs,len, count) do { \
  131. int __i = (len); \
  132. while(__i >= sizeof(cs)-1) { \
  133. FMT((fn),(arg),(cs),sizeof(cs)-1,(count)); \
  134. __i -= sizeof(cs)-1; \
  135. } \
  136. if (__i) FMT((fn),(arg),(cs),__i,(count)); \
  137. } while(0)
  138. #define BLANKS(fn,arg,n,count) FILL((fn),(arg),blanks,(n),count)
  139. #define ZEROS(fn,arg,n,count) FILL((fn),(arg),zeros,(n),count)
  140. #define SIGN(X) ((X) > 0 ? 1 : ((X) < 0 ? -1 : 0))
  141. #define USIGN(X) ((X) == 0 ? 0 : 1)
  142. int (*erts_printf_eterm_func)(fmtfn_t, void*, ErlPfEterm, long) = NULL;
  143. static int
  144. noop_fn(void *vfp, char* buf, size_t len)
  145. {
  146. return 0;
  147. }
  148. static int fmt_fld(fmtfn_t fn,void* arg,
  149. char* wbuf, int w, int sign,
  150. int width,int precision,int fmt,int* count)
  151. {
  152. char prefix[8];
  153. char* pp = prefix;
  154. int pw = 0;
  155. int len;
  156. /* format the prefix */
  157. if ((sign || (fmt & (FMTF_sgn|FMTF_blk)))
  158. && (fmt & FMTC_MASK) == FMTC_d) {
  159. if (sign < 0)
  160. *pp++ = '-';
  161. else if ((fmt & FMTF_sgn))
  162. *pp++ = '+';
  163. else if (fmt & FMTF_blk)
  164. *pp++ = ' ';
  165. }
  166. if ((fmt & FMTF_alt)) {
  167. switch((fmt & FMTC_MASK)) {
  168. case FMTC_X: *pp++ = '0'; *pp++ = 'X'; break;
  169. case FMTC_x: *pp++ = '0'; *pp++ = 'x'; break;
  170. case FMTC_o: *pp++ = '0'; if (precision>1) precision--; break;
  171. }
  172. }
  173. pw = pp-prefix;
  174. len = ((w < precision) ? precision : w) + pw;
  175. if (fmt & FMTF_adj) { /* left adjust */
  176. if (pw)
  177. FMT(fn,arg,prefix,pw,*count);
  178. if (w < precision)
  179. ZEROS(fn,arg,precision-w,*count);
  180. FMT(fn,arg, wbuf, w, *count);
  181. if (len < width)
  182. BLANKS(fn,arg,width-len,*count);
  183. }
  184. else if ((fmt & FMTF_pad) && (precision<0)) { /* pad zeros */
  185. if (pw)
  186. FMT(fn,arg, prefix, pw, *count);
  187. if (w < precision)
  188. ZEROS(fn, arg, precision-w, *count);
  189. if (len < width)
  190. ZEROS(fn,arg,width-len,*count);
  191. FMT(fn,arg,wbuf,w,*count);
  192. }
  193. else {
  194. if (len < width)
  195. BLANKS(fn,arg,width-len,*count);
  196. if (pw)
  197. FMT(fn,arg,prefix,pw,*count);
  198. if (w < precision)
  199. ZEROS(fn,arg,precision-w,*count);
  200. FMT(fn,arg,wbuf,w,*count);
  201. }
  202. return 0;
  203. }
  204. static int fmt_uword(fmtfn_t fn,void* arg,int sign,ErlPfUWord uval,
  205. int width,int precision,int fmt,int* count)
  206. {
  207. char buf[32];
  208. int base = 10;
  209. int w = 0;
  210. char* dc = hex;
  211. char* p = buf+sizeof(buf);
  212. switch(fmt & FMTC_MASK) {
  213. case FMTC_d:
  214. case FMTC_u:
  215. break;
  216. case FMTC_o:
  217. base = 8;
  218. break;
  219. case FMTC_X:
  220. dc = heX;
  221. case FMTC_x:
  222. base = 16;
  223. break;
  224. default:
  225. return -EINVAL;
  226. }
  227. /* format the unsigned value */
  228. if (!sign && precision) {
  229. *--p = '0';
  230. w++;
  231. }
  232. else {
  233. while(uval) {
  234. *--p = dc[(uval % base)];
  235. uval /= base;
  236. w++;
  237. }
  238. }
  239. return fmt_fld(fn, arg, p, w, sign, width, precision, fmt, count);
  240. }
  241. #if SIZEOF_LONG_LONG
  242. static inline int
  243. do_div(unsigned_long_long *n, unsigned_long_long base)
  244. {
  245. unsigned_long_long q = *n/base;
  246. int mod = (int) (*n - q*base);
  247. *n = q;
  248. return mod;
  249. }
  250. static int fmt_long_long(fmtfn_t fn,void* arg,int sign,
  251. unsigned_long_long uval,
  252. int width,int precision,int fmt,int* count)
  253. {
  254. char buf[32];
  255. int base = 10;
  256. int w = 0;
  257. char* dc = hex;
  258. char* p = buf+sizeof(buf);
  259. switch(fmt & FMTC_MASK) {
  260. case FMTC_d:
  261. case FMTC_u:
  262. break;
  263. case FMTC_o:
  264. base = 8;
  265. break;
  266. case FMTC_X:
  267. dc = heX;
  268. case FMTC_x:
  269. base = 16;
  270. break;
  271. default:
  272. return -EINVAL;
  273. }
  274. /* format the unsigned value */
  275. if (!sign && precision) {
  276. *--p = '0';
  277. w++;
  278. }
  279. else {
  280. while(uval) {
  281. int m = do_div(&uval,base);
  282. *--p = dc[m];
  283. w++;
  284. }
  285. }
  286. return fmt_fld(fn, arg, p, w, sign, width, precision, fmt, count);
  287. }
  288. #endif /* #if SIZEOF_LONG_LONG */
  289. static int fmt_double(fmtfn_t fn,void*arg,double val,
  290. int width, int precision, int fmt,int* count)
  291. {
  292. int res;
  293. int fi = 0;
  294. char format_str[8];
  295. char sbuf[32];
  296. char *bufp = sbuf;
  297. double dexp;
  298. int exp;
  299. size_t max_size = 2; /* including possible sign */
  300. int size;
  301. int new_fmt = fmt;
  302. int fpe_was_unmasked;
  303. fpe_was_unmasked = erts_printf_block_fpe ? (*erts_printf_block_fpe)() : 0;
  304. if (val < 0.0)
  305. dexp = log10(-val);
  306. else if (val == 0.0)
  307. dexp = 0.0;
  308. else
  309. dexp = log10(val);
  310. exp = (int) dexp;
  311. new_fmt &= ~FMTF_sgn;
  312. new_fmt &= ~FMTF_blk;
  313. format_str[fi++] = '%';
  314. if (fmt & FMTF_alt)
  315. format_str[fi++] = '#';
  316. if (fmt & FMTF_sgn)
  317. format_str[fi++] = '+';
  318. else if (fmt & FMTF_blk)
  319. format_str[fi++] = ' ';
  320. format_str[fi++] = '0';
  321. format_str[fi++] = '.';
  322. format_str[fi++] = '*';
  323. switch(fmt & FMTC_MASK) {
  324. case FMTC_G:
  325. format_str[fi] = 'E';
  326. goto gG_common;
  327. case FMTC_g:
  328. format_str[fi] = 'e';
  329. gG_common:
  330. if (dexp < -4.0 || exp >= precision) {
  331. fi++;
  332. precision--;
  333. if (precision < 1)
  334. precision = 1;
  335. goto eE_common;
  336. }
  337. /* fall through ... */
  338. case FMTC_f:
  339. format_str[fi++] = 'f';
  340. max_size += exp > 0 ? exp : 1;
  341. max_size++;
  342. if (precision)
  343. max_size += precision;
  344. else if (fmt & FMTF_alt)
  345. max_size++;
  346. break;
  347. case FMTC_E:
  348. format_str[fi++] = 'E';
  349. goto eE_common;
  350. case FMTC_e:
  351. format_str[fi++] = 'e';
  352. eE_common: {
  353. int aexp;
  354. max_size += 4;
  355. if (precision)
  356. max_size += precision;
  357. else if (fmt & FMTF_alt)
  358. max_size++;
  359. aexp = exp >= 0 ? exp : -exp;
  360. if (aexp < 100)
  361. max_size += 2;
  362. else {
  363. while (aexp) {
  364. max_size++;
  365. aexp /= 10;
  366. }
  367. }
  368. break;
  369. }
  370. default:
  371. res = -EINVAL;
  372. goto out;
  373. }
  374. format_str[fi++] = '\0';
  375. ASSERT(fi <= sizeof(format_str));
  376. max_size++; /* '\0' */
  377. if (max_size >= sizeof(sbuf)) {
  378. bufp = (char *) malloc(sizeof(char)*max_size);
  379. if (!bufp) {
  380. res = -ENOMEM;
  381. /* Make sure not to trigger free */
  382. bufp = sbuf;
  383. goto out;
  384. }
  385. }
  386. size = sprintf(bufp, format_str, precision, val);
  387. if (size < 0) {
  388. if (errno > 0)
  389. res = -errno;
  390. else
  391. res = -EIO;
  392. goto out;
  393. }
  394. ASSERT(max_size >= size);
  395. res = fmt_fld(fn, arg, bufp, size, 0, width, 0, new_fmt, count);
  396. out:
  397. if (bufp != sbuf)
  398. free((void *) bufp);
  399. if (erts_printf_unblock_fpe)
  400. (*erts_printf_unblock_fpe)(fpe_was_unmasked);
  401. return res;
  402. }
  403. /* strnlen doesn't exist everywhere */
  404. static size_t my_strnlen(const char *s, size_t maxlen)
  405. {
  406. size_t i = 0;
  407. while (i < maxlen && s[i] != '\0')
  408. i++;
  409. return i;
  410. }
  411. int erts_printf_format(fmtfn_t fn, void* arg, char* fmt, va_list ap)
  412. {
  413. char* ptr0 = fmt;
  414. char* ptr = ptr0;
  415. int count = 0;
  416. int n;
  417. int res = 0;
  418. while(*ptr) {
  419. ErlPfUWord ul_val;
  420. int fmt = 0;
  421. int width = -1;
  422. int precision = -1;
  423. if (res < 0)
  424. return res;
  425. if (*ptr == '%') {
  426. if ((n=ptr-ptr0))
  427. FMT(fn,arg,ptr0,n,count);
  428. ptr++;
  429. do_flag:
  430. switch(*ptr) {
  431. case '#': fmt |= FMTF_alt; ptr++; goto do_flag;
  432. case '0': fmt |= FMTF_pad; ptr++; goto do_flag;
  433. case '-': fmt |= FMTF_adj; ptr++; goto do_flag;
  434. case ' ': fmt |= FMTF_blk; ptr++; goto do_flag;
  435. case '+': fmt |= FMTF_sgn; ptr++; goto do_flag;
  436. case '\'': fmt |= FMTF_cnv; ptr++; goto do_flag;
  437. case 'I': fmt |= FMTF_cnV; ptr++; goto do_flag;
  438. }
  439. /* width */
  440. if (*ptr == '*') {
  441. width = va_arg(ap, int);
  442. ptr++;
  443. }
  444. else if (isdigit((int) *ptr)) {
  445. width = *ptr++ - '0';
  446. while(isdigit((int) *ptr))
  447. width = 10*width + (*ptr++ - '0');
  448. }
  449. /* precision */
  450. if (*ptr == '.') {
  451. ptr++;
  452. if (*ptr == '*') {
  453. precision = va_arg(ap, int);
  454. ptr++;
  455. }
  456. else if (isdigit((int) *ptr)) {
  457. precision = *ptr++ - '0';
  458. while(isdigit((int) *ptr))
  459. precision = 10*precision + (*ptr++ - '0');
  460. }
  461. }
  462. /* length modifier */
  463. switch(*ptr) {
  464. case 'b': {
  465. ptr++;
  466. if (*ptr == 'p') {
  467. ptr++;
  468. #if SIZEOF_INT == SIZEOF_VOID_P
  469. #elif SIZEOF_LONG == SIZEOF_VOID_P
  470. fmt |= FMTL_l;
  471. #elif SIZEOF_LONG_LONG == SIZEOF_VOID_P
  472. fmt |= FMTL_ll;
  473. #else
  474. #error No integer datatype with the same size as 'void *' found
  475. #endif
  476. }
  477. else if (*ptr == 'e') {
  478. ptr++;
  479. #if SIZEOF_INT == ERTS_SIZEOF_ETERM
  480. #elif SIZEOF_LONG == ERTS_SIZEOF_ETERM
  481. fmt |= FMTL_l;
  482. #elif SIZEOF_LONG_LONG == ERTS_SIZEOF_ETERM
  483. fmt |= FMTL_ll;
  484. #else
  485. #error No integer datatype with the same size as Eterm found
  486. #endif
  487. }
  488. else {
  489. int bits = 0;
  490. while(isdigit((int) *ptr))
  491. bits = 10*bits + (*ptr++ - '0');
  492. switch (bits) {
  493. case 64:
  494. #if SIZEOF_INT == 8
  495. #elif SIZEOF_LONG == 8
  496. fmt |= FMTL_l;
  497. #elif SIZEOF_LONG_LONG == 8
  498. fmt |= FMTL_ll;
  499. #else
  500. #error No 64-bit integer datatype found
  501. #endif
  502. break;
  503. case 32:
  504. #if SIZEOF_INT == 4
  505. #elif SIZEOF_SHORT == 4
  506. fmt |= FMTL_h;
  507. #elif SIZEOF_LONG == 4
  508. fmt |= FMTL_l;
  509. #elif SIZEOF_LONG_LONG == 4
  510. fmt |= FMTL_ll;
  511. #else
  512. #error No 32-bit integer datatype found
  513. #endif
  514. break;
  515. case 16:
  516. #if SIZEOF_INT == 2
  517. #elif SIZEOF_SHORT == 2
  518. fmt |= FMTL_h;
  519. #elif SIZEOF_LONG == 2
  520. fmt |= FMTL_l;
  521. #else
  522. #error No 16-bit integer datatype found
  523. #endif
  524. case 8:
  525. #if SIZEOF_CHAR == 1
  526. fmt |= FMTL_hh;
  527. #else
  528. #error Unexpected size of char
  529. #endif
  530. break;
  531. default:
  532. return -EINVAL;
  533. }
  534. }
  535. break;
  536. }
  537. case 'h':
  538. ptr++;
  539. if (*ptr == 'h') {
  540. ptr++;
  541. fmt |= FMTL_hh;
  542. }
  543. else
  544. fmt |= FMTL_h;
  545. break;
  546. case 'l':
  547. ptr++;
  548. if (*ptr == 'l') {
  549. ptr++;
  550. #if SIZEOF_LONG_LONG
  551. fmt |= FMTL_ll;
  552. #else
  553. fmt |= FMTL_l;
  554. #endif
  555. }
  556. else
  557. fmt |= FMTL_l;
  558. break;
  559. case 'L': ptr++; fmt |= FMTL_L; break;
  560. case 'j': ptr++; fmt |= FMTL_j; break;
  561. case 't': ptr++; fmt |= FMTL_t; break;
  562. }
  563. /* specifier */
  564. switch(*ptr) {
  565. case 'd': ptr++; fmt |= FMTC_d; break;
  566. case 'i': ptr++; fmt |= FMTC_d; break;
  567. case 'o': ptr++; fmt |= FMTC_o; break;
  568. case 'u': ptr++; fmt |= FMTC_u; break;
  569. case 'x': ptr++; fmt |= FMTC_x; break;
  570. case 'X': ptr++; fmt |= FMTC_X; break;
  571. case 'e': ptr++; fmt |= FMTC_e; break;
  572. case 'E': ptr++; fmt |= FMTC_E; break;
  573. case 'f': ptr++; fmt |= FMTC_f; break;
  574. case 'g': ptr++; fmt |= FMTC_g; break;
  575. case 'G': ptr++; fmt |= FMTC_G; break;
  576. case 'c': ptr++; fmt |= FMTC_c; break;
  577. case 's': ptr++; fmt |= FMTC_s; break;
  578. case 'p': ptr++; fmt |= FMTC_p; break;
  579. case 'n': ptr++; fmt |= FMTC_n; break;
  580. case 'T': ptr++; fmt |= FMTC_T; break;
  581. case '%':
  582. FMT(fn,arg,ptr,1,count);
  583. ptr++;
  584. ptr0 = ptr;
  585. continue;
  586. default:
  587. /* ignore */
  588. ptr0 = ptr;
  589. continue;
  590. }
  591. switch(fmt & FMTC_MASK) {
  592. case FMTC_d:
  593. switch(fmt & FMTL_MASK) {
  594. case FMTL_hh: {
  595. signed char tval = (signed char) va_arg(ap,int);
  596. ul_val = (ErlPfUWord) (tval < 0 ? (-tval) : tval);
  597. res = fmt_uword(fn,arg,SIGN(tval),ul_val,
  598. width,precision,fmt,&count);
  599. break;
  600. }
  601. case FMTL_h: {
  602. signed short tval = (signed short) va_arg(ap,int);
  603. ul_val = (ErlPfUWord) (tval < 0 ? (-tval) : tval);
  604. res = fmt_uword(fn,arg,SIGN(tval),ul_val,
  605. width,precision,fmt,&count);
  606. break;
  607. }
  608. case FMTL_l: {
  609. signed long tval = (signed long) va_arg(ap,long);
  610. ul_val = (ErlPfUWord) (tval < 0 ? (-tval) : tval);
  611. res = fmt_uword(fn,arg,SIGN(tval),ul_val,
  612. width,precision,fmt,&count);
  613. break;
  614. }
  615. #if SIZEOF_LONG_LONG
  616. case FMTL_ll: {
  617. unsigned_long_long ull_val;
  618. signed_long_long tval;
  619. tval = (signed_long_long) va_arg(ap,long_long);
  620. ull_val = (unsigned_long_long) (tval < 0 ? (-tval) : tval);
  621. res = fmt_long_long(fn,arg,SIGN(tval),ull_val,
  622. width,precision,fmt,&count);
  623. break;
  624. }
  625. #endif
  626. default: {
  627. signed int tval = (signed int) va_arg(ap,int);
  628. ul_val = (ErlPfUWord) (tval < 0 ? (-tval) : tval);
  629. res = fmt_uword(fn,arg,SIGN(tval),ul_val,
  630. width,precision,fmt,&count);
  631. break;
  632. }
  633. }
  634. break;
  635. case FMTC_o:
  636. case FMTC_u:
  637. case FMTC_x:
  638. case FMTC_X:
  639. switch(fmt & FMTL_MASK) {
  640. case FMTL_hh: {
  641. unsigned char tval = (unsigned char) va_arg(ap,int);
  642. ul_val = (ErlPfUWord) tval;
  643. res = fmt_uword(fn,arg,USIGN(tval),ul_val,
  644. width,precision,fmt,&count);
  645. break;
  646. }
  647. case FMTL_h: {
  648. unsigned short tval = (unsigned short) va_arg(ap,int);
  649. ul_val = (ErlPfUWord) tval;
  650. res = fmt_uword(fn,arg,USIGN(tval),ul_val,
  651. width,precision,fmt,&count);
  652. break;
  653. }
  654. case FMTL_l: {
  655. ul_val = (ErlPfUWord) va_arg(ap,long);
  656. res = fmt_uword(fn,arg,USIGN(ul_val),ul_val,
  657. width,precision,fmt,&count);
  658. break;
  659. }
  660. #if SIZEOF_LONG_LONG
  661. case FMTL_ll: {
  662. unsigned_long_long ull_val;
  663. ull_val = (signed_long_long) va_arg(ap,long_long);
  664. res = fmt_long_long(fn,arg,USIGN(ull_val),ull_val,
  665. width,precision,fmt,&count);
  666. break;
  667. }
  668. #endif
  669. default: {
  670. unsigned int tval = (unsigned int) va_arg(ap,int);
  671. ul_val = (ErlPfUWord) tval;
  672. res = fmt_uword(fn,arg,USIGN(tval),ul_val,
  673. width,precision,fmt,&count);
  674. break;
  675. }
  676. }
  677. break;
  678. case FMTC_e:
  679. case FMTC_E:
  680. case FMTC_f:
  681. case FMTC_g:
  682. case FMTC_G:
  683. if (precision < 0)
  684. precision = 6;
  685. switch(fmt & FMTL_MASK) {
  686. case FMTL_L:
  687. return -EINVAL;
  688. break;
  689. default:
  690. res = fmt_double(fn,arg,va_arg(ap,double),
  691. width,precision,fmt,&count);
  692. break;
  693. }
  694. break;
  695. case FMTC_c: {
  696. /* fixme: add wide char support l-modifier */
  697. char c = va_arg(ap,int);
  698. int len = 1;
  699. if (precision == 0)
  700. len = 0;
  701. if (width > 0 && !(fmt & FMTF_adj)) {
  702. if (width > len)
  703. BLANKS(fn, arg, width - len, count);
  704. }
  705. if (len)
  706. FMT(fn,arg,&c,len,count);
  707. if (width > len && fmt & FMTF_adj)
  708. BLANKS(fn, arg, width - len, count);
  709. break;
  710. }
  711. case FMTC_s: {
  712. char* str = va_arg(ap,char*);
  713. int len = (precision >= 0) ? my_strnlen(str,precision) : strlen(str);
  714. if (width > 0 && !(fmt & FMTF_adj)) {
  715. if (width > len)
  716. BLANKS(fn, arg, width - len, count);
  717. }
  718. if (len)
  719. FMT(fn,arg,str,len,count);
  720. if (width > len && fmt & FMTF_adj)
  721. BLANKS(fn, arg, width - len, count);
  722. break;
  723. }
  724. case FMTC_p: {
  725. void* addr = va_arg(ap, void*);
  726. res = fmt_uword(fn,
  727. arg,
  728. USIGN((ErlPfUWord) addr),
  729. (ErlPfUWord) addr,
  730. width < 0 ? ((int) 2*sizeof(void *)) : width,
  731. (precision < 0
  732. ? ((int) 2*sizeof(void *))
  733. : precision),
  734. FMTC_x|FMTF_pad|FMTF_alt,
  735. &count);
  736. break;
  737. }
  738. case FMTC_n:
  739. switch(fmt & FMTL_MASK) {
  740. case FMTL_hh: *va_arg(ap,char*) = count; break;
  741. case FMTL_h: *va_arg(ap,short*) = count; break;
  742. case FMTL_l: *va_arg(ap,long*) = count; break;
  743. #if SIZEOF_LONG_LONG
  744. case FMTL_ll: *va_arg(ap,long_long*) = count; break;
  745. #endif
  746. default: *va_arg(ap,int*) = count; break;
  747. }
  748. break;
  749. case FMTC_T: { /* Eterm */
  750. long prec;
  751. ErlPfEterm eterm;
  752. if (!erts_printf_eterm_func)
  753. return -EINVAL;
  754. if (precision < 0)
  755. prec = 100000;
  756. else if (precision == INT_MAX)
  757. prec = LONG_MAX;
  758. else
  759. prec = (long) precision;
  760. eterm = va_arg(ap, ErlPfEterm);
  761. if (width > 0 && !(fmt & FMTF_adj)) {
  762. res = (*erts_printf_eterm_func)(noop_fn, NULL, eterm, prec);
  763. if (res < 0)
  764. return res;
  765. if (width > res)
  766. BLANKS(fn, arg, width - res, count);
  767. }
  768. res = (*erts_printf_eterm_func)(fn, arg, eterm, prec);
  769. if (res < 0)
  770. return res;
  771. count += res;
  772. if (width > res && fmt & FMTF_adj)
  773. BLANKS(fn, arg, width - res, count);
  774. break;
  775. }
  776. default:
  777. if ((n=ptr-ptr0))
  778. FMT(fn,arg,ptr0,n,count);
  779. }
  780. ptr0 = ptr;
  781. }
  782. else
  783. ptr++;
  784. }
  785. if ((n=ptr-ptr0))
  786. FMT(fn,arg,ptr0,n,count);
  787. return count;
  788. }
  789. int
  790. erts_printf_char(fmtfn_t fn, void *arg, char c)
  791. {
  792. return (*fn)(arg, &c, 1);
  793. }
  794. int
  795. erts_printf_string(fmtfn_t fn, void *arg, char *str)
  796. {
  797. size_t sz = strlen(str);
  798. return (*fn)(arg, str, sz);
  799. }
  800. int
  801. erts_printf_buf(fmtfn_t fn, void *arg, char *buf, size_t sz)
  802. {
  803. return (*fn)(arg, buf, sz);
  804. }
  805. int
  806. erts_printf_pointer(fmtfn_t fn, void *arg, void *ptr)
  807. {
  808. int count = 0;
  809. int res = fmt_uword(fn, arg, USIGN((ErlPfUWord) ptr),
  810. (ErlPfUWord) ptr, 2*sizeof(void *),
  811. 2*sizeof(void *), FMTC_x|FMTF_pad|FMTF_alt, &count);
  812. if (res < 0)
  813. return res;
  814. return count;
  815. }
  816. int
  817. erts_printf_uword(fmtfn_t fn, void *arg, char conv, int pad, int width,
  818. ErlPfUWord val)
  819. {
  820. int count = 0;
  821. int res;
  822. int fmt = 0;
  823. int prec = -1;
  824. switch (conv) {
  825. case 'o': fmt |= FMTC_o; break;
  826. case 'u': fmt |= FMTC_u; break;
  827. case 'x': fmt |= FMTC_x; break;
  828. case 'X': fmt |= FMTC_X; break;
  829. case 'p': fmt |= FMTC_p; break;
  830. default:
  831. return -EINVAL;
  832. }
  833. if (pad)
  834. prec = width;
  835. res = fmt_uword(fn, arg, USIGN(val), val, width, prec, fmt, &count);
  836. if (res < 0)
  837. return res;
  838. return count;
  839. }
  840. int
  841. erts_printf_sword(fmtfn_t fn, void *arg, char conv, int pad, int width,
  842. ErlPfSWord val)
  843. {
  844. int count = 0;
  845. int res;
  846. int fmt = 0;
  847. int prec = -1;
  848. ErlPfUWord ul_val;
  849. switch (conv) {
  850. case 'd': fmt |= FMTC_d; break;
  851. case 'i': fmt |= FMTC_d; break;
  852. case 'o': fmt |= FMTC_o; break;
  853. case 'x': fmt |= FMTC_x; break;
  854. case 'X': fmt |= FMTC_X; break;
  855. default:
  856. return -EINVAL;
  857. }
  858. if (pad)
  859. prec = width;
  860. ul_val = (ErlPfUWord) (val < 0 ? -val : val);
  861. res = fmt_uword(fn, arg, SIGN(val), ul_val, width, prec, fmt, &count);
  862. if (res < 0)
  863. return res;
  864. return count;
  865. }
  866. int
  867. erts_printf_double(fmtfn_t fn, void *arg, char conv, int precision, int width,
  868. double val)
  869. {
  870. int count = 0;
  871. int res;
  872. int fmt = 0;
  873. switch (conv) {
  874. case 'e': fmt |= FMTC_e; break;
  875. case 'E': fmt |= FMTC_E; break;
  876. case 'f': fmt |= FMTC_f; break;
  877. case 'g': fmt |= FMTC_g; break;
  878. case 'G': fmt |= FMTC_G; break;
  879. default:
  880. return -EINVAL;
  881. }
  882. res = fmt_double(fn, arg, val, width, precision, fmt, &count);
  883. if (res < 0)
  884. return res;
  885. return count;
  886. }