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#include "apr.h"
18251875Speter#include "apr_strings.h"
19251875Speter#include "apr_private.h"
20251875Speter#include "apr_lib.h"
21251875Speter
22251875Speter#if APR_HAVE_SYS_TYPES_H
23251875Speter#include <sys/types.h>
24251875Speter#endif
25251875Speter#if APR_HAVE_STRING_H
26251875Speter#include <string.h>
27251875Speter#endif
28251875Speter#if APR_HAVE_CTYPE_H
29251875Speter#include <ctype.h>
30251875Speter#endif
31251875Speter
32251875Speter/*
33251875Speter * Apache's "replacement" for the strncpy() function. We roll our
34251875Speter * own to implement these specific changes:
35251875Speter *   (1) strncpy() doesn't always null terminate and we want it to.
36251875Speter *   (2) strncpy() null fills, which is bogus, esp. when copy 8byte
37251875Speter *       strings into 8k blocks.
38251875Speter *   (3) Instead of returning the pointer to the beginning of
39251875Speter *       the destination string, we return a pointer to the
40251875Speter *       terminating '\0' to allow us to "check" for truncation
41266735Speter *   (4) If src is NULL, null terminate dst (empty string copy)
42251875Speter *
43251875Speter * apr_cpystrn() follows the same call structure as strncpy().
44251875Speter */
45251875Speter
46251875SpeterAPR_DECLARE(char *) apr_cpystrn(char *dst, const char *src, apr_size_t dst_size)
47251875Speter{
48251875Speter
49266735Speter    char *d = dst, *end;
50251875Speter
51251875Speter    if (dst_size == 0) {
52251875Speter        return (dst);
53251875Speter    }
54251875Speter
55266735Speter    if (src) {
56266735Speter        end = dst + dst_size - 1;
57251875Speter
58266735Speter        for (; d < end; ++d, ++src) {
59266735Speter            if (!(*d = *src)) {
60266735Speter                return (d);
61266735Speter            }
62266735Speter        }
63251875Speter    }
64251875Speter
65251875Speter    *d = '\0';	/* always null terminate */
66251875Speter
67251875Speter    return (d);
68251875Speter}
69251875Speter
70251875Speter
71251875Speter/*
72251875Speter * This function provides a way to parse a generic argument string
73251875Speter * into a standard argv[] form of argument list. It respects the
74251875Speter * usual "whitespace" and quoteing rules. In the future this could
75251875Speter * be expanded to include support for the apr_call_exec command line
76251875Speter * string processing (including converting '+' to ' ' and doing the
77251875Speter * url processing. It does not currently support this function.
78251875Speter *
79251875Speter *    token_context: Context from which pool allocations will occur.
80251875Speter *    arg_str:       Input argument string for conversion to argv[].
81251875Speter *    argv_out:      Output location. This is a pointer to an array
82251875Speter *                   of pointers to strings (ie. &(char *argv[]).
83251875Speter *                   This value will be allocated from the contexts
84251875Speter *                   pool and filled in with copies of the tokens
85251875Speter *                   found during parsing of the arg_str.
86251875Speter */
87251875SpeterAPR_DECLARE(apr_status_t) apr_tokenize_to_argv(const char *arg_str,
88251875Speter                                            char ***argv_out,
89251875Speter                                            apr_pool_t *token_context)
90251875Speter{
91251875Speter    const char *cp;
92251875Speter    const char *ct;
93251875Speter    char *cleaned, *dirty;
94251875Speter    int escaped;
95251875Speter    int isquoted, numargs = 0, argnum;
96251875Speter
97251875Speter#define SKIP_WHITESPACE(cp) \
98251875Speter    for ( ; *cp == ' ' || *cp == '\t'; ) { \
99251875Speter        cp++; \
100251875Speter    };
101251875Speter
102251875Speter#define CHECK_QUOTATION(cp,isquoted) \
103251875Speter    isquoted = 0; \
104251875Speter    if (*cp == '"') { \
105251875Speter        isquoted = 1; \
106251875Speter        cp++; \
107251875Speter    } \
108251875Speter    else if (*cp == '\'') { \
109251875Speter        isquoted = 2; \
110251875Speter        cp++; \
111251875Speter    }
112251875Speter
113251875Speter/* DETERMINE_NEXTSTRING:
114251875Speter * At exit, cp will point to one of the following:  NULL, SPACE, TAB or QUOTE.
115251875Speter * NULL implies the argument string has been fully traversed.
116251875Speter */
117251875Speter#define DETERMINE_NEXTSTRING(cp,isquoted) \
118251875Speter    for ( ; *cp != '\0'; cp++) { \
119251875Speter        if (   (*cp == '\\' && (*(cp+1) == ' ' || *(cp+1) == '\t' || \
120251875Speter                                *(cp+1) == '"' || *(cp+1) == '\''))) { \
121251875Speter            cp++; \
122251875Speter            continue; \
123251875Speter        } \
124251875Speter        if (   (!isquoted && (*cp == ' ' || *cp == '\t')) \
125251875Speter            || (isquoted == 1 && *cp == '"') \
126251875Speter            || (isquoted == 2 && *cp == '\'')                 ) { \
127251875Speter            break; \
128251875Speter        } \
129251875Speter    }
130251875Speter
131251875Speter/* REMOVE_ESCAPE_CHARS:
132251875Speter * Compresses the arg string to remove all of the '\' escape chars.
133251875Speter * The final argv strings should not have any extra escape chars in it.
134251875Speter */
135251875Speter#define REMOVE_ESCAPE_CHARS(cleaned, dirty, escaped) \
136251875Speter    escaped = 0; \
137251875Speter    while(*dirty) { \
138251875Speter        if (!escaped && *dirty == '\\') { \
139251875Speter            escaped = 1; \
140251875Speter        } \
141251875Speter        else { \
142251875Speter            escaped = 0; \
143251875Speter            *cleaned++ = *dirty; \
144251875Speter        } \
145251875Speter        ++dirty; \
146251875Speter    } \
147251875Speter    *cleaned = 0;        /* last line of macro... */
148251875Speter
149251875Speter    cp = arg_str;
150251875Speter    SKIP_WHITESPACE(cp);
151251875Speter    ct = cp;
152251875Speter
153251875Speter    /* This is ugly and expensive, but if anyone wants to figure a
154251875Speter     * way to support any number of args without counting and
155251875Speter     * allocating, please go ahead and change the code.
156251875Speter     *
157251875Speter     * Must account for the trailing NULL arg.
158251875Speter     */
159251875Speter    numargs = 1;
160251875Speter    while (*ct != '\0') {
161251875Speter        CHECK_QUOTATION(ct, isquoted);
162251875Speter        DETERMINE_NEXTSTRING(ct, isquoted);
163251875Speter        if (*ct != '\0') {
164251875Speter            ct++;
165251875Speter        }
166251875Speter        numargs++;
167251875Speter        SKIP_WHITESPACE(ct);
168251875Speter    }
169251875Speter    *argv_out = apr_palloc(token_context, numargs * sizeof(char*));
170251875Speter
171251875Speter    /*  determine first argument */
172251875Speter    for (argnum = 0; argnum < (numargs-1); argnum++) {
173251875Speter        SKIP_WHITESPACE(cp);
174251875Speter        CHECK_QUOTATION(cp, isquoted);
175251875Speter        ct = cp;
176251875Speter        DETERMINE_NEXTSTRING(cp, isquoted);
177251875Speter        cp++;
178251875Speter        (*argv_out)[argnum] = apr_palloc(token_context, cp - ct);
179251875Speter        apr_cpystrn((*argv_out)[argnum], ct, cp - ct);
180251875Speter        cleaned = dirty = (*argv_out)[argnum];
181251875Speter        REMOVE_ESCAPE_CHARS(cleaned, dirty, escaped);
182251875Speter    }
183251875Speter    (*argv_out)[argnum] = NULL;
184251875Speter
185251875Speter    return APR_SUCCESS;
186251875Speter}
187251875Speter
188251875Speter/* Filepath_name_get returns the final element of the pathname.
189251875Speter * Using the current platform's filename syntax.
190251875Speter *   "/foo/bar/gum" -> "gum"
191251875Speter *   "/foo/bar/gum/" -> ""
192251875Speter *   "gum" -> "gum"
193251875Speter *   "wi\\n32\\stuff" -> "stuff
194251875Speter *
195251875Speter * Corrected Win32 to accept "a/b\\stuff", "a:stuff"
196251875Speter */
197251875Speter
198251875SpeterAPR_DECLARE(const char *) apr_filepath_name_get(const char *pathname)
199251875Speter{
200251875Speter    const char path_separator = '/';
201251875Speter    const char *s = strrchr(pathname, path_separator);
202251875Speter
203251875Speter#ifdef WIN32
204251875Speter    const char path_separator_win = '\\';
205251875Speter    const char drive_separator_win = ':';
206251875Speter    const char *s2 = strrchr(pathname, path_separator_win);
207251875Speter
208251875Speter    if (s2 > s) s = s2;
209251875Speter
210251875Speter    if (!s) s = strrchr(pathname, drive_separator_win);
211251875Speter#endif
212251875Speter
213251875Speter    return s ? ++s : pathname;
214251875Speter}
215251875Speter
216251875Speter/* length of dest assumed >= length of src
217251875Speter * collapse in place (src == dest) is legal.
218251875Speter * returns terminating null ptr to dest string.
219251875Speter */
220251875SpeterAPR_DECLARE(char *) apr_collapse_spaces(char *dest, const char *src)
221251875Speter{
222251875Speter    while (*src) {
223251875Speter        if (!apr_isspace(*src))
224251875Speter            *dest++ = *src;
225251875Speter        ++src;
226251875Speter    }
227251875Speter    *dest = 0;
228251875Speter    return (dest);
229251875Speter}
230251875Speter
231251875Speter#if !APR_HAVE_STRDUP
232251875Speterchar *strdup(const char *str)
233251875Speter{
234251875Speter    char *sdup;
235251875Speter    size_t len = strlen(str) + 1;
236251875Speter
237251875Speter    sdup = (char *) malloc(len);
238251875Speter    memcpy(sdup, str, len);
239251875Speter
240251875Speter    return sdup;
241251875Speter}
242251875Speter#endif
243251875Speter
244251875Speter/* The following two routines were donated for SVR4 by Andreas Vogel */
245251875Speter#if (!APR_HAVE_STRCASECMP && !APR_HAVE_STRICMP)
246251875Speterint strcasecmp(const char *a, const char *b)
247251875Speter{
248251875Speter    const char *p = a;
249251875Speter    const char *q = b;
250251875Speter    for (p = a, q = b; *p && *q; p++, q++) {
251251875Speter        int diff = apr_tolower(*p) - apr_tolower(*q);
252251875Speter        if (diff)
253251875Speter            return diff;
254251875Speter    }
255251875Speter    if (*p)
256251875Speter        return 1;               /* p was longer than q */
257251875Speter    if (*q)
258251875Speter        return -1;              /* p was shorter than q */
259251875Speter    return 0;                   /* Exact match */
260251875Speter}
261251875Speter
262251875Speter#endif
263251875Speter
264251875Speter#if (!APR_HAVE_STRNCASECMP && !APR_HAVE_STRNICMP)
265251875Speterint strncasecmp(const char *a, const char *b, size_t n)
266251875Speter{
267251875Speter    const char *p = a;
268251875Speter    const char *q = b;
269251875Speter
270251875Speter    for (p = a, q = b; /*NOTHING */ ; p++, q++) {
271251875Speter        int diff;
272251875Speter        if (p == a + n)
273251875Speter            return 0;           /*   Match up to n characters */
274251875Speter        if (!(*p && *q))
275251875Speter            return *p - *q;
276251875Speter        diff = apr_tolower(*p) - apr_tolower(*q);
277251875Speter        if (diff)
278251875Speter            return diff;
279251875Speter    }
280251875Speter    /*NOTREACHED */
281251875Speter}
282251875Speter#endif
283251875Speter
284251875Speter/* The following routine was donated for UTS21 by dwd@bell-labs.com */
285251875Speter#if (!APR_HAVE_STRSTR)
286251875Speterchar *strstr(char *s1, char *s2)
287251875Speter{
288251875Speter    char *p1, *p2;
289251875Speter    if (*s2 == '\0') {
290251875Speter        /* an empty s2 */
291251875Speter        return(s1);
292251875Speter    }
293251875Speter    while((s1 = strchr(s1, *s2)) != NULL) {
294251875Speter        /* found first character of s2, see if the rest matches */
295251875Speter        p1 = s1;
296251875Speter        p2 = s2;
297251875Speter        while (*++p1 == *++p2) {
298251875Speter            if (*p1 == '\0') {
299251875Speter                /* both strings ended together */
300251875Speter                return(s1);
301251875Speter            }
302251875Speter        }
303251875Speter        if (*p2 == '\0') {
304251875Speter            /* second string ended, a match */
305251875Speter            break;
306251875Speter        }
307251875Speter        /* didn't find a match here, try starting at next character in s1 */
308251875Speter        s1++;
309251875Speter    }
310251875Speter    return(s1);
311251875Speter}
312251875Speter#endif
313251875Speter
314