fspr_cpystrn.c 8.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312
  1. /* Licensed to the Apache Software Foundation (ASF) under one or more
  2. * contributor license agreements. See the NOTICE file distributed with
  3. * this work for additional information regarding copyright ownership.
  4. * The ASF licenses this file to You under the Apache License, Version 2.0
  5. * (the "License"); you may not use this file except in compliance with
  6. * the License. You may obtain a copy of the License at
  7. *
  8. * http://www.apache.org/licenses/LICENSE-2.0
  9. *
  10. * Unless required by applicable law or agreed to in writing, software
  11. * distributed under the License is distributed on an "AS IS" BASIS,
  12. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. * See the License for the specific language governing permissions and
  14. * limitations under the License.
  15. */
  16. #include "fspr.h"
  17. #include "fspr_strings.h"
  18. #include "fspr_private.h"
  19. #include "fspr_lib.h"
  20. #if APR_HAVE_SYS_TYPES_H
  21. #include <sys/types.h>
  22. #endif
  23. #if APR_HAVE_STRING_H
  24. #include <string.h>
  25. #endif
  26. #if APR_HAVE_CTYPE_H
  27. #include <ctype.h>
  28. #endif
  29. /*
  30. * Apache's "replacement" for the strncpy() function. We roll our
  31. * own to implement these specific changes:
  32. * (1) strncpy() doesn't always null terminate and we want it to.
  33. * (2) strncpy() null fills, which is bogus, esp. when copy 8byte
  34. * strings into 8k blocks.
  35. * (3) Instead of returning the pointer to the beginning of
  36. * the destination string, we return a pointer to the
  37. * terminating '\0' to allow us to "check" for truncation
  38. *
  39. * fspr_cpystrn() follows the same call structure as strncpy().
  40. */
  41. APR_DECLARE(char *) fspr_cpystrn(char *dst, const char *src, fspr_size_t dst_size)
  42. {
  43. char *d, *end;
  44. if (dst_size == 0) {
  45. return (dst);
  46. }
  47. d = dst;
  48. end = dst + dst_size - 1;
  49. for (; d < end; ++d, ++src) {
  50. if (!(*d = *src)) {
  51. return (d);
  52. }
  53. }
  54. *d = '\0'; /* always null terminate */
  55. return (d);
  56. }
  57. /*
  58. * This function provides a way to parse a generic argument string
  59. * into a standard argv[] form of argument list. It respects the
  60. * usual "whitespace" and quoteing rules. In the future this could
  61. * be expanded to include support for the fspr_call_exec command line
  62. * string processing (including converting '+' to ' ' and doing the
  63. * url processing. It does not currently support this function.
  64. *
  65. * token_context: Context from which pool allocations will occur.
  66. * arg_str: Input argument string for conversion to argv[].
  67. * argv_out: Output location. This is a pointer to an array
  68. * of pointers to strings (ie. &(char *argv[]).
  69. * This value will be allocated from the contexts
  70. * pool and filled in with copies of the tokens
  71. * found during parsing of the arg_str.
  72. */
  73. APR_DECLARE(fspr_status_t) fspr_tokenize_to_argv(const char *arg_str,
  74. char ***argv_out,
  75. fspr_pool_t *token_context)
  76. {
  77. const char *cp;
  78. const char *ct;
  79. char *cleaned, *dirty;
  80. int escaped;
  81. int isquoted, numargs = 0, argnum;
  82. #define SKIP_WHITESPACE(cp) \
  83. for ( ; *cp == ' ' || *cp == '\t'; ) { \
  84. cp++; \
  85. };
  86. #define CHECK_QUOTATION(cp,isquoted) \
  87. isquoted = 0; \
  88. if (*cp == '"') { \
  89. isquoted = 1; \
  90. cp++; \
  91. } \
  92. else if (*cp == '\'') { \
  93. isquoted = 2; \
  94. cp++; \
  95. }
  96. /* DETERMINE_NEXTSTRING:
  97. * At exit, cp will point to one of the following: NULL, SPACE, TAB or QUOTE.
  98. * NULL implies the argument string has been fully traversed.
  99. */
  100. #define DETERMINE_NEXTSTRING(cp,isquoted) \
  101. for ( ; *cp != '\0'; cp++) { \
  102. if ( (isquoted && (*cp == ' ' || *cp == '\t')) \
  103. || (*cp == '\\' && (*(cp+1) == ' ' || *(cp+1) == '\t' || \
  104. *(cp+1) == '"' || *(cp+1) == '\''))) { \
  105. cp++; \
  106. continue; \
  107. } \
  108. if ( (!isquoted && (*cp == ' ' || *cp == '\t')) \
  109. || (isquoted == 1 && *cp == '"') \
  110. || (isquoted == 2 && *cp == '\'') ) { \
  111. break; \
  112. } \
  113. }
  114. /* REMOVE_ESCAPE_CHARS:
  115. * Compresses the arg string to remove all of the '\' escape chars.
  116. * The final argv strings should not have any extra escape chars in it.
  117. */
  118. #define REMOVE_ESCAPE_CHARS(cleaned, dirty, escaped) \
  119. escaped = 0; \
  120. while(*dirty) { \
  121. if (!escaped && *dirty == '\\') { \
  122. escaped = 1; \
  123. } \
  124. else { \
  125. escaped = 0; \
  126. *cleaned++ = *dirty; \
  127. } \
  128. ++dirty; \
  129. } \
  130. *cleaned = 0; /* last line of macro... */
  131. cp = arg_str;
  132. SKIP_WHITESPACE(cp);
  133. ct = cp;
  134. /* This is ugly and expensive, but if anyone wants to figure a
  135. * way to support any number of args without counting and
  136. * allocating, please go ahead and change the code.
  137. *
  138. * Must account for the trailing NULL arg.
  139. */
  140. numargs = 1;
  141. while (*ct != '\0') {
  142. CHECK_QUOTATION(ct, isquoted);
  143. DETERMINE_NEXTSTRING(ct, isquoted);
  144. if (*ct != '\0') {
  145. ct++;
  146. }
  147. numargs++;
  148. SKIP_WHITESPACE(ct);
  149. }
  150. *argv_out = fspr_palloc(token_context, numargs * sizeof(char*));
  151. /* determine first argument */
  152. for (argnum = 0; argnum < (numargs-1); argnum++) {
  153. SKIP_WHITESPACE(cp);
  154. CHECK_QUOTATION(cp, isquoted);
  155. ct = cp;
  156. DETERMINE_NEXTSTRING(cp, isquoted);
  157. cp++;
  158. (*argv_out)[argnum] = fspr_palloc(token_context, cp - ct);
  159. fspr_cpystrn((*argv_out)[argnum], ct, cp - ct);
  160. cleaned = dirty = (*argv_out)[argnum];
  161. REMOVE_ESCAPE_CHARS(cleaned, dirty, escaped);
  162. }
  163. (*argv_out)[argnum] = NULL;
  164. return APR_SUCCESS;
  165. }
  166. /* Filepath_name_get returns the final element of the pathname.
  167. * Using the current platform's filename syntax.
  168. * "/foo/bar/gum" -> "gum"
  169. * "/foo/bar/gum/" -> ""
  170. * "gum" -> "gum"
  171. * "wi\\n32\\stuff" -> "stuff
  172. *
  173. * Corrected Win32 to accept "a/b\\stuff", "a:stuff"
  174. */
  175. APR_DECLARE(const char *) fspr_filepath_name_get(const char *pathname)
  176. {
  177. const char path_separator = '/';
  178. const char *s = strrchr(pathname, path_separator);
  179. #ifdef WIN32
  180. const char path_separator_win = '\\';
  181. const char drive_separator_win = ':';
  182. const char *s2 = strrchr(pathname, path_separator_win);
  183. if (s2 > s) s = s2;
  184. if (!s) s = strrchr(pathname, drive_separator_win);
  185. #endif
  186. return s ? ++s : pathname;
  187. }
  188. /* length of dest assumed >= length of src
  189. * collapse in place (src == dest) is legal.
  190. * returns terminating null ptr to dest string.
  191. */
  192. APR_DECLARE(char *) fspr_collapse_spaces(char *dest, const char *src)
  193. {
  194. while (*src) {
  195. if (!fspr_isspace(*src))
  196. *dest++ = *src;
  197. ++src;
  198. }
  199. *dest = 0;
  200. return (dest);
  201. }
  202. #if !APR_HAVE_STRDUP
  203. char *strdup(const char *str)
  204. {
  205. char *sdup;
  206. size_t len = strlen(str) + 1;
  207. sdup = (char *) malloc(len);
  208. memcpy(sdup, str, len);
  209. return sdup;
  210. }
  211. #endif
  212. /* The following two routines were donated for SVR4 by Andreas Vogel */
  213. #if (!APR_HAVE_STRCASECMP && !APR_HAVE_STRICMP)
  214. int strcasecmp(const char *a, const char *b)
  215. {
  216. const char *p = a;
  217. const char *q = b;
  218. for (p = a, q = b; *p && *q; p++, q++) {
  219. int diff = fspr_tolower(*p) - fspr_tolower(*q);
  220. if (diff)
  221. return diff;
  222. }
  223. if (*p)
  224. return 1; /* p was longer than q */
  225. if (*q)
  226. return -1; /* p was shorter than q */
  227. return 0; /* Exact match */
  228. }
  229. #endif
  230. #if (!APR_HAVE_STRNCASECMP && !APR_HAVE_STRNICMP)
  231. int strncasecmp(const char *a, const char *b, size_t n)
  232. {
  233. const char *p = a;
  234. const char *q = b;
  235. for (p = a, q = b; /*NOTHING */ ; p++, q++) {
  236. int diff;
  237. if (p == a + n)
  238. return 0; /* Match up to n characters */
  239. if (!(*p && *q))
  240. return *p - *q;
  241. diff = fspr_tolower(*p) - fspr_tolower(*q);
  242. if (diff)
  243. return diff;
  244. }
  245. /*NOTREACHED */
  246. }
  247. #endif
  248. /* The following routine was donated for UTS21 by dwd@bell-labs.com */
  249. #if (!APR_HAVE_STRSTR)
  250. char *strstr(char *s1, char *s2)
  251. {
  252. char *p1, *p2;
  253. if (*s2 == '\0') {
  254. /* an empty s2 */
  255. return(s1);
  256. }
  257. while((s1 = strchr(s1, *s2)) != NULL) {
  258. /* found first character of s2, see if the rest matches */
  259. p1 = s1;
  260. p2 = s2;
  261. while (*++p1 == *++p2) {
  262. if (*p1 == '\0') {
  263. /* both strings ended together */
  264. return(s1);
  265. }
  266. }
  267. if (*p2 == '\0') {
  268. /* second string ended, a match */
  269. break;
  270. }
  271. /* didn't find a match here, try starting at next character in s1 */
  272. s1++;
  273. }
  274. return(s1);
  275. }
  276. #endif