printf.c 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803
  1. // Copyright (C) 2004-2025 Artifex Software, Inc.
  2. //
  3. // This file is part of MuPDF.
  4. //
  5. // MuPDF is free software: you can redistribute it and/or modify it under the
  6. // terms of the GNU Affero General Public License as published by the Free
  7. // Software Foundation, either version 3 of the License, or (at your option)
  8. // any later version.
  9. //
  10. // MuPDF is distributed in the hope that it will be useful, but WITHOUT ANY
  11. // WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
  12. // FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
  13. // details.
  14. //
  15. // You should have received a copy of the GNU Affero General Public License
  16. // along with MuPDF. If not, see <https://www.gnu.org/licenses/agpl-3.0.en.html>
  17. //
  18. // Alternative licensing terms are available from the licensor.
  19. // For commercial licensing, see <https://www.artifex.com/> or contact
  20. // Artifex Software, Inc., 39 Mesa Street, Suite 108A, San Francisco,
  21. // CA 94129, USA, for further information.
  22. #include "mupdf/fitz.h"
  23. #include <float.h>
  24. #include <math.h>
  25. #include <stdarg.h>
  26. #include <stdio.h>
  27. #ifdef _MSC_VER
  28. #if _MSC_VER < 1500 /* MSVC 2008 */
  29. int snprintf(char *s, size_t n, const char *fmt, ...)
  30. {
  31. int r;
  32. va_list ap;
  33. va_start(ap, fmt);
  34. r = vsprintf(s, fmt, ap);
  35. va_end(ap);
  36. return r;
  37. }
  38. #else if _MSC_VER < 1900 /* MSVC 2015 */
  39. #define snprintf _snprintf
  40. #endif
  41. #endif
  42. static const char *fz_hex_digits = "0123456789abcdef";
  43. static const char *fz_hex_digits_UC = "0123456789ABCDEF";
  44. struct fmtbuf
  45. {
  46. fz_context *ctx;
  47. void *user;
  48. void (*emit)(fz_context *ctx, void *user, int c);
  49. };
  50. static inline void fmtputc(struct fmtbuf *out, int c)
  51. {
  52. out->emit(out->ctx, out->user, c);
  53. }
  54. /*
  55. * Convert float to shortest possible string that won't lose precision, except:
  56. * NaN to 0, +Inf to FLT_MAX, -Inf to -FLT_MAX.
  57. */
  58. static void fmtfloat(struct fmtbuf *out, float f)
  59. {
  60. char digits[40], *s = digits;
  61. int exp, ndigits, point;
  62. if (isnan(f)) f = 0;
  63. if (isinf(f)) f = f < 0 ? -FLT_MAX : FLT_MAX;
  64. if (signbit(f))
  65. fmtputc(out, '-');
  66. if (f == 0)
  67. {
  68. fmtputc(out, '0');
  69. return;
  70. }
  71. ndigits = fz_grisu(f, digits, &exp);
  72. point = exp + ndigits;
  73. if (point <= 0)
  74. {
  75. fmtputc(out, '.');
  76. while (point++ < 0)
  77. fmtputc(out, '0');
  78. while (ndigits-- > 0)
  79. fmtputc(out, *s++);
  80. }
  81. else
  82. {
  83. while (ndigits-- > 0)
  84. {
  85. fmtputc(out, *s++);
  86. if (--point == 0 && ndigits > 0)
  87. fmtputc(out, '.');
  88. }
  89. while (point-- > 0)
  90. fmtputc(out, '0');
  91. }
  92. }
  93. static void fmtfloat_e(struct fmtbuf *out, double f, int w, int p)
  94. {
  95. char buf[100], *s = buf;
  96. snprintf(buf, sizeof buf, "%*.*e", w, p, f);
  97. while (*s)
  98. fmtputc(out, *s++);
  99. }
  100. static void fmtfloat_f(struct fmtbuf *out, double f, int w, int p)
  101. {
  102. char buf[100], *s = buf;
  103. snprintf(buf, sizeof buf, "%*.*f", w, p, f);
  104. while (*s)
  105. fmtputc(out, *s++);
  106. }
  107. static void fmtuint32(struct fmtbuf *out, unsigned int a, int s, int z, int w, int base, int q)
  108. {
  109. char buf[40];
  110. int i;
  111. const char *hex_digits = fz_hex_digits;
  112. if (base < 0)
  113. {
  114. base = -base;
  115. hex_digits = fz_hex_digits_UC;
  116. }
  117. i = 0;
  118. if (a == 0)
  119. buf[i++] = '0';
  120. while (a) {
  121. buf[i++] = hex_digits[a % base];
  122. a /= base;
  123. }
  124. if (s) {
  125. if (z == '0')
  126. while (i < w - 1)
  127. buf[i++] = z;
  128. buf[i++] = s;
  129. }
  130. while (i < w)
  131. buf[i++] = z;
  132. while (i > 0)
  133. {
  134. fmtputc(out, buf[--i]);
  135. if (q && i != 0 && i % 3 == 0)
  136. fmtputc(out, q);
  137. }
  138. }
  139. static void fmtuint64(struct fmtbuf *out, uint64_t a, int s, int z, int w, int base, int q)
  140. {
  141. char buf[80];
  142. int i;
  143. const char *hex_digits = fz_hex_digits;
  144. if (base < 0)
  145. {
  146. base = -base;
  147. hex_digits = fz_hex_digits_UC;
  148. }
  149. i = 0;
  150. if (a == 0)
  151. buf[i++] = '0';
  152. while (a) {
  153. buf[i++] = hex_digits[a % base];
  154. a /= base;
  155. }
  156. if (s) {
  157. if (z == '0')
  158. while (i < w - 1)
  159. buf[i++] = z;
  160. buf[i++] = s;
  161. }
  162. while (i < w)
  163. buf[i++] = z;
  164. while (i > 0)
  165. {
  166. fmtputc(out, buf[--i]);
  167. if (q && i != 0 && i % 3 == 0)
  168. fmtputc(out, q);
  169. }
  170. }
  171. static void fmtint32(struct fmtbuf *out, int value, int s, int z, int w, int base, int q)
  172. {
  173. unsigned int a;
  174. if (value < 0)
  175. {
  176. s = '-';
  177. a = -value;
  178. }
  179. else if (s)
  180. {
  181. s = '+';
  182. a = value;
  183. }
  184. else
  185. {
  186. s = 0;
  187. a = value;
  188. }
  189. fmtuint32(out, a, s, z, w, base, q);
  190. }
  191. static void fmtint64(struct fmtbuf *out, int64_t value, int s, int z, int w, int base, int q)
  192. {
  193. uint64_t a;
  194. if (value < 0)
  195. {
  196. s = '-';
  197. a = -value;
  198. }
  199. else if (s)
  200. {
  201. s = '+';
  202. a = value;
  203. }
  204. else
  205. {
  206. s = 0;
  207. a = value;
  208. }
  209. fmtuint64(out, a, s, z, w, base, q);
  210. }
  211. static void fmtquote(struct fmtbuf *out, const char *s, int sq, int eq, int verbatim)
  212. {
  213. int i, n, c;
  214. fmtputc(out, sq);
  215. while (*s != 0) {
  216. n = fz_chartorune(&c, s);
  217. switch (c) {
  218. default:
  219. if (c < 32) {
  220. fmtputc(out, '\\');
  221. fmtputc(out, 'x');
  222. fmtputc(out, "0123456789ABCDEF"[(c>>4)&15]);
  223. fmtputc(out, "0123456789ABCDEF"[(c)&15]);
  224. } else if (c > 127) {
  225. if (verbatim)
  226. {
  227. for (i = 0; i < n; ++i)
  228. fmtputc(out, s[i]);
  229. }
  230. else if (c <= 0xffff)
  231. {
  232. fmtputc(out, '\\');
  233. fmtputc(out, 'u');
  234. fmtputc(out, "0123456789ABCDEF"[(c>>12)&15]);
  235. fmtputc(out, "0123456789ABCDEF"[(c>>8)&15]);
  236. fmtputc(out, "0123456789ABCDEF"[(c>>4)&15]);
  237. fmtputc(out, "0123456789ABCDEF"[(c)&15]);
  238. }
  239. else
  240. {
  241. /* Use a surrogate pair */
  242. int hi = 0xd800 + ((c - 0x10000) >> 10);
  243. int lo = 0xdc00 + ((c - 0x10000) & 0x3ff);
  244. fmtputc(out, '\\');
  245. fmtputc(out, 'u');
  246. fmtputc(out, "0123456789ABCDEF"[(hi>>12)&15]);
  247. fmtputc(out, "0123456789ABCDEF"[(hi>>8)&15]);
  248. fmtputc(out, "0123456789ABCDEF"[(hi>>4)&15]);
  249. fmtputc(out, "0123456789ABCDEF"[(hi)&15]);
  250. fmtputc(out, '\\');
  251. fmtputc(out, 'u');
  252. fmtputc(out, "0123456789ABCDEF"[(lo>>12)&15]);
  253. fmtputc(out, "0123456789ABCDEF"[(lo>>8)&15]);
  254. fmtputc(out, "0123456789ABCDEF"[(lo>>4)&15]);
  255. fmtputc(out, "0123456789ABCDEF"[(lo)&15]);
  256. }
  257. } else {
  258. if (c == sq || c == eq)
  259. fmtputc(out, '\\');
  260. fmtputc(out, c);
  261. }
  262. break;
  263. case '\\': fmtputc(out, '\\'); fmtputc(out, '\\'); break;
  264. case '\b': fmtputc(out, '\\'); fmtputc(out, 'b'); break;
  265. case '\f': fmtputc(out, '\\'); fmtputc(out, 'f'); break;
  266. case '\n': fmtputc(out, '\\'); fmtputc(out, 'n'); break;
  267. case '\r': fmtputc(out, '\\'); fmtputc(out, 'r'); break;
  268. case '\t': fmtputc(out, '\\'); fmtputc(out, 't'); break;
  269. }
  270. s += n;
  271. }
  272. fmtputc(out, eq);
  273. }
  274. static void fmtquote_pdf(struct fmtbuf *out, const char *s, int sq, int eq)
  275. {
  276. int c;
  277. fmtputc(out, sq);
  278. while ((c = (unsigned char)*s++) != 0) {
  279. switch (c) {
  280. default:
  281. if (c < 32 || c > 127) {
  282. fmtputc(out, '\\');
  283. if (sq == '(')
  284. {
  285. fmtputc(out, '0' + ((c >> 6) & 7));
  286. fmtputc(out, '0' + ((c >> 3) & 7));
  287. fmtputc(out, '0' + ((c) & 7));
  288. }
  289. else
  290. {
  291. fmtputc(out, 'x');
  292. fmtputc(out, "0123456789ABCDEF"[(c>>4)&15]);
  293. fmtputc(out, "0123456789ABCDEF"[(c)&15]);
  294. }
  295. } else {
  296. if (c == sq || c == eq)
  297. fmtputc(out, '\\');
  298. fmtputc(out, c);
  299. }
  300. break;
  301. case '\\': fmtputc(out, '\\'); fmtputc(out, '\\'); break;
  302. case '\b': fmtputc(out, '\\'); fmtputc(out, 'b'); break;
  303. case '\f': fmtputc(out, '\\'); fmtputc(out, 'f'); break;
  304. case '\n': fmtputc(out, '\\'); fmtputc(out, 'n'); break;
  305. case '\r': fmtputc(out, '\\'); fmtputc(out, 'r'); break;
  306. case '\t': fmtputc(out, '\\'); fmtputc(out, 't'); break;
  307. }
  308. }
  309. fmtputc(out, eq);
  310. }
  311. int
  312. fz_is_valid_xml_char(int c)
  313. {
  314. if (c == 9 || c == 10 || c == 13)
  315. return 1;
  316. if (c < 32)
  317. return 0;
  318. if (c < 0xd800)
  319. return 1;
  320. if (c < 0xe000)
  321. return 0;
  322. if (c <= 0xfffd)
  323. return 1;
  324. if (c < 0x10000)
  325. return 0;
  326. if (c <= 0x10FFFF)
  327. return 1;
  328. return 0;
  329. }
  330. int
  331. fz_is_valid_xml_string(const char *s)
  332. {
  333. int c, n;
  334. while (*s != 0) {
  335. n = fz_chartorune(&c, s);
  336. if (!fz_is_valid_xml_char(c))
  337. return 0;
  338. s += n;
  339. }
  340. return 1;
  341. }
  342. int
  343. fz_range_limit_xml_char(int c)
  344. {
  345. if (fz_is_valid_xml_char(c))
  346. return c;
  347. return 0xFFFD;
  348. }
  349. static void fmtquote_xml(struct fmtbuf *out, const char *s)
  350. {
  351. int c, n;
  352. fmtputc(out, '"');
  353. while (*s != 0) {
  354. n = fz_chartorune(&c, s);
  355. switch (c) {
  356. case '"':
  357. fmtputc(out, '&');
  358. fmtputc(out, 'q');
  359. fmtputc(out, 'u');
  360. fmtputc(out, 'o');
  361. fmtputc(out, 't');
  362. fmtputc(out, ';');
  363. break;
  364. case '&':
  365. fmtputc(out, '&');
  366. fmtputc(out, 'a');
  367. fmtputc(out, 'm');
  368. fmtputc(out, 'p');
  369. fmtputc(out, ';');
  370. break;
  371. case '<':
  372. fmtputc(out, '&');
  373. fmtputc(out, 'l');
  374. fmtputc(out, 't');
  375. fmtputc(out, ';');
  376. break;
  377. case '>':
  378. fmtputc(out, '&');
  379. fmtputc(out, 'g');
  380. fmtputc(out, 't');
  381. fmtputc(out, ';');
  382. break;
  383. default:
  384. c = fz_range_limit_xml_char(c);
  385. if (c < 32 || c >= 127)
  386. {
  387. fmtputc(out, '&');
  388. fmtputc(out, '#');
  389. fmtputc(out, 'x');
  390. if (c > 65535)
  391. {
  392. fmtputc(out, "0123456789ABCDEF"[(c>>20)&15]);
  393. fmtputc(out, "0123456789ABCDEF"[(c>>16)&15]);
  394. }
  395. if (c > 255)
  396. {
  397. fmtputc(out, "0123456789ABCDEF"[(c>>12)&15]);
  398. fmtputc(out, "0123456789ABCDEF"[(c>>8)&15]);
  399. }
  400. fmtputc(out, "0123456789ABCDEF"[(c>>4)&15]);
  401. fmtputc(out, "0123456789ABCDEF"[(c)&15]);
  402. fmtputc(out, ';');
  403. }
  404. else
  405. fmtputc(out, c);
  406. break;
  407. }
  408. s += n;
  409. }
  410. fmtputc(out, '"');
  411. }
  412. static void fmtquote_hex(struct fmtbuf *out, const char *s)
  413. {
  414. int c;
  415. fmtputc(out, '"');
  416. while ((c = *s++) != 0)
  417. {
  418. fmtputc(out, "0123456789ABCDEF"[(c>>4)&15]);
  419. fmtputc(out, "0123456789ABCDEF"[(c)&15]);
  420. }
  421. fmtputc(out, '"');
  422. }
  423. static void fmtname(struct fmtbuf *out, const char *s)
  424. {
  425. int c;
  426. fmtputc(out, '/');
  427. while ((c = *s++) != 0) {
  428. if (c <= 32 || c == '/' || c == '#') {
  429. fmtputc(out, '#');
  430. fmtputc(out, "0123456789ABCDEF"[(c>>4)&15]);
  431. fmtputc(out, "0123456789ABCDEF"[(c)&15]);
  432. } else {
  433. fmtputc(out, c);
  434. }
  435. }
  436. }
  437. void
  438. fz_format_string(fz_context *ctx, void *user, void (*emit)(fz_context *ctx, void *user, int c), const char *fmt, va_list args)
  439. {
  440. struct fmtbuf out;
  441. int c, s, z, p, w, q;
  442. int32_t i32;
  443. int64_t i64;
  444. const char *str;
  445. size_t bits;
  446. out.ctx = ctx;
  447. out.user = user;
  448. out.emit = emit;
  449. while ((c = *fmt++) != 0)
  450. {
  451. if (c == '%')
  452. {
  453. q = 0;
  454. s = 0;
  455. z = ' ';
  456. /* flags */
  457. while ((c = *fmt++) != 0)
  458. {
  459. /* plus sign */
  460. if (c == '+')
  461. s = 1;
  462. /* space sign */
  463. else if (c == ' ')
  464. s = ' ';
  465. /* zero padding */
  466. else if (c == '0')
  467. z = '0';
  468. /* comma separators */
  469. else if (c == '\'')
  470. q = '\'';
  471. else if (c == ',')
  472. q = ',';
  473. else if (c == '_')
  474. q = '_';
  475. /* TODO: '-' to left justify */
  476. else
  477. break;
  478. }
  479. if (c == 0)
  480. break;
  481. /* width */
  482. w = 0;
  483. if (c == '*') {
  484. c = *fmt++;
  485. w = va_arg(args, int);
  486. } else {
  487. while (c >= '0' && c <= '9') {
  488. w = w * 10 + c - '0';
  489. c = *fmt++;
  490. }
  491. }
  492. if (c == 0)
  493. break;
  494. /* precision */
  495. p = 6;
  496. if (c == '.') {
  497. c = *fmt++;
  498. if (c == 0)
  499. break;
  500. if (c == '*') {
  501. c = *fmt++;
  502. p = va_arg(args, int);
  503. } else {
  504. if (c >= '0' && c <= '9')
  505. p = 0;
  506. while (c >= '0' && c <= '9') {
  507. p = p * 10 + c - '0';
  508. c = *fmt++;
  509. }
  510. }
  511. }
  512. if (c == 0)
  513. break;
  514. /* lengths */
  515. bits = 0;
  516. if (c == 'l') {
  517. c = *fmt++;
  518. bits = sizeof(int64_t) * 8;
  519. if (c == 0)
  520. break;
  521. }
  522. if (c == 't') {
  523. c = *fmt++;
  524. bits = sizeof(ptrdiff_t) * 8;
  525. if (c == 0)
  526. break;
  527. }
  528. if (c == 'z') {
  529. c = *fmt++;
  530. bits = sizeof(size_t) * 8;
  531. if (c == 0)
  532. break;
  533. }
  534. switch (c) {
  535. default:
  536. fmtputc(&out, '%');
  537. fmtputc(&out, c);
  538. break;
  539. case '%':
  540. fmtputc(&out, '%');
  541. break;
  542. case 'M':
  543. {
  544. fz_matrix *matrix = va_arg(args, fz_matrix*);
  545. fmtfloat(&out, matrix->a); fmtputc(&out, ' ');
  546. fmtfloat(&out, matrix->b); fmtputc(&out, ' ');
  547. fmtfloat(&out, matrix->c); fmtputc(&out, ' ');
  548. fmtfloat(&out, matrix->d); fmtputc(&out, ' ');
  549. fmtfloat(&out, matrix->e); fmtputc(&out, ' ');
  550. fmtfloat(&out, matrix->f);
  551. }
  552. break;
  553. case 'R':
  554. {
  555. fz_rect *rect = va_arg(args, fz_rect*);
  556. fmtfloat(&out, rect->x0); fmtputc(&out, ' ');
  557. fmtfloat(&out, rect->y0); fmtputc(&out, ' ');
  558. fmtfloat(&out, rect->x1); fmtputc(&out, ' ');
  559. fmtfloat(&out, rect->y1);
  560. }
  561. break;
  562. case 'P':
  563. {
  564. fz_point *point = va_arg(args, fz_point*);
  565. fmtfloat(&out, point->x); fmtputc(&out, ' ');
  566. fmtfloat(&out, point->y);
  567. }
  568. break;
  569. case 'C': /* unicode char */
  570. c = va_arg(args, int);
  571. if (c < 128)
  572. fmtputc(&out, c);
  573. else {
  574. char buf[10];
  575. int i, n = fz_runetochar(buf, c);
  576. for (i=0; i < n; ++i)
  577. fmtputc(&out, buf[i]);
  578. }
  579. break;
  580. case 'c':
  581. c = va_arg(args, int);
  582. fmtputc(&out, c);
  583. break;
  584. case 'e':
  585. fmtfloat_e(&out, va_arg(args, double), w, p);
  586. break;
  587. case 'f':
  588. fmtfloat_f(&out, va_arg(args, double), w, p);
  589. break;
  590. case 'g':
  591. fmtfloat(&out, va_arg(args, double));
  592. break;
  593. case 'p':
  594. bits = 8 * sizeof(void *);
  595. z = '0';
  596. fmtputc(&out, '0');
  597. fmtputc(&out, 'x');
  598. q = 0;
  599. /* fallthrough */
  600. case 'x':
  601. if (bits == 64)
  602. {
  603. i64 = va_arg(args, int64_t);
  604. fmtuint64(&out, i64, 0, z, w, 16, q);
  605. }
  606. else
  607. {
  608. i32 = va_arg(args, int);
  609. fmtuint32(&out, i32, 0, z, w, 16, q);
  610. }
  611. break;
  612. case 'X':
  613. if (bits == 64)
  614. {
  615. i64 = va_arg(args, int64_t);
  616. fmtuint64(&out, i64, 0, z, w, -16, q);
  617. }
  618. else
  619. {
  620. i32 = va_arg(args, int);
  621. fmtuint32(&out, i32, 0, z, w, -16, q);
  622. }
  623. break;
  624. case 'd':
  625. case 'i':
  626. if (bits == 64)
  627. {
  628. i64 = va_arg(args, int64_t);
  629. fmtint64(&out, i64, s, z, w, 10, q);
  630. }
  631. else
  632. {
  633. i32 = va_arg(args, int);
  634. fmtint32(&out, i32, s, z, w, 10, q);
  635. }
  636. break;
  637. case 'u':
  638. if (bits == 64)
  639. {
  640. i64 = va_arg(args, int64_t);
  641. fmtuint64(&out, i64, 0, z, w, 10, q);
  642. }
  643. else
  644. {
  645. i32 = va_arg(args, int);
  646. fmtuint32(&out, i32, 0, z, w, 10, q);
  647. }
  648. break;
  649. case 's':
  650. str = va_arg(args, const char*);
  651. if (!str)
  652. str = "(null)";
  653. while ((c = *str++) != 0)
  654. fmtputc(&out, c);
  655. break;
  656. case 'Q': /* quoted string (with verbatim unicode) */
  657. str = va_arg(args, const char*);
  658. if (!str) str = "";
  659. fmtquote(&out, str, '"', '"', 1);
  660. break;
  661. case 'q': /* quoted string */
  662. str = va_arg(args, const char*);
  663. if (!str) str = "";
  664. fmtquote(&out, str, '"', '"', 0);
  665. break;
  666. case '<': /* quoted string for xml */
  667. str = va_arg(args, const char*);
  668. if (!str) str = "";
  669. fmtquote_xml(&out, str);
  670. break;
  671. case '>': /* hex string */
  672. str = va_arg(args, const char*);
  673. if (!str) str = "";
  674. fmtquote_hex(&out, str);
  675. break;
  676. case '(': /* pdf string */
  677. str = va_arg(args, const char*);
  678. if (!str) str = "";
  679. fmtquote_pdf(&out, str, '(', ')');
  680. break;
  681. case 'n': /* pdf name */
  682. str = va_arg(args, const char*);
  683. if (!str) str = "";
  684. fmtname(&out, str);
  685. break;
  686. }
  687. }
  688. else
  689. {
  690. fmtputc(&out, c);
  691. }
  692. }
  693. }
  694. struct snprintf_buffer
  695. {
  696. char *p;
  697. size_t s, n;
  698. };
  699. static void snprintf_emit(fz_context *ctx, void *out_, int c)
  700. {
  701. struct snprintf_buffer *out = out_;
  702. if (out->n < out->s)
  703. out->p[out->n] = c;
  704. ++(out->n);
  705. }
  706. size_t
  707. fz_vsnprintf(char *buffer, size_t space, const char *fmt, va_list args)
  708. {
  709. struct snprintf_buffer out;
  710. out.p = buffer;
  711. out.s = space > 0 ? space - 1 : 0;
  712. out.n = 0;
  713. /* Note: using a NULL context is safe here */
  714. fz_format_string(NULL, &out, snprintf_emit, fmt, args);
  715. if (space > 0)
  716. out.p[out.n < space ? out.n : space - 1] = '\0';
  717. return out.n;
  718. }
  719. size_t
  720. fz_snprintf(char *buffer, size_t space, const char *fmt, ...)
  721. {
  722. va_list ap;
  723. struct snprintf_buffer out;
  724. out.p = buffer;
  725. out.s = space > 0 ? space - 1 : 0;
  726. out.n = 0;
  727. va_start(ap, fmt);
  728. /* Note: using a NULL context is safe here */
  729. fz_format_string(NULL, &out, snprintf_emit, fmt, ap);
  730. if (space > 0)
  731. out.p[out.n < space ? out.n : space - 1] = '\0';
  732. va_end(ap);
  733. return out.n;
  734. }
  735. char *
  736. fz_asprintf(fz_context *ctx, const char *fmt, ...)
  737. {
  738. size_t len;
  739. char *mem;
  740. va_list ap;
  741. va_start(ap, fmt);
  742. len = fz_vsnprintf(NULL, 0, fmt, ap);
  743. va_end(ap);
  744. mem = Memento_label(fz_malloc(ctx, len+1), "asprintf");
  745. va_start(ap, fmt);
  746. fz_vsnprintf(mem, len+1, fmt, ap);
  747. va_end(ap);
  748. return mem;
  749. }