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