/src/httpd/srclib/apr/strings/apr_strings.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 | | * Copyright (c) 1990, 1993 |
18 | | * The Regents of the University of California. All rights reserved. |
19 | | * |
20 | | * Redistribution and use in source and binary forms, with or without |
21 | | * modification, are permitted provided that the following conditions |
22 | | * are met: |
23 | | * 1. Redistributions of source code must retain the above copyright |
24 | | * notice, this list of conditions and the following disclaimer. |
25 | | * 2. Redistributions in binary form must reproduce the above copyright |
26 | | * notice, this list of conditions and the following disclaimer in the |
27 | | * documentation and/or other materials provided with the distribution. |
28 | | * 3. All advertising materials mentioning features or use of this software |
29 | | * must display the following acknowledgement: |
30 | | * This product includes software developed by the University of |
31 | | * California, Berkeley and its contributors. |
32 | | * 4. Neither the name of the University nor the names of its contributors |
33 | | * may be used to endorse or promote products derived from this software |
34 | | * without specific prior written permission. |
35 | | * |
36 | | * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND |
37 | | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
38 | | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
39 | | * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE |
40 | | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL |
41 | | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS |
42 | | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) |
43 | | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT |
44 | | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY |
45 | | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF |
46 | | * SUCH DAMAGE. |
47 | | */ |
48 | | |
49 | | #include "apr.h" |
50 | | #include "apr_strings.h" |
51 | | #include "apr_general.h" |
52 | | #include "apr_private.h" |
53 | | #include "apr_lib.h" |
54 | | #define APR_WANT_STDIO |
55 | | #define APR_WANT_STRFUNC |
56 | | #include "apr_want.h" |
57 | | |
58 | | #ifdef HAVE_STDDEF_H |
59 | | #include <stddef.h> /* NULL */ |
60 | | #endif |
61 | | #ifdef HAVE_LIMITS_H |
62 | | #include <limits.h> /* INT_MAX */ |
63 | | #endif |
64 | | |
65 | | #ifdef HAVE_STDLIB_H |
66 | | #include <stdlib.h> /* strtol and strtoll */ |
67 | | #endif |
68 | | |
69 | | /** this is used to cache lengths in apr_pstrcat */ |
70 | 7.74k | #define MAX_SAVED_LENGTHS 6 |
71 | | |
72 | | APR_DECLARE(char *) apr_pstrdup(apr_pool_t *a, const char *s) |
73 | 54.4k | { |
74 | 54.4k | char *res; |
75 | 54.4k | apr_size_t len; |
76 | | |
77 | 54.4k | if (s == NULL) { |
78 | 0 | return NULL; |
79 | 0 | } |
80 | 54.4k | len = strlen(s) + 1; |
81 | 54.4k | res = apr_pmemdup(a, s, len); |
82 | 54.4k | return res; |
83 | 54.4k | } |
84 | | |
85 | | APR_DECLARE(char *) apr_pstrndup(apr_pool_t *a, const char *s, apr_size_t n) |
86 | 209 | { |
87 | 209 | char *res; |
88 | 209 | const char *end; |
89 | | |
90 | 209 | if (s == NULL) { |
91 | 0 | return NULL; |
92 | 0 | } |
93 | 209 | end = memchr(s, '\0', n); |
94 | 209 | if (end != NULL) |
95 | 0 | n = end - s; |
96 | 209 | res = apr_palloc(a, n + 1); |
97 | 209 | memcpy(res, s, n); |
98 | 209 | res[n] = '\0'; |
99 | 209 | return res; |
100 | 209 | } |
101 | | |
102 | | APR_DECLARE(char *) apr_pstrmemdup(apr_pool_t *a, const char *s, apr_size_t n) |
103 | 6.34k | { |
104 | 6.34k | char *res; |
105 | | |
106 | 6.34k | if (s == NULL) { |
107 | 0 | return NULL; |
108 | 0 | } |
109 | 6.34k | res = apr_palloc(a, n + 1); |
110 | 6.34k | memcpy(res, s, n); |
111 | 6.34k | res[n] = '\0'; |
112 | 6.34k | return res; |
113 | 6.34k | } |
114 | | |
115 | | APR_DECLARE(void *) apr_pmemdup(apr_pool_t *a, const void *m, apr_size_t n) |
116 | 68.7k | { |
117 | 68.7k | void *res; |
118 | | |
119 | 68.7k | if (m == NULL) |
120 | 0 | return NULL; |
121 | 68.7k | res = apr_palloc(a, n); |
122 | 68.7k | memcpy(res, m, n); |
123 | 68.7k | return res; |
124 | 68.7k | } |
125 | | |
126 | | APR_DECLARE_NONSTD(char *) apr_pstrcat(apr_pool_t *a, ...) |
127 | 816 | { |
128 | 816 | char *cp, *argp, *res; |
129 | 816 | apr_size_t saved_lengths[MAX_SAVED_LENGTHS]; |
130 | 816 | int nargs = 0; |
131 | | |
132 | | /* Pass one --- find length of required string */ |
133 | | |
134 | 816 | apr_size_t len = 0; |
135 | 816 | va_list adummy; |
136 | | |
137 | 816 | va_start(adummy, a); |
138 | | |
139 | 4.68k | while ((cp = va_arg(adummy, char *)) != NULL) { |
140 | 3.87k | apr_size_t cplen = strlen(cp); |
141 | 3.87k | if (nargs < MAX_SAVED_LENGTHS) { |
142 | 3.72k | saved_lengths[nargs++] = cplen; |
143 | 3.72k | } |
144 | 3.87k | len += cplen; |
145 | 3.87k | } |
146 | | |
147 | 816 | va_end(adummy); |
148 | | |
149 | | /* Allocate the required string */ |
150 | | |
151 | 816 | res = (char *) apr_palloc(a, len + 1); |
152 | 816 | cp = res; |
153 | | |
154 | | /* Pass two --- copy the argument strings into the result space */ |
155 | | |
156 | 816 | va_start(adummy, a); |
157 | | |
158 | 816 | nargs = 0; |
159 | 4.68k | while ((argp = va_arg(adummy, char *)) != NULL) { |
160 | 3.87k | if (nargs < MAX_SAVED_LENGTHS) { |
161 | 3.72k | len = saved_lengths[nargs++]; |
162 | 3.72k | } |
163 | 150 | else { |
164 | 150 | len = strlen(argp); |
165 | 150 | } |
166 | | |
167 | 3.87k | memcpy(cp, argp, len); |
168 | 3.87k | cp += len; |
169 | 3.87k | } |
170 | | |
171 | 816 | va_end(adummy); |
172 | | |
173 | | /* Return the result string */ |
174 | | |
175 | 816 | *cp = '\0'; |
176 | | |
177 | 816 | return res; |
178 | 816 | } |
179 | | |
180 | | APR_DECLARE(char *) apr_pstrcatv(apr_pool_t *a, const struct iovec *vec, |
181 | | apr_size_t nvec, apr_size_t *nbytes) |
182 | 0 | { |
183 | 0 | apr_size_t i; |
184 | 0 | apr_size_t len; |
185 | 0 | const struct iovec *src; |
186 | 0 | char *res; |
187 | 0 | char *dst; |
188 | | |
189 | | /* Pass one --- find length of required string */ |
190 | 0 | len = 0; |
191 | 0 | src = vec; |
192 | 0 | for (i = nvec; i; i--) { |
193 | 0 | len += src->iov_len; |
194 | 0 | src++; |
195 | 0 | } |
196 | 0 | if (nbytes) { |
197 | 0 | *nbytes = len; |
198 | 0 | } |
199 | | |
200 | | /* Allocate the required string */ |
201 | 0 | res = (char *) apr_palloc(a, len + 1); |
202 | | |
203 | | /* Pass two --- copy the argument strings into the result space */ |
204 | 0 | src = vec; |
205 | 0 | dst = res; |
206 | 0 | for (i = nvec; i; i--) { |
207 | 0 | memcpy(dst, src->iov_base, src->iov_len); |
208 | 0 | dst += src->iov_len; |
209 | 0 | src++; |
210 | 0 | } |
211 | | |
212 | | /* Return the result string */ |
213 | 0 | *dst = '\0'; |
214 | |
|
215 | 0 | return res; |
216 | 0 | } |
217 | | |
218 | | #if defined(HAVE_WEAK_SYMBOLS) |
219 | | void apr__memzero_explicit(void *buffer, apr_size_t size); |
220 | | |
221 | | __attribute__ ((weak)) |
222 | | void apr__memzero_explicit(void *buffer, apr_size_t size) |
223 | 0 | { |
224 | 0 | memset(buffer, 0, size); |
225 | 0 | } |
226 | | #endif |
227 | | |
228 | | APR_DECLARE(apr_status_t) apr_memzero_explicit(void *buffer, apr_size_t size) |
229 | 0 | { |
230 | | #if defined(WIN32) |
231 | | SecureZeroMemory(buffer, size); |
232 | | #elif defined(HAVE_EXPLICIT_BZERO) |
233 | | explicit_bzero(buffer, size); |
234 | | #elif defined(HAVE_MEMSET_S) |
235 | | if (size) { |
236 | | return memset_s(buffer, (rsize_t)size, 0, (rsize_t)size); |
237 | | } |
238 | | #elif defined(HAVE_WEAK_SYMBOLS) |
239 | | apr__memzero_explicit(buffer, size); |
240 | | #else |
241 | | apr_size_t i; |
242 | | volatile unsigned char *volatile ptr = buffer; |
243 | | for (i = 0; i < size; ++i) { |
244 | | ptr[i] = 0; |
245 | | } |
246 | | #endif |
247 | 0 | return APR_SUCCESS; |
248 | 0 | } |
249 | | |
250 | | /* A volatile variable which is always zero but allows to block the compiler |
251 | | * from optimizing or eliding code using it. Volatile forces the compiler to |
252 | | * emit a memory load for which no value can be assumed, so for instance an |
253 | | * add/sub/xor/or with "optblocker" is a noop that will hide the result to |
254 | | * the optimizer. |
255 | | */ |
256 | | static volatile const apr_uint32_t optblocker; |
257 | | |
258 | | /* Return whether x is not zero, with no branching controlled by x. |
259 | | * |
260 | | * Taken from the cryptoint library (public domain) by D. J. Bernstein, |
261 | | * which provides timing attacks safe integer operations/primitives. |
262 | | * Code: |
263 | | * https://lib.mceliece.org/libmceliece-20250507/cryptoint/crypto_uint32.h |
264 | | * Paper: |
265 | | * https://cr.yp.to/papers/cryptoint-20250424.pdf |
266 | | */ |
267 | | #if __has_attribute(always_inline) |
268 | | __attribute__((always_inline)) |
269 | | #endif |
270 | | static APR_INLINE int test_nonzero_timingsafe(apr_uint32_t x) |
271 | 0 | { |
272 | 0 | x |= -x; /* sets the most significant bit unless x == 0 */ |
273 | | |
274 | | /* shift bit 31 (MSB) to bit 0 */ |
275 | 0 | x >>= 32-6; /* keep 6 bits */ |
276 | 0 | x += optblocker; /* lose the optimizer */ |
277 | 0 | x >>= 5; /* keep the (original) MSB only */ |
278 | | |
279 | | /* x is now 0 or 1 */ |
280 | 0 | return x & INT_MAX; |
281 | 0 | } |
282 | | |
283 | | APR_DECLARE(int) apr_memeq_timingsafe(const void *buf1, const void *buf2, |
284 | | apr_size_t n) |
285 | 0 | { |
286 | 0 | apr_uint32_t diff = 0; |
287 | 0 | volatile apr_size_t count = n; /* prevent loop unrolling */ |
288 | 0 | apr_size_t i = 0; |
289 | |
|
290 | 0 | for (; i < count; ++i) { |
291 | 0 | const unsigned char c1 = ((volatile const unsigned char *)buf1)[i]; |
292 | 0 | const unsigned char c2 = ((volatile const unsigned char *)buf2)[i]; |
293 | |
|
294 | 0 | diff |= c1 ^ c2; /* sets diff to non-zero whenever c1 != c2 */ |
295 | 0 | } |
296 | | |
297 | | /* (diff == 0) <=> (diff != 0) ^ 1 */ |
298 | 0 | return test_nonzero_timingsafe(diff) ^ 1; |
299 | 0 | } |
300 | | |
301 | | APR_DECLARE(int) apr_streq_timingsafe(const char *sec1, const char *str2) |
302 | 0 | { |
303 | 0 | apr_uint32_t diff = 0; |
304 | 0 | apr_size_t i1 = 0, i2 = 0; |
305 | |
|
306 | 0 | for (;; ++i2) { |
307 | 0 | const unsigned char c1 = ((volatile const unsigned char *)sec1)[i1]; |
308 | 0 | const unsigned char c2 = ((volatile const unsigned char *)str2)[i2]; |
309 | |
|
310 | 0 | diff |= c1 ^ c2; /* sets diff to non-zero whenever c1 != c2 */ |
311 | | |
312 | | /* Not a shortest/longest match because an attacker would usually know |
313 | | * one of the strings and could then determine the length of the other. |
314 | | * So assume only sec1 and its length are secret and stop the loop at |
315 | | * the end of str2. If sec1 is shorter than str2 the loop will continue |
316 | | * by comparing the rest of str2 with the trailing NUL byte of sec1. |
317 | | * In any case since the diff above is computed up to and including a |
318 | | * NUL byte, only the same content and length will raise match. |
319 | | */ |
320 | 0 | if (!c2) { |
321 | 0 | break; |
322 | 0 | } |
323 | | |
324 | | /* Don't go above sec1's NUL byte */ |
325 | 0 | i1 += test_nonzero_timingsafe(c1); |
326 | 0 | } |
327 | | |
328 | | /* (diff == 0) <=> (diff != 0) ^ 1 */ |
329 | 0 | return test_nonzero_timingsafe(diff) ^ 1; |
330 | 0 | } |
331 | | |
332 | | APR_DECLARE(int) apr_strneq_timingsafe(const char *sec1, const char *str2, |
333 | | apr_size_t n) |
334 | 0 | { |
335 | 0 | apr_uint32_t diff = 0; |
336 | 0 | volatile apr_size_t count = n; /* prevent loop unrolling */ |
337 | 0 | apr_size_t i1 = 0, i2 = 0; |
338 | |
|
339 | 0 | for (; i2 < count; ++i2) { |
340 | 0 | const unsigned char c1 = ((volatile const unsigned char *)sec1)[i1]; |
341 | 0 | const unsigned char c2 = ((volatile const unsigned char *)str2)[i2]; |
342 | |
|
343 | 0 | diff |= c1 ^ c2; /* sets diff to non-zero whenever c1 != c2 */ |
344 | | |
345 | | /* Not a shortest/longest match because an attacker would usually know |
346 | | * one of the strings and could then determine the length of the other. |
347 | | * So assume only sec1 and its length are secret and stop the loop at |
348 | | * the end of str2. If sec1 is shorter than str2 the loop will continue |
349 | | * by comparing the rest of str2 with the trailing NUL byte of sec1. |
350 | | * In any case since the diff above is computed up to and including a |
351 | | * NUL byte, only the same content and length will raise match. |
352 | | */ |
353 | 0 | if (!c2) { |
354 | 0 | break; |
355 | 0 | } |
356 | | |
357 | | /* Don't go above sec1's NUL byte */ |
358 | 0 | i1 += test_nonzero_timingsafe(c1); |
359 | 0 | } |
360 | | |
361 | | /* (diff == 0) <=> (diff != 0) ^ 1 */ |
362 | 0 | return test_nonzero_timingsafe(diff) ^ 1; |
363 | 0 | } |
364 | | |
365 | | #if (!APR_HAVE_MEMCHR) |
366 | | void *memchr(const void *s, int c, size_t n) |
367 | | { |
368 | | const char *cp; |
369 | | |
370 | | for (cp = s; n > 0; n--, cp++) { |
371 | | if (*cp == c) |
372 | | return (char *) cp; /* Casting away the const here */ |
373 | | } |
374 | | |
375 | | return NULL; |
376 | | } |
377 | | #endif |
378 | | |
379 | | #ifndef INT64_MAX |
380 | | #define INT64_MAX APR_INT64_C(0x7fffffffffffffff) |
381 | | #endif |
382 | | #ifndef INT64_MIN |
383 | | #define INT64_MIN (-APR_INT64_C(0x7fffffffffffffff) - APR_INT64_C(1)) |
384 | | #endif |
385 | | |
386 | | APR_DECLARE(apr_status_t) apr_strtoff(apr_off_t *offset, const char *nptr, |
387 | | char **endptr, int base) |
388 | 0 | { |
389 | 0 | errno = 0; |
390 | 0 | *offset = APR_OFF_T_STRFN(nptr, endptr, base); |
391 | 0 | return APR_FROM_OS_ERROR(errno); |
392 | 0 | } |
393 | | |
394 | | APR_DECLARE(apr_int64_t) apr_strtoi64(const char *nptr, char **endptr, int base) |
395 | 1.25k | { |
396 | 1.25k | #ifdef APR_INT64_STRFN |
397 | 1.25k | errno = 0; |
398 | 1.25k | return APR_INT64_STRFN(nptr, endptr, base); |
399 | | #else |
400 | | const char *s; |
401 | | apr_int64_t acc; |
402 | | apr_int64_t val; |
403 | | int neg, any; |
404 | | char c; |
405 | | |
406 | | errno = 0; |
407 | | /* |
408 | | * Skip white space and pick up leading +/- sign if any. |
409 | | * If base is 0, allow 0x for hex and 0 for octal, else |
410 | | * assume decimal; if base is already 16, allow 0x. |
411 | | */ |
412 | | s = nptr; |
413 | | do { |
414 | | c = *s++; |
415 | | } while (apr_isspace(c)); |
416 | | if (c == '-') { |
417 | | neg = 1; |
418 | | c = *s++; |
419 | | } else { |
420 | | neg = 0; |
421 | | if (c == '+') |
422 | | c = *s++; |
423 | | } |
424 | | if ((base == 0 || base == 16) && |
425 | | c == '0' && (*s == 'x' || *s == 'X')) { |
426 | | c = s[1]; |
427 | | s += 2; |
428 | | base = 16; |
429 | | } |
430 | | if (base == 0) |
431 | | base = c == '0' ? 8 : 10; |
432 | | acc = any = 0; |
433 | | if (base < 2 || base > 36) { |
434 | | errno = EINVAL; |
435 | | if (endptr != NULL) |
436 | | *endptr = (char *)(any ? s - 1 : nptr); |
437 | | return acc; |
438 | | } |
439 | | |
440 | | /* The classic bsd implementation requires div/mod operators |
441 | | * to compute a cutoff. Benchmarking proves that is very, very |
442 | | * evil to some 32 bit processors. Instead, look for underflow |
443 | | * in both the mult and add/sub operation. Unlike the bsd impl, |
444 | | * we also work strictly in a signed int64 word as we haven't |
445 | | * implemented the unsigned type in win32. |
446 | | * |
447 | | * Set 'any' if any `digits' consumed; make it negative to indicate |
448 | | * overflow. |
449 | | */ |
450 | | val = 0; |
451 | | for ( ; ; c = *s++) { |
452 | | if (c >= '0' && c <= '9') |
453 | | c -= '0'; |
454 | | #if (('Z' - 'A') == 25) |
455 | | else if (c >= 'A' && c <= 'Z') |
456 | | c -= 'A' - 10; |
457 | | else if (c >= 'a' && c <= 'z') |
458 | | c -= 'a' - 10; |
459 | | #elif APR_CHARSET_EBCDIC |
460 | | else if (c >= 'A' && c <= 'I') |
461 | | c -= 'A' - 10; |
462 | | else if (c >= 'J' && c <= 'R') |
463 | | c -= 'J' - 19; |
464 | | else if (c >= 'S' && c <= 'Z') |
465 | | c -= 'S' - 28; |
466 | | else if (c >= 'a' && c <= 'i') |
467 | | c -= 'a' - 10; |
468 | | else if (c >= 'j' && c <= 'r') |
469 | | c -= 'j' - 19; |
470 | | else if (c >= 's' && c <= 'z') |
471 | | c -= 'z' - 28; |
472 | | #else |
473 | | #error "CANNOT COMPILE apr_strtoi64(), only ASCII and EBCDIC supported" |
474 | | #endif |
475 | | else |
476 | | break; |
477 | | if (c >= base) |
478 | | break; |
479 | | val *= base; |
480 | | if ( (any < 0) /* already noted an over/under flow - short circuit */ |
481 | | || (neg && (val > acc || (val -= c) > acc)) /* underflow */ |
482 | | || (!neg && (val < acc || (val += c) < acc))) { /* overflow */ |
483 | | any = -1; /* once noted, over/underflows never go away */ |
484 | | #ifdef APR_STRTOI64_OVERFLOW_IS_BAD_CHAR |
485 | | break; |
486 | | #endif |
487 | | } else { |
488 | | acc = val; |
489 | | any = 1; |
490 | | } |
491 | | } |
492 | | |
493 | | if (any < 0) { |
494 | | acc = neg ? INT64_MIN : INT64_MAX; |
495 | | errno = ERANGE; |
496 | | } else if (!any) { |
497 | | errno = EINVAL; |
498 | | } |
499 | | if (endptr != NULL) |
500 | | *endptr = (char *)(any ? s - 1 : nptr); |
501 | | return (acc); |
502 | | #endif |
503 | 1.25k | } |
504 | | |
505 | | APR_DECLARE(apr_int64_t) apr_atoi64(const char *buf) |
506 | 0 | { |
507 | 0 | return apr_strtoi64(buf, NULL, 10); |
508 | 0 | } |
509 | | |
510 | | APR_DECLARE(char *) apr_itoa(apr_pool_t *p, int n) |
511 | 0 | { |
512 | 0 | const int BUFFER_SIZE = sizeof(int) * 3 + 2; |
513 | 0 | char *buf = apr_palloc(p, BUFFER_SIZE); |
514 | 0 | char *start = buf + BUFFER_SIZE - 1; |
515 | 0 | unsigned int un; |
516 | 0 | int negative; |
517 | 0 | if (n < 0) { |
518 | 0 | negative = 1; |
519 | 0 | un = -n; |
520 | 0 | } |
521 | 0 | else { |
522 | 0 | negative = 0; |
523 | 0 | un = n; |
524 | 0 | } |
525 | 0 | *start = 0; |
526 | 0 | do { |
527 | 0 | *--start = '0' + (un % 10); |
528 | 0 | un /= 10; |
529 | 0 | } while (un); |
530 | 0 | if (negative) { |
531 | 0 | *--start = '-'; |
532 | 0 | } |
533 | 0 | return start; |
534 | 0 | } |
535 | | |
536 | | APR_DECLARE(char *) apr_ltoa(apr_pool_t *p, long n) |
537 | 0 | { |
538 | 0 | const int BUFFER_SIZE = sizeof(long) * 3 + 2; |
539 | 0 | char *buf = apr_palloc(p, BUFFER_SIZE); |
540 | 0 | char *start = buf + BUFFER_SIZE - 1; |
541 | 0 | int negative; |
542 | 0 | unsigned int un; |
543 | 0 | if (n < 0) { |
544 | 0 | negative = 1; |
545 | 0 | un = -n; |
546 | 0 | } |
547 | 0 | else { |
548 | 0 | negative = 0; |
549 | 0 | un = n; |
550 | 0 | } |
551 | 0 | *start = 0; |
552 | 0 | do { |
553 | 0 | *--start = (char)('0' + (un % 10)); |
554 | 0 | un /= 10; |
555 | 0 | } while (un); |
556 | 0 | if (negative) { |
557 | 0 | *--start = '-'; |
558 | 0 | } |
559 | 0 | return start; |
560 | 0 | } |
561 | | |
562 | | APR_DECLARE(char *) apr_off_t_toa(apr_pool_t *p, apr_off_t n) |
563 | 0 | { |
564 | 0 | const int BUFFER_SIZE = sizeof(apr_off_t) * 3 + 2; |
565 | 0 | char *buf = apr_palloc(p, BUFFER_SIZE); |
566 | 0 | char *start = buf + BUFFER_SIZE - 1; |
567 | 0 | int negative; |
568 | 0 | if (n < 0) { |
569 | 0 | negative = 1; |
570 | 0 | n = -n; |
571 | 0 | } |
572 | 0 | else { |
573 | 0 | negative = 0; |
574 | 0 | } |
575 | 0 | *start = 0; |
576 | 0 | do { |
577 | 0 | *--start = '0' + (char)(n % 10); |
578 | 0 | n /= 10; |
579 | 0 | } while (n); |
580 | 0 | if (negative) { |
581 | 0 | *--start = '-'; |
582 | 0 | } |
583 | 0 | return start; |
584 | 0 | } |
585 | | |
586 | | APR_DECLARE(char *) apr_strfsize(apr_off_t size, char *buf) |
587 | 0 | { |
588 | 0 | const char ord[] = "KMGTPE"; |
589 | 0 | const char *o = ord; |
590 | 0 | int remain; |
591 | |
|
592 | 0 | if (size < 0) { |
593 | 0 | return strcpy(buf, " - "); |
594 | 0 | } |
595 | 0 | if (size < 973) { |
596 | 0 | if (apr_snprintf(buf, 5, "%3d ", (int) size) < 0) |
597 | 0 | return strcpy(buf, "****"); |
598 | 0 | return buf; |
599 | 0 | } |
600 | 0 | do { |
601 | 0 | remain = (int)(size & 1023); |
602 | 0 | size >>= 10; |
603 | 0 | if (size >= 973) { |
604 | 0 | ++o; |
605 | 0 | continue; |
606 | 0 | } |
607 | 0 | if (size < 9 || (size == 9 && remain < 973)) { |
608 | 0 | if ((remain = ((remain * 5) + 256) / 512) >= 10) |
609 | 0 | ++size, remain = 0; |
610 | 0 | if (apr_snprintf(buf, 5, "%d.%d%c", (int) size, remain, *o) < 0) |
611 | 0 | return strcpy(buf, "****"); |
612 | 0 | return buf; |
613 | 0 | } |
614 | 0 | if (remain >= 512) |
615 | 0 | ++size; |
616 | 0 | if (apr_snprintf(buf, 5, "%3d%c", (int) size, *o) < 0) |
617 | 0 | return strcpy(buf, "****"); |
618 | 0 | return buf; |
619 | 0 | } while (1); |
620 | 0 | } |
621 | | |