18232165peter/* Licensed to the Apache Software Foundation (ASF) under one or more
28232165peter * contributor license agreements.  See the NOTICE file distributed with
38232165peter * this work for additional information regarding copyright ownership.
48232165peter * The ASF licenses this file to You under the Apache License, Version 2.0
58232165peter * (the "License"); you may not use this file except in compliance with
68232165peter * the License.  You may obtain a copy of the License at
78232165peter *
88232165peter *     http://www.apache.org/licenses/LICENSE-2.0
98232165peter *
108232165peter * Unless required by applicable law or agreed to in writing, software
118232165peter * distributed under the License is distributed on an "AS IS" BASIS,
128232165peter * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
138232165peter * See the License for the specific language governing permissions and
148232165peter * limitations under the License.
158232165peter */
168232165peter
178232165peter#include "apr.h"
188232165peter#include "apr_strings.h"
198232165peter#include "apr_private.h"
208232165peter#include "apr_lib.h"
218232165peter
228232165peter#if APR_HAVE_SYS_TYPES_H
238232165peter#include <sys/types.h>
248232165peter#endif
258232165peter#if APR_HAVE_STRING_H
268232165peter#include <string.h>
278232165peter#endif
288232165peter#if APR_HAVE_CTYPE_H
298232165peter#include <ctype.h>
308232165peter#endif
318232165peter
328232165peter/*
338232165peter * Apache's "replacement" for the strncpy() function. We roll our
348232165peter * own to implement these specific changes:
358232165peter *   (1) strncpy() doesn't always null terminate and we want it to.
368232165peter *   (2) strncpy() null fills, which is bogus, esp. when copy 8byte
378232165peter *       strings into 8k blocks.
388232165peter *   (3) Instead of returning the pointer to the beginning of
398232165peter *       the destination string, we return a pointer to the
408232165peter *       terminating '\0' to allow us to "check" for truncation
41ca02a2bpeter *   (4) If src is NULL, null terminate dst (empty string copy)
428232165peter *
438232165peter * apr_cpystrn() follows the same call structure as strncpy().
448232165peter */
458232165peter
468232165peterAPR_DECLARE(char *) apr_cpystrn(char *dst, const char *src, apr_size_t dst_size)
478232165peter{
488232165peter
49ca02a2bpeter    char *d = dst, *end;
508232165peter
518232165peter    if (dst_size == 0) {
528232165peter        return (dst);
538232165peter    }
548232165peter
55ca02a2bpeter    if (src) {
56ca02a2bpeter        end = dst + dst_size - 1;
578232165peter
58ca02a2bpeter        for (; d < end; ++d, ++src) {
59ca02a2bpeter            if (!(*d = *src)) {
60ca02a2bpeter                return (d);
61ca02a2bpeter            }
62ca02a2bpeter        }
638232165peter    }
648232165peter
658232165peter    *d = '\0';	/* always null terminate */
668232165peter
678232165peter    return (d);
688232165peter}
698232165peter
708232165peter
718232165peter/*
728232165peter * This function provides a way to parse a generic argument string
738232165peter * into a standard argv[] form of argument list. It respects the
748232165peter * usual "whitespace" and quoteing rules. In the future this could
758232165peter * be expanded to include support for the apr_call_exec command line
768232165peter * string processing (including converting '+' to ' ' and doing the
778232165peter * url processing. It does not currently support this function.
788232165peter *
798232165peter *    token_context: Context from which pool allocations will occur.
808232165peter *    arg_str:       Input argument string for conversion to argv[].
818232165peter *    argv_out:      Output location. This is a pointer to an array
828232165peter *                   of pointers to strings (ie. &(char *argv[]).
838232165peter *                   This value will be allocated from the contexts
848232165peter *                   pool and filled in with copies of the tokens
858232165peter *                   found during parsing of the arg_str.
868232165peter */
878232165peterAPR_DECLARE(apr_status_t) apr_tokenize_to_argv(const char *arg_str,
888232165peter                                            char ***argv_out,
898232165peter                                            apr_pool_t *token_context)
908232165peter{
918232165peter    const char *cp;
928232165peter    const char *ct;
938232165peter    char *cleaned, *dirty;
948232165peter    int escaped;
958232165peter    int isquoted, numargs = 0, argnum;
968232165peter
978232165peter#define SKIP_WHITESPACE(cp) \
988232165peter    for ( ; *cp == ' ' || *cp == '\t'; ) { \
998232165peter        cp++; \
1008232165peter    };
1018232165peter
1028232165peter#define CHECK_QUOTATION(cp,isquoted) \
1038232165peter    isquoted = 0; \
1048232165peter    if (*cp == '"') { \
1058232165peter        isquoted = 1; \
1068232165peter        cp++; \
1078232165peter    } \
1088232165peter    else if (*cp == '\'') { \
1098232165peter        isquoted = 2; \
1108232165peter        cp++; \
1118232165peter    }
1128232165peter
1138232165peter/* DETERMINE_NEXTSTRING:
1148232165peter * At exit, cp will point to one of the following:  NULL, SPACE, TAB or QUOTE.
1158232165peter * NULL implies the argument string has been fully traversed.
1168232165peter */
1178232165peter#define DETERMINE_NEXTSTRING(cp,isquoted) \
1188232165peter    for ( ; *cp != '\0'; cp++) { \
1198232165peter        if (   (*cp == '\\' && (*(cp+1) == ' ' || *(cp+1) == '\t' || \
1208232165peter                                *(cp+1) == '"' || *(cp+1) == '\''))) { \
1218232165peter            cp++; \
1228232165peter            continue; \
1238232165peter        } \
1248232165peter        if (   (!isquoted && (*cp == ' ' || *cp == '\t')) \
1258232165peter            || (isquoted == 1 && *cp == '"') \
1268232165peter            || (isquoted == 2 && *cp == '\'')                 ) { \
1278232165peter            break; \
1288232165peter        } \
1298232165peter    }
1308232165peter
1318232165peter/* REMOVE_ESCAPE_CHARS:
1328232165peter * Compresses the arg string to remove all of the '\' escape chars.
1338232165peter * The final argv strings should not have any extra escape chars in it.
1348232165peter */
1358232165peter#define REMOVE_ESCAPE_CHARS(cleaned, dirty, escaped) \
1368232165peter    escaped = 0; \
1378232165peter    while(*dirty) { \
1388232165peter        if (!escaped && *dirty == '\\') { \
1398232165peter            escaped = 1; \
1408232165peter        } \
1418232165peter        else { \
1428232165peter            escaped = 0; \
1438232165peter            *cleaned++ = *dirty; \
1448232165peter        } \
1458232165peter        ++dirty; \
1468232165peter    } \
1478232165peter    *cleaned = 0;        /* last line of macro... */
1488232165peter
1498232165peter    cp = arg_str;
1508232165peter    SKIP_WHITESPACE(cp);
1518232165peter    ct = cp;
1528232165peter
1538232165peter    /* This is ugly and expensive, but if anyone wants to figure a
1548232165peter     * way to support any number of args without counting and
1558232165peter     * allocating, please go ahead and change the code.
1568232165peter     *
1578232165peter     * Must account for the trailing NULL arg.
1588232165peter     */
1598232165peter    numargs = 1;
1608232165peter    while (*ct != '\0') {
1618232165peter        CHECK_QUOTATION(ct, isquoted);
1628232165peter        DETERMINE_NEXTSTRING(ct, isquoted);
1638232165peter        if (*ct != '\0') {
1648232165peter            ct++;
1658232165peter        }
1668232165peter        numargs++;
1678232165peter        SKIP_WHITESPACE(ct);
1688232165peter    }
1698232165peter    *argv_out = apr_palloc(token_context, numargs * sizeof(char*));
1708232165peter
1718232165peter    /*  determine first argument */
1728232165peter    for (argnum = 0; argnum < (numargs-1); argnum++) {
1738232165peter        SKIP_WHITESPACE(cp);
1748232165peter        CHECK_QUOTATION(cp, isquoted);
1758232165peter        ct = cp;
1768232165peter        DETERMINE_NEXTSTRING(cp, isquoted);
1778232165peter        cp++;
1788232165peter        (*argv_out)[argnum] = apr_palloc(token_context, cp - ct);
1798232165peter        apr_cpystrn((*argv_out)[argnum], ct, cp - ct);
1808232165peter        cleaned = dirty = (*argv_out)[argnum];
1818232165peter        REMOVE_ESCAPE_CHARS(cleaned, dirty, escaped);
1828232165peter    }
1838232165peter    (*argv_out)[argnum] = NULL;
1848232165peter
1858232165peter    return APR_SUCCESS;
1868232165peter}
1878232165peter
1888232165peter/* Filepath_name_get returns the final element of the pathname.
1898232165peter * Using the current platform's filename syntax.
1908232165peter *   "/foo/bar/gum" -> "gum"
1918232165peter *   "/foo/bar/gum/" -> ""
1928232165peter *   "gum" -> "gum"
1938232165peter *   "wi\\n32\\stuff" -> "stuff
1948232165peter *
1958232165peter * Corrected Win32 to accept "a/b\\stuff", "a:stuff"
1968232165peter */
1978232165peter
1988232165peterAPR_DECLARE(const char *) apr_filepath_name_get(const char *pathname)
1998232165peter{
2008232165peter    const char path_separator = '/';
2018232165peter    const char *s = strrchr(pathname, path_separator);
2028232165peter
2038232165peter#ifdef WIN32
2048232165peter    const char path_separator_win = '\\';
2058232165peter    const char drive_separator_win = ':';
2068232165peter    const char *s2 = strrchr(pathname, path_separator_win);
2078232165peter
2088232165peter    if (s2 > s) s = s2;
2098232165peter
2108232165peter    if (!s) s = strrchr(pathname, drive_separator_win);
2118232165peter#endif
2128232165peter
2138232165peter    return s ? ++s : pathname;
2148232165peter}
2158232165peter
2168232165peter/* length of dest assumed >= length of src
2178232165peter * collapse in place (src == dest) is legal.
2188232165peter * returns terminating null ptr to dest string.
2198232165peter */
2208232165peterAPR_DECLARE(char *) apr_collapse_spaces(char *dest, const char *src)
2218232165peter{
2228232165peter    while (*src) {
2238232165peter        if (!apr_isspace(*src))
2248232165peter            *dest++ = *src;
2258232165peter        ++src;
2268232165peter    }
2278232165peter    *dest = 0;
2288232165peter    return (dest);
2298232165peter}
2308232165peter
2318232165peter#if !APR_HAVE_STRDUP
2328232165peterchar *strdup(const char *str)
2338232165peter{
2348232165peter    char *sdup;
2358232165peter    size_t len = strlen(str) + 1;
2368232165peter
2378232165peter    sdup = (char *) malloc(len);
238c88884apeter    if (sdup == NULL)
239c88884apeter        return NULL;
2408232165peter    memcpy(sdup, str, len);
2418232165peter
2428232165peter    return sdup;
2438232165peter}
2448232165peter#endif
2458232165peter
2468232165peter/* The following two routines were donated for SVR4 by Andreas Vogel */
2478232165peter#if (!APR_HAVE_STRCASECMP && !APR_HAVE_STRICMP)
2488232165peterint strcasecmp(const char *a, const char *b)
2498232165peter{
2508232165peter    const char *p = a;
2518232165peter    const char *q = b;
2528232165peter    for (p = a, q = b; *p && *q; p++, q++) {
2538232165peter        int diff = apr_tolower(*p) - apr_tolower(*q);
2548232165peter        if (diff)
2558232165peter            return diff;
2568232165peter    }
2578232165peter    if (*p)
2588232165peter        return 1;               /* p was longer than q */
2598232165peter    if (*q)
2608232165peter        return -1;              /* p was shorter than q */
2618232165peter    return 0;                   /* Exact match */
2628232165peter}
2638232165peter
2648232165peter#endif
2658232165peter
2668232165peter#if (!APR_HAVE_STRNCASECMP && !APR_HAVE_STRNICMP)
2678232165peterint strncasecmp(const char *a, const char *b, size_t n)
2688232165peter{
2698232165peter    const char *p = a;
2708232165peter    const char *q = b;
2718232165peter
2728232165peter    for (p = a, q = b; /*NOTHING */ ; p++, q++) {
2738232165peter        int diff;
2748232165peter        if (p == a + n)
2758232165peter            return 0;           /*   Match up to n characters */
2768232165peter        if (!(*p && *q))
2778232165peter            return *p - *q;
2788232165peter        diff = apr_tolower(*p) - apr_tolower(*q);
2798232165peter        if (diff)
2808232165peter            return diff;
2818232165peter    }
2828232165peter    /*NOTREACHED */
2838232165peter}
2848232165peter#endif
2858232165peter
2868232165peter/* The following routine was donated for UTS21 by dwd@bell-labs.com */
2878232165peter#if (!APR_HAVE_STRSTR)
2888232165peterchar *strstr(char *s1, char *s2)
2898232165peter{
2908232165peter    char *p1, *p2;
2918232165peter    if (*s2 == '\0') {
2928232165peter        /* an empty s2 */
2938232165peter        return(s1);
2948232165peter    }
2958232165peter    while((s1 = strchr(s1, *s2)) != NULL) {
2968232165peter        /* found first character of s2, see if the rest matches */
2978232165peter        p1 = s1;
2988232165peter        p2 = s2;
2998232165peter        while (*++p1 == *++p2) {
3008232165peter            if (*p1 == '\0') {
3018232165peter                /* both strings ended together */
3028232165peter                return(s1);
3038232165peter            }
3048232165peter        }
3058232165peter        if (*p2 == '\0') {
3068232165peter            /* second string ended, a match */
3078232165peter            break;
3088232165peter        }
3098232165peter        /* didn't find a match here, try starting at next character in s1 */
3108232165peter        s1++;
3118232165peter    }
3128232165peter    return(s1);
3138232165peter}
3148232165peter#endif
3158232165peter
316