/src/ghostpdl/base/gssprintf.c
Line | Count | Source (jump to first uncovered line) |
1 | | /* Licensed to the Apache Software Foundation (ASF) under one or more |
2 | | * contributor license agreements. See the NOTICE file distributed with |
3 | | * this work for additional information regarding copyright ownership. |
4 | | * The ASF licenses this file to You under the Apache License, Version 2.0 |
5 | | * (the "License"); you may not use this file except in compliance with |
6 | | * the License. You may obtain a copy of the License at |
7 | | * |
8 | | * http://www.apache.org/licenses/LICENSE-2.0 |
9 | | * |
10 | | * Unless required by applicable law or agreed to in writing, software |
11 | | * distributed under the License is distributed on an "AS IS" BASIS, |
12 | | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
13 | | * See the License for the specific language governing permissions and |
14 | | * limitations under the License. |
15 | | */ |
16 | | /* From: https://svn.apache.org/repos/asf/apr/apr/trunk/strings/apr_snprintf.c */ |
17 | | /* Additional modifications to work outside Apache for use with Ghostscript */ |
18 | | |
19 | | #include "unistd_.h" |
20 | | #include "gp.h" |
21 | | #include "stdio_.h" |
22 | | #include "string_.h" |
23 | | #include <stdarg.h> |
24 | | #include "math_.h" |
25 | | #include <ctype.h> |
26 | | |
27 | | #define APR_HAVE_IPV6 0 |
28 | | #define APR_HAS_THREADS 0 |
29 | | |
30 | | #define FOR_GS 1 |
31 | | |
32 | 62.6M | #define apr_isalpha(c) isalpha(c) |
33 | 663M | #define apr_islower(c) islower(c) |
34 | 127M | #define apr_isdigit(c) isdigit(c) |
35 | | |
36 | | |
37 | | typedef uint32_t apr_uint32_t; |
38 | | typedef int32_t apr_int32_t; |
39 | | typedef uint64_t apr_uint64_t; |
40 | | typedef int64_t apr_int64_t; |
41 | | typedef size_t apr_size_t; |
42 | | typedef int64_t apr_off_t; |
43 | | |
44 | | |
45 | | typedef struct apr_vformatter_buff_t apr_vformatter_buff_t; |
46 | | |
47 | | /** |
48 | | * Structure used by the variable-formatter routines. |
49 | | */ |
50 | | struct apr_vformatter_buff_t { |
51 | | /** The current position */ |
52 | | char *curpos; |
53 | | /** The end position of the format string */ |
54 | | char *endpos; |
55 | | }; |
56 | | |
57 | | typedef enum { |
58 | | NO = 0, YES = 1 |
59 | | } boolean_e; |
60 | | |
61 | | #ifndef FALSE |
62 | 716k | #define FALSE 0 |
63 | | #endif |
64 | | #ifndef TRUE |
65 | | #define TRUE 1 |
66 | | #endif |
67 | 2.05G | #define NUL '\0' |
68 | | |
69 | | #define APR_INT64_C(x) ((int64_t)x) |
70 | | #define APR_UINT64_C(x) ((uint64_t)x) |
71 | | |
72 | | #define APR_INT16_MIN (-0x7fff - 1) |
73 | | #define APR_INT16_MAX (0x7fff) |
74 | | #define APR_UINT16_MAX (0xffff) |
75 | 271M | #define APR_INT32_MIN (-0x7fffffff - 1) |
76 | 272M | #define APR_INT32_MAX 0x7fffffff |
77 | 274M | #define APR_UINT32_MAX (0xffffffffU) |
78 | | #define APR_INT64_MIN (APR_INT64_C(-0x7fffffffffffffff) - 1) |
79 | | #define APR_INT64_MAX APR_INT64_C(0x7fffffffffffffff) |
80 | | #define APR_UINT64_MAX APR_UINT64_C(0xffffffffffffffff) |
81 | | #define APR_SIZE_MAX (~((apr_size_t)0)) |
82 | | |
83 | | #define APR_SIZEOF_VOIDP ARCH_SIZEOF_PTR |
84 | | |
85 | 2.79G | #define APR_INT64_T_FMT PRId64 |
86 | | #define APR_UINT64_T_FMT PRIu64 |
87 | | #define APR_UINT64_T_HEX_FMT PRIx64 |
88 | 663M | #define APR_OFF_T_FMT PRId64 |
89 | | |
90 | | static const char null_string[] = "(null)"; |
91 | 681M | #define S_NULL ((char *)null_string) |
92 | 0 | #define S_NULL_LEN 6 |
93 | | |
94 | 219M | #define FLOAT_DIGITS 6 |
95 | 0 | #define EXPONENT_LENGTH 10 |
96 | | |
97 | | /* |
98 | | * NUM_BUF_SIZE is the size of the buffer used for arithmetic conversions |
99 | | * |
100 | | * NOTICE: this is a magic number; do not decrease it |
101 | | */ |
102 | 338M | #define NUM_BUF_SIZE 512 |
103 | | |
104 | | /* |
105 | | * cvt - IEEE floating point formatting routines. |
106 | | * Derived from UNIX V7, Copyright(C) Caldera International Inc. |
107 | | */ |
108 | | |
109 | | /* |
110 | | * apr_ecvt converts to decimal |
111 | | * the number of digits is specified by ndigit |
112 | | * decpt is set to the position of the decimal point |
113 | | * sign is set to 0 for positive, 1 for negative |
114 | | */ |
115 | | |
116 | 2.43G | #define NDIG 80 |
117 | | |
118 | | /* buf must have at least NDIG bytes */ |
119 | | static char *apr_cvt(double arg, int ndigits, int *decpt, int *sign, |
120 | | int eflag, char *buf) |
121 | 220M | { |
122 | 220M | register int r2; |
123 | 220M | double fi, fj; |
124 | 220M | register char *p, *p1; |
125 | | |
126 | 220M | if (ndigits >= NDIG - 1) |
127 | 0 | ndigits = NDIG - 2; |
128 | 220M | r2 = 0; |
129 | 220M | *sign = 0; |
130 | 220M | p = &buf[0]; |
131 | 220M | if (arg < 0) { |
132 | 8.69M | *sign = 1; |
133 | 8.69M | arg = -arg; |
134 | 8.69M | } |
135 | 220M | arg = modf(arg, &fi); |
136 | | /* |
137 | | * Do integer part |
138 | | */ |
139 | 220M | if (fi != 0) { |
140 | 200M | p1 = &buf[NDIG]; |
141 | 745M | while (p1 > &buf[0] && fi != 0) { |
142 | 544M | fj = modf(fi / 10, &fi); |
143 | 544M | *--p1 = (int) ((fj + .03) * 10) + '0'; |
144 | 544M | r2++; |
145 | 544M | } |
146 | 745M | while (p1 < &buf[NDIG]) |
147 | 544M | *p++ = *p1++; |
148 | 200M | } |
149 | 19.4M | else if (arg > 0) { |
150 | 20.4M | while ((fj = arg * 10) < 1) { |
151 | 14.3M | arg = fj; |
152 | 14.3M | r2--; |
153 | 14.3M | } |
154 | 6.05M | } |
155 | 220M | p1 = &buf[ndigits]; |
156 | 220M | if (eflag == 0) |
157 | 62.6M | p1 += r2; |
158 | 220M | if (p1 < &buf[0]) { |
159 | 1.79k | *decpt = -ndigits; |
160 | 1.79k | buf[0] = '\0'; |
161 | 1.79k | return (buf); |
162 | 1.79k | } |
163 | 220M | *decpt = r2; |
164 | 1.26G | while (p <= p1 && p < &buf[NDIG]) { |
165 | 1.04G | arg *= 10; |
166 | 1.04G | arg = modf(arg, &fj); |
167 | 1.04G | *p++ = (int) fj + '0'; |
168 | 1.04G | } |
169 | 220M | if (p1 >= &buf[NDIG]) { |
170 | 0 | buf[NDIG - 1] = '\0'; |
171 | 0 | return (buf); |
172 | 0 | } |
173 | 220M | p = p1; |
174 | 220M | *p1 += 5; |
175 | 252M | while (*p1 > '9') { |
176 | 32.5M | *p1 = '0'; |
177 | 32.5M | if (p1 > buf) |
178 | 32.3M | ++ * --p1; |
179 | 167k | else { |
180 | 167k | *p1 = '1'; |
181 | 167k | (*decpt)++; |
182 | 167k | if (eflag == 0) { |
183 | 192 | if (p > buf) |
184 | 101 | *p = '0'; |
185 | 192 | p++; |
186 | 192 | } |
187 | 167k | } |
188 | 32.5M | } |
189 | 220M | *p = '\0'; |
190 | 220M | return (buf); |
191 | 220M | } |
192 | | |
193 | | static char *apr_ecvt(double arg, int ndigits, int *decpt, int *sign, char *buf) |
194 | 157M | { |
195 | 157M | return (apr_cvt(arg, ndigits, decpt, sign, 1, buf)); |
196 | 157M | } |
197 | | |
198 | | static char *apr_fcvt(double arg, int ndigits, int *decpt, int *sign, char *buf) |
199 | 62.6M | { |
200 | 62.6M | return (apr_cvt(arg, ndigits, decpt, sign, 0, buf)); |
201 | 62.6M | } |
202 | | |
203 | | /* |
204 | | * apr_gcvt - Floating output conversion to |
205 | | * minimal length string |
206 | | */ |
207 | | |
208 | | static char *apr_gcvt(double number, int ndigit, char *buf, boolean_e altform) |
209 | 157M | { |
210 | 157M | int sign, decpt; |
211 | 157M | register char *p1, *p2; |
212 | 157M | register int i; |
213 | 157M | char buf1[NDIG]; |
214 | 157M | int nd = ndigit; |
215 | 157M | double magn = number < 0 ? -number : number; |
216 | | |
217 | 157M | p1 = apr_ecvt(number, ndigit, &decpt, &sign, buf1); |
218 | 157M | p2 = buf; |
219 | 157M | if (sign) |
220 | 8.52M | *p2++ = '-'; |
221 | 501M | for (i = ndigit - 1; i > 0 && p1[i] == '0'; i--) |
222 | 343M | ndigit--; |
223 | | #if !FOR_GS |
224 | | if ((decpt >= 0 && decpt - ndigit > 4) |
225 | | || (decpt < 0 && decpt < -3)) { /* use E-style */ |
226 | | #else |
227 | 157M | if (magn != 0 && ((magn < (double)9.9999989999999991e-05) |
228 | 152M | || (magn >= pow(10, nd)))) { /* use E-style */ |
229 | 1.26M | #endif |
230 | 1.26M | decpt--; |
231 | 1.26M | *p2++ = *p1++; |
232 | | |
233 | 1.26M | if (ndigit >= 2) |
234 | 1.26M | *p2++ = '.'; |
235 | 7.18M | for (i = 1; i < ndigit; i++) |
236 | 5.91M | *p2++ = *p1++; |
237 | 1.26M | *p2++ = 'e'; |
238 | 1.26M | if (decpt < 0) { |
239 | 392k | decpt = -decpt; |
240 | 392k | *p2++ = '-'; |
241 | 392k | } |
242 | 872k | else |
243 | 872k | *p2++ = '+'; |
244 | 1.26M | if (decpt / 100 > 0) |
245 | 0 | *p2++ = decpt / 100 + '0'; |
246 | | |
247 | | #if !FOR_GS /* We want the extra zero here so we get, for example, 2e+08 instead of 2e+8 */ |
248 | | if (decpt / 10 > 0) |
249 | | #endif |
250 | 1.26M | *p2++ = (decpt % 100) / 10 + '0'; |
251 | 1.26M | *p2++ = decpt % 10 + '0'; |
252 | 1.26M | } |
253 | 156M | else { |
254 | 156M | if (decpt <= 0) { |
255 | 8.37M | if (*p1 != '0') { |
256 | 3.39M | *p2++ = '0'; |
257 | 3.39M | *p2++ = '.'; |
258 | 3.39M | } |
259 | 8.91M | while (decpt < 0) { |
260 | 537k | decpt++; |
261 | 537k | *p2++ = '0'; |
262 | 537k | } |
263 | 8.37M | } |
264 | 751M | for (i = 1; i <= ndigit; i++) { |
265 | 594M | *p2++ = *p1++; |
266 | 594M | if (i == decpt) |
267 | 136M | *p2++ = '.'; |
268 | 594M | } |
269 | 156M | if (ndigit < decpt) { |
270 | 24.5M | while (ndigit++ < decpt) |
271 | 13.3M | *p2++ = '0'; |
272 | 11.2M | *p2++ = '.'; |
273 | 11.2M | } |
274 | 156M | } |
275 | 157M | if (p2[-1] == '.' && !altform) |
276 | 108M | p2--; |
277 | 157M | *p2 = '\0'; |
278 | 157M | return (buf); |
279 | 157M | } |
280 | | |
281 | | /* |
282 | | * The INS_CHAR macro inserts a character in the buffer and writes |
283 | | * the buffer back to disk if necessary |
284 | | * It uses the char pointers sp and bep: |
285 | | * sp points to the next available character in the buffer |
286 | | * bep points to the end-of-buffer+1 |
287 | | * While using this macro, note that the nextb pointer is NOT updated. |
288 | | * |
289 | | * NOTE: Evaluation of the c argument should not have any side-effects |
290 | | */ |
291 | 6.20G | #define INS_CHAR(c, sp, bep, cc) \ |
292 | 6.20G | { \ |
293 | 6.20G | if (sp) { \ |
294 | 6.20G | if (sp >= bep) { \ |
295 | 0 | vbuff->curpos = sp; \ |
296 | 0 | if (flush_func(vbuff)) \ |
297 | 0 | return -1; \ |
298 | 0 | sp = vbuff->curpos; \ |
299 | 0 | bep = vbuff->endpos; \ |
300 | 0 | } \ |
301 | 6.20G | *sp++ = (c); \ |
302 | 6.20G | } \ |
303 | 6.20G | cc++; \ |
304 | 6.20G | } |
305 | | |
306 | 126M | #define NUM(c) (c - '0') |
307 | | |
308 | | #define STR_TO_DEC(str, num) \ |
309 | 126M | num = NUM(*str++); \ |
310 | 126M | while (apr_isdigit(*str)) \ |
311 | 126M | { \ |
312 | 0 | num *= 10 ; \ |
313 | 0 | num += NUM(*str++); \ |
314 | 0 | } |
315 | | |
316 | | /* |
317 | | * This macro does zero padding so that the precision |
318 | | * requirement is satisfied. The padding is done by |
319 | | * adding '0's to the left of the string that is going |
320 | | * to be printed. We don't allow precision to be large |
321 | | * enough that we continue past the start of s. |
322 | | * |
323 | | * NOTE: this makes use of the magic info that s is |
324 | | * always based on num_buf with a size of NUM_BUF_SIZE. |
325 | | */ |
326 | | #define FIX_PRECISION(adjust, precision, s, s_len) \ |
327 | 337M | if (adjust) { \ |
328 | 0 | apr_size_t p = (precision + 1 < NUM_BUF_SIZE) \ |
329 | 0 | ? precision : NUM_BUF_SIZE - 1; \ |
330 | 0 | while (s_len < p) \ |
331 | 0 | { \ |
332 | 0 | *--s = '0'; \ |
333 | 0 | s_len++; \ |
334 | 0 | } \ |
335 | 0 | } |
336 | | |
337 | | /* |
338 | | * Macro that does padding. The padding is done by printing |
339 | | * the character ch. |
340 | | */ |
341 | 67.2M | #define PAD(width, len, ch) \ |
342 | 124M | do \ |
343 | 124M | { \ |
344 | 124M | INS_CHAR(ch, sp, bep, cc); \ |
345 | 124M | width--; \ |
346 | 124M | } \ |
347 | 124M | while (width > len) |
348 | | |
349 | | /* |
350 | | * Prefix the character ch to the string str |
351 | | * Increase length |
352 | | * Set the has_prefix flag |
353 | | */ |
354 | | #define PREFIX(str, length, ch) \ |
355 | | *--str = ch; \ |
356 | | length++; \ |
357 | | has_prefix=YES; |
358 | | |
359 | | |
360 | | /* |
361 | | * Convert num to its decimal format. |
362 | | * Return value: |
363 | | * - a pointer to a string containing the number (no sign) |
364 | | * - len contains the length of the string |
365 | | * - is_negative is set to TRUE or FALSE depending on the sign |
366 | | * of the number (always set to FALSE if is_unsigned is TRUE) |
367 | | * |
368 | | * The caller provides a buffer for the string: that is the buf_end argument |
369 | | * which is a pointer to the END of the buffer + 1 (i.e. if the buffer |
370 | | * is declared as buf[ 100 ], buf_end should be &buf[ 100 ]) |
371 | | * |
372 | | * Note: we have 2 versions. One is used when we need to use quads |
373 | | * (conv_10_quad), the other when we don't (conv_10). We're assuming the |
374 | | * latter is faster. |
375 | | */ |
376 | | static char *conv_10(register apr_int32_t num, register int is_unsigned, |
377 | | register int *is_negative, char *buf_end, |
378 | | register apr_size_t *len) |
379 | 212M | { |
380 | 212M | register char *p = buf_end; |
381 | 212M | register apr_uint32_t magnitude = num; |
382 | | |
383 | 212M | if (is_unsigned) { |
384 | 710k | *is_negative = FALSE; |
385 | 710k | } |
386 | 211M | else { |
387 | 211M | *is_negative = (num < 0); |
388 | | |
389 | | /* |
390 | | * On a 2's complement machine, negating the most negative integer |
391 | | * results in a number that cannot be represented as a signed integer. |
392 | | * Here is what we do to obtain the number's magnitude: |
393 | | * a. add 1 to the number |
394 | | * b. negate it (becomes positive) |
395 | | * c. convert it to unsigned |
396 | | * d. add 1 |
397 | | */ |
398 | 211M | if (*is_negative) { |
399 | 8.98M | apr_int32_t t = num + 1; |
400 | 8.98M | magnitude = ((apr_uint32_t) -t) + 1; |
401 | 8.98M | } |
402 | 211M | } |
403 | | |
404 | | /* |
405 | | * We use a do-while loop so that we write at least 1 digit |
406 | | */ |
407 | 396M | do { |
408 | 396M | register apr_uint32_t new_magnitude = magnitude / 10; |
409 | | |
410 | 396M | *--p = (char) (magnitude - new_magnitude * 10 + '0'); |
411 | 396M | magnitude = new_magnitude; |
412 | 396M | } |
413 | 396M | while (magnitude); |
414 | | |
415 | 212M | *len = buf_end - p; |
416 | 212M | return (p); |
417 | 212M | } |
418 | | |
419 | | static char *conv_10_quad(apr_int64_t num, register int is_unsigned, |
420 | | register int *is_negative, char *buf_end, |
421 | | register apr_size_t *len) |
422 | 136M | { |
423 | 136M | register char *p = buf_end; |
424 | 136M | apr_uint64_t magnitude = num; |
425 | | |
426 | | /* |
427 | | * We see if we can use the faster non-quad version by checking the |
428 | | * number against the largest long value it can be. If <=, we |
429 | | * punt to the quicker version. |
430 | | */ |
431 | 136M | if ((magnitude <= APR_UINT32_MAX && is_unsigned) |
432 | 136M | || (num <= APR_INT32_MAX && num >= APR_INT32_MIN && !is_unsigned)) |
433 | 135M | return(conv_10((apr_int32_t)num, is_unsigned, is_negative, buf_end, len)); |
434 | | |
435 | 1.10M | if (is_unsigned) { |
436 | 5.36k | *is_negative = FALSE; |
437 | 5.36k | } |
438 | 1.09M | else { |
439 | 1.09M | *is_negative = (num < 0); |
440 | | |
441 | | /* |
442 | | * On a 2's complement machine, negating the most negative integer |
443 | | * results in a number that cannot be represented as a signed integer. |
444 | | * Here is what we do to obtain the number's magnitude: |
445 | | * a. add 1 to the number |
446 | | * b. negate it (becomes positive) |
447 | | * c. convert it to unsigned |
448 | | * d. add 1 |
449 | | */ |
450 | 1.09M | if (*is_negative) { |
451 | 2.63k | apr_int64_t t = num + 1; |
452 | 2.63k | magnitude = ((apr_uint64_t) -t) + 1; |
453 | 2.63k | } |
454 | 1.09M | } |
455 | | |
456 | | /* |
457 | | * We use a do-while loop so that we write at least 1 digit |
458 | | */ |
459 | 11.0M | do { |
460 | 11.0M | apr_uint64_t new_magnitude = magnitude / 10; |
461 | | |
462 | 11.0M | *--p = (char) (magnitude - new_magnitude * 10 + '0'); |
463 | 11.0M | magnitude = new_magnitude; |
464 | 11.0M | } |
465 | 11.0M | while (magnitude); |
466 | | |
467 | 1.10M | *len = buf_end - p; |
468 | 1.10M | return (p); |
469 | 136M | } |
470 | | |
471 | | #if !FOR_GS |
472 | | static char *conv_in_addr(struct in_addr *ia, char *buf_end, apr_size_t *len) |
473 | | { |
474 | | unsigned addr = ntohl(ia->s_addr); |
475 | | char *p = buf_end; |
476 | | int is_negative; |
477 | | apr_size_t sub_len; |
478 | | |
479 | | p = conv_10((addr & 0x000000FF) , TRUE, &is_negative, p, &sub_len); |
480 | | *--p = '.'; |
481 | | p = conv_10((addr & 0x0000FF00) >> 8, TRUE, &is_negative, p, &sub_len); |
482 | | *--p = '.'; |
483 | | p = conv_10((addr & 0x00FF0000) >> 16, TRUE, &is_negative, p, &sub_len); |
484 | | *--p = '.'; |
485 | | p = conv_10((addr & 0xFF000000) >> 24, TRUE, &is_negative, p, &sub_len); |
486 | | |
487 | | *len = buf_end - p; |
488 | | return (p); |
489 | | } |
490 | | |
491 | | /* Must be passed a buffer of size NUM_BUF_SIZE where buf_end points |
492 | | * to 1 byte past the end of the buffer. */ |
493 | | static char *conv_apr_sockaddr(apr_sockaddr_t *sa, char *buf_end, apr_size_t *len) |
494 | | { |
495 | | char *p = buf_end; |
496 | | int is_negative; |
497 | | apr_size_t sub_len; |
498 | | char *ipaddr_str; |
499 | | |
500 | | p = conv_10(sa->port, TRUE, &is_negative, p, &sub_len); |
501 | | *--p = ':'; |
502 | | ipaddr_str = buf_end - NUM_BUF_SIZE; |
503 | | if (apr_sockaddr_ip_getbuf(ipaddr_str, sa->addr_str_len, sa)) { |
504 | | /* Should only fail if the buffer is too small, which it |
505 | | * should not be; but fail safe anyway: */ |
506 | | *--p = '?'; |
507 | | *len = buf_end - p; |
508 | | return p; |
509 | | } |
510 | | sub_len = strlen(ipaddr_str); |
511 | | #if APR_HAVE_IPV6 |
512 | | if (sa->family == APR_INET6 && |
513 | | !IN6_IS_ADDR_V4MAPPED(&sa->sa.sin6.sin6_addr)) { |
514 | | *(p - 1) = ']'; |
515 | | p -= sub_len + 2; |
516 | | *p = '['; |
517 | | memcpy(p + 1, ipaddr_str, sub_len); |
518 | | } |
519 | | else |
520 | | #endif |
521 | | { |
522 | | p -= sub_len; |
523 | | memcpy(p, ipaddr_str, sub_len); |
524 | | } |
525 | | |
526 | | *len = buf_end - p; |
527 | | return (p); |
528 | | } |
529 | | #endif |
530 | | |
531 | | |
532 | | |
533 | | #if APR_HAS_THREADS |
534 | | static char *conv_os_thread_t(apr_os_thread_t *tid, char *buf_end, apr_size_t *len) |
535 | | { |
536 | | union { |
537 | | apr_os_thread_t tid; |
538 | | apr_uint64_t u64; |
539 | | apr_uint32_t u32; |
540 | | } u; |
541 | | int is_negative; |
542 | | |
543 | | u.tid = *tid; |
544 | | switch(sizeof(u.tid)) { |
545 | | case sizeof(apr_int32_t): |
546 | | return conv_10(u.u32, TRUE, &is_negative, buf_end, len); |
547 | | case sizeof(apr_int64_t): |
548 | | return conv_10_quad(u.u64, TRUE, &is_negative, buf_end, len); |
549 | | default: |
550 | | /* not implemented; stick 0 in the buffer */ |
551 | | return conv_10(0, TRUE, &is_negative, buf_end, len); |
552 | | } |
553 | | } |
554 | | #endif |
555 | | |
556 | | |
557 | | |
558 | | /* |
559 | | * Convert a floating point number to a string formats 'f', 'e' or 'E'. |
560 | | * The result is placed in buf, and len denotes the length of the string |
561 | | * The sign is returned in the is_negative argument (and is not placed |
562 | | * in buf). |
563 | | */ |
564 | | static char *conv_fp(register char format, register double num, |
565 | | boolean_e add_dp, int precision, int *is_negative, |
566 | | char *buf, apr_size_t *len) |
567 | 62.6M | { |
568 | 62.6M | register char *s = buf; |
569 | 62.6M | register char *p; |
570 | 62.6M | int decimal_point; |
571 | 62.6M | char buf1[NDIG]; |
572 | | |
573 | 62.6M | if (format == 'f') |
574 | 62.6M | p = apr_fcvt(num, precision, &decimal_point, is_negative, buf1); |
575 | 0 | else /* either e or E format */ |
576 | 0 | p = apr_ecvt(num, precision + 1, &decimal_point, is_negative, buf1); |
577 | | |
578 | | /* |
579 | | * Check for Infinity and NaN |
580 | | */ |
581 | 62.6M | if (apr_isalpha(*p)) { |
582 | 0 | *len = strlen(p); |
583 | 0 | memcpy(buf, p, *len + 1); |
584 | 0 | *is_negative = FALSE; |
585 | 0 | return (buf); |
586 | 0 | } |
587 | | |
588 | 62.6M | if (format == 'f') { |
589 | 62.6M | if (decimal_point <= 0) { |
590 | 10.5M | *s++ = '0'; |
591 | 10.5M | if (precision > 0) { |
592 | 10.5M | *s++ = '.'; |
593 | 12.7M | while (decimal_point++ < 0) |
594 | 2.20M | *s++ = '0'; |
595 | 10.5M | } |
596 | 0 | else if (add_dp) |
597 | 0 | *s++ = '.'; |
598 | 10.5M | } |
599 | 52.1M | else { |
600 | 106M | while (decimal_point-- > 0) |
601 | 54.6M | *s++ = *p++; |
602 | 52.1M | if (precision > 0 || add_dp) |
603 | 52.1M | *s++ = '.'; |
604 | 52.1M | } |
605 | 62.6M | } |
606 | 0 | else { |
607 | 0 | *s++ = *p++; |
608 | 0 | if (precision > 0 || add_dp) |
609 | 0 | *s++ = '.'; |
610 | 0 | } |
611 | | |
612 | | /* |
613 | | * copy the rest of p, the NUL is NOT copied |
614 | | */ |
615 | 434M | while (*p) |
616 | 371M | *s++ = *p++; |
617 | | |
618 | 62.6M | if (format != 'f') { |
619 | 0 | char temp[EXPONENT_LENGTH]; /* for exponent conversion */ |
620 | 0 | apr_size_t t_len; |
621 | 0 | int exponent_is_negative; |
622 | |
|
623 | 0 | *s++ = format; /* either e or E */ |
624 | 0 | decimal_point--; |
625 | 0 | if (decimal_point != 0) { |
626 | 0 | p = conv_10((apr_int32_t) decimal_point, FALSE, &exponent_is_negative, |
627 | 0 | &temp[EXPONENT_LENGTH], &t_len); |
628 | 0 | *s++ = exponent_is_negative ? '-' : '+'; |
629 | | |
630 | | /* |
631 | | * Make sure the exponent has at least 2 digits |
632 | | */ |
633 | 0 | if (t_len == 1) |
634 | 0 | *s++ = '0'; |
635 | 0 | while (t_len--) |
636 | 0 | *s++ = *p++; |
637 | 0 | } |
638 | 0 | else { |
639 | 0 | *s++ = '+'; |
640 | 0 | *s++ = '0'; |
641 | 0 | *s++ = '0'; |
642 | 0 | } |
643 | 0 | } |
644 | | |
645 | 62.6M | *len = s - buf; |
646 | 62.6M | return (buf); |
647 | 62.6M | } |
648 | | |
649 | | |
650 | | /* |
651 | | * Convert num to a base X number where X is a power of 2. nbits determines X. |
652 | | * For example, if nbits is 3, we do base 8 conversion |
653 | | * Return value: |
654 | | * a pointer to a string containing the number |
655 | | * |
656 | | * The caller provides a buffer for the string: that is the buf_end argument |
657 | | * which is a pointer to the END of the buffer + 1 (i.e. if the buffer |
658 | | * is declared as buf[ 100 ], buf_end should be &buf[ 100 ]) |
659 | | * |
660 | | * As with conv_10, we have a faster version which is used when |
661 | | * the number isn't quad size. |
662 | | */ |
663 | | static char *conv_p2(register apr_uint32_t num, register int nbits, |
664 | | char format, char *buf_end, register apr_size_t *len) |
665 | 124M | { |
666 | 124M | register int mask = (1 << nbits) - 1; |
667 | 124M | register char *p = buf_end; |
668 | 124M | static const char low_digits[] = "0123456789abcdef"; |
669 | 124M | static const char upper_digits[] = "0123456789ABCDEF"; |
670 | 124M | register const char *digits = (format == 'X') ? upper_digits : low_digits; |
671 | | |
672 | 415M | do { |
673 | 415M | *--p = digits[num & mask]; |
674 | 415M | num >>= nbits; |
675 | 415M | } |
676 | 415M | while (num); |
677 | | |
678 | 124M | *len = buf_end - p; |
679 | 124M | return (p); |
680 | 124M | } |
681 | | |
682 | | static char *conv_p2_quad(apr_uint64_t num, register int nbits, |
683 | | char format, char *buf_end, register apr_size_t *len) |
684 | 742k | { |
685 | 742k | register int mask = (1 << nbits) - 1; |
686 | 742k | register char *p = buf_end; |
687 | 742k | static const char low_digits[] = "0123456789abcdef"; |
688 | 742k | static const char upper_digits[] = "0123456789ABCDEF"; |
689 | 742k | register const char *digits = (format == 'X') ? upper_digits : low_digits; |
690 | | |
691 | 742k | if (num <= APR_UINT32_MAX) |
692 | 0 | return(conv_p2((apr_uint32_t)num, nbits, format, buf_end, len)); |
693 | | |
694 | 8.91M | do { |
695 | 8.91M | *--p = digits[num & mask]; |
696 | 8.91M | num >>= nbits; |
697 | 8.91M | } |
698 | 8.91M | while (num); |
699 | | |
700 | 742k | *len = buf_end - p; |
701 | 742k | return (p); |
702 | 742k | } |
703 | | |
704 | | #if APR_HAS_THREADS |
705 | | static char *conv_os_thread_t_hex(apr_os_thread_t *tid, char *buf_end, apr_size_t *len) |
706 | | { |
707 | | union { |
708 | | apr_os_thread_t tid; |
709 | | apr_uint64_t u64; |
710 | | apr_uint32_t u32; |
711 | | } u; |
712 | | int is_negative; |
713 | | |
714 | | u.tid = *tid; |
715 | | switch(sizeof(u.tid)) { |
716 | | case sizeof(apr_int32_t): |
717 | | return conv_p2(u.u32, 4, 'x', buf_end, len); |
718 | | case sizeof(apr_int64_t): |
719 | | return conv_p2_quad(u.u64, 4, 'x', buf_end, len); |
720 | | default: |
721 | | /* not implemented; stick 0 in the buffer */ |
722 | | return conv_10(0, TRUE, &is_negative, buf_end, len); |
723 | | } |
724 | | } |
725 | | #endif |
726 | | |
727 | | /* |
728 | | * Do format conversion placing the output in buffer |
729 | | */ |
730 | | static int apr_vformatter(int (*flush_func)(apr_vformatter_buff_t *), |
731 | | apr_vformatter_buff_t *vbuff, const char *fmt, va_list ap) |
732 | 453M | { |
733 | 453M | register char *sp; |
734 | 453M | register char *bep; |
735 | 453M | register int cc = 0; |
736 | 453M | register apr_size_t i; |
737 | | |
738 | 453M | register char *s = NULL; |
739 | 453M | char *q; |
740 | 453M | apr_size_t s_len = 0; |
741 | | |
742 | 453M | register apr_size_t min_width = 0; |
743 | 453M | apr_size_t precision = 0; |
744 | 453M | enum { |
745 | 453M | LEFT, RIGHT |
746 | 453M | } adjust; |
747 | 453M | char pad_char; |
748 | 453M | char prefix_char; |
749 | | |
750 | 453M | double fp_num; |
751 | 453M | apr_int64_t i_quad = 0; |
752 | 453M | apr_uint64_t ui_quad; |
753 | 453M | apr_int32_t i_num = 0; |
754 | 453M | apr_uint32_t ui_num = 0; |
755 | | |
756 | 453M | char num_buf[NUM_BUF_SIZE]; |
757 | 453M | char char_buf[2]; /* for printing %% and %<unknown> */ |
758 | 453M | char inf[] = "#INF"; |
759 | 453M | char nan[] = "#NAN"; |
760 | | |
761 | 453M | enum var_type_enum { |
762 | 453M | IS_QUAD, IS_LONG, IS_SHORT, IS_INT |
763 | 453M | }; |
764 | 453M | enum var_type_enum var_type = IS_INT; |
765 | | |
766 | | /* |
767 | | * Flag variables |
768 | | */ |
769 | 453M | boolean_e alternate_form; |
770 | 453M | boolean_e print_sign; |
771 | 453M | boolean_e print_blank; |
772 | 453M | boolean_e adjust_precision; |
773 | 453M | boolean_e adjust_width; |
774 | 453M | int is_negative; |
775 | | |
776 | 453M | sp = vbuff->curpos; |
777 | 453M | bep = vbuff->endpos; |
778 | | |
779 | 3.96G | while (*fmt) { |
780 | 3.51G | if (*fmt != '%') { |
781 | 2.84G | INS_CHAR(*fmt, sp, bep, cc); |
782 | 2.84G | } |
783 | 663M | else { |
784 | | /* |
785 | | * Default variable settings |
786 | | */ |
787 | 663M | boolean_e print_something = YES; |
788 | 663M | adjust = RIGHT; |
789 | 663M | alternate_form = print_sign = print_blank = NO; |
790 | 663M | pad_char = ' '; |
791 | 663M | prefix_char = NUL; |
792 | | |
793 | 663M | fmt++; |
794 | | |
795 | | /* |
796 | | * Try to avoid checking for flags, width or precision |
797 | | */ |
798 | 663M | if (!apr_islower(*fmt)) { |
799 | | /* |
800 | | * Recognize flags: -, #, BLANK, + |
801 | | */ |
802 | 252M | for (;; fmt++) { |
803 | 252M | if (*fmt == '-') |
804 | 0 | adjust = LEFT; |
805 | 252M | else if (*fmt == '+') |
806 | 0 | print_sign = YES; |
807 | 252M | else if (*fmt == '#') |
808 | 0 | alternate_form = YES; |
809 | 252M | else if (*fmt == ' ') |
810 | 0 | print_blank = YES; |
811 | 252M | else if (*fmt == '0') |
812 | 125M | pad_char = '0'; |
813 | 126M | else |
814 | 126M | break; |
815 | 252M | } |
816 | | |
817 | | /* |
818 | | * Check if a width was specified |
819 | | */ |
820 | 126M | if (apr_isdigit(*fmt)) { |
821 | 126M | STR_TO_DEC(fmt, min_width); |
822 | 126M | adjust_width = YES; |
823 | 126M | } |
824 | 430k | else if (*fmt == '*') { |
825 | 0 | int v = va_arg(ap, int); |
826 | 0 | fmt++; |
827 | 0 | adjust_width = YES; |
828 | 0 | if (v < 0) { |
829 | 0 | adjust = LEFT; |
830 | 0 | min_width = (apr_size_t)(-v); |
831 | 0 | } |
832 | 0 | else |
833 | 0 | min_width = (apr_size_t)v; |
834 | 0 | } |
835 | 430k | else |
836 | 430k | adjust_width = NO; |
837 | | |
838 | | /* |
839 | | * Check if a precision was specified |
840 | | */ |
841 | 126M | if (*fmt == '.') { |
842 | 451k | adjust_precision = YES; |
843 | 451k | fmt++; |
844 | 451k | if (apr_isdigit(*fmt)) { |
845 | 451k | STR_TO_DEC(fmt, precision); |
846 | 451k | } |
847 | 0 | else if (*fmt == '*') { |
848 | 0 | int v = va_arg(ap, int); |
849 | 0 | fmt++; |
850 | 0 | precision = (v < 0) ? 0 : (apr_size_t)v; |
851 | 0 | } |
852 | 0 | else |
853 | 0 | precision = 0; |
854 | 451k | } |
855 | 126M | else |
856 | 126M | adjust_precision = NO; |
857 | 126M | } |
858 | 537M | else |
859 | 537M | adjust_precision = adjust_width = NO; |
860 | | |
861 | | /* |
862 | | * Modifier check. In same cases, APR_OFF_T_FMT can be |
863 | | * "lld" and APR_INT64_T_FMT can be "ld" (that is, off_t is |
864 | | * "larger" than int64). Check that case 1st. |
865 | | * Note that if APR_OFF_T_FMT is "d", |
866 | | * the first if condition is never true. If APR_INT64_T_FMT |
867 | | * is "d' then the second if condition is never true. |
868 | | */ |
869 | 663M | if ((sizeof(APR_OFF_T_FMT) > sizeof(APR_INT64_T_FMT)) && |
870 | 663M | ((sizeof(APR_OFF_T_FMT) == 4 && |
871 | 0 | fmt[0] == APR_OFF_T_FMT[0] && |
872 | 0 | fmt[1] == APR_OFF_T_FMT[1]) || |
873 | 0 | (sizeof(APR_OFF_T_FMT) == 3 && |
874 | 0 | fmt[0] == APR_OFF_T_FMT[0]) || |
875 | 0 | (sizeof(APR_OFF_T_FMT) > 4 && |
876 | 0 | strncmp(fmt, APR_OFF_T_FMT, |
877 | 0 | sizeof(APR_OFF_T_FMT) - 2) == 0))) { |
878 | | /* Need to account for trailing 'd' and null in sizeof() */ |
879 | 0 | var_type = IS_QUAD; |
880 | 0 | fmt += (sizeof(APR_OFF_T_FMT) - 2); |
881 | 0 | } |
882 | 663M | else if ((sizeof(APR_INT64_T_FMT) == 4 && |
883 | 663M | fmt[0] == APR_INT64_T_FMT[0] && |
884 | 663M | fmt[1] == APR_INT64_T_FMT[1]) || |
885 | 663M | (sizeof(APR_INT64_T_FMT) == 3 && |
886 | 663M | fmt[0] == APR_INT64_T_FMT[0]) || |
887 | 663M | (sizeof(APR_INT64_T_FMT) > 4 && |
888 | 0 | strncmp(fmt, APR_INT64_T_FMT, |
889 | 136M | sizeof(APR_INT64_T_FMT) - 2) == 0)) { |
890 | | /* Need to account for trailing 'd' and null in sizeof() */ |
891 | 136M | var_type = IS_QUAD; |
892 | 136M | fmt += (sizeof(APR_INT64_T_FMT) - 2); |
893 | 136M | } |
894 | 527M | else if (*fmt == 'q') { |
895 | 0 | var_type = IS_QUAD; |
896 | 0 | fmt++; |
897 | 0 | } |
898 | 527M | else if (*fmt == 'l') { |
899 | 0 | var_type = IS_LONG; |
900 | 0 | fmt++; |
901 | 0 | } |
902 | 527M | else if (*fmt == 'h') { |
903 | 0 | var_type = IS_SHORT; |
904 | 0 | fmt++; |
905 | 0 | } |
906 | 527M | else { |
907 | 527M | var_type = IS_INT; |
908 | 527M | } |
909 | | |
910 | | /* |
911 | | * Argument extraction and printing. |
912 | | * First we determine the argument type. |
913 | | * Then, we convert the argument to a string. |
914 | | * On exit from the switch, s points to the string that |
915 | | * must be printed, s_len has the length of the string |
916 | | * The precision requirements, if any, are reflected in s_len. |
917 | | * |
918 | | * NOTE: pad_char may be set to '0' because of the 0 flag. |
919 | | * It is reset to ' ' by non-numeric formats |
920 | | */ |
921 | 663M | switch (*fmt) { |
922 | 716k | case 'u': |
923 | 716k | if (var_type == IS_QUAD) { |
924 | 393k | i_quad = va_arg(ap, apr_uint64_t); |
925 | 393k | s = conv_10_quad(i_quad, 1, &is_negative, |
926 | 393k | &num_buf[NUM_BUF_SIZE], &s_len); |
927 | 393k | } |
928 | 322k | else { |
929 | 322k | if (var_type == IS_LONG) |
930 | 0 | i_num = (apr_int32_t) va_arg(ap, apr_uint32_t); |
931 | 322k | else if (var_type == IS_SHORT) |
932 | 0 | i_num = (apr_int32_t) (unsigned short) va_arg(ap, unsigned int); |
933 | 322k | else |
934 | 322k | i_num = (apr_int32_t) va_arg(ap, unsigned int); |
935 | 322k | s = conv_10(i_num, 1, &is_negative, |
936 | 322k | &num_buf[NUM_BUF_SIZE], &s_len); |
937 | 322k | } |
938 | 716k | FIX_PRECISION(adjust_precision, precision, s, s_len); |
939 | 716k | break; |
940 | | |
941 | 212M | case 'd': |
942 | 212M | case 'i': |
943 | 212M | if (var_type == IS_QUAD) { |
944 | 136M | i_quad = va_arg(ap, apr_int64_t); |
945 | 136M | s = conv_10_quad(i_quad, 0, &is_negative, |
946 | 136M | &num_buf[NUM_BUF_SIZE], &s_len); |
947 | 136M | } |
948 | 76.1M | else { |
949 | 76.1M | if (var_type == IS_LONG) |
950 | 0 | i_num = va_arg(ap, apr_int32_t); |
951 | 76.1M | else if (var_type == IS_SHORT) |
952 | 0 | i_num = (short) va_arg(ap, int); |
953 | 76.1M | else |
954 | 76.1M | i_num = va_arg(ap, int); |
955 | 76.1M | s = conv_10(i_num, 0, &is_negative, |
956 | 76.1M | &num_buf[NUM_BUF_SIZE], &s_len); |
957 | 76.1M | } |
958 | 212M | FIX_PRECISION(adjust_precision, precision, s, s_len); |
959 | | |
960 | 212M | if (is_negative) |
961 | 8.98M | prefix_char = '-'; |
962 | 203M | else if (print_sign) |
963 | 0 | prefix_char = '+'; |
964 | 203M | else if (print_blank) |
965 | 0 | prefix_char = ' '; |
966 | 212M | break; |
967 | | |
968 | | |
969 | 0 | case 'o': |
970 | 0 | if (var_type == IS_QUAD) { |
971 | 0 | ui_quad = va_arg(ap, apr_uint64_t); |
972 | 0 | s = conv_p2_quad(ui_quad, 3, *fmt, |
973 | 0 | &num_buf[NUM_BUF_SIZE], &s_len); |
974 | 0 | } |
975 | 0 | else { |
976 | 0 | if (var_type == IS_LONG) |
977 | 0 | ui_num = va_arg(ap, apr_uint32_t); |
978 | 0 | else if (var_type == IS_SHORT) |
979 | 0 | ui_num = (unsigned short) va_arg(ap, unsigned int); |
980 | 0 | else |
981 | 0 | ui_num = va_arg(ap, unsigned int); |
982 | 0 | s = conv_p2(ui_num, 3, *fmt, |
983 | 0 | &num_buf[NUM_BUF_SIZE], &s_len); |
984 | 0 | } |
985 | 0 | FIX_PRECISION(adjust_precision, precision, s, s_len); |
986 | 0 | if (alternate_form && *s != '0') { |
987 | 0 | *--s = '0'; |
988 | 0 | s_len++; |
989 | 0 | } |
990 | 0 | break; |
991 | | |
992 | | |
993 | 104M | case 'x': |
994 | 124M | case 'X': |
995 | 124M | if (var_type == IS_QUAD) { |
996 | 0 | ui_quad = va_arg(ap, apr_uint64_t); |
997 | 0 | s = conv_p2_quad(ui_quad, 4, *fmt, |
998 | 0 | &num_buf[NUM_BUF_SIZE], &s_len); |
999 | 0 | } |
1000 | 124M | else { |
1001 | 124M | if (var_type == IS_LONG) |
1002 | 0 | ui_num = va_arg(ap, apr_uint32_t); |
1003 | 124M | else if (var_type == IS_SHORT) |
1004 | 0 | ui_num = (unsigned short) va_arg(ap, unsigned int); |
1005 | 124M | else |
1006 | 124M | ui_num = va_arg(ap, unsigned int); |
1007 | 124M | s = conv_p2(ui_num, 4, *fmt, |
1008 | 124M | &num_buf[NUM_BUF_SIZE], &s_len); |
1009 | 124M | } |
1010 | 124M | FIX_PRECISION(adjust_precision, precision, s, s_len); |
1011 | 124M | if (alternate_form && ui_num != 0) { |
1012 | 0 | *--s = *fmt; /* 'x' or 'X' */ |
1013 | 0 | *--s = '0'; |
1014 | 0 | s_len += 2; |
1015 | 0 | } |
1016 | 124M | break; |
1017 | | |
1018 | | |
1019 | 104M | case 's': |
1020 | 104M | s = va_arg(ap, char *); |
1021 | 104M | if (s != NULL) { |
1022 | 104M | if (!adjust_precision) { |
1023 | 104M | s_len = strlen(s); |
1024 | 104M | } |
1025 | 0 | else { |
1026 | | /* From the C library standard in section 7.9.6.1: |
1027 | | * ...if the precision is specified, no more then |
1028 | | * that many characters are written. If the |
1029 | | * precision is not specified or is greater |
1030 | | * than the size of the array, the array shall |
1031 | | * contain a null character. |
1032 | | * |
1033 | | * My reading is is precision is specified and |
1034 | | * is less then or equal to the size of the |
1035 | | * array, no null character is required. So |
1036 | | * we can't do a strlen. |
1037 | | * |
1038 | | * This figures out the length of the string |
1039 | | * up to the precision. Once it's long enough |
1040 | | * for the specified precision, we don't care |
1041 | | * anymore. |
1042 | | * |
1043 | | * NOTE: you must do the length comparison |
1044 | | * before the check for the null character. |
1045 | | * Otherwise, you'll check one beyond the |
1046 | | * last valid character. |
1047 | | */ |
1048 | 0 | const char *walk; |
1049 | |
|
1050 | 0 | for (walk = s, s_len = 0; |
1051 | 0 | (s_len < precision) && (*walk != '\0'); |
1052 | 0 | ++walk, ++s_len); |
1053 | 0 | } |
1054 | 104M | } |
1055 | 0 | else { |
1056 | 0 | s = S_NULL; |
1057 | 0 | s_len = S_NULL_LEN; |
1058 | 0 | } |
1059 | 104M | pad_char = ' '; |
1060 | 104M | break; |
1061 | | |
1062 | | |
1063 | 62.6M | case 'f': |
1064 | 62.6M | case 'e': |
1065 | 62.6M | case 'E': |
1066 | 62.6M | fp_num = va_arg(ap, double); |
1067 | | /* |
1068 | | * We use &num_buf[ 1 ], so that we have room for the sign |
1069 | | */ |
1070 | 62.6M | s = NULL; |
1071 | 62.6M | #ifdef HAVE_ISNAN |
1072 | 62.6M | if (isnan(fp_num)) { |
1073 | 0 | s = nan; |
1074 | 0 | s_len = strlen(nan); |
1075 | 0 | } |
1076 | 62.6M | #endif |
1077 | 62.6M | #ifdef HAVE_ISINF |
1078 | 62.6M | if (!s && isinf(fp_num)) { |
1079 | 0 | s = inf; |
1080 | 0 | s_len = strlen(inf); |
1081 | 0 | } |
1082 | 62.6M | #endif |
1083 | 62.6M | if (!s) { |
1084 | 62.6M | s = conv_fp(*fmt, fp_num, alternate_form, |
1085 | 62.6M | (int)((adjust_precision == NO) ? FLOAT_DIGITS : precision), |
1086 | 62.6M | &is_negative, &num_buf[1], &s_len); |
1087 | 62.6M | if (is_negative) |
1088 | 163k | prefix_char = '-'; |
1089 | 62.4M | else if (print_sign) |
1090 | 0 | prefix_char = '+'; |
1091 | 62.4M | else if (print_blank) |
1092 | 0 | prefix_char = ' '; |
1093 | 62.6M | } |
1094 | 62.6M | break; |
1095 | | |
1096 | | |
1097 | 157M | case 'g': |
1098 | 157M | case 'G': |
1099 | 157M | fp_num = va_arg(ap, double); |
1100 | 157M | s = NULL; |
1101 | 157M | #ifdef HAVE_ISNAN |
1102 | 157M | if (isnan(fp_num)) { |
1103 | 29.1k | s = nan; |
1104 | 29.1k | s_len = strlen(nan); |
1105 | 29.1k | } |
1106 | 157M | #endif |
1107 | 157M | #ifdef HAVE_ISINF |
1108 | 157M | if (!s && isinf(fp_num)) { |
1109 | 31.4k | s = inf; |
1110 | 31.4k | s_len = strlen(inf); |
1111 | 31.4k | } |
1112 | 157M | #endif |
1113 | 157M | if (!s) { |
1114 | 157M | if (adjust_precision == NO) |
1115 | 157M | precision = FLOAT_DIGITS; |
1116 | 307 | else if (precision == 0) |
1117 | 0 | precision = 1; |
1118 | | /* |
1119 | | * * We use &num_buf[ 1 ], so that we have room for the sign |
1120 | | */ |
1121 | 157M | s = apr_gcvt(fp_num, (int) precision, &num_buf[1], |
1122 | 157M | alternate_form); |
1123 | 157M | if (*s == '-') |
1124 | 8.52M | prefix_char = *s++; |
1125 | 149M | else if (print_sign) |
1126 | 0 | prefix_char = '+'; |
1127 | 149M | else if (print_blank) |
1128 | 0 | prefix_char = ' '; |
1129 | | |
1130 | 157M | s_len = strlen(s); |
1131 | | |
1132 | 157M | if (alternate_form && (q = strchr(s, '.')) == NULL) { |
1133 | 0 | s[s_len++] = '.'; |
1134 | 0 | s[s_len] = '\0'; /* delimit for following strchr() */ |
1135 | 0 | } |
1136 | 157M | if (*fmt == 'G' && (q = strchr(s, 'e')) != NULL) |
1137 | 0 | *q = 'E'; |
1138 | 157M | } |
1139 | 157M | break; |
1140 | | |
1141 | | |
1142 | 34.0k | case 'c': |
1143 | 34.0k | char_buf[0] = (char) (va_arg(ap, int)); |
1144 | 34.0k | s = &char_buf[0]; |
1145 | 34.0k | s_len = 1; |
1146 | 34.0k | pad_char = ' '; |
1147 | 34.0k | break; |
1148 | | |
1149 | | |
1150 | 366k | case '%': |
1151 | 366k | char_buf[0] = '%'; |
1152 | 366k | s = &char_buf[0]; |
1153 | 366k | s_len = 1; |
1154 | 366k | pad_char = ' '; |
1155 | 366k | break; |
1156 | | |
1157 | | |
1158 | 0 | case 'n': |
1159 | 0 | if (var_type == IS_QUAD) |
1160 | 0 | *(va_arg(ap, apr_int64_t *)) = cc; |
1161 | 0 | else if (var_type == IS_LONG) |
1162 | 0 | *(va_arg(ap, long *)) = cc; |
1163 | 0 | else if (var_type == IS_SHORT) |
1164 | 0 | *(va_arg(ap, short *)) = cc; |
1165 | 0 | else |
1166 | 0 | *(va_arg(ap, int *)) = cc; |
1167 | 0 | print_something = NO; |
1168 | 0 | break; |
1169 | | |
1170 | | /* |
1171 | | * This is where we extend the printf format, with a second |
1172 | | * type specifier |
1173 | | */ |
1174 | 742k | case 'p': |
1175 | 742k | switch(*++fmt) { |
1176 | | /* |
1177 | | * If the pointer size is equal to or smaller than the size |
1178 | | * of the largest unsigned int, we convert the pointer to a |
1179 | | * hex number, otherwise we print "%p" to indicate that we |
1180 | | * don't handle "%p". |
1181 | | */ |
1182 | 0 | case 'p': |
1183 | 0 | #if APR_SIZEOF_VOIDP == 8 |
1184 | 0 | if (sizeof(void *) <= sizeof(apr_uint64_t)) { |
1185 | 0 | ui_quad = (apr_uint64_t) va_arg(ap, void *); |
1186 | 0 | s = conv_p2_quad(ui_quad, 4, 'x', |
1187 | 0 | &num_buf[NUM_BUF_SIZE], &s_len); |
1188 | 0 | } |
1189 | | #else |
1190 | | if (sizeof(void *) <= sizeof(apr_uint32_t)) { |
1191 | | ui_num = (apr_uint32_t) va_arg(ap, void *); |
1192 | | s = conv_p2(ui_num, 4, 'x', |
1193 | | &num_buf[NUM_BUF_SIZE], &s_len); |
1194 | | } |
1195 | | #endif |
1196 | 0 | else { |
1197 | 0 | s = (char *)"%p"; |
1198 | 0 | s_len = 2; |
1199 | 0 | prefix_char = NUL; |
1200 | 0 | } |
1201 | 0 | pad_char = ' '; |
1202 | 0 | break; |
1203 | | |
1204 | | #if !FOR_GS |
1205 | | /* print an apr_sockaddr_t as a.b.c.d:port */ |
1206 | | case 'I': |
1207 | | { |
1208 | | apr_sockaddr_t *sa; |
1209 | | |
1210 | | sa = va_arg(ap, apr_sockaddr_t *); |
1211 | | if (sa != NULL) { |
1212 | | s = conv_apr_sockaddr(sa, &num_buf[NUM_BUF_SIZE], &s_len); |
1213 | | if (adjust_precision && precision < s_len) |
1214 | | s_len = precision; |
1215 | | } |
1216 | | else { |
1217 | | s = S_NULL; |
1218 | | s_len = S_NULL_LEN; |
1219 | | } |
1220 | | pad_char = ' '; |
1221 | | } |
1222 | | break; |
1223 | | |
1224 | | /* print a struct in_addr as a.b.c.d */ |
1225 | | case 'A': |
1226 | | { |
1227 | | struct in_addr *ia; |
1228 | | |
1229 | | ia = va_arg(ap, struct in_addr *); |
1230 | | if (ia != NULL) { |
1231 | | s = conv_in_addr(ia, &num_buf[NUM_BUF_SIZE], &s_len); |
1232 | | if (adjust_precision && precision < s_len) |
1233 | | s_len = precision; |
1234 | | } |
1235 | | else { |
1236 | | s = S_NULL; |
1237 | | s_len = S_NULL_LEN; |
1238 | | } |
1239 | | pad_char = ' '; |
1240 | | } |
1241 | | break; |
1242 | | |
1243 | | /* print the error for an apr_status_t */ |
1244 | | case 'm': |
1245 | | { |
1246 | | apr_status_t *mrv; |
1247 | | |
1248 | | mrv = va_arg(ap, apr_status_t *); |
1249 | | if (mrv != NULL) { |
1250 | | s = apr_strerror(*mrv, num_buf, NUM_BUF_SIZE-1); |
1251 | | s_len = strlen(s); |
1252 | | } |
1253 | | else { |
1254 | | s = S_NULL; |
1255 | | s_len = S_NULL_LEN; |
1256 | | } |
1257 | | pad_char = ' '; |
1258 | | } |
1259 | | break; |
1260 | | #endif |
1261 | | |
1262 | 0 | case 'T': |
1263 | | #if APR_HAS_THREADS |
1264 | | { |
1265 | | apr_os_thread_t *tid; |
1266 | | |
1267 | | tid = va_arg(ap, apr_os_thread_t *); |
1268 | | if (tid != NULL) { |
1269 | | s = conv_os_thread_t(tid, &num_buf[NUM_BUF_SIZE], &s_len); |
1270 | | if (adjust_precision && precision < s_len) |
1271 | | s_len = precision; |
1272 | | } |
1273 | | else { |
1274 | | s = S_NULL; |
1275 | | s_len = S_NULL_LEN; |
1276 | | } |
1277 | | pad_char = ' '; |
1278 | | } |
1279 | | #else |
1280 | 0 | char_buf[0] = '0'; |
1281 | 0 | s = &char_buf[0]; |
1282 | 0 | s_len = 1; |
1283 | 0 | pad_char = ' '; |
1284 | 0 | #endif |
1285 | 0 | break; |
1286 | | |
1287 | 0 | case 't': |
1288 | | #if APR_HAS_THREADS |
1289 | | { |
1290 | | apr_os_thread_t *tid; |
1291 | | |
1292 | | tid = va_arg(ap, apr_os_thread_t *); |
1293 | | if (tid != NULL) { |
1294 | | s = conv_os_thread_t_hex(tid, &num_buf[NUM_BUF_SIZE], &s_len); |
1295 | | if (adjust_precision && precision < s_len) |
1296 | | s_len = precision; |
1297 | | } |
1298 | | else { |
1299 | | s = S_NULL; |
1300 | | s_len = S_NULL_LEN; |
1301 | | } |
1302 | | pad_char = ' '; |
1303 | | } |
1304 | | #else |
1305 | 0 | char_buf[0] = '0'; |
1306 | 0 | s = &char_buf[0]; |
1307 | 0 | s_len = 1; |
1308 | 0 | pad_char = ' '; |
1309 | 0 | #endif |
1310 | 0 | break; |
1311 | | |
1312 | | #if !FOR_GS |
1313 | | case 'B': |
1314 | | case 'F': |
1315 | | case 'S': |
1316 | | { |
1317 | | char buf[5]; |
1318 | | apr_off_t size = 0; |
1319 | | |
1320 | | if (*fmt == 'B') { |
1321 | | apr_uint32_t *arg = va_arg(ap, apr_uint32_t *); |
1322 | | size = (arg) ? *arg : 0; |
1323 | | } |
1324 | | else if (*fmt == 'F') { |
1325 | | apr_off_t *arg = va_arg(ap, apr_off_t *); |
1326 | | size = (arg) ? *arg : 0; |
1327 | | } |
1328 | | else { |
1329 | | apr_size_t *arg = va_arg(ap, apr_size_t *); |
1330 | | size = (arg) ? *arg : 0; |
1331 | | } |
1332 | | |
1333 | | s = apr_strfsize(size, buf); |
1334 | | s_len = strlen(s); |
1335 | | pad_char = ' '; |
1336 | | } |
1337 | | break; |
1338 | | #endif |
1339 | | |
1340 | 742k | case NUL: |
1341 | | /* if %p ends the string, treat it as pointer */ |
1342 | 742k | #if APR_SIZEOF_VOIDP == 8 |
1343 | 742k | if (sizeof(void *) <= sizeof(apr_uint64_t)) { |
1344 | 742k | ui_quad = (apr_uint64_t) va_arg(ap, void *); |
1345 | 742k | s = conv_p2_quad(ui_quad, 4, 'x', |
1346 | 742k | &num_buf[NUM_BUF_SIZE], &s_len); |
1347 | 742k | } |
1348 | | #else |
1349 | | if (sizeof(void *) <= sizeof(apr_uint32_t)) { |
1350 | | ui_num = (apr_uint32_t) va_arg(ap, void *); |
1351 | | s = conv_p2(ui_num, 4, 'x', |
1352 | | &num_buf[NUM_BUF_SIZE], &s_len); |
1353 | | } |
1354 | | #endif |
1355 | 0 | else { |
1356 | 0 | s = (char *)"%p"; |
1357 | 0 | s_len = 2; |
1358 | 0 | prefix_char = NUL; |
1359 | 0 | } |
1360 | 742k | pad_char = ' '; |
1361 | 742k | fmt--; |
1362 | 742k | break; |
1363 | | |
1364 | 0 | default: |
1365 | 0 | s = (char *)"bogus %p"; |
1366 | 0 | s_len = 8; |
1367 | 0 | prefix_char = NUL; |
1368 | 0 | (void)va_arg(ap, void *); /* skip the bogus argument on the stack */ |
1369 | 0 | break; |
1370 | 742k | } |
1371 | 742k | break; |
1372 | | |
1373 | 742k | case NUL: |
1374 | | /* |
1375 | | * The last character of the format string was %. |
1376 | | * We ignore it. |
1377 | | */ |
1378 | 0 | continue; |
1379 | | |
1380 | | |
1381 | | /* |
1382 | | * The default case is for unrecognized %'s. |
1383 | | * We print %<char> to help the user identify what |
1384 | | * option is not understood. |
1385 | | * This is also useful in case the user wants to pass |
1386 | | * the output of format_converter to another function |
1387 | | * that understands some other %<char> (like syslog). |
1388 | | * Note that we can't point s inside fmt because the |
1389 | | * unknown <char> could be preceded by width etc. |
1390 | | */ |
1391 | 0 | default: |
1392 | 0 | char_buf[0] = '%'; |
1393 | 0 | char_buf[1] = *fmt; |
1394 | 0 | s = char_buf; |
1395 | 0 | s_len = 2; |
1396 | 0 | pad_char = ' '; |
1397 | 0 | break; |
1398 | 663M | } |
1399 | | |
1400 | 663M | if (prefix_char != NUL && s != S_NULL && s != char_buf) { |
1401 | 17.6M | *--s = prefix_char; |
1402 | 17.6M | s_len++; |
1403 | 17.6M | } |
1404 | | |
1405 | 663M | if (adjust_width && adjust == RIGHT && min_width > s_len) { |
1406 | 67.2M | if (pad_char == '0' && prefix_char != NUL) { |
1407 | 0 | INS_CHAR(*s, sp, bep, cc); |
1408 | 0 | s++; |
1409 | 0 | s_len--; |
1410 | 0 | min_width--; |
1411 | 0 | } |
1412 | 67.2M | PAD(min_width, s_len, pad_char); |
1413 | 67.2M | } |
1414 | | |
1415 | | /* |
1416 | | * Print the string s. |
1417 | | */ |
1418 | 663M | if (print_something == YES) { |
1419 | 3.89G | for (i = s_len; i != 0; i--) { |
1420 | 3.23G | INS_CHAR(*s, sp, bep, cc); |
1421 | 3.23G | s++; |
1422 | 3.23G | } |
1423 | 663M | } |
1424 | | |
1425 | 663M | if (adjust_width && adjust == LEFT && min_width > s_len) |
1426 | 0 | PAD(min_width, s_len, pad_char); |
1427 | 663M | } |
1428 | 3.51G | fmt++; |
1429 | 3.51G | } |
1430 | 453M | vbuff->curpos = sp; |
1431 | | |
1432 | 453M | return cc; |
1433 | 453M | } |
1434 | | |
1435 | | |
1436 | | static int snprintf_flush(apr_vformatter_buff_t *vbuff) |
1437 | 0 | { |
1438 | | /* if the buffer fills we have to abort immediately, there is no way |
1439 | | * to "flush" an apr_snprintf... there's nowhere to flush it to. |
1440 | | */ |
1441 | 0 | return -1; |
1442 | 0 | } |
1443 | | |
1444 | | int gs_snprintf(char *buf, int len, |
1445 | | const char *format, ...) |
1446 | 453M | { |
1447 | 453M | int cc; |
1448 | 453M | va_list ap; |
1449 | 453M | apr_vformatter_buff_t vbuff; |
1450 | | |
1451 | 453M | if (len == 0) { |
1452 | | /* NOTE: This is a special case; we just want to return the number |
1453 | | * of chars that would be written (minus \0) if the buffer |
1454 | | * size was infinite. We leverage the fact that INS_CHAR |
1455 | | * just does actual inserts iff the buffer pointer is non-NULL. |
1456 | | * In this case, we don't care what buf is; it can be NULL, since |
1457 | | * we don't touch it at all. |
1458 | | */ |
1459 | 0 | vbuff.curpos = NULL; |
1460 | 0 | vbuff.endpos = NULL; |
1461 | 453M | } else { |
1462 | | /* save one byte for nul terminator */ |
1463 | 453M | vbuff.curpos = buf; |
1464 | 453M | vbuff.endpos = buf + len - 1; |
1465 | 453M | } |
1466 | 453M | va_start(ap, format); |
1467 | 453M | cc = apr_vformatter(snprintf_flush, &vbuff, format, ap); |
1468 | 453M | va_end(ap); |
1469 | 453M | if (len != 0) { |
1470 | 453M | *vbuff.curpos = '\0'; |
1471 | 453M | } |
1472 | 453M | return (cc == -1) ? (int)len - 1 : cc; |
1473 | 453M | } |
1474 | | |
1475 | | int gs_vsnprintf(char *buf, int len, const char *format, |
1476 | | va_list ap) |
1477 | 0 | { |
1478 | 0 | int cc; |
1479 | 0 | apr_vformatter_buff_t vbuff; |
1480 | |
|
1481 | 0 | if (len == 0) { |
1482 | | /* See above note */ |
1483 | 0 | vbuff.curpos = NULL; |
1484 | 0 | vbuff.endpos = NULL; |
1485 | 0 | } else { |
1486 | | /* save one byte for nul terminator */ |
1487 | 0 | vbuff.curpos = buf; |
1488 | 0 | vbuff.endpos = buf + len - 1; |
1489 | 0 | } |
1490 | 0 | cc = apr_vformatter(snprintf_flush, &vbuff, format, ap); |
1491 | 0 | if (len != 0) { |
1492 | 0 | *vbuff.curpos = '\0'; |
1493 | 0 | } |
1494 | |
|
1495 | 0 | return (cc == -1) ? (int)len - 1 : cc; |
1496 | 0 | } |
1497 | | |
1498 | | int gs_vsprintf(char *buf, const char *format, va_list ap) |
1499 | 0 | { |
1500 | 0 | int cc; |
1501 | 0 | apr_vformatter_buff_t vbuff; |
1502 | | |
1503 | | /* save one byte for nul terminator */ |
1504 | 0 | vbuff.curpos = buf; |
1505 | 0 | vbuff.endpos = buf + NUM_BUF_SIZE - 1; |
1506 | |
|
1507 | 0 | cc = apr_vformatter(snprintf_flush, &vbuff, format, ap); |
1508 | 0 | *vbuff.curpos = '\0'; |
1509 | |
|
1510 | 0 | return cc; |
1511 | 0 | } |