2 * svn17_compat.c : a library to make Subversion 1.6 look like 1.7.
4 * ====================================================================
5 * This file is derived from code licensed to the Apache
6 * Software Foundation (ASF) under one or more contributor
7 * license agreements. See the NOTICE file distributed with
8 * this file for additional information regarding copyright
9 * ownership. The ASF licenses those portions to you under
10 * the Apache License, Version 2.0 (the "License"); you may
11 * not use those portions except in compliance with the
12 * License. You may obtain a copy of the License at
14 * http://www.apache.org/licenses/LICENSE-2.0
16 * Unless required by applicable law or agreed to in writing,
17 * software distributed under the License is distributed on an
18 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
19 * KIND, either express or implied. See the License for the
20 * specific language governing permissions and limitations
23 * Any code in this file not licensed from the ASF is
24 * original code in the public domain. You may freely use,
25 * modify, distribute, and relicense such code.
26 * ====================================================================
34 #include <apr_strings.h>
37 #include <apr_errno.h>
38 #include <apr_pools.h>
40 #include <svn_error.h>
41 #include <svn_config.h>
43 #include <svn_dirent_uri.h>
45 #include <svn_ctype.h>
46 #include "svn17_compat.h"
48 /* TRUE if s is the canonical empty path, FALSE otherwise
49 From libsvn_subr/dirent_uri.c. */
50 #define SVN_PATH_IS_EMPTY(s) ((s)[0] == '\0')
52 /* Path type definition. Used only by internal functions.
53 From libsvn_subr/dirent_uri.c. */
60 /* Here is the BNF for path components in a URI. "pchar" is a
61 character in a path component.
63 pchar = unreserved | escaped |
64 ":" | "@" | "&" | "=" | "+" | "$" | ","
65 unreserved = alphanum | mark
66 mark = "-" | "_" | "." | "!" | "~" | "*" | "'" | "(" | ")"
68 Note that "escaped" doesn't really apply to what users can put in
69 their paths, so that really means the set of characters is:
71 alphanum | mark | ":" | "@" | "&" | "=" | "+" | "$" | ","
73 From libsvn_subr/path.c. */
74 static const char svn_uri__char_validity
[256] = {
75 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
76 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
77 0, 1, 0, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
78 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 0, 0,
81 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
82 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1,
83 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
84 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 0,
87 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
88 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
89 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
90 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
93 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
94 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
95 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
96 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
99 /* From libsvn_subr/dirent_uri.c. */
101 svn_uri_is_canonical(const char *uri
, apr_pool_t
*pool
)
103 const char *ptr
= uri
, *seg
= uri
;
104 const char *schema_data
= NULL
;
106 /* URI is canonical if it has:
108 * - no closing '/', unless for the root path '/' itself
110 * - lowercase URL scheme
111 * - lowercase URL hostname
117 /* Maybe parse hostname and scheme. */
120 while (*ptr
&& (*ptr
!= '/') && (*ptr
!= ':'))
123 if (*ptr
== ':' && *(ptr
+1) == '/' && *(ptr
+2) == '/')
125 /* Found a scheme, check that it's all lowercase. */
129 if (*ptr
>= 'A' && *ptr
<= 'Z')
136 /* This might be the hostname */
138 while (*ptr
&& (*ptr
!= '/') && (*ptr
!= '@'))
147 /* Found a hostname, check that it's all lowercase. */
149 while (*ptr
&& *ptr
!= '/')
151 if (*ptr
>= 'A' && *ptr
<= 'Z')
160 /* Didn't find a scheme; finish the segment. */
161 while (*ptr
&& *ptr
!= '/')
166 #ifdef SVN_USE_DOS_PATHS
167 if (schema_data
&& *ptr
== '/')
169 /* If this is a file url, ptr now points to the third '/' in
170 file:///C:/path. Check that if we have such a URL the drive
171 letter is in uppercase. */
172 if (strncmp(uri
, "file:", 5) == 0 &&
173 ! (*(ptr
+1) >= 'A' && *(ptr
+1) <= 'Z') &&
177 #endif /* SVN_USE_DOS_PATHS */
179 /* Now validate the rest of the URI. */
182 apr_size_t seglen
= ptr
- seg
;
184 if (seglen
== 1 && *seg
== '.')
185 return FALSE
; /* /./ */
187 if (*ptr
== '/' && *(ptr
+1) == '/')
188 return FALSE
; /* // */
190 if (! *ptr
&& *(ptr
- 1) == '/' && ptr
- 1 != uri
)
191 return FALSE
; /* foo/ */
201 while (*ptr
&& (*ptr
!= '/'))
216 /* Can't use svn_ctype_isxdigit() because lower case letters are
217 not in our canonical format */
218 if (((*(ptr
+1) < '0' || *(ptr
+1) > '9'))
219 && (*(ptr
+1) < 'A' || *(ptr
+1) > 'F'))
221 else if (((*(ptr
+2) < '0' || *(ptr
+2) > '9'))
222 && (*(ptr
+2) < 'A' || *(ptr
+2) > 'F'))
225 digitz
[0] = *(++ptr
);
226 digitz
[1] = *(++ptr
);
228 val
= (int)strtol(digitz
, NULL
, 16);
230 if (svn_uri__char_validity
[val
])
231 return FALSE
; /* Should not have been escaped */
233 else if (*ptr
!= '/' && !svn_uri__char_validity
[(unsigned char)*ptr
])
234 return FALSE
; /* Character should have been escaped */
242 /* From libsvn_subr/dirent_uri.c. */
244 svn_uri_is_absolute(const char *uri
)
246 /* uri is absolute if it starts with '/' */
247 if (uri
&& uri
[0] == '/')
250 /* URLs are absolute. */
251 return svn_path_is_url(uri
);
254 /* Calculates the length occupied by the schema defined root of URI
255 From libsvn_subr/dirent_uri.c. */
257 uri_schema_root_length(const char *uri
, apr_size_t len
)
261 for (i
= 0; i
< len
; i
++)
265 if (i
> 0 && uri
[i
-1] == ':' && i
< len
-1 && uri
[i
+1] == '/')
267 /* We have an absolute uri */
268 if (i
== 5 && strncmp("file", uri
, 4) == 0)
269 return 7; /* file:// */
272 for (i
+= 2; i
< len
; i
++)
276 return len
; /* Only a hostname is found */
287 /* From libsvn_subr/dirent_uri.c. */
289 svn_uri_join(const char *base
, const char *component
, apr_pool_t
*pool
)
291 apr_size_t blen
= strlen(base
);
292 apr_size_t clen
= strlen(component
);
295 assert(svn_uri_is_canonical(base
, pool
));
296 assert(svn_uri_is_canonical(component
, pool
));
298 /* If either is empty return the other */
299 if (SVN_PATH_IS_EMPTY(base
))
300 return apr_pmemdup(pool
, component
, clen
+ 1);
301 if (SVN_PATH_IS_EMPTY(component
))
302 return apr_pmemdup(pool
, base
, blen
+ 1);
304 /* If the component is absolute, then return it. */
305 if (svn_uri_is_absolute(component
))
307 if (*component
!= '/')
308 return apr_pmemdup(pool
, component
, clen
+ 1);
311 /* The uri is not absolute enough; use only the root from base */
312 apr_size_t n
= uri_schema_root_length(base
, blen
);
314 path
= apr_palloc(pool
, n
+ clen
+ 1);
317 memcpy(path
, base
, n
);
319 memcpy(path
+ n
, component
, clen
+ 1); /* Include '\0' */
325 if (blen
== 1 && base
[0] == '/')
326 blen
= 0; /* Ignore base, just return separator + component */
328 /* Construct the new, combined path. */
329 path
= apr_palloc(pool
, blen
+ 1 + clen
+ 1);
330 memcpy(path
, base
, blen
);
332 memcpy(path
+ blen
+ 1, component
, clen
+ 1);
337 /* From libsvn_subr/dirent_uri.c. */
339 svn_relpath_is_canonical(const char *relpath
,
342 const char *ptr
= relpath
, *seg
= relpath
;
344 /* RELPATH is canonical if it has:
346 * - no start and closing '/'
350 if (*relpath
== '\0')
356 /* Now validate the rest of the path. */
359 apr_size_t seglen
= ptr
- seg
;
361 if (seglen
== 1 && *seg
== '.')
362 return FALSE
; /* /./ */
364 if (*ptr
== '/' && *(ptr
+1) == '/')
365 return FALSE
; /* // */
367 if (! *ptr
&& *(ptr
- 1) == '/')
368 return FALSE
; /* foo/ */
377 while (*ptr
&& (*ptr
!= '/'))
384 /* From libsvn_subr/dirent_uri.c. */
386 svn_relpath_basename(const char *relpath
,
389 apr_size_t len
= strlen(relpath
);
392 assert(!pool
|| svn_relpath_is_canonical(relpath
, pool
));
395 while (start
> 0 && relpath
[start
- 1] != '/')
399 return apr_pstrmemdup(pool
, relpath
+ start
, len
- start
);
401 return relpath
+ start
;
404 /* Return the length of substring necessary to encompass the entire
405 * previous relpath segment in RELPATH, which should be a LEN byte string.
407 * A trailing slash will not be included in the returned length.
408 * From libsvn_subr/dirent_uri.c.
411 relpath_previous_segment(const char *relpath
,
418 while (len
> 0 && relpath
[len
] != '/')
424 /* From libsvn_subr/dirent_uri.c. */
426 svn_relpath_dirname(const char *relpath
,
429 apr_size_t len
= strlen(relpath
);
431 assert(svn_relpath_is_canonical(relpath
, pool
));
433 return apr_pstrmemdup(pool
, relpath
,
434 relpath_previous_segment(relpath
, len
));
437 /* From libsvn_subr/dirent_uri.c. */
439 svn_dirent_basename(const char *dirent
, apr_pool_t
*pool
)
441 apr_size_t len
= strlen(dirent
);
444 assert(!pool
|| svn_dirent_is_canonical(dirent
, pool
));
446 if (svn_dirent_is_root(dirent
, len
))
451 while (start
> 0 && dirent
[start
- 1] != '/'
452 #ifdef SVN_USE_DOS_PATHS
453 && dirent
[start
- 1] != ':'
460 return apr_pstrmemdup(pool
, dirent
+ start
, len
- start
);
462 return dirent
+ start
;
465 /* Return the string length of the longest common ancestor of PATH1 and PATH2.
466 * Pass type_uri for TYPE if PATH1 and PATH2 are URIs, and type_dirent if
467 * PATH1 and PATH2 are regular paths.
469 * If the two paths do not share a common ancestor, return 0.
471 * New strings are allocated in POOL.
472 * From libsvn_subr/dirent_uri.c.
475 get_longest_ancestor_length(path_type_t types
,
480 apr_size_t path1_len
, path2_len
;
482 apr_size_t last_dirsep
= 0;
483 #ifdef SVN_USE_DOS_PATHS
484 svn_boolean_t unc
= FALSE
;
487 path1_len
= strlen(path1
);
488 path2_len
= strlen(path2
);
490 if (SVN_PATH_IS_EMPTY(path1
) || SVN_PATH_IS_EMPTY(path2
))
493 while (path1
[i
] == path2
[i
])
495 /* Keep track of the last directory separator we hit. */
501 /* If we get to the end of either path, break out. */
502 if ((i
== path1_len
) || (i
== path2_len
))
506 /* two special cases:
507 1. '/' is the longest common ancestor of '/' and '/foo' */
508 if (i
== 1 && path1
[0] == '/' && path2
[0] == '/')
510 /* 2. '' is the longest common ancestor of any non-matching
511 * strings 'foo' and 'bar' */
512 if (types
== type_dirent
&& i
== 0)
515 /* Handle some windows specific cases */
516 #ifdef SVN_USE_DOS_PATHS
517 if (types
== type_dirent
)
519 /* don't count the '//' from UNC paths */
520 if (last_dirsep
== 1 && path1
[0] == '/' && path1
[1] == '/')
527 if (i
== 3 && path1
[2] == '/' && path1
[1] == ':')
530 /* Cannot use SVN_ERR_ASSERT here, so we'll have to crash, sorry.
531 * Note that this assertion triggers only if the code above has
532 * been broken. The code below relies on this assertion, because
533 * it uses [i - 1] as index. */
537 if ((path1
[i
- 1] == ':' && path2
[i
] == '/') ||
538 (path2
[i
- 1] == ':' && path1
[i
] == '/'))
541 if (path1
[i
- 1] == ':' || path2
[i
- 1] == ':')
544 #endif /* SVN_USE_DOS_PATHS */
546 /* last_dirsep is now the offset of the last directory separator we
547 crossed before reaching a non-matching byte. i is the offset of
548 that non-matching byte, and is guaranteed to be <= the length of
549 whichever path is shorter.
550 If one of the paths is the common part return that. */
551 if (((i
== path1_len
) && (path2
[i
] == '/'))
552 || ((i
== path2_len
) && (path1
[i
] == '/'))
553 || ((i
== path1_len
) && (i
== path2_len
)))
557 /* Nothing in common but the root folder '/' or 'X:/' for Windows
559 #ifdef SVN_USE_DOS_PATHS
562 /* X:/foo and X:/bar returns X:/ */
563 if ((types
== type_dirent
) &&
564 last_dirsep
== 2 && path1
[1] == ':' && path1
[2] == '/'
565 && path2
[1] == ':' && path2
[2] == '/')
567 #endif /* SVN_USE_DOS_PATHS */
568 if (last_dirsep
== 0 && path1
[0] == '/' && path2
[0] == '/')
570 #ifdef SVN_USE_DOS_PATHS
578 /* From libsvn_subr/dirent_uri.c. */
580 svn_relpath_get_longest_ancestor(const char *relpath1
,
581 const char *relpath2
,
584 return apr_pstrndup(pool
, relpath1
,
585 get_longest_ancestor_length(type_relpath
, relpath1
,
589 /* From libsvn_subr/dirent_uri.c. */
591 svn_relpath_skip_ancestor(const char *parent_relpath
,
592 const char *child_relpath
)
594 apr_size_t len
= strlen(parent_relpath
);
596 if (0 != memcmp(parent_relpath
, child_relpath
, len
))
597 return child_relpath
; /* parent_relpath is no ancestor of child_relpath */
599 if (child_relpath
[len
] == 0)
600 return ""; /* parent_relpath == child_relpath */
602 if (len
== 1 && child_relpath
[0] == '/')
603 return child_relpath
+ 1;
605 if (child_relpath
[len
] == '/')
606 return child_relpath
+ len
+ 1;
608 return child_relpath
;
611 /* From libsvn_subr/dirent_uri.c. */
613 svn_relpath_join(const char *base
,
614 const char *component
,
617 apr_size_t blen
= strlen(base
);
618 apr_size_t clen
= strlen(component
);
621 assert(svn_relpath_is_canonical(base
, pool
));
622 assert(svn_relpath_is_canonical(component
, pool
));
624 /* If either is empty return the other */
626 return apr_pmemdup(pool
, component
, clen
+ 1);
628 return apr_pmemdup(pool
, base
, blen
+ 1);
630 path
= apr_palloc(pool
, blen
+ 1 + clen
+ 1);
631 memcpy(path
, base
, blen
);
633 memcpy(path
+ blen
+ 1, component
, clen
+ 1);
638 /* Locale insensitive tolower() for converting parts of dirents and urls
639 while canonicalizing. From libsvn_subr/dirent_uri.c. */
641 canonicalize_to_lower(char c
)
643 if (c
< 'A' || c
> 'Z')
646 return c
- 'A' + 'a';
649 /* Locale insensitive toupper() for converting parts of dirents and urls
650 while canonicalizing. From libsvn_subr/dirent_uri.c. */
652 canonicalize_to_upper(char c
)
654 if (c
< 'a' || c
> 'z')
657 return c
- 'a' + 'A';
661 /* Return the canonicalized version of PATH, of type TYPE, allocated in
662 * POOL. From libsvn_subr/dirent_uri.c.
665 canonicalize(path_type_t type
, const char *path
, apr_pool_t
*pool
)
670 apr_size_t schemelen
= 0;
671 apr_size_t canon_segments
= 0;
672 svn_boolean_t url
= FALSE
;
673 char *schema_data
= NULL
;
675 /* "" is already canonical, so just return it; note that later code
676 depends on path not being zero-length. */
677 if (SVN_PATH_IS_EMPTY(path
))
680 dst
= canon
= apr_pcalloc(pool
, strlen(path
) + 1);
682 /* If this is supposed to be an URI and it starts with "scheme://", then
683 copy the scheme, host name, etc. to DST and set URL = TRUE. */
685 if (type
== type_uri
&& *src
!= '/')
687 while (*src
&& (*src
!= '/') && (*src
!= ':'))
690 if (*src
== ':' && *(src
+1) == '/' && *(src
+2) == '/')
696 /* Found a scheme, convert to lowercase and copy to dst. */
700 *(dst
++) = canonicalize_to_lower((*src
++));
709 /* This might be the hostname */
711 while (*src
&& (*src
!= '/') && (*src
!= '@'))
716 /* Copy the username & password. */
717 seglen
= src
- seg
+ 1;
718 memcpy(dst
, seg
, seglen
);
725 /* Found a hostname, convert to lowercase and copy to dst. */
726 while (*src
&& (*src
!= '/'))
727 *(dst
++) = canonicalize_to_lower((*src
++));
729 /* Copy trailing slash, or null-terminator. */
732 /* Move src and dst forward only if we are not
733 * at null-terminator yet. */
745 /* Copy to DST any separator or drive letter that must come before the
746 first regular path segment. */
747 if (! url
&& type
!= type_relpath
)
750 /* If this is an absolute path, then just copy over the initial
751 separator character. */
756 #ifdef SVN_USE_DOS_PATHS
757 /* On Windows permit two leading separator characters which means an
759 if ((type
== type_dirent
) && *src
== '/')
761 #endif /* SVN_USE_DOS_PATHS */
763 #ifdef SVN_USE_DOS_PATHS
764 /* On Windows the first segment can be a drive letter, which we normalize
766 else if (type
== type_dirent
&&
767 ((*src
>= 'a' && *src
<= 'z') ||
768 (*src
>= 'A' && *src
<= 'Z')) &&
771 *(dst
++) = canonicalize_to_upper(*(src
++));
772 /* Leave the ':' to be processed as (or as part of) a path segment
773 by the following code block, so we need not care whether it has
776 #endif /* SVN_USE_DOS_PATHS */
781 /* Parse each segment, find the closing '/' */
782 const char *next
= src
;
783 while (*next
&& (*next
!= '/'))
788 if (seglen
== 0 || (seglen
== 1 && src
[0] == '.'))
790 /* Noop segment, so do nothing. */
792 #ifdef SVN_USE_DOS_PATHS
793 /* If this is the first path segment of a file:// URI and it contains a
794 windows drive letter, convert the drive letter to upper case. */
795 else if (url
&& canon_segments
== 1 && seglen
== 2 &&
796 (strncmp(canon
, "file:", 5) == 0) &&
797 src
[0] >= 'a' && src
[0] <= 'z' && src
[1] == ':')
799 *(dst
++) = canonicalize_to_upper(src
[0]);
805 #endif /* SVN_USE_DOS_PATHS */
808 /* An actual segment, append it to the destination path */
811 memcpy(dst
, src
, seglen
);
816 /* Skip over trailing slash to the next segment. */
822 /* Remove the trailing slash if there was at least one
823 * canonical segment and the last segment ends with a slash.
825 * But keep in mind that, for URLs, the scheme counts as a
826 * canonical segment -- so if path is ONLY a scheme (such
827 * as "https://") we should NOT remove the trailing slash. */
828 if ((canon_segments
> 0 && *(dst
- 1) == '/')
829 && ! (url
&& path
[schemelen
] == '\0'))
836 #ifdef SVN_USE_DOS_PATHS
837 /* Skip leading double slashes when there are less than 2
838 * canon segments. UNC paths *MUST* have two segments. */
839 if ((type
== type_dirent
) && canon
[0] == '/' && canon
[1] == '/')
841 if (canon_segments
< 2)
845 /* Now we're sure this is a valid UNC path, convert the server name
846 (the first path segment) to lowercase as Windows treats it as case
848 Note: normally the share name is treated as case insensitive too,
849 but it seems to be possible to configure Samba to treat those as
850 case sensitive, so better leave that alone. */
852 while (*dst
&& *dst
!= '/')
853 *(dst
++) = canonicalize_to_lower(*dst
);
856 #endif /* SVN_USE_DOS_PATHS */
858 /* Check the normalization of characters in a uri */
871 if (!svn_ctype_isxdigit(*(src
+1)) ||
872 !svn_ctype_isxdigit(*(src
+2)))
878 if (!svn_uri__char_validity
[(unsigned char)*src
])
887 apr_size_t pre_schema_size
= (apr_size_t
)(schema_data
- canon
);
889 dst
= apr_palloc(pool
, (apr_size_t
)(src
- canon
) + need_extra
+ 1);
890 memcpy(dst
, canon
, pre_schema_size
);
893 dst
+= pre_schema_size
;
908 if (!svn_ctype_isxdigit(*(src
+1)) ||
909 !svn_ctype_isxdigit(*(src
+2)))
920 digitz
[0] = *(++src
);
921 digitz
[1] = *(++src
);
924 val
= (int)strtol(digitz
, NULL
, 16);
926 if (svn_uri__char_validity
[(unsigned char)val
])
927 *(dst
++) = (char)val
;
931 *(dst
++) = canonicalize_to_upper(digitz
[0]);
932 *(dst
++) = canonicalize_to_upper(digitz
[1]);
937 if (!svn_uri__char_validity
[(unsigned char)*src
])
939 apr_snprintf(dst
, 4, "%%%02X", (unsigned char)*src
);
954 /* From libsvn_subr/dirent_uri.c. */
956 svn_uri_canonicalize(const char *uri
, apr_pool_t
*pool
)
958 return canonicalize(type_uri
, uri
, pool
);
961 /* From libsvn_subr/dirent_uri.c. */
963 svn_relpath_canonicalize(const char *relpath
, apr_pool_t
*pool
)
965 return canonicalize(type_relpath
, relpath
, pool
);
968 /* New code (public domain). */
970 svn_io_remove_file2(const char *path
,
971 svn_boolean_t ignore_enoent
,
972 apr_pool_t
*scratch_pool
)
974 svn_error_t
*err
= svn_io_remove_file(path
, scratch_pool
);
975 if (ignore_enoent
&& err
&& APR_STATUS_IS_ENOENT(err
->apr_err
))
977 svn_error_clear(err
);
983 /* Note about the type casts: apr_hash_this() does not expect a const hash
984 * index pointer even though it does not modify the hash index. In
985 * Subversion we're trying to be const-correct, so these functions all take
986 * a const hash index and we cast away the const when passing it down to
987 * APR. (A compiler may warn about casting away 'const', but at least this
988 * cast is explicit and gathered in one place.)
990 * From libsvn_subr/iter.c. */
991 const void *svn__apr_hash_index_key(const apr_hash_index_t
*hi
)
995 apr_hash_this((apr_hash_index_t
*)hi
, &key
, NULL
, NULL
);
999 void *svn__apr_hash_index_val(const apr_hash_index_t
*hi
)
1003 apr_hash_this((apr_hash_index_t
*)hi
, NULL
, NULL
, &val
);
1008 /* From libsvn_subr/cmdline.c. */
1010 svn_cmdline__apply_config_options(apr_hash_t
*config
,
1011 const apr_array_header_t
*config_options
,
1013 const char *argument_name
)
1017 for (i
= 0; i
< config_options
->nelts
; i
++)
1020 svn_cmdline__config_argument_t
*arg
=
1021 APR_ARRAY_IDX(config_options
, i
,
1022 svn_cmdline__config_argument_t
*);
1024 cfg
= apr_hash_get(config
, arg
->file
, APR_HASH_KEY_STRING
);
1028 svn_config_set(cfg
, arg
->section
, arg
->option
, arg
->value
);
1032 svn_error_t
*err
= svn_error_createf(SVN_ERR_CL_ARG_PARSING_ERROR
, NULL
,
1033 _("Unrecognized file in argument of %s"), argument_name
);
1035 svn_handle_warning2(stderr
, err
, prefix
);
1036 svn_error_clear(err
);
1040 return SVN_NO_ERROR
;
1043 /* From libsvn_subr/cmdline.c. */
1045 svn_cmdline__parse_config_option(apr_array_header_t
*config_options
,
1046 const char *opt_arg
,
1049 svn_cmdline__config_argument_t
*config_option
;
1050 const char *first_colon
, *second_colon
, *equals_sign
;
1051 apr_size_t len
= strlen(opt_arg
);
1052 if ((first_colon
= strchr(opt_arg
, ':')) && (first_colon
!= opt_arg
))
1054 if ((second_colon
= strchr(first_colon
+ 1, ':')) &&
1055 (second_colon
!= first_colon
+ 1))
1057 if ((equals_sign
= strchr(second_colon
+ 1, '=')) &&
1058 (equals_sign
!= second_colon
+ 1))
1060 config_option
= apr_pcalloc(pool
, sizeof(*config_option
));
1061 config_option
->file
= apr_pstrndup(pool
, opt_arg
,
1062 first_colon
- opt_arg
);
1063 config_option
->section
= apr_pstrndup(pool
, first_colon
+ 1,
1064 second_colon
- first_colon
- 1);
1065 config_option
->option
= apr_pstrndup(pool
, second_colon
+ 1,
1066 equals_sign
- second_colon
- 1);
1068 if (! (strchr(config_option
->option
, ':')))
1070 config_option
->value
= apr_pstrndup(pool
, equals_sign
+ 1,
1071 opt_arg
+ len
- equals_sign
- 1);
1072 APR_ARRAY_PUSH(config_options
, svn_cmdline__config_argument_t
*)
1074 return SVN_NO_ERROR
;
1079 return svn_error_create(SVN_ERR_CL_ARG_PARSING_ERROR
, NULL
,
1080 _("Invalid syntax of argument of --config-option"));