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