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