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