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