1251875Speter/* Licensed to the Apache Software Foundation (ASF) under one or more 2251875Speter * contributor license agreements. See the NOTICE file distributed with 3251875Speter * this work for additional information regarding copyright ownership. 4251875Speter * The ASF licenses this file to You under the Apache License, Version 2.0 5251875Speter * (the "License"); you may not use this file except in compliance with 6251875Speter * the License. You may obtain a copy of the License at 7251875Speter * 8251875Speter * http://www.apache.org/licenses/LICENSE-2.0 9251875Speter * 10251875Speter * Unless required by applicable law or agreed to in writing, software 11251875Speter * distributed under the License is distributed on an "AS IS" BASIS, 12251875Speter * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13251875Speter * See the License for the specific language governing permissions and 14251875Speter * limitations under the License. 15251875Speter */ 16251875Speter/* 17251875Speter * Copyright (c) 1990, 1993 18251875Speter * The Regents of the University of California. All rights reserved. 19251875Speter * 20251875Speter * Redistribution and use in source and binary forms, with or without 21251875Speter * modification, are permitted provided that the following conditions 22251875Speter * are met: 23251875Speter * 1. Redistributions of source code must retain the above copyright 24251875Speter * notice, this list of conditions and the following disclaimer. 25251875Speter * 2. Redistributions in binary form must reproduce the above copyright 26251875Speter * notice, this list of conditions and the following disclaimer in the 27251875Speter * documentation and/or other materials provided with the distribution. 28251875Speter * 3. All advertising materials mentioning features or use of this software 29251875Speter * must display the following acknowledgement: 30251875Speter * This product includes software developed by the University of 31251875Speter * California, Berkeley and its contributors. 32251875Speter * 4. Neither the name of the University nor the names of its contributors 33251875Speter * may be used to endorse or promote products derived from this software 34251875Speter * without specific prior written permission. 35251875Speter * 36251875Speter * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 37251875Speter * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 38251875Speter * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 39251875Speter * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 40251875Speter * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 41251875Speter * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 42251875Speter * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 43251875Speter * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 44251875Speter * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 45251875Speter * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 46251875Speter * SUCH DAMAGE. 47251875Speter */ 48251875Speter 49251875Speter#include "apr.h" 50251875Speter#include "apr_strings.h" 51251875Speter#include "apr_general.h" 52251875Speter#include "apr_private.h" 53251875Speter#include "apr_lib.h" 54251875Speter#define APR_WANT_STDIO 55251875Speter#define APR_WANT_STRFUNC 56251875Speter#include "apr_want.h" 57251875Speter 58251875Speter#ifdef HAVE_STDDEF_H 59251875Speter#include <stddef.h> /* NULL */ 60251875Speter#endif 61251875Speter 62251875Speter#ifdef HAVE_STDLIB_H 63251875Speter#include <stdlib.h> /* strtol and strtoll */ 64251875Speter#endif 65251875Speter 66251875Speter/** this is used to cache lengths in apr_pstrcat */ 67251875Speter#define MAX_SAVED_LENGTHS 6 68251875Speter 69251875SpeterAPR_DECLARE(char *) apr_pstrdup(apr_pool_t *a, const char *s) 70251875Speter{ 71251875Speter char *res; 72251875Speter apr_size_t len; 73251875Speter 74251875Speter if (s == NULL) { 75251875Speter return NULL; 76251875Speter } 77251875Speter len = strlen(s) + 1; 78269847Speter res = apr_pmemdup(a, s, len); 79251875Speter return res; 80251875Speter} 81251875Speter 82251875SpeterAPR_DECLARE(char *) apr_pstrndup(apr_pool_t *a, const char *s, apr_size_t n) 83251875Speter{ 84251875Speter char *res; 85251875Speter const char *end; 86251875Speter 87251875Speter if (s == NULL) { 88251875Speter return NULL; 89251875Speter } 90251875Speter end = memchr(s, '\0', n); 91251875Speter if (end != NULL) 92251875Speter n = end - s; 93251875Speter res = apr_palloc(a, n + 1); 94251875Speter memcpy(res, s, n); 95251875Speter res[n] = '\0'; 96251875Speter return res; 97251875Speter} 98251875Speter 99251875SpeterAPR_DECLARE(char *) apr_pstrmemdup(apr_pool_t *a, const char *s, apr_size_t n) 100251875Speter{ 101251875Speter char *res; 102251875Speter 103251875Speter if (s == NULL) { 104251875Speter return NULL; 105251875Speter } 106251875Speter res = apr_palloc(a, n + 1); 107251875Speter memcpy(res, s, n); 108251875Speter res[n] = '\0'; 109251875Speter return res; 110251875Speter} 111251875Speter 112251875SpeterAPR_DECLARE(void *) apr_pmemdup(apr_pool_t *a, const void *m, apr_size_t n) 113251875Speter{ 114251875Speter void *res; 115251875Speter 116251875Speter if (m == NULL) 117251875Speter return NULL; 118251875Speter res = apr_palloc(a, n); 119251875Speter memcpy(res, m, n); 120251875Speter return res; 121251875Speter} 122251875Speter 123251875SpeterAPR_DECLARE_NONSTD(char *) apr_pstrcat(apr_pool_t *a, ...) 124251875Speter{ 125251875Speter char *cp, *argp, *res; 126251875Speter apr_size_t saved_lengths[MAX_SAVED_LENGTHS]; 127251875Speter int nargs = 0; 128251875Speter 129251875Speter /* Pass one --- find length of required string */ 130251875Speter 131251875Speter apr_size_t len = 0; 132251875Speter va_list adummy; 133251875Speter 134251875Speter va_start(adummy, a); 135251875Speter 136251875Speter while ((cp = va_arg(adummy, char *)) != NULL) { 137251875Speter apr_size_t cplen = strlen(cp); 138251875Speter if (nargs < MAX_SAVED_LENGTHS) { 139251875Speter saved_lengths[nargs++] = cplen; 140251875Speter } 141251875Speter len += cplen; 142251875Speter } 143251875Speter 144251875Speter va_end(adummy); 145251875Speter 146251875Speter /* Allocate the required string */ 147251875Speter 148251875Speter res = (char *) apr_palloc(a, len + 1); 149251875Speter cp = res; 150251875Speter 151251875Speter /* Pass two --- copy the argument strings into the result space */ 152251875Speter 153251875Speter va_start(adummy, a); 154251875Speter 155251875Speter nargs = 0; 156251875Speter while ((argp = va_arg(adummy, char *)) != NULL) { 157251875Speter if (nargs < MAX_SAVED_LENGTHS) { 158251875Speter len = saved_lengths[nargs++]; 159251875Speter } 160251875Speter else { 161251875Speter len = strlen(argp); 162251875Speter } 163251875Speter 164251875Speter memcpy(cp, argp, len); 165251875Speter cp += len; 166251875Speter } 167251875Speter 168251875Speter va_end(adummy); 169251875Speter 170251875Speter /* Return the result string */ 171251875Speter 172251875Speter *cp = '\0'; 173251875Speter 174251875Speter return res; 175251875Speter} 176251875Speter 177251875SpeterAPR_DECLARE(char *) apr_pstrcatv(apr_pool_t *a, const struct iovec *vec, 178251875Speter apr_size_t nvec, apr_size_t *nbytes) 179251875Speter{ 180251875Speter apr_size_t i; 181251875Speter apr_size_t len; 182251875Speter const struct iovec *src; 183251875Speter char *res; 184251875Speter char *dst; 185251875Speter 186251875Speter /* Pass one --- find length of required string */ 187251875Speter len = 0; 188251875Speter src = vec; 189251875Speter for (i = nvec; i; i--) { 190251875Speter len += src->iov_len; 191251875Speter src++; 192251875Speter } 193251875Speter if (nbytes) { 194251875Speter *nbytes = len; 195251875Speter } 196251875Speter 197251875Speter /* Allocate the required string */ 198251875Speter res = (char *) apr_palloc(a, len + 1); 199251875Speter 200251875Speter /* Pass two --- copy the argument strings into the result space */ 201251875Speter src = vec; 202251875Speter dst = res; 203251875Speter for (i = nvec; i; i--) { 204251875Speter memcpy(dst, src->iov_base, src->iov_len); 205251875Speter dst += src->iov_len; 206251875Speter src++; 207251875Speter } 208251875Speter 209251875Speter /* Return the result string */ 210251875Speter *dst = '\0'; 211251875Speter 212251875Speter return res; 213251875Speter} 214251875Speter 215251875Speter#if (!APR_HAVE_MEMCHR) 216251875Spetervoid *memchr(const void *s, int c, size_t n) 217251875Speter{ 218251875Speter const char *cp; 219251875Speter 220251875Speter for (cp = s; n > 0; n--, cp++) { 221251875Speter if (*cp == c) 222251875Speter return (char *) cp; /* Casting away the const here */ 223251875Speter } 224251875Speter 225251875Speter return NULL; 226251875Speter} 227251875Speter#endif 228251875Speter 229251875Speter#ifndef INT64_MAX 230251875Speter#define INT64_MAX APR_INT64_C(0x7fffffffffffffff) 231251875Speter#endif 232251875Speter#ifndef INT64_MIN 233251875Speter#define INT64_MIN (-APR_INT64_C(0x7fffffffffffffff) - APR_INT64_C(1)) 234251875Speter#endif 235251875Speter 236251875SpeterAPR_DECLARE(apr_status_t) apr_strtoff(apr_off_t *offset, const char *nptr, 237251875Speter char **endptr, int base) 238251875Speter{ 239251875Speter errno = 0; 240251875Speter *offset = APR_OFF_T_STRFN(nptr, endptr, base); 241251875Speter return APR_FROM_OS_ERROR(errno); 242251875Speter} 243251875Speter 244251875SpeterAPR_DECLARE(apr_int64_t) apr_strtoi64(const char *nptr, char **endptr, int base) 245251875Speter{ 246251875Speter#ifdef APR_INT64_STRFN 247251875Speter errno = 0; 248251875Speter return APR_INT64_STRFN(nptr, endptr, base); 249251875Speter#else 250251875Speter const char *s; 251251875Speter apr_int64_t acc; 252251875Speter apr_int64_t val; 253251875Speter int neg, any; 254251875Speter char c; 255251875Speter 256251875Speter errno = 0; 257251875Speter /* 258251875Speter * Skip white space and pick up leading +/- sign if any. 259251875Speter * If base is 0, allow 0x for hex and 0 for octal, else 260251875Speter * assume decimal; if base is already 16, allow 0x. 261251875Speter */ 262251875Speter s = nptr; 263251875Speter do { 264251875Speter c = *s++; 265251875Speter } while (apr_isspace(c)); 266251875Speter if (c == '-') { 267251875Speter neg = 1; 268251875Speter c = *s++; 269251875Speter } else { 270251875Speter neg = 0; 271251875Speter if (c == '+') 272251875Speter c = *s++; 273251875Speter } 274251875Speter if ((base == 0 || base == 16) && 275251875Speter c == '0' && (*s == 'x' || *s == 'X')) { 276251875Speter c = s[1]; 277251875Speter s += 2; 278251875Speter base = 16; 279251875Speter } 280251875Speter if (base == 0) 281251875Speter base = c == '0' ? 8 : 10; 282251875Speter acc = any = 0; 283251875Speter if (base < 2 || base > 36) { 284251875Speter errno = EINVAL; 285251875Speter if (endptr != NULL) 286251875Speter *endptr = (char *)(any ? s - 1 : nptr); 287251875Speter return acc; 288251875Speter } 289251875Speter 290251875Speter /* The classic bsd implementation requires div/mod operators 291251875Speter * to compute a cutoff. Benchmarking proves that is very, very 292251875Speter * evil to some 32 bit processors. Instead, look for underflow 293251875Speter * in both the mult and add/sub operation. Unlike the bsd impl, 294251875Speter * we also work strictly in a signed int64 word as we haven't 295251875Speter * implemented the unsigned type in win32. 296251875Speter * 297251875Speter * Set 'any' if any `digits' consumed; make it negative to indicate 298251875Speter * overflow. 299251875Speter */ 300251875Speter val = 0; 301251875Speter for ( ; ; c = *s++) { 302251875Speter if (c >= '0' && c <= '9') 303251875Speter c -= '0'; 304251875Speter#if (('Z' - 'A') == 25) 305251875Speter else if (c >= 'A' && c <= 'Z') 306251875Speter c -= 'A' - 10; 307251875Speter else if (c >= 'a' && c <= 'z') 308251875Speter c -= 'a' - 10; 309251875Speter#elif APR_CHARSET_EBCDIC 310251875Speter else if (c >= 'A' && c <= 'I') 311251875Speter c -= 'A' - 10; 312251875Speter else if (c >= 'J' && c <= 'R') 313251875Speter c -= 'J' - 19; 314251875Speter else if (c >= 'S' && c <= 'Z') 315251875Speter c -= 'S' - 28; 316251875Speter else if (c >= 'a' && c <= 'i') 317251875Speter c -= 'a' - 10; 318251875Speter else if (c >= 'j' && c <= 'r') 319251875Speter c -= 'j' - 19; 320251875Speter else if (c >= 's' && c <= 'z') 321251875Speter c -= 'z' - 28; 322251875Speter#else 323251875Speter#error "CANNOT COMPILE apr_strtoi64(), only ASCII and EBCDIC supported" 324251875Speter#endif 325251875Speter else 326251875Speter break; 327251875Speter if (c >= base) 328251875Speter break; 329251875Speter val *= base; 330251875Speter if ( (any < 0) /* already noted an over/under flow - short circuit */ 331251875Speter || (neg && (val > acc || (val -= c) > acc)) /* underflow */ 332251875Speter || (!neg && (val < acc || (val += c) < acc))) { /* overflow */ 333251875Speter any = -1; /* once noted, over/underflows never go away */ 334251875Speter#ifdef APR_STRTOI64_OVERFLOW_IS_BAD_CHAR 335251875Speter break; 336251875Speter#endif 337251875Speter } else { 338251875Speter acc = val; 339251875Speter any = 1; 340251875Speter } 341251875Speter } 342251875Speter 343251875Speter if (any < 0) { 344251875Speter acc = neg ? INT64_MIN : INT64_MAX; 345251875Speter errno = ERANGE; 346251875Speter } else if (!any) { 347251875Speter errno = EINVAL; 348251875Speter } 349251875Speter if (endptr != NULL) 350251875Speter *endptr = (char *)(any ? s - 1 : nptr); 351251875Speter return (acc); 352251875Speter#endif 353251875Speter} 354251875Speter 355251875SpeterAPR_DECLARE(apr_int64_t) apr_atoi64(const char *buf) 356251875Speter{ 357251875Speter return apr_strtoi64(buf, NULL, 10); 358251875Speter} 359251875Speter 360251875SpeterAPR_DECLARE(char *) apr_itoa(apr_pool_t *p, int n) 361251875Speter{ 362251875Speter const int BUFFER_SIZE = sizeof(int) * 3 + 2; 363251875Speter char *buf = apr_palloc(p, BUFFER_SIZE); 364251875Speter char *start = buf + BUFFER_SIZE - 1; 365251875Speter int negative; 366251875Speter if (n < 0) { 367251875Speter negative = 1; 368251875Speter n = -n; 369251875Speter } 370251875Speter else { 371251875Speter negative = 0; 372251875Speter } 373251875Speter *start = 0; 374251875Speter do { 375251875Speter *--start = '0' + (n % 10); 376251875Speter n /= 10; 377251875Speter } while (n); 378251875Speter if (negative) { 379251875Speter *--start = '-'; 380251875Speter } 381251875Speter return start; 382251875Speter} 383251875Speter 384251875SpeterAPR_DECLARE(char *) apr_ltoa(apr_pool_t *p, long n) 385251875Speter{ 386251875Speter const int BUFFER_SIZE = sizeof(long) * 3 + 2; 387251875Speter char *buf = apr_palloc(p, BUFFER_SIZE); 388251875Speter char *start = buf + BUFFER_SIZE - 1; 389251875Speter int negative; 390251875Speter if (n < 0) { 391251875Speter negative = 1; 392251875Speter n = -n; 393251875Speter } 394251875Speter else { 395251875Speter negative = 0; 396251875Speter } 397251875Speter *start = 0; 398251875Speter do { 399251875Speter *--start = (char)('0' + (n % 10)); 400251875Speter n /= 10; 401251875Speter } while (n); 402251875Speter if (negative) { 403251875Speter *--start = '-'; 404251875Speter } 405251875Speter return start; 406251875Speter} 407251875Speter 408251875SpeterAPR_DECLARE(char *) apr_off_t_toa(apr_pool_t *p, apr_off_t n) 409251875Speter{ 410251875Speter const int BUFFER_SIZE = sizeof(apr_off_t) * 3 + 2; 411251875Speter char *buf = apr_palloc(p, BUFFER_SIZE); 412251875Speter char *start = buf + BUFFER_SIZE - 1; 413251875Speter int negative; 414251875Speter if (n < 0) { 415251875Speter negative = 1; 416251875Speter n = -n; 417251875Speter } 418251875Speter else { 419251875Speter negative = 0; 420251875Speter } 421251875Speter *start = 0; 422251875Speter do { 423251875Speter *--start = '0' + (char)(n % 10); 424251875Speter n /= 10; 425251875Speter } while (n); 426251875Speter if (negative) { 427251875Speter *--start = '-'; 428251875Speter } 429251875Speter return start; 430251875Speter} 431251875Speter 432251875SpeterAPR_DECLARE(char *) apr_strfsize(apr_off_t size, char *buf) 433251875Speter{ 434251875Speter const char ord[] = "KMGTPE"; 435251875Speter const char *o = ord; 436251875Speter int remain; 437251875Speter 438251875Speter if (size < 0) { 439251875Speter return strcpy(buf, " - "); 440251875Speter } 441251875Speter if (size < 973) { 442251875Speter if (apr_snprintf(buf, 5, "%3d ", (int) size) < 0) 443251875Speter return strcpy(buf, "****"); 444251875Speter return buf; 445251875Speter } 446251875Speter do { 447251875Speter remain = (int)(size & 1023); 448251875Speter size >>= 10; 449251875Speter if (size >= 973) { 450251875Speter ++o; 451251875Speter continue; 452251875Speter } 453251875Speter if (size < 9 || (size == 9 && remain < 973)) { 454251875Speter if ((remain = ((remain * 5) + 256) / 512) >= 10) 455251875Speter ++size, remain = 0; 456251875Speter if (apr_snprintf(buf, 5, "%d.%d%c", (int) size, remain, *o) < 0) 457251875Speter return strcpy(buf, "****"); 458251875Speter return buf; 459251875Speter } 460251875Speter if (remain >= 512) 461251875Speter ++size; 462251875Speter if (apr_snprintf(buf, 5, "%3d%c", (int) size, *o) < 0) 463251875Speter return strcpy(buf, "****"); 464251875Speter return buf; 465251875Speter } while (1); 466251875Speter} 467251875Speter 468