apr_cpystrn.c revision 266735
1168561Sthompsa/* Licensed to the Apache Software Foundation (ASF) under one or more
2168561Sthompsa * contributor license agreements.  See the NOTICE file distributed with
3168561Sthompsa * this work for additional information regarding copyright ownership.
4168561Sthompsa * The ASF licenses this file to You under the Apache License, Version 2.0
5168561Sthompsa * (the "License"); you may not use this file except in compliance with
6168561Sthompsa * the License.  You may obtain a copy of the License at
7168561Sthompsa *
8168561Sthompsa *     http://www.apache.org/licenses/LICENSE-2.0
9168561Sthompsa *
10168561Sthompsa * Unless required by applicable law or agreed to in writing, software
11168561Sthompsa * distributed under the License is distributed on an "AS IS" BASIS,
12168561Sthompsa * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13168561Sthompsa * See the License for the specific language governing permissions and
14168561Sthompsa * limitations under the License.
15168561Sthompsa */
16168561Sthompsa
17168561Sthompsa#include "apr.h"
18168561Sthompsa#include "apr_strings.h"
19168561Sthompsa#include "apr_private.h"
20168561Sthompsa#include "apr_lib.h"
21168561Sthompsa
22168561Sthompsa#if APR_HAVE_SYS_TYPES_H
23168561Sthompsa#include <sys/types.h>
24168561Sthompsa#endif
25168561Sthompsa#if APR_HAVE_STRING_H
26168561Sthompsa#include <string.h>
27168561Sthompsa#endif
28168561Sthompsa#if APR_HAVE_CTYPE_H
29168561Sthompsa#include <ctype.h>
30168561Sthompsa#endif
31168561Sthompsa
32168561Sthompsa/*
33168561Sthompsa * Apache's "replacement" for the strncpy() function. We roll our
34168561Sthompsa * own to implement these specific changes:
35168561Sthompsa *   (1) strncpy() doesn't always null terminate and we want it to.
36168561Sthompsa *   (2) strncpy() null fills, which is bogus, esp. when copy 8byte
37168561Sthompsa *       strings into 8k blocks.
38168561Sthompsa *   (3) Instead of returning the pointer to the beginning of
39168561Sthompsa *       the destination string, we return a pointer to the
40168561Sthompsa *       terminating '\0' to allow us to "check" for truncation
41168561Sthompsa *   (4) If src is NULL, null terminate dst (empty string copy)
42168561Sthompsa *
43168561Sthompsa * apr_cpystrn() follows the same call structure as strncpy().
44168561Sthompsa */
45168561Sthompsa
46168561SthompsaAPR_DECLARE(char *) apr_cpystrn(char *dst, const char *src, apr_size_t dst_size)
47168561Sthompsa{
48168561Sthompsa
49168561Sthompsa    char *d = dst, *end;
50168561Sthompsa
51168561Sthompsa    if (dst_size == 0) {
52168561Sthompsa        return (dst);
53168561Sthompsa    }
54168561Sthompsa
55168561Sthompsa    if (src) {
56168561Sthompsa        end = dst + dst_size - 1;
57168561Sthompsa
58168561Sthompsa        for (; d < end; ++d, ++src) {
59168561Sthompsa            if (!(*d = *src)) {
60168561Sthompsa                return (d);
61168561Sthompsa            }
62168561Sthompsa        }
63168561Sthompsa    }
64170599Sthompsa
65170599Sthompsa    *d = '\0';	/* always null terminate */
66168561Sthompsa
67168561Sthompsa    return (d);
68168561Sthompsa}
69168561Sthompsa
70168561Sthompsa
71168561Sthompsa/*
72168561Sthompsa * This function provides a way to parse a generic argument string
73168561Sthompsa * into a standard argv[] form of argument list. It respects the
74168561Sthompsa * usual "whitespace" and quoteing rules. In the future this could
75168561Sthompsa * be expanded to include support for the apr_call_exec command line
76168561Sthompsa * string processing (including converting '+' to ' ' and doing the
77168561Sthompsa * url processing. It does not currently support this function.
78287723Shrs *
79168561Sthompsa *    token_context: Context from which pool allocations will occur.
80168561Sthompsa *    arg_str:       Input argument string for conversion to argv[].
81168561Sthompsa *    argv_out:      Output location. This is a pointer to an array
82168561Sthompsa *                   of pointers to strings (ie. &(char *argv[]).
83168561Sthompsa *                   This value will be allocated from the contexts
84168561Sthompsa *                   pool and filled in with copies of the tokens
85168561Sthompsa *                   found during parsing of the arg_str.
86168561Sthompsa */
87168561SthompsaAPR_DECLARE(apr_status_t) apr_tokenize_to_argv(const char *arg_str,
88168561Sthompsa                                            char ***argv_out,
89168561Sthompsa                                            apr_pool_t *token_context)
90168561Sthompsa{
91168561Sthompsa    const char *cp;
92168561Sthompsa    const char *ct;
93168561Sthompsa    char *cleaned, *dirty;
94168561Sthompsa    int escaped;
95168561Sthompsa    int isquoted, numargs = 0, argnum;
96168561Sthompsa
97168561Sthompsa#define SKIP_WHITESPACE(cp) \
98168561Sthompsa    for ( ; *cp == ' ' || *cp == '\t'; ) { \
99168561Sthompsa        cp++; \
100168561Sthompsa    };
101168561Sthompsa
102168561Sthompsa#define CHECK_QUOTATION(cp,isquoted) \
103168561Sthompsa    isquoted = 0; \
104168561Sthompsa    if (*cp == '"') { \
105168561Sthompsa        isquoted = 1; \
106168561Sthompsa        cp++; \
107168561Sthompsa    } \
108168561Sthompsa    else if (*cp == '\'') { \
109168561Sthompsa        isquoted = 2; \
110168561Sthompsa        cp++; \
111168561Sthompsa    }
112168561Sthompsa
113168561Sthompsa/* DETERMINE_NEXTSTRING:
114168561Sthompsa * At exit, cp will point to one of the following:  NULL, SPACE, TAB or QUOTE.
115168561Sthompsa * NULL implies the argument string has been fully traversed.
116168561Sthompsa */
117168561Sthompsa#define DETERMINE_NEXTSTRING(cp,isquoted) \
118168561Sthompsa    for ( ; *cp != '\0'; cp++) { \
119168561Sthompsa        if (   (*cp == '\\' && (*(cp+1) == ' ' || *(cp+1) == '\t' || \
120168561Sthompsa                                *(cp+1) == '"' || *(cp+1) == '\''))) { \
121168561Sthompsa            cp++; \
122168561Sthompsa            continue; \
123168561Sthompsa        } \
124168561Sthompsa        if (   (!isquoted && (*cp == ' ' || *cp == '\t')) \
125168561Sthompsa            || (isquoted == 1 && *cp == '"') \
126168561Sthompsa            || (isquoted == 2 && *cp == '\'')                 ) { \
127168561Sthompsa            break; \
128168561Sthompsa        } \
129168561Sthompsa    }
130168561Sthompsa
131170599Sthompsa/* REMOVE_ESCAPE_CHARS:
132168561Sthompsa * Compresses the arg string to remove all of the '\' escape chars.
133170599Sthompsa * The final argv strings should not have any extra escape chars in it.
134168561Sthompsa */
135168561Sthompsa#define REMOVE_ESCAPE_CHARS(cleaned, dirty, escaped) \
136168561Sthompsa    escaped = 0; \
137168561Sthompsa    while(*dirty) { \
138168561Sthompsa        if (!escaped && *dirty == '\\') { \
139168561Sthompsa            escaped = 1; \
140168561Sthompsa        } \
141168561Sthompsa        else { \
142168561Sthompsa            escaped = 0; \
143168561Sthompsa            *cleaned++ = *dirty; \
144168561Sthompsa        } \
145168561Sthompsa        ++dirty; \
146168561Sthompsa    } \
147168561Sthompsa    *cleaned = 0;        /* last line of macro... */
148168561Sthompsa
149168561Sthompsa    cp = arg_str;
150168561Sthompsa    SKIP_WHITESPACE(cp);
151168561Sthompsa    ct = cp;
152168561Sthompsa
153168561Sthompsa    /* This is ugly and expensive, but if anyone wants to figure a
154168561Sthompsa     * way to support any number of args without counting and
155168561Sthompsa     * allocating, please go ahead and change the code.
156168561Sthompsa     *
157169739Sthompsa     * Must account for the trailing NULL arg.
158169739Sthompsa     */
159169739Sthompsa    numargs = 1;
160169739Sthompsa    while (*ct != '\0') {
161169739Sthompsa        CHECK_QUOTATION(ct, isquoted);
162169739Sthompsa        DETERMINE_NEXTSTRING(ct, isquoted);
163169739Sthompsa        if (*ct != '\0') {
164169739Sthompsa            ct++;
165169739Sthompsa        }
166169739Sthompsa        numargs++;
167169739Sthompsa        SKIP_WHITESPACE(ct);
168168561Sthompsa    }
169169739Sthompsa    *argv_out = apr_palloc(token_context, numargs * sizeof(char*));
170169739Sthompsa
171169739Sthompsa    /*  determine first argument */
172169739Sthompsa    for (argnum = 0; argnum < (numargs-1); argnum++) {
173169739Sthompsa        SKIP_WHITESPACE(cp);
174169739Sthompsa        CHECK_QUOTATION(cp, isquoted);
175169739Sthompsa        ct = cp;
176169739Sthompsa        DETERMINE_NEXTSTRING(cp, isquoted);
177169739Sthompsa        cp++;
178169739Sthompsa        (*argv_out)[argnum] = apr_palloc(token_context, cp - ct);
179169739Sthompsa        apr_cpystrn((*argv_out)[argnum], ct, cp - ct);
180169739Sthompsa        cleaned = dirty = (*argv_out)[argnum];
181169739Sthompsa        REMOVE_ESCAPE_CHARS(cleaned, dirty, escaped);
182168561Sthompsa    }
183168561Sthompsa    (*argv_out)[argnum] = NULL;
184168561Sthompsa
185168561Sthompsa    return APR_SUCCESS;
186168561Sthompsa}
187168561Sthompsa
188168561Sthompsa/* Filepath_name_get returns the final element of the pathname.
189168561Sthompsa * Using the current platform's filename syntax.
190168561Sthompsa *   "/foo/bar/gum" -> "gum"
191168561Sthompsa *   "/foo/bar/gum/" -> ""
192168561Sthompsa *   "gum" -> "gum"
193168561Sthompsa *   "wi\\n32\\stuff" -> "stuff
194168561Sthompsa *
195168561Sthompsa * Corrected Win32 to accept "a/b\\stuff", "a:stuff"
196177274Sthompsa */
197177274Sthompsa
198177274SthompsaAPR_DECLARE(const char *) apr_filepath_name_get(const char *pathname)
199177274Sthompsa{
200177274Sthompsa    const char path_separator = '/';
201177274Sthompsa    const char *s = strrchr(pathname, path_separator);
202177274Sthompsa
203168561Sthompsa#ifdef WIN32
204168561Sthompsa    const char path_separator_win = '\\';
205168561Sthompsa    const char drive_separator_win = ':';
206168561Sthompsa    const char *s2 = strrchr(pathname, path_separator_win);
207168793Sthompsa
208168561Sthompsa    if (s2 > s) s = s2;
209168561Sthompsa
210168561Sthompsa    if (!s) s = strrchr(pathname, drive_separator_win);
211169739Sthompsa#endif
212168561Sthompsa
213168561Sthompsa    return s ? ++s : pathname;
214169739Sthompsa}
215168561Sthompsa
216168561Sthompsa/* length of dest assumed >= length of src
217168561Sthompsa * collapse in place (src == dest) is legal.
218168561Sthompsa * returns terminating null ptr to dest string.
219168561Sthompsa */
220168561SthompsaAPR_DECLARE(char *) apr_collapse_spaces(char *dest, const char *src)
221168561Sthompsa{
222169327Sthompsa    while (*src) {
223168561Sthompsa        if (!apr_isspace(*src))
224168561Sthompsa            *dest++ = *src;
225168561Sthompsa        ++src;
226168561Sthompsa    }
227168561Sthompsa    *dest = 0;
228168561Sthompsa    return (dest);
229168561Sthompsa}
230168561Sthompsa
231168561Sthompsa#if !APR_HAVE_STRDUP
232168561Sthompsachar *strdup(const char *str)
233168561Sthompsa{
234170599Sthompsa    char *sdup;
235168561Sthompsa    size_t len = strlen(str) + 1;
236168561Sthompsa
237168561Sthompsa    sdup = (char *) malloc(len);
238170599Sthompsa    memcpy(sdup, str, len);
239177274Sthompsa
240168561Sthompsa    return sdup;
241168561Sthompsa}
242168561Sthompsa#endif
243168561Sthompsa
244168561Sthompsa/* The following two routines were donated for SVR4 by Andreas Vogel */
245168561Sthompsa#if (!APR_HAVE_STRCASECMP && !APR_HAVE_STRICMP)
246177274Sthompsaint strcasecmp(const char *a, const char *b)
247177274Sthompsa{
248168561Sthompsa    const char *p = a;
249253687Sadrian    const char *q = b;
250253687Sadrian    for (p = a, q = b; *p && *q; p++, q++) {
251253687Sadrian        int diff = apr_tolower(*p) - apr_tolower(*q);
252253687Sadrian        if (diff)
253253687Sadrian            return diff;
254287808Shiren    }
255168561Sthompsa    if (*p)
256168561Sthompsa        return 1;               /* p was longer than q */
257168561Sthompsa    if (*q)
258168561Sthompsa        return -1;              /* p was shorter than q */
259168561Sthompsa    return 0;                   /* Exact match */
260168561Sthompsa}
261168561Sthompsa
262168561Sthompsa#endif
263168561Sthompsa
264168561Sthompsa#if (!APR_HAVE_STRNCASECMP && !APR_HAVE_STRNICMP)
265168561Sthompsaint strncasecmp(const char *a, const char *b, size_t n)
266168561Sthompsa{
267168561Sthompsa    const char *p = a;
268169739Sthompsa    const char *q = b;
269168561Sthompsa
270168561Sthompsa    for (p = a, q = b; /*NOTHING */ ; p++, q++) {
271168561Sthompsa        int diff;
272168561Sthompsa        if (p == a + n)
273169741Sthompsa            return 0;           /*   Match up to n characters */
274169741Sthompsa        if (!(*p && *q))
275168793Sthompsa            return *p - *q;
276168793Sthompsa        diff = apr_tolower(*p) - apr_tolower(*q);
277168561Sthompsa        if (diff)
278177274Sthompsa            return diff;
279177289Sthompsa    }
280177289Sthompsa    /*NOTREACHED */
281177274Sthompsa}
282177274Sthompsa#endif
283177274Sthompsa
284177274Sthompsa/* The following routine was donated for UTS21 by dwd@bell-labs.com */
285175005Sthompsa#if (!APR_HAVE_STRSTR)
286168793Sthompsachar *strstr(char *s1, char *s2)
287287723Shrs{
288287723Shrs    char *p1, *p2;
289168793Sthompsa    if (*s2 == '\0') {
290168793Sthompsa        /* an empty s2 */
291168793Sthompsa        return(s1);
292168793Sthompsa    }
293168793Sthompsa    while((s1 = strchr(s1, *s2)) != NULL) {
294171247Sthompsa        /* found first character of s2, see if the rest matches */
295171247Sthompsa        p1 = s1;
296168561Sthompsa        p2 = s2;
297177274Sthompsa        while (*++p1 == *++p2) {
298177274Sthompsa            if (*p1 == '\0') {
299177274Sthompsa                /* both strings ended together */
300177274Sthompsa                return(s1);
301177274Sthompsa            }
302177274Sthompsa        }
303177274Sthompsa        if (*p2 == '\0') {
304177274Sthompsa            /* second string ended, a match */
305177274Sthompsa            break;
306177274Sthompsa        }
307177274Sthompsa        /* didn't find a match here, try starting at next character in s1 */
308177274Sthompsa        s1++;
309177274Sthompsa    }
310177274Sthompsa    return(s1);
311177274Sthompsa}
312177274Sthompsa#endif
313177274Sthompsa
314177274Sthompsa