Main Page | Modules | Namespace List | Alphabetical List | Data Structures | Directories | File List | Data Fields | Globals | Related Pages | Examples

apr_cpystrn.c

Go to the documentation of this file.
00001 /* Copyright 2000-2005 The Apache Software Foundation or its licensors, as
00002  * applicable.
00003  *
00004  * Licensed under the Apache License, Version 2.0 (the "License");
00005  * you may not use this file except in compliance with the License.
00006  * You may obtain a copy of the License at
00007  *
00008  *     http://www.apache.org/licenses/LICENSE-2.0
00009  *
00010  * Unless required by applicable law or agreed to in writing, software
00011  * distributed under the License is distributed on an "AS IS" BASIS,
00012  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
00013  * See the License for the specific language governing permissions and
00014  * limitations under the License.
00015  */
00016 
00017 #include "apr.h"
00018 #include "apr_strings.h"
00019 #include "apr_private.h"
00020 #include "apr_lib.h"
00021 
00022 #if APR_HAVE_SYS_TYPES_H
00023 #include <sys/types.h>
00024 #endif
00025 #if APR_HAVE_STRING_H
00026 #include <string.h>
00027 #endif
00028 #if APR_HAVE_CTYPE_H
00029 #include <ctype.h>
00030 #endif
00031 
00032 /*
00033  * Apache's "replacement" for the strncpy() function. We roll our
00034  * own to implement these specific changes:
00035  *   (1) strncpy() doesn't always null terminate and we want it to.
00036  *   (2) strncpy() null fills, which is bogus, esp. when copy 8byte
00037  *       strings into 8k blocks.
00038  *   (3) Instead of returning the pointer to the beginning of
00039  *       the destination string, we return a pointer to the
00040  *       terminating '\0' to allow us to "check" for truncation
00041  *
00042  * apr_cpystrn() follows the same call structure as strncpy().
00043  */
00044 
00045 APR_DECLARE(char *) apr_cpystrn(char *dst, const char *src, apr_size_t dst_size)
00046 {
00047 
00048     char *d, *end;
00049 
00050     if (dst_size == 0) {
00051         return (dst);
00052     }
00053 
00054     d = dst;
00055     end = dst + dst_size - 1;
00056 
00057     for (; d < end; ++d, ++src) {
00058         if (!(*d = *src)) {
00059             return (d);
00060         }
00061     }
00062 
00063     *d = '\0';  /* always null terminate */
00064 
00065     return (d);
00066 }
00067 
00068 
00069 /*
00070  * This function provides a way to parse a generic argument string
00071  * into a standard argv[] form of argument list. It respects the 
00072  * usual "whitespace" and quoteing rules. In the future this could
00073  * be expanded to include support for the apr_call_exec command line
00074  * string processing (including converting '+' to ' ' and doing the 
00075  * url processing. It does not currently support this function.
00076  *
00077  *    token_context: Context from which pool allocations will occur.
00078  *    arg_str:       Input argument string for conversion to argv[].
00079  *    argv_out:      Output location. This is a pointer to an array
00080  *                   of pointers to strings (ie. &(char *argv[]).
00081  *                   This value will be allocated from the contexts
00082  *                   pool and filled in with copies of the tokens
00083  *                   found during parsing of the arg_str. 
00084  */
00085 APR_DECLARE(apr_status_t) apr_tokenize_to_argv(const char *arg_str, 
00086                                             char ***argv_out,
00087                                             apr_pool_t *token_context)
00088 {
00089     const char *cp;
00090     const char *ct;
00091     char *cleaned, *dirty;
00092     int escaped;
00093     int isquoted, numargs = 0, argnum;
00094 
00095 #define SKIP_WHITESPACE(cp) \
00096     for ( ; *cp == ' ' || *cp == '\t'; ) { \
00097         cp++; \
00098     };
00099 
00100 #define CHECK_QUOTATION(cp,isquoted) \
00101     isquoted = 0; \
00102     if (*cp == '"') { \
00103         isquoted = 1; \
00104         cp++; \
00105     } \
00106     else if (*cp == '\'') { \
00107         isquoted = 2; \
00108         cp++; \
00109     }
00110 
00111 /* DETERMINE_NEXTSTRING:
00112  * At exit, cp will point to one of the following:  NULL, SPACE, TAB or QUOTE.
00113  * NULL implies the argument string has been fully traversed.
00114  */
00115 #define DETERMINE_NEXTSTRING(cp,isquoted) \
00116     for ( ; *cp != '\0'; cp++) { \
00117         if (   (isquoted    && (*cp     == ' ' || *cp     == '\t')) \
00118             || (*cp == '\\' && (*(cp+1) == ' ' || *(cp+1) == '\t' || \
00119                                 *(cp+1) == '"' || *(cp+1) == '\''))) { \
00120             cp++; \
00121             continue; \
00122         } \
00123         if (   (!isquoted && (*cp == ' ' || *cp == '\t')) \
00124             || (isquoted == 1 && *cp == '"') \
00125             || (isquoted == 2 && *cp == '\'')                 ) { \
00126             break; \
00127         } \
00128     }
00129  
00130 /* REMOVE_ESCAPE_CHARS:
00131  * Compresses the arg string to remove all of the '\' escape chars.
00132  * The final argv strings should not have any extra escape chars in it.
00133  */
00134 #define REMOVE_ESCAPE_CHARS(cleaned, dirty, escaped) \
00135     escaped = 0; \
00136     while(*dirty) { \
00137         if (!escaped && *dirty == '\\') { \
00138             escaped = 1; \
00139         } \
00140         else { \
00141             escaped = 0; \
00142             *cleaned++ = *dirty; \
00143         } \
00144         ++dirty; \
00145     } \
00146     *cleaned = 0;        /* last line of macro... */
00147 
00148     cp = arg_str;
00149     SKIP_WHITESPACE(cp);
00150     ct = cp;
00151 
00152     /* This is ugly and expensive, but if anyone wants to figure a
00153      * way to support any number of args without counting and 
00154      * allocating, please go ahead and change the code.
00155      *
00156      * Must account for the trailing NULL arg.
00157      */
00158     numargs = 1;
00159     while (*ct != '\0') {
00160         CHECK_QUOTATION(ct, isquoted);
00161         DETERMINE_NEXTSTRING(ct, isquoted);
00162         if (*ct != '\0') {
00163             ct++;
00164         }
00165         numargs++;
00166         SKIP_WHITESPACE(ct);
00167     }
00168     *argv_out = apr_palloc(token_context, numargs * sizeof(char*));
00169 
00170     /*  determine first argument */
00171     for (argnum = 0; argnum < (numargs-1); argnum++) {
00172         CHECK_QUOTATION(cp, isquoted);
00173         ct = cp;
00174         DETERMINE_NEXTSTRING(cp, isquoted);
00175         cp++;
00176         (*argv_out)[argnum] = apr_palloc(token_context, cp - ct);
00177         apr_cpystrn((*argv_out)[argnum], ct, cp - ct);
00178         cleaned = dirty = (*argv_out)[argnum];
00179         REMOVE_ESCAPE_CHARS(cleaned, dirty, escaped);
00180         SKIP_WHITESPACE(cp);
00181     }
00182     (*argv_out)[argnum] = NULL;
00183 
00184     return APR_SUCCESS;
00185 }
00186 
00187 /* Filepath_name_get returns the final element of the pathname.
00188  * Using the current platform's filename syntax.
00189  *   "/foo/bar/gum" -> "gum"
00190  *   "/foo/bar/gum/" -> ""
00191  *   "gum" -> "gum"
00192  *   "wi\\n32\\stuff" -> "stuff
00193  *
00194  * Corrected Win32 to accept "a/b\\stuff", "a:stuff"
00195  */
00196 
00197 APR_DECLARE(const char *) apr_filepath_name_get(const char *pathname)
00198 {
00199     const char path_separator = '/';
00200     const char *s = strrchr(pathname, path_separator);
00201 
00202 #ifdef WIN32
00203     const char path_separator_win = '\\';
00204     const char drive_separator_win = ':';
00205     const char *s2 = strrchr(pathname, path_separator_win);
00206 
00207     if (s2 > s) s = s2;
00208 
00209     if (!s) s = strrchr(pathname, drive_separator_win);
00210 #endif
00211 
00212     return s ? ++s : pathname;
00213 }
00214 
00215 /* deprecated */
00216 APR_DECLARE(const char *) apr_filename_of_pathname(const char *pathname)
00217 {
00218         return apr_filepath_name_get(pathname);
00219 }
00220 
00221 /* length of dest assumed >= length of src
00222  * collapse in place (src == dest) is legal.
00223  * returns terminating null ptr to dest string.
00224  */
00225 APR_DECLARE(char *) apr_collapse_spaces(char *dest, const char *src)
00226 {
00227     while (*src) {
00228         if (!apr_isspace(*src)) 
00229             *dest++ = *src;
00230         ++src;
00231     }
00232     *dest = 0;
00233     return (dest);
00234 }
00235 
00236 #if !APR_HAVE_STRDUP
00237 char *strdup(const char *str)
00238 {
00239     char *sdup;
00240     size_t len = strlen(str) + 1;
00241 
00242     sdup = (char *) malloc(len);
00243     memcpy(sdup, str, len);
00244 
00245     return sdup;
00246 }
00247 #endif
00248 
00249 /* The following two routines were donated for SVR4 by Andreas Vogel */
00250 #if (!APR_HAVE_STRCASECMP && !APR_HAVE_STRICMP)
00251 int strcasecmp(const char *a, const char *b)
00252 {
00253     const char *p = a;
00254     const char *q = b;
00255     for (p = a, q = b; *p && *q; p++, q++) {
00256         int diff = apr_tolower(*p) - apr_tolower(*q);
00257         if (diff)
00258             return diff;
00259     }
00260     if (*p)
00261         return 1;               /* p was longer than q */
00262     if (*q)
00263         return -1;              /* p was shorter than q */
00264     return 0;                   /* Exact match */
00265 }
00266 
00267 #endif
00268 
00269 #if (!APR_HAVE_STRNCASECMP && !APR_HAVE_STRNICMP)
00270 int strncasecmp(const char *a, const char *b, size_t n)
00271 {
00272     const char *p = a;
00273     const char *q = b;
00274 
00275     for (p = a, q = b; /*NOTHING */ ; p++, q++) {
00276         int diff;
00277         if (p == a + n)
00278             return 0;           /*   Match up to n characters */
00279         if (!(*p && *q))
00280             return *p - *q;
00281         diff = apr_tolower(*p) - apr_tolower(*q);
00282         if (diff)
00283             return diff;
00284     }
00285     /*NOTREACHED */
00286 }
00287 #endif
00288 
00289 /* The following routine was donated for UTS21 by dwd@bell-labs.com */
00290 #if (!APR_HAVE_STRSTR)
00291 char *strstr(char *s1, char *s2)
00292 {
00293     char *p1, *p2;
00294     if (*s2 == '\0') {
00295         /* an empty s2 */
00296         return(s1);
00297     }
00298     while((s1 = strchr(s1, *s2)) != NULL) {
00299         /* found first character of s2, see if the rest matches */
00300         p1 = s1;
00301         p2 = s2;
00302         while (*++p1 == *++p2) {
00303             if (*p1 == '\0') {
00304                 /* both strings ended together */
00305                 return(s1);
00306             }
00307         }
00308         if (*p2 == '\0') {
00309             /* second string ended, a match */
00310             break;
00311         }
00312         /* didn't find a match here, try starting at next character in s1 */
00313         s1++;
00314     }
00315     return(s1);
00316 }
00317 #endif
00318