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