/src/mupdf/source/fitz/printf.c
Line | Count | Source (jump to first uncovered line) |
1 | | // Copyright (C) 2004-2021 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 | | |
23 | | #include "mupdf/fitz.h" |
24 | | |
25 | | #include <float.h> |
26 | | #include <math.h> |
27 | | #include <stdarg.h> |
28 | | #include <stdio.h> |
29 | | |
30 | | #ifdef _MSC_VER |
31 | | #if _MSC_VER < 1500 /* MSVC 2008 */ |
32 | | int snprintf(char *s, size_t n, const char *fmt, ...) |
33 | | { |
34 | | int r; |
35 | | va_list ap; |
36 | | va_start(ap, fmt); |
37 | | r = vsprintf(s, fmt, ap); |
38 | | va_end(ap); |
39 | | return r; |
40 | | } |
41 | | #else if _MSC_VER < 1900 /* MSVC 2015 */ |
42 | | #define snprintf _snprintf |
43 | | #endif |
44 | | #endif |
45 | | |
46 | | static const char *fz_hex_digits = "0123456789abcdef"; |
47 | | |
48 | | struct fmtbuf |
49 | | { |
50 | | fz_context *ctx; |
51 | | void *user; |
52 | | void (*emit)(fz_context *ctx, void *user, int c); |
53 | | }; |
54 | | |
55 | | static inline void fmtputc(struct fmtbuf *out, int c) |
56 | 1.44G | { |
57 | 1.44G | out->emit(out->ctx, out->user, c); |
58 | 1.44G | } |
59 | | |
60 | | /* |
61 | | * Convert float to shortest possible string that won't lose precision, except: |
62 | | * NaN to 0, +Inf to FLT_MAX, -Inf to -FLT_MAX. |
63 | | */ |
64 | | static void fmtfloat(struct fmtbuf *out, float f) |
65 | 1.29M | { |
66 | 1.29M | char digits[40], *s = digits; |
67 | 1.29M | int exp, ndigits, point; |
68 | | |
69 | 1.29M | if (isnan(f)) f = 0; |
70 | 1.29M | if (isinf(f)) f = f < 0 ? -FLT_MAX : FLT_MAX; |
71 | | |
72 | 1.29M | if (signbit(f)) |
73 | 592k | fmtputc(out, '-'); |
74 | | |
75 | 1.29M | if (f == 0) |
76 | 17.1k | { |
77 | 17.1k | fmtputc(out, '0'); |
78 | 17.1k | return; |
79 | 17.1k | } |
80 | | |
81 | 1.28M | ndigits = fz_grisu(f, digits, &exp); |
82 | 1.28M | point = exp + ndigits; |
83 | | |
84 | 1.28M | if (point <= 0) |
85 | 6.27k | { |
86 | 6.27k | fmtputc(out, '.'); |
87 | 6.66k | while (point++ < 0) |
88 | 386 | fmtputc(out, '0'); |
89 | 30.2k | while (ndigits-- > 0) |
90 | 24.0k | fmtputc(out, *s++); |
91 | 6.27k | } |
92 | | |
93 | 1.27M | else |
94 | 1.27M | { |
95 | 10.8M | while (ndigits-- > 0) |
96 | 9.57M | { |
97 | 9.57M | fmtputc(out, *s++); |
98 | 9.57M | if (--point == 0 && ndigits > 0) |
99 | 657k | fmtputc(out, '.'); |
100 | 9.57M | } |
101 | 2.14M | while (point-- > 0) |
102 | 869k | fmtputc(out, '0'); |
103 | 1.27M | } |
104 | 1.28M | } |
105 | | |
106 | | static void fmtfloat_e(struct fmtbuf *out, double f, int w, int p) |
107 | 0 | { |
108 | 0 | char buf[100], *s = buf; |
109 | 0 | snprintf(buf, sizeof buf, "%*.*e", w, p, f); |
110 | 0 | while (*s) |
111 | 0 | fmtputc(out, *s++); |
112 | 0 | } |
113 | | |
114 | | static void fmtfloat_f(struct fmtbuf *out, double f, int w, int p) |
115 | 0 | { |
116 | 0 | char buf[100], *s = buf; |
117 | 0 | snprintf(buf, sizeof buf, "%*.*f", w, p, f); |
118 | 0 | while (*s) |
119 | 0 | fmtputc(out, *s++); |
120 | 0 | } |
121 | | |
122 | | static void fmtuint32(struct fmtbuf *out, unsigned int a, int s, int z, int w, int base) |
123 | 1.91M | { |
124 | 1.91M | char buf[40]; |
125 | 1.91M | int i; |
126 | | |
127 | 1.91M | i = 0; |
128 | 1.91M | if (a == 0) |
129 | 180k | buf[i++] = '0'; |
130 | 7.43M | while (a) { |
131 | 5.51M | buf[i++] = fz_hex_digits[a % base]; |
132 | 5.51M | a /= base; |
133 | 5.51M | } |
134 | 1.91M | if (s) { |
135 | 5.10k | if (z == '0') |
136 | 0 | while (i < w - 1) |
137 | 0 | buf[i++] = z; |
138 | 5.10k | buf[i++] = s; |
139 | 5.10k | } |
140 | 1.91M | while (i < w) |
141 | 27 | buf[i++] = z; |
142 | 7.62M | while (i > 0) |
143 | 5.70M | fmtputc(out, buf[--i]); |
144 | 1.91M | } |
145 | | |
146 | | static void fmtuint64(struct fmtbuf *out, uint64_t a, int s, int z, int w, int base) |
147 | 75 | { |
148 | 75 | char buf[80]; |
149 | 75 | int i; |
150 | | |
151 | 75 | i = 0; |
152 | 75 | if (a == 0) |
153 | 0 | buf[i++] = '0'; |
154 | 739 | while (a) { |
155 | 664 | buf[i++] = fz_hex_digits[a % base]; |
156 | 664 | a /= base; |
157 | 664 | } |
158 | 75 | if (s) { |
159 | 0 | if (z == '0') |
160 | 0 | while (i < w - 1) |
161 | 0 | buf[i++] = z; |
162 | 0 | buf[i++] = s; |
163 | 0 | } |
164 | 75 | while (i < w) |
165 | 0 | buf[i++] = z; |
166 | 739 | while (i > 0) |
167 | 664 | fmtputc(out, buf[--i]); |
168 | 75 | } |
169 | | |
170 | | static void fmtint32(struct fmtbuf *out, int value, int s, int z, int w, int base) |
171 | 1.38M | { |
172 | 1.38M | unsigned int a; |
173 | | |
174 | 1.38M | if (value < 0) |
175 | 5.10k | { |
176 | 5.10k | s = '-'; |
177 | 5.10k | a = -value; |
178 | 5.10k | } |
179 | 1.38M | else if (s) |
180 | 0 | { |
181 | 0 | s = '+'; |
182 | 0 | a = value; |
183 | 0 | } |
184 | 1.38M | else |
185 | 1.38M | { |
186 | 1.38M | s = 0; |
187 | 1.38M | a = value; |
188 | 1.38M | } |
189 | 1.38M | fmtuint32(out, a, s, z, w, base); |
190 | 1.38M | } |
191 | | |
192 | | static void fmtint64(struct fmtbuf *out, int64_t value, int s, int z, int w, int base) |
193 | 0 | { |
194 | 0 | uint64_t a; |
195 | |
|
196 | 0 | if (value < 0) |
197 | 0 | { |
198 | 0 | s = '-'; |
199 | 0 | a = -value; |
200 | 0 | } |
201 | 0 | else if (s) |
202 | 0 | { |
203 | 0 | s = '+'; |
204 | 0 | a = value; |
205 | 0 | } |
206 | 0 | else |
207 | 0 | { |
208 | 0 | s = 0; |
209 | 0 | a = value; |
210 | 0 | } |
211 | 0 | fmtuint64(out, a, s, z, w, base); |
212 | 0 | } |
213 | | |
214 | | static void fmtquote(struct fmtbuf *out, const char *s, int sq, int eq, int verbatim) |
215 | 0 | { |
216 | 0 | int i, n, c; |
217 | 0 | fmtputc(out, sq); |
218 | 0 | while (*s != 0) { |
219 | 0 | n = fz_chartorune(&c, s); |
220 | 0 | switch (c) { |
221 | 0 | default: |
222 | 0 | if (c < 32) { |
223 | 0 | fmtputc(out, '\\'); |
224 | 0 | fmtputc(out, 'x'); |
225 | 0 | fmtputc(out, "0123456789ABCDEF"[(c>>4)&15]); |
226 | 0 | fmtputc(out, "0123456789ABCDEF"[(c)&15]); |
227 | 0 | } else if (c > 127) { |
228 | 0 | if (verbatim) |
229 | 0 | { |
230 | 0 | for (i = 0; i < n; ++i) |
231 | 0 | fmtputc(out, s[i]); |
232 | 0 | } |
233 | 0 | else |
234 | 0 | { |
235 | 0 | fmtputc(out, '\\'); |
236 | 0 | fmtputc(out, 'u'); |
237 | 0 | fmtputc(out, "0123456789ABCDEF"[(c>>12)&15]); |
238 | 0 | fmtputc(out, "0123456789ABCDEF"[(c>>8)&15]); |
239 | 0 | fmtputc(out, "0123456789ABCDEF"[(c>>4)&15]); |
240 | 0 | fmtputc(out, "0123456789ABCDEF"[(c)&15]); |
241 | 0 | } |
242 | 0 | } else { |
243 | 0 | if (c == sq || c == eq) |
244 | 0 | fmtputc(out, '\\'); |
245 | 0 | fmtputc(out, c); |
246 | 0 | } |
247 | 0 | break; |
248 | 0 | case '\\': fmtputc(out, '\\'); fmtputc(out, '\\'); break; |
249 | 0 | case '\b': fmtputc(out, '\\'); fmtputc(out, 'b'); break; |
250 | 0 | case '\f': fmtputc(out, '\\'); fmtputc(out, 'f'); break; |
251 | 0 | case '\n': fmtputc(out, '\\'); fmtputc(out, 'n'); break; |
252 | 0 | case '\r': fmtputc(out, '\\'); fmtputc(out, 'r'); break; |
253 | 0 | case '\t': fmtputc(out, '\\'); fmtputc(out, 't'); break; |
254 | 0 | } |
255 | 0 | s += n; |
256 | 0 | } |
257 | 0 | fmtputc(out, eq); |
258 | 0 | } |
259 | | |
260 | | static void fmtquote_pdf(struct fmtbuf *out, const char *s, int sq, int eq) |
261 | 0 | { |
262 | 0 | int c; |
263 | 0 | fmtputc(out, sq); |
264 | 0 | while ((c = (unsigned char)*s++) != 0) { |
265 | 0 | switch (c) { |
266 | 0 | default: |
267 | 0 | if (c < 32 || c > 127) { |
268 | 0 | fmtputc(out, '\\'); |
269 | 0 | if (sq == '(') |
270 | 0 | { |
271 | 0 | fmtputc(out, '0' + ((c >> 6) & 7)); |
272 | 0 | fmtputc(out, '0' + ((c >> 3) & 7)); |
273 | 0 | fmtputc(out, '0' + ((c) & 7)); |
274 | 0 | } |
275 | 0 | else |
276 | 0 | { |
277 | 0 | fmtputc(out, 'x'); |
278 | 0 | fmtputc(out, "0123456789ABCDEF"[(c>>4)&15]); |
279 | 0 | fmtputc(out, "0123456789ABCDEF"[(c)&15]); |
280 | 0 | } |
281 | 0 | } else { |
282 | 0 | if (c == sq || c == eq) |
283 | 0 | fmtputc(out, '\\'); |
284 | 0 | fmtputc(out, c); |
285 | 0 | } |
286 | 0 | break; |
287 | 0 | case '\\': fmtputc(out, '\\'); fmtputc(out, '\\'); break; |
288 | 0 | case '\b': fmtputc(out, '\\'); fmtputc(out, 'b'); break; |
289 | 0 | case '\f': fmtputc(out, '\\'); fmtputc(out, 'f'); break; |
290 | 0 | case '\n': fmtputc(out, '\\'); fmtputc(out, 'n'); break; |
291 | 0 | case '\r': fmtputc(out, '\\'); fmtputc(out, 'r'); break; |
292 | 0 | case '\t': fmtputc(out, '\\'); fmtputc(out, 't'); break; |
293 | 0 | } |
294 | 0 | } |
295 | 0 | fmtputc(out, eq); |
296 | 0 | } |
297 | | |
298 | | static void fmtname(struct fmtbuf *out, const char *s) |
299 | 0 | { |
300 | 0 | int c; |
301 | 0 | fmtputc(out, '/'); |
302 | 0 | while ((c = *s++) != 0) { |
303 | 0 | if (c <= 32 || c == '/' || c == '#') { |
304 | 0 | fmtputc(out, '#'); |
305 | 0 | fmtputc(out, "0123456789ABCDEF"[(c>>4)&15]); |
306 | 0 | fmtputc(out, "0123456789ABCDEF"[(c)&15]); |
307 | 0 | } else { |
308 | 0 | fmtputc(out, c); |
309 | 0 | } |
310 | 0 | } |
311 | 0 | } |
312 | | |
313 | | void |
314 | | fz_format_string(fz_context *ctx, void *user, void (*emit)(fz_context *ctx, void *user, int c), const char *fmt, va_list args) |
315 | 41.9M | { |
316 | 41.9M | struct fmtbuf out; |
317 | 41.9M | int c, s, z, p, w; |
318 | 41.9M | int32_t i32; |
319 | 41.9M | int64_t i64; |
320 | 41.9M | const char *str; |
321 | 41.9M | size_t bits; |
322 | | |
323 | 41.9M | out.ctx = ctx; |
324 | 41.9M | out.user = user; |
325 | 41.9M | out.emit = emit; |
326 | | |
327 | 1.26G | while ((c = *fmt++) != 0) |
328 | 1.21G | { |
329 | 1.21G | if (c == '%') |
330 | 11.4M | { |
331 | 11.4M | s = 0; |
332 | 11.4M | z = ' '; |
333 | | |
334 | | /* flags */ |
335 | 11.4M | while ((c = *fmt++) != 0) |
336 | 11.4M | { |
337 | | /* plus sign */ |
338 | 11.4M | if (c == '+') |
339 | 0 | s = 1; |
340 | | /* space sign */ |
341 | 11.4M | else if (c == ' ') |
342 | 0 | s = ' '; |
343 | | /* zero padding */ |
344 | 11.4M | else if (c == '0') |
345 | 5.97k | z = '0'; |
346 | | /* TODO: '-' to left justify */ |
347 | 11.4M | else |
348 | 11.4M | break; |
349 | 11.4M | } |
350 | 11.4M | if (c == 0) |
351 | 0 | break; |
352 | | |
353 | | /* width */ |
354 | 11.4M | w = 0; |
355 | 11.4M | if (c == '*') { |
356 | 0 | c = *fmt++; |
357 | 0 | w = va_arg(args, int); |
358 | 11.4M | } else { |
359 | 11.4M | while (c >= '0' && c <= '9') { |
360 | 5.97k | w = w * 10 + c - '0'; |
361 | 5.97k | c = *fmt++; |
362 | 5.97k | } |
363 | 11.4M | } |
364 | 11.4M | if (c == 0) |
365 | 0 | break; |
366 | | |
367 | | /* precision */ |
368 | 11.4M | p = 6; |
369 | 11.4M | if (c == '.') { |
370 | 0 | c = *fmt++; |
371 | 0 | if (c == 0) |
372 | 0 | break; |
373 | 0 | if (c == '*') { |
374 | 0 | c = *fmt++; |
375 | 0 | p = va_arg(args, int); |
376 | 0 | } else { |
377 | 0 | if (c >= '0' && c <= '9') |
378 | 0 | p = 0; |
379 | 0 | while (c >= '0' && c <= '9') { |
380 | 0 | p = p * 10 + c - '0'; |
381 | 0 | c = *fmt++; |
382 | 0 | } |
383 | 0 | } |
384 | 0 | } |
385 | 11.4M | if (c == 0) |
386 | 0 | break; |
387 | | |
388 | | /* lengths */ |
389 | 11.4M | bits = 0; |
390 | 11.4M | if (c == 'l') { |
391 | 0 | c = *fmt++; |
392 | 0 | bits = sizeof(int64_t) * 8; |
393 | 0 | if (c == 0) |
394 | 0 | break; |
395 | 0 | } |
396 | 11.4M | if (c == 't') { |
397 | 0 | c = *fmt++; |
398 | 0 | bits = sizeof(ptrdiff_t) * 8; |
399 | 0 | if (c == 0) |
400 | 0 | break; |
401 | 0 | } |
402 | 11.4M | if (c == 'z') { |
403 | 75 | c = *fmt++; |
404 | 75 | bits = sizeof(size_t) * 8; |
405 | 75 | if (c == 0) |
406 | 0 | break; |
407 | 75 | } |
408 | | |
409 | 11.4M | switch (c) { |
410 | 0 | default: |
411 | 0 | fmtputc(&out, '%'); |
412 | 0 | fmtputc(&out, c); |
413 | 0 | break; |
414 | 0 | case '%': |
415 | 0 | fmtputc(&out, '%'); |
416 | 0 | break; |
417 | | |
418 | 0 | case 'M': |
419 | 0 | { |
420 | 0 | fz_matrix *matrix = va_arg(args, fz_matrix*); |
421 | 0 | fmtfloat(&out, matrix->a); fmtputc(&out, ' '); |
422 | 0 | fmtfloat(&out, matrix->b); fmtputc(&out, ' '); |
423 | 0 | fmtfloat(&out, matrix->c); fmtputc(&out, ' '); |
424 | 0 | fmtfloat(&out, matrix->d); fmtputc(&out, ' '); |
425 | 0 | fmtfloat(&out, matrix->e); fmtputc(&out, ' '); |
426 | 0 | fmtfloat(&out, matrix->f); |
427 | 0 | } |
428 | 0 | break; |
429 | 0 | case 'R': |
430 | 0 | { |
431 | 0 | fz_rect *rect = va_arg(args, fz_rect*); |
432 | 0 | fmtfloat(&out, rect->x0); fmtputc(&out, ' '); |
433 | 0 | fmtfloat(&out, rect->y0); fmtputc(&out, ' '); |
434 | 0 | fmtfloat(&out, rect->x1); fmtputc(&out, ' '); |
435 | 0 | fmtfloat(&out, rect->y1); |
436 | 0 | } |
437 | 0 | break; |
438 | 0 | case 'P': |
439 | 0 | { |
440 | 0 | fz_point *point = va_arg(args, fz_point*); |
441 | 0 | fmtfloat(&out, point->x); fmtputc(&out, ' '); |
442 | 0 | fmtfloat(&out, point->y); |
443 | 0 | } |
444 | 0 | break; |
445 | | |
446 | 0 | case 'C': /* unicode char */ |
447 | 0 | c = va_arg(args, int); |
448 | 0 | if (c < 128) |
449 | 0 | fmtputc(&out, c); |
450 | 0 | else { |
451 | 0 | char buf[10]; |
452 | 0 | int i, n = fz_runetochar(buf, c); |
453 | 0 | for (i=0; i < n; ++i) |
454 | 0 | fmtputc(&out, buf[i]); |
455 | 0 | } |
456 | 0 | break; |
457 | 5.34k | case 'c': |
458 | 5.34k | c = va_arg(args, int); |
459 | 5.34k | fmtputc(&out, c); |
460 | 5.34k | break; |
461 | | |
462 | 0 | case 'e': |
463 | 0 | fmtfloat_e(&out, va_arg(args, double), w, p); |
464 | 0 | break; |
465 | 0 | case 'f': |
466 | 0 | fmtfloat_f(&out, va_arg(args, double), w, p); |
467 | 0 | break; |
468 | 1.29M | case 'g': |
469 | 1.29M | fmtfloat(&out, va_arg(args, double)); |
470 | 1.29M | break; |
471 | | |
472 | 0 | case 'p': |
473 | 0 | bits = 8 * sizeof(void *); |
474 | 0 | z = '0'; |
475 | 0 | fmtputc(&out, '0'); |
476 | 0 | fmtputc(&out, 'x'); |
477 | | /* fallthrough */ |
478 | 5.99k | case 'x': |
479 | 5.99k | if (bits == 64) |
480 | 0 | { |
481 | 0 | i64 = va_arg(args, int64_t); |
482 | 0 | fmtuint64(&out, i64, 0, z, w, 16); |
483 | 0 | } |
484 | 5.99k | else |
485 | 5.99k | { |
486 | 5.99k | i32 = va_arg(args, int); |
487 | 5.99k | fmtuint32(&out, i32, 0, z, w, 16); |
488 | 5.99k | } |
489 | 5.99k | break; |
490 | 1.38M | case 'd': |
491 | 1.38M | case 'i': |
492 | 1.38M | if (bits == 64) |
493 | 0 | { |
494 | 0 | i64 = va_arg(args, int64_t); |
495 | 0 | fmtint64(&out, i64, s, z, w, 10); |
496 | 0 | } |
497 | 1.38M | else |
498 | 1.38M | { |
499 | 1.38M | i32 = va_arg(args, int); |
500 | 1.38M | fmtint32(&out, i32, s, z, w, 10); |
501 | 1.38M | } |
502 | 1.38M | break; |
503 | 526k | case 'u': |
504 | 526k | if (bits == 64) |
505 | 75 | { |
506 | 75 | i64 = va_arg(args, int64_t); |
507 | 75 | fmtuint64(&out, i64, 0, z, w, 10); |
508 | 75 | } |
509 | 526k | else |
510 | 526k | { |
511 | 526k | i32 = va_arg(args, int); |
512 | 526k | fmtuint32(&out, i32, 0, z, w, 10); |
513 | 526k | } |
514 | 526k | break; |
515 | | |
516 | 8.25M | case 's': |
517 | 8.25M | str = va_arg(args, const char*); |
518 | 8.25M | if (!str) |
519 | 0 | str = "(null)"; |
520 | 231M | while ((c = *str++) != 0) |
521 | 223M | fmtputc(&out, c); |
522 | 8.25M | break; |
523 | 0 | case 'Q': /* quoted string (with verbatim unicode) */ |
524 | 0 | str = va_arg(args, const char*); |
525 | 0 | if (!str) str = ""; |
526 | 0 | fmtquote(&out, str, '"', '"', 1); |
527 | 0 | break; |
528 | 0 | case 'q': /* quoted string */ |
529 | 0 | str = va_arg(args, const char*); |
530 | 0 | if (!str) str = ""; |
531 | 0 | fmtquote(&out, str, '"', '"', 0); |
532 | 0 | break; |
533 | 0 | case '(': /* pdf string */ |
534 | 0 | str = va_arg(args, const char*); |
535 | 0 | if (!str) str = ""; |
536 | 0 | fmtquote_pdf(&out, str, '(', ')'); |
537 | 0 | break; |
538 | 0 | case 'n': /* pdf name */ |
539 | 0 | str = va_arg(args, const char*); |
540 | 0 | if (!str) str = ""; |
541 | 0 | fmtname(&out, str); |
542 | 0 | break; |
543 | 11.4M | } |
544 | 11.4M | } |
545 | 1.20G | else |
546 | 1.20G | { |
547 | 1.20G | fmtputc(&out, c); |
548 | 1.20G | } |
549 | 1.21G | } |
550 | 41.9M | } |
551 | | |
552 | | struct snprintf_buffer |
553 | | { |
554 | | char *p; |
555 | | size_t s, n; |
556 | | }; |
557 | | |
558 | | static void snprintf_emit(fz_context *ctx, void *out_, int c) |
559 | 1.43G | { |
560 | 1.43G | struct snprintf_buffer *out = out_; |
561 | 1.43G | if (out->n < out->s) |
562 | 1.43G | out->p[out->n] = c; |
563 | 1.43G | ++(out->n); |
564 | 1.43G | } |
565 | | |
566 | | size_t |
567 | | fz_vsnprintf(char *buffer, size_t space, const char *fmt, va_list args) |
568 | 41.1M | { |
569 | 41.1M | struct snprintf_buffer out; |
570 | 41.1M | out.p = buffer; |
571 | 41.1M | out.s = space > 0 ? space - 1 : 0; |
572 | 41.1M | out.n = 0; |
573 | | |
574 | | /* Note: using a NULL context is safe here */ |
575 | 41.1M | fz_format_string(NULL, &out, snprintf_emit, fmt, args); |
576 | 41.1M | if (space > 0) |
577 | 41.1M | out.p[out.n < space ? out.n : space - 1] = '\0'; |
578 | | |
579 | 41.1M | return out.n; |
580 | 41.1M | } |
581 | | |
582 | | size_t |
583 | | fz_snprintf(char *buffer, size_t space, const char *fmt, ...) |
584 | 97.1k | { |
585 | 97.1k | va_list ap; |
586 | 97.1k | struct snprintf_buffer out; |
587 | 97.1k | out.p = buffer; |
588 | 97.1k | out.s = space > 0 ? space - 1 : 0; |
589 | 97.1k | out.n = 0; |
590 | | |
591 | 97.1k | va_start(ap, fmt); |
592 | | /* Note: using a NULL context is safe here */ |
593 | 97.1k | fz_format_string(NULL, &out, snprintf_emit, fmt, ap); |
594 | 97.1k | if (space > 0) |
595 | 97.1k | out.p[out.n < space ? out.n : space - 1] = '\0'; |
596 | 97.1k | va_end(ap); |
597 | | |
598 | 97.1k | return out.n; |
599 | 97.1k | } |
600 | | |
601 | | char * |
602 | | fz_asprintf(fz_context *ctx, const char *fmt, ...) |
603 | 813 | { |
604 | 813 | size_t len; |
605 | 813 | char *mem; |
606 | 813 | va_list ap; |
607 | 813 | va_start(ap, fmt); |
608 | 813 | len = fz_vsnprintf(NULL, 0, fmt, ap); |
609 | 813 | va_end(ap); |
610 | 813 | mem = Memento_label(fz_malloc(ctx, len+1), "asprintf"); |
611 | 813 | va_start(ap, fmt); |
612 | 813 | fz_vsnprintf(mem, len+1, fmt, ap); |
613 | 813 | va_end(ap); |
614 | 813 | return mem; |
615 | 813 | } |