2 * svn_string.h: routines to manipulate counted-length strings
3 * (svn_stringbuf_t and svn_string_t) and C strings.
6 * ====================================================================
7 * Copyright (c) 2000-2008 CollabNet. All rights reserved.
9 * This software is licensed as described in the file COPYING, which
10 * you should have received as part of this distribution. The terms
11 * are also available at http://subversion.tigris.org/license-1.html.
12 * If newer versions of this license are posted there, you may use a
13 * newer version instead, at your option.
15 * This software consists of voluntary contributions made by many
16 * individuals. For exact contribution history, see the revision
17 * history and logs, available at http://subversion.tigris.org/.
18 * ====================================================================
23 #include <string.h> /* for memcpy(), memcmp(), strlen() */
24 #include <apr_lib.h> /* for apr_isspace() */
25 #include <apr_fnmatch.h>
26 #include "svn_string.h" /* loads "svn_types.h" and <apr_pools.h> */
27 #include "svn_ctype.h"
31 /* Our own realloc, since APR doesn't have one. Note: this is a
32 generic realloc for memory pools, *not* for strings. */
34 my__realloc(char *data
, apr_size_t oldsize
, apr_size_t request
,
39 /* kff todo: it's a pity APR doesn't give us this -- sometimes it
40 could realloc the block merely by extending in place, sparing us
41 a memcpy(), but only the pool would know enough to be able to do
42 this. We should add a realloc() to APR if someone hasn't
46 new_area
= apr_palloc(pool
, request
);
48 /* copy data to new area */
49 memcpy(new_area
, data
, oldsize
);
51 /* I'm NOT freeing old area here -- cuz we're using pools, ugh. */
57 static APR_INLINE svn_boolean_t
58 string_compare(const char *str1
,
67 /* now the strings must have identical lenghths */
69 if ((memcmp(str1
, str2
, len1
)) == 0)
75 static APR_INLINE apr_size_t
76 string_first_non_whitespace(const char *str
, apr_size_t len
)
80 for (i
= 0; i
< len
; i
++)
82 if (! apr_isspace(str
[i
]))
86 /* if we get here, then the string must be entirely whitespace */
90 static APR_INLINE apr_size_t
91 find_char_backward(const char *str
, apr_size_t len
, char ch
)
101 /* char was not found, return len */
106 /* svn_string functions */
108 static svn_string_t
*
109 create_string(const char *data
, apr_size_t size
,
112 svn_string_t
*new_string
;
114 new_string
= apr_palloc(pool
, sizeof(*new_string
));
116 new_string
->data
= data
;
117 new_string
->len
= size
;
123 svn_string_ncreate(const char *bytes
, apr_size_t size
, apr_pool_t
*pool
)
127 data
= apr_palloc(pool
, size
+ 1);
128 memcpy(data
, bytes
, size
);
130 /* Null termination is the convention -- even if we suspect the data
131 to be binary, it's not up to us to decide, it's the caller's
132 call. Heck, that's why they call it the caller! */
135 /* wrap an svn_string_t around the new data */
136 return create_string(data
, size
, pool
);
141 svn_string_create(const char *cstring
, apr_pool_t
*pool
)
143 return svn_string_ncreate(cstring
, strlen(cstring
), pool
);
148 svn_string_create_from_buf(const svn_stringbuf_t
*strbuf
, apr_pool_t
*pool
)
150 return svn_string_ncreate(strbuf
->data
, strbuf
->len
, pool
);
155 svn_string_createv(apr_pool_t
*pool
, const char *fmt
, va_list ap
)
157 char *data
= apr_pvsprintf(pool
, fmt
, ap
);
159 /* wrap an svn_string_t around the new data */
160 return create_string(data
, strlen(data
), pool
);
165 svn_string_createf(apr_pool_t
*pool
, const char *fmt
, ...)
171 str
= svn_string_createv(pool
, fmt
, ap
);
179 svn_string_isempty(const svn_string_t
*str
)
181 return (str
->len
== 0);
186 svn_string_dup(const svn_string_t
*original_string
, apr_pool_t
*pool
)
188 return (svn_string_ncreate(original_string
->data
,
189 original_string
->len
, pool
));
195 svn_string_compare(const svn_string_t
*str1
, const svn_string_t
*str2
)
198 string_compare(str1
->data
, str2
->data
, str1
->len
, str2
->len
);
204 svn_string_first_non_whitespace(const svn_string_t
*str
)
207 string_first_non_whitespace(str
->data
, str
->len
);
212 svn_string_find_char_backward(const svn_string_t
*str
, char ch
)
214 return find_char_backward(str
->data
, str
->len
, ch
);
219 /* svn_stringbuf functions */
221 static svn_stringbuf_t
*
222 create_stringbuf(char *data
, apr_size_t size
, apr_size_t blocksize
, apr_pool_t
*pool
)
224 svn_stringbuf_t
*new_string
;
226 new_string
= apr_palloc(pool
, sizeof(*new_string
));
228 new_string
->data
= data
;
229 new_string
->len
= size
;
230 new_string
->blocksize
= blocksize
;
231 new_string
->pool
= pool
;
237 svn_stringbuf_create_ensure(apr_size_t blocksize
, apr_pool_t
*pool
)
239 char *data
= apr_palloc(pool
, ++blocksize
); /* + space for '\0' */
243 /* wrap an svn_stringbuf_t around the new data buffer. */
244 return create_stringbuf(data
, 0, blocksize
, pool
);
248 svn_stringbuf_ncreate(const char *bytes
, apr_size_t size
, apr_pool_t
*pool
)
250 /* Ensure string buffer of size + 1 */
251 svn_stringbuf_t
*strbuf
= svn_stringbuf_create_ensure(size
, pool
);
253 memcpy(strbuf
->data
, bytes
, size
);
255 /* Null termination is the convention -- even if we suspect the data
256 to be binary, it's not up to us to decide, it's the caller's
257 call. Heck, that's why they call it the caller! */
258 strbuf
->data
[size
] = '\0';
266 svn_stringbuf_create(const char *cstring
, apr_pool_t
*pool
)
268 return svn_stringbuf_ncreate(cstring
, strlen(cstring
), pool
);
273 svn_stringbuf_create_from_string(const svn_string_t
*str
, apr_pool_t
*pool
)
275 return svn_stringbuf_ncreate(str
->data
, str
->len
, pool
);
280 svn_stringbuf_createv(apr_pool_t
*pool
, const char *fmt
, va_list ap
)
282 char *data
= apr_pvsprintf(pool
, fmt
, ap
);
283 apr_size_t size
= strlen(data
);
285 /* wrap an svn_stringbuf_t around the new data */
286 return create_stringbuf(data
, size
, size
+ 1, pool
);
291 svn_stringbuf_createf(apr_pool_t
*pool
, const char *fmt
, ...)
293 svn_stringbuf_t
*str
;
297 str
= svn_stringbuf_createv(pool
, fmt
, ap
);
305 svn_stringbuf_fillchar(svn_stringbuf_t
*str
, unsigned char c
)
307 memset(str
->data
, c
, str
->len
);
312 svn_stringbuf_set(svn_stringbuf_t
*str
, const char *value
)
314 apr_size_t amt
= strlen(value
);
316 svn_stringbuf_ensure(str
, amt
+ 1);
317 memcpy(str
->data
, value
, amt
+ 1);
322 svn_stringbuf_setempty(svn_stringbuf_t
*str
)
332 svn_stringbuf_chop(svn_stringbuf_t
*str
, apr_size_t nbytes
)
334 if (nbytes
> str
->len
)
339 str
->data
[str
->len
] = '\0';
344 svn_stringbuf_isempty(const svn_stringbuf_t
*str
)
346 return (str
->len
== 0);
351 svn_stringbuf_ensure(svn_stringbuf_t
*str
, apr_size_t minimum_size
)
353 /* Keep doubling capacity until have enough. */
354 if (str
->blocksize
< minimum_size
)
356 if (str
->blocksize
== 0)
357 str
->blocksize
= minimum_size
;
359 while (str
->blocksize
< minimum_size
)
361 apr_size_t prev_size
= str
->blocksize
;
363 /* check for apr_size_t overflow */
364 if (prev_size
> str
->blocksize
)
366 str
->blocksize
= minimum_size
;
371 str
->data
= (char *) my__realloc(str
->data
,
373 /* We need to maintain (and thus copy)
382 svn_stringbuf_appendbytes(svn_stringbuf_t
*str
, const char *bytes
,
385 apr_size_t total_len
;
388 total_len
= str
->len
+ count
; /* total size needed */
390 /* +1 for null terminator. */
391 svn_stringbuf_ensure(str
, (total_len
+ 1));
393 /* get address 1 byte beyond end of original bytestring */
394 start_address
= (str
->data
+ str
->len
);
396 memcpy(start_address
, bytes
, count
);
397 str
->len
= total_len
;
399 str
->data
[str
->len
] = '\0'; /* We don't know if this is binary
400 data or not, but convention is
401 to null-terminate. */
406 svn_stringbuf_appendstr(svn_stringbuf_t
*targetstr
,
407 const svn_stringbuf_t
*appendstr
)
409 svn_stringbuf_appendbytes(targetstr
, appendstr
->data
, appendstr
->len
);
414 svn_stringbuf_appendcstr(svn_stringbuf_t
*targetstr
, const char *cstr
)
416 svn_stringbuf_appendbytes(targetstr
, cstr
, strlen(cstr
));
421 svn_stringbuf_dup(const svn_stringbuf_t
*original_string
, apr_pool_t
*pool
)
423 return (svn_stringbuf_ncreate(original_string
->data
,
424 original_string
->len
, pool
));
430 svn_stringbuf_compare(const svn_stringbuf_t
*str1
,
431 const svn_stringbuf_t
*str2
)
433 return string_compare(str1
->data
, str2
->data
, str1
->len
, str2
->len
);
439 svn_stringbuf_first_non_whitespace(const svn_stringbuf_t
*str
)
441 return string_first_non_whitespace(str
->data
, str
->len
);
446 svn_stringbuf_strip_whitespace(svn_stringbuf_t
*str
)
448 /* Find first non-whitespace character */
449 apr_size_t offset
= svn_stringbuf_first_non_whitespace(str
);
451 /* Go ahead! Waste some RAM, we've got pools! :) */
454 str
->blocksize
-= offset
;
456 /* Now that we've trimmed the front, trim the end, wasting more RAM. */
457 while ((str
->len
> 0) && apr_isspace(str
->data
[str
->len
- 1]))
459 str
->data
[str
->len
] = '\0';
464 svn_stringbuf_find_char_backward(const svn_stringbuf_t
*str
, char ch
)
466 return find_char_backward(str
->data
, str
->len
, ch
);
471 svn_string_compare_stringbuf(const svn_string_t
*str1
,
472 const svn_stringbuf_t
*str2
)
474 return string_compare(str1
->data
, str2
->data
, str1
->len
, str2
->len
);
479 /*** C string stuff. ***/
482 svn_cstring_split_append(apr_array_header_t
*array
,
484 const char *sep_chars
,
485 svn_boolean_t chop_whitespace
,
492 pats
= apr_pstrdup(pool
, input
); /* strtok wants non-const data */
493 p
= apr_strtok(pats
, sep_chars
, &last
);
499 while (apr_isspace(*p
))
503 char *e
= p
+ (strlen(p
) - 1);
504 while ((e
>= p
) && (apr_isspace(*e
)))
511 APR_ARRAY_PUSH(array
, const char *) = p
;
513 p
= apr_strtok(NULL
, sep_chars
, &last
);
521 svn_cstring_split(const char *input
,
522 const char *sep_chars
,
523 svn_boolean_t chop_whitespace
,
526 apr_array_header_t
*a
= apr_array_make(pool
, 5, sizeof(input
));
527 svn_cstring_split_append(a
, input
, sep_chars
, chop_whitespace
, pool
);
532 svn_boolean_t
svn_cstring_match_glob_list(const char *str
,
533 apr_array_header_t
*list
)
537 for (i
= 0; i
< list
->nelts
; i
++)
539 const char *this_pattern
= APR_ARRAY_IDX(list
, i
, char *);
541 if (apr_fnmatch(this_pattern
, str
, 0) == APR_SUCCESS
)
548 int svn_cstring_count_newlines(const char *msg
)
553 for (p
= msg
; *p
; p
++)
558 if (*(p
+ 1) == '\r')
564 if (*(p
+ 1) == '\n')
573 svn_cstring_join(const apr_array_header_t
*strings
,
574 const char *separator
,
577 svn_stringbuf_t
*new_str
= svn_stringbuf_create("", pool
);
578 int sep_len
= strlen(separator
);
581 for (i
= 0; i
< strings
->nelts
; i
++)
583 const char *string
= APR_ARRAY_IDX(strings
, i
, const char *);
584 svn_stringbuf_appendbytes(new_str
, string
, strlen(string
));
585 svn_stringbuf_appendbytes(new_str
, separator
, sep_len
);
587 return new_str
->data
;
591 svn_cstring_casecmp(const char *str1
, const char *str2
)
595 const int a
= *str1
++;
596 const int b
= *str2
++;
597 const int cmp
= svn_ctype_casecmp(a
, b
);