Remove no-longer-used svn_*_get_mergeinfo_for_tree APIs.
[svn.git] / subversion / libsvn_subr / svn_string.c
blob44ab5b6133f8e14fd020a79f2eb17762a428d3c6
1 /*
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-2007 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_md5.h>
26 #include <apr_fnmatch.h>
27 #include "svn_string.h" /* loads "svn_types.h" and <apr_pools.h> */
28 #include "svn_ctype.h"
32 /* Our own realloc, since APR doesn't have one. Note: this is a
33 generic realloc for memory pools, *not* for strings. */
34 static void *
35 my__realloc(char *data, apr_size_t oldsize, apr_size_t request,
36 apr_pool_t *pool)
38 void *new_area;
40 /* kff todo: it's a pity APR doesn't give us this -- sometimes it
41 could realloc the block merely by extending in place, sparing us
42 a memcpy(), but only the pool would know enough to be able to do
43 this. We should add a realloc() to APR if someone hasn't
44 already. */
46 /* malloc new area */
47 new_area = apr_palloc(pool, request);
49 /* copy data to new area */
50 memcpy(new_area, data, oldsize);
52 /* I'm NOT freeing old area here -- cuz we're using pools, ugh. */
54 /* return new area */
55 return new_area;
58 static APR_INLINE svn_boolean_t
59 string_compare(const char *str1,
60 const char *str2,
61 apr_size_t len1,
62 apr_size_t len2)
64 /* easy way out :) */
65 if (len1 != len2)
66 return FALSE;
68 /* now the strings must have identical lenghths */
70 if ((memcmp(str1, str2, len1)) == 0)
71 return TRUE;
72 else
73 return FALSE;
76 static APR_INLINE apr_size_t
77 string_first_non_whitespace(const char *str, apr_size_t len)
79 apr_size_t i;
81 for (i = 0; i < len; i++)
83 if (! apr_isspace(str[i]))
84 return i;
87 /* if we get here, then the string must be entirely whitespace */
88 return len;
91 static APR_INLINE apr_size_t
92 find_char_backward(const char *str, apr_size_t len, char ch)
94 apr_size_t i = len;
96 while (i != 0)
98 if (str[--i] == ch)
99 return i;
102 /* char was not found, return len */
103 return len;
107 /* svn_string functions */
109 static svn_string_t *
110 create_string(const char *data, apr_size_t size,
111 apr_pool_t *pool)
113 svn_string_t *new_string;
115 new_string = apr_palloc(pool, sizeof(*new_string));
117 new_string->data = data;
118 new_string->len = size;
120 return new_string;
123 svn_string_t *
124 svn_string_ncreate(const char *bytes, apr_size_t size, apr_pool_t *pool)
126 char *data;
128 data = apr_palloc(pool, size + 1);
129 memcpy(data, bytes, size);
131 /* Null termination is the convention -- even if we suspect the data
132 to be binary, it's not up to us to decide, it's the caller's
133 call. Heck, that's why they call it the caller! */
134 data[size] = '\0';
136 /* wrap an svn_string_t around the new data */
137 return create_string(data, size, pool);
141 svn_string_t *
142 svn_string_create(const char *cstring, apr_pool_t *pool)
144 return svn_string_ncreate(cstring, strlen(cstring), pool);
148 svn_string_t *
149 svn_string_create_from_buf(const svn_stringbuf_t *strbuf, apr_pool_t *pool)
151 return svn_string_ncreate(strbuf->data, strbuf->len, pool);
155 svn_string_t *
156 svn_string_createv(apr_pool_t *pool, const char *fmt, va_list ap)
158 char *data = apr_pvsprintf(pool, fmt, ap);
160 /* wrap an svn_string_t around the new data */
161 return create_string(data, strlen(data), pool);
165 svn_string_t *
166 svn_string_createf(apr_pool_t *pool, const char *fmt, ...)
168 svn_string_t *str;
170 va_list ap;
171 va_start(ap, fmt);
172 str = svn_string_createv(pool, fmt, ap);
173 va_end(ap);
175 return str;
179 svn_boolean_t
180 svn_string_isempty(const svn_string_t *str)
182 return (str->len == 0);
186 svn_string_t *
187 svn_string_dup(const svn_string_t *original_string, apr_pool_t *pool)
189 return (svn_string_ncreate(original_string->data,
190 original_string->len, pool));
195 svn_boolean_t
196 svn_string_compare(const svn_string_t *str1, const svn_string_t *str2)
198 return
199 string_compare(str1->data, str2->data, str1->len, str2->len);
204 apr_size_t
205 svn_string_first_non_whitespace(const svn_string_t *str)
207 return
208 string_first_non_whitespace(str->data, str->len);
212 apr_size_t
213 svn_string_find_char_backward(const svn_string_t *str, char ch)
215 return find_char_backward(str->data, str->len, ch);
220 /* svn_stringbuf functions */
222 static svn_stringbuf_t *
223 create_stringbuf(char *data, apr_size_t size, apr_pool_t *pool)
225 svn_stringbuf_t *new_string;
227 new_string = apr_palloc(pool, sizeof(*new_string));
229 new_string->data = data;
230 new_string->len = size;
231 new_string->blocksize = size + 1; /* we know there is a null-term */
232 new_string->pool = pool;
234 return new_string;
237 svn_stringbuf_t *
238 svn_stringbuf_ncreate(const char *bytes, apr_size_t size, apr_pool_t *pool)
240 char *data;
242 data = apr_palloc(pool, size + 1);
243 memcpy(data, bytes, size);
245 /* Null termination is the convention -- even if we suspect the data
246 to be binary, it's not up to us to decide, it's the caller's
247 call. Heck, that's why they call it the caller! */
248 data[size] = '\0';
250 /* wrap an svn_stringbuf_t around the new data */
251 return create_stringbuf(data, size, pool);
255 svn_stringbuf_t *
256 svn_stringbuf_create(const char *cstring, apr_pool_t *pool)
258 return svn_stringbuf_ncreate(cstring, strlen(cstring), pool);
262 svn_stringbuf_t *
263 svn_stringbuf_create_from_string(const svn_string_t *str, apr_pool_t *pool)
265 return svn_stringbuf_ncreate(str->data, str->len, pool);
269 svn_stringbuf_t *
270 svn_stringbuf_createv(apr_pool_t *pool, const char *fmt, va_list ap)
272 char *data = apr_pvsprintf(pool, fmt, ap);
274 /* wrap an svn_stringbuf_t around the new data */
275 return create_stringbuf(data, strlen(data), pool);
279 svn_stringbuf_t *
280 svn_stringbuf_createf(apr_pool_t *pool, const char *fmt, ...)
282 svn_stringbuf_t *str;
284 va_list ap;
285 va_start(ap, fmt);
286 str = svn_stringbuf_createv(pool, fmt, ap);
287 va_end(ap);
289 return str;
293 void
294 svn_stringbuf_fillchar(svn_stringbuf_t *str, unsigned char c)
296 memset(str->data, c, str->len);
300 void
301 svn_stringbuf_set(svn_stringbuf_t *str, const char *value)
303 apr_size_t amt = strlen(value);
305 svn_stringbuf_ensure(str, amt + 1);
306 memcpy(str->data, value, amt + 1);
307 str->len = amt;
310 void
311 svn_stringbuf_setempty(svn_stringbuf_t *str)
313 if (str->len > 0)
314 str->data[0] = '\0';
316 str->len = 0;
320 void
321 svn_stringbuf_chop(svn_stringbuf_t *str, apr_size_t nbytes)
323 if (nbytes > str->len)
324 str->len = 0;
325 else
326 str->len -= nbytes;
328 str->data[str->len] = '\0';
332 svn_boolean_t
333 svn_stringbuf_isempty(const svn_stringbuf_t *str)
335 return (str->len == 0);
339 void
340 svn_stringbuf_ensure(svn_stringbuf_t *str, apr_size_t minimum_size)
342 /* Keep doubling capacity until have enough. */
343 if (str->blocksize < minimum_size)
345 if (str->blocksize == 0)
346 str->blocksize = minimum_size;
347 else
348 while (str->blocksize < minimum_size)
350 apr_size_t prev_size = str->blocksize;
351 str->blocksize *= 2;
352 /* check for apr_size_t overflow */
353 if (prev_size > str->blocksize)
355 str->blocksize = minimum_size;
356 break;
360 str->data = (char *) my__realloc(str->data,
361 str->len + 1,
362 /* We need to maintain (and thus copy)
363 the trailing nul */
364 str->blocksize,
365 str->pool);
370 void
371 svn_stringbuf_appendbytes(svn_stringbuf_t *str, const char *bytes,
372 apr_size_t count)
374 apr_size_t total_len;
375 void *start_address;
377 total_len = str->len + count; /* total size needed */
379 /* +1 for null terminator. */
380 svn_stringbuf_ensure(str, (total_len + 1));
382 /* get address 1 byte beyond end of original bytestring */
383 start_address = (str->data + str->len);
385 memcpy(start_address, bytes, count);
386 str->len = total_len;
388 str->data[str->len] = '\0'; /* We don't know if this is binary
389 data or not, but convention is
390 to null-terminate. */
394 void
395 svn_stringbuf_appendstr(svn_stringbuf_t *targetstr,
396 const svn_stringbuf_t *appendstr)
398 svn_stringbuf_appendbytes(targetstr, appendstr->data, appendstr->len);
402 void
403 svn_stringbuf_appendcstr(svn_stringbuf_t *targetstr, const char *cstr)
405 svn_stringbuf_appendbytes(targetstr, cstr, strlen(cstr));
411 svn_stringbuf_t *
412 svn_stringbuf_dup(const svn_stringbuf_t *original_string, apr_pool_t *pool)
414 return (svn_stringbuf_ncreate(original_string->data,
415 original_string->len, pool));
420 svn_boolean_t
421 svn_stringbuf_compare(const svn_stringbuf_t *str1,
422 const svn_stringbuf_t *str2)
424 return string_compare(str1->data, str2->data, str1->len, str2->len);
429 apr_size_t
430 svn_stringbuf_first_non_whitespace(const svn_stringbuf_t *str)
432 return string_first_non_whitespace(str->data, str->len);
436 void
437 svn_stringbuf_strip_whitespace(svn_stringbuf_t *str)
439 /* Find first non-whitespace character */
440 apr_size_t offset = svn_stringbuf_first_non_whitespace(str);
442 /* Go ahead! Waste some RAM, we've got pools! :) */
443 str->data += offset;
444 str->len -= offset;
445 str->blocksize -= offset;
447 /* Now that we've trimmed the front, trim the end, wasting more RAM. */
448 while ((str->len > 0) && apr_isspace(str->data[str->len - 1]))
449 str->len--;
450 str->data[str->len] = '\0';
454 apr_size_t
455 svn_stringbuf_find_char_backward(const svn_stringbuf_t *str, char ch)
457 return find_char_backward(str->data, str->len, ch);
461 svn_boolean_t
462 svn_string_compare_stringbuf(const svn_string_t *str1,
463 const svn_stringbuf_t *str2)
465 return string_compare(str1->data, str2->data, str1->len, str2->len);
470 /*** C string stuff. ***/
472 void
473 svn_cstring_split_append(apr_array_header_t *array,
474 const char *input,
475 const char *sep_chars,
476 svn_boolean_t chop_whitespace,
477 apr_pool_t *pool)
479 char *last;
480 char *pats;
481 char *p;
483 pats = apr_pstrdup(pool, input); /* strtok wants non-const data */
484 p = apr_strtok(pats, sep_chars, &last);
486 while (p)
488 if (chop_whitespace)
490 while (apr_isspace(*p))
491 p++;
494 char *e = p + (strlen(p) - 1);
495 while ((e >= p) && (apr_isspace(*e)))
496 e--;
497 *(++e) = '\0';
501 if (p[0] != '\0')
502 APR_ARRAY_PUSH(array, const char *) = p;
504 p = apr_strtok(NULL, sep_chars, &last);
507 return;
511 apr_array_header_t *
512 svn_cstring_split(const char *input,
513 const char *sep_chars,
514 svn_boolean_t chop_whitespace,
515 apr_pool_t *pool)
517 apr_array_header_t *a = apr_array_make(pool, 5, sizeof(input));
518 svn_cstring_split_append(a, input, sep_chars, chop_whitespace, pool);
519 return a;
523 svn_boolean_t svn_cstring_match_glob_list(const char *str,
524 apr_array_header_t *list)
526 int i;
528 for (i = 0; i < list->nelts; i++)
530 const char *this_pattern = APR_ARRAY_IDX(list, i, char *);
532 if (apr_fnmatch(this_pattern, str, 0) == APR_SUCCESS)
533 return TRUE;
536 return FALSE;
539 int svn_cstring_count_newlines(const char *msg)
541 int count = 0;
542 const char *p;
544 for (p = msg; *p; p++)
546 if (*p == '\n')
548 count++;
549 if (*(p + 1) == '\r')
550 p++;
552 else if (*p == '\r')
554 count++;
555 if (*(p + 1) == '\n')
556 p++;
560 return count;
563 char *
564 svn_cstring_join(apr_array_header_t *strings,
565 const char *separator,
566 apr_pool_t *pool)
568 svn_stringbuf_t *new_str = svn_stringbuf_create("", pool);
569 int sep_len = strlen(separator);
570 int i;
572 for (i = 0; i < strings->nelts; i++)
574 const char *string = APR_ARRAY_IDX(strings, i, const char *);
575 svn_stringbuf_appendbytes(new_str, string, strlen(string));
576 svn_stringbuf_appendbytes(new_str, separator, sep_len);
578 return new_str->data;
582 svn_cstring_casecmp(const char *str1, const char *str2)
584 for (;;)
586 const int a = *str1++;
587 const int b = *str2++;
588 const int cmp = svn_ctype_casecmp(a, b);
589 if (cmp || !a || !b)
590 return cmp;