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 "svn17_compat.h"
47 /* TRUE if s is the canonical empty path, FALSE otherwise
48 From libsvn_subr/dirent_uri.c. */
49 #define SVN_PATH_IS_EMPTY(s) ((s)[0] == '\0')
51 /* Path type definition. Used only by internal functions.
52 From libsvn_subr/dirent_uri.c. */
59 /* Here is the BNF for path components in a URI. "pchar" is a
60 character in a path component.
62 pchar = unreserved | escaped |
63 ":" | "@" | "&" | "=" | "+" | "$" | ","
64 unreserved = alphanum | mark
65 mark = "-" | "_" | "." | "!" | "~" | "*" | "'" | "(" | ")"
67 Note that "escaped" doesn't really apply to what users can put in
68 their paths, so that really means the set of characters is:
70 alphanum | mark | ":" | "@" | "&" | "=" | "+" | "$" | ","
72 From libsvn_subr/path.c. */
73 static const char svn_uri__char_validity
[256] = {
74 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
75 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
76 0, 1, 0, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
77 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 0, 0,
80 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
81 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1,
82 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
83 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 0,
86 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 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,
92 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,
98 /* From libsvn_subr/dirent_uri.c. */
100 svn_uri_is_canonical(const char *uri
, apr_pool_t
*pool
)
102 const char *ptr
= uri
, *seg
= uri
;
103 const char *schema_data
= NULL
;
105 /* URI is canonical if it has:
107 * - no closing '/', unless for the root path '/' itself
109 * - lowercase URL scheme
110 * - lowercase URL hostname
116 /* Maybe parse hostname and scheme. */
119 while (*ptr
&& (*ptr
!= '/') && (*ptr
!= ':'))
122 if (*ptr
== ':' && *(ptr
+1) == '/' && *(ptr
+2) == '/')
124 /* Found a scheme, check that it's all lowercase. */
128 if (*ptr
>= 'A' && *ptr
<= 'Z')
135 /* This might be the hostname */
137 while (*ptr
&& (*ptr
!= '/') && (*ptr
!= '@'))
146 /* Found a hostname, check that it's all lowercase. */
148 while (*ptr
&& *ptr
!= '/')
150 if (*ptr
>= 'A' && *ptr
<= 'Z')
159 /* Didn't find a scheme; finish the segment. */
160 while (*ptr
&& *ptr
!= '/')
165 #ifdef SVN_USE_DOS_PATHS
166 if (schema_data
&& *ptr
== '/')
168 /* If this is a file url, ptr now points to the third '/' in
169 file:///C:/path. Check that if we have such a URL the drive
170 letter is in uppercase. */
171 if (strncmp(uri
, "file:", 5) == 0 &&
172 ! (*(ptr
+1) >= 'A' && *(ptr
+1) <= 'Z') &&
176 #endif /* SVN_USE_DOS_PATHS */
178 /* Now validate the rest of the URI. */
181 apr_size_t seglen
= ptr
- seg
;
183 if (seglen
== 1 && *seg
== '.')
184 return FALSE
; /* /./ */
186 if (*ptr
== '/' && *(ptr
+1) == '/')
187 return FALSE
; /* // */
189 if (! *ptr
&& *(ptr
- 1) == '/' && ptr
- 1 != uri
)
190 return FALSE
; /* foo/ */
200 while (*ptr
&& (*ptr
!= '/'))
215 /* Can't use apr_isxdigit() because lower case letters are
216 not in our canonical format */
217 if (((*(ptr
+1) < '0' || (*ptr
+1) > '9'))
218 && (*(ptr
+1) < 'A' || (*ptr
+1) > 'F'))
220 else if (((*(ptr
+2) < '0' || (*ptr
+2) > '9'))
221 && (*(ptr
+2) < 'A' || (*ptr
+2) > 'F'))
224 digitz
[0] = *(++ptr
);
225 digitz
[1] = *(++ptr
);
227 val
= (int)strtol(digitz
, NULL
, 16);
229 if (svn_uri__char_validity
[val
])
230 return FALSE
; /* Should not have been escaped */
232 else if (*ptr
!= '/' && !svn_uri__char_validity
[(unsigned char)*ptr
])
233 return FALSE
; /* Character should have been escaped */
241 /* From libsvn_subr/dirent_uri.c. */
243 svn_uri_is_absolute(const char *uri
)
245 /* uri is absolute if it starts with '/' */
246 if (uri
&& uri
[0] == '/')
249 /* URLs are absolute. */
250 return svn_path_is_url(uri
);
253 /* Calculates the length occupied by the schema defined root of URI
254 From libsvn_subr/dirent_uri.c. */
256 uri_schema_root_length(const char *uri
, apr_size_t len
)
260 for (i
= 0; i
< len
; i
++)
264 if (i
> 0 && uri
[i
-1] == ':' && i
< len
-1 && uri
[i
+1] == '/')
266 /* We have an absolute uri */
267 if (i
== 5 && strncmp("file", uri
, 4) == 0)
268 return 7; /* file:// */
271 for (i
+= 2; i
< len
; i
++)
275 return len
; /* Only a hostname is found */
286 /* From libsvn_subr/dirent_uri.c. */
288 svn_uri_join(const char *base
, const char *component
, apr_pool_t
*pool
)
290 apr_size_t blen
= strlen(base
);
291 apr_size_t clen
= strlen(component
);
294 assert(svn_uri_is_canonical(base
, pool
));
295 assert(svn_uri_is_canonical(component
, pool
));
297 /* If either is empty return the other */
298 if (SVN_PATH_IS_EMPTY(base
))
299 return apr_pmemdup(pool
, component
, clen
+ 1);
300 if (SVN_PATH_IS_EMPTY(component
))
301 return apr_pmemdup(pool
, base
, blen
+ 1);
303 /* If the component is absolute, then return it. */
304 if (svn_uri_is_absolute(component
))
306 if (*component
!= '/')
307 return apr_pmemdup(pool
, component
, clen
+ 1);
310 /* The uri is not absolute enough; use only the root from base */
311 apr_size_t n
= uri_schema_root_length(base
, blen
);
313 path
= apr_palloc(pool
, n
+ clen
+ 1);
316 memcpy(path
, base
, n
);
318 memcpy(path
+ n
, component
, clen
+ 1); /* Include '\0' */
324 if (blen
== 1 && base
[0] == '/')
325 blen
= 0; /* Ignore base, just return separator + component */
327 /* Construct the new, combined path. */
328 path
= apr_palloc(pool
, blen
+ 1 + clen
+ 1);
329 memcpy(path
, base
, blen
);
331 memcpy(path
+ blen
+ 1, component
, clen
+ 1);
336 /* From libsvn_subr/dirent_uri.c. */
338 svn_relpath_is_canonical(const char *relpath
,
341 const char *ptr
= relpath
, *seg
= relpath
;
343 /* RELPATH is canonical if it has:
345 * - no start and closing '/'
349 if (*relpath
== '\0')
355 /* Now validate the rest of the path. */
358 apr_size_t seglen
= ptr
- seg
;
360 if (seglen
== 1 && *seg
== '.')
361 return FALSE
; /* /./ */
363 if (*ptr
== '/' && *(ptr
+1) == '/')
364 return FALSE
; /* // */
366 if (! *ptr
&& *(ptr
- 1) == '/')
367 return FALSE
; /* foo/ */
376 while (*ptr
&& (*ptr
!= '/'))
383 /* From libsvn_subr/dirent_uri.c. */
385 svn_relpath_basename(const char *relpath
,
388 apr_size_t len
= strlen(relpath
);
391 assert(!pool
|| svn_relpath_is_canonical(relpath
, pool
));
394 while (start
> 0 && relpath
[start
- 1] != '/')
398 return apr_pstrmemdup(pool
, relpath
+ start
, len
- start
);
400 return relpath
+ start
;
403 /* Return the length of substring necessary to encompass the entire
404 * previous relpath segment in RELPATH, which should be a LEN byte string.
406 * A trailing slash will not be included in the returned length.
407 * From libsvn_subr/dirent_uri.c.
410 relpath_previous_segment(const char *relpath
,
417 while (len
> 0 && relpath
[len
] != '/')
423 /* From libsvn_subr/dirent_uri.c. */
425 svn_relpath_dirname(const char *relpath
,
428 apr_size_t len
= strlen(relpath
);
430 assert(svn_relpath_is_canonical(relpath
, pool
));
432 return apr_pstrmemdup(pool
, relpath
,
433 relpath_previous_segment(relpath
, len
));
436 /* From libsvn_subr/dirent_uri.c. */
438 svn_dirent_basename(const char *dirent
, apr_pool_t
*pool
)
440 apr_size_t len
= strlen(dirent
);
443 assert(!pool
|| svn_dirent_is_canonical(dirent
, pool
));
445 if (svn_dirent_is_root(dirent
, len
))
450 while (start
> 0 && dirent
[start
- 1] != '/'
451 #ifdef SVN_USE_DOS_PATHS
452 && dirent
[start
- 1] != ':'
459 return apr_pstrmemdup(pool
, dirent
+ start
, len
- start
);
461 return dirent
+ start
;
464 /* Return the string length of the longest common ancestor of PATH1 and PATH2.
465 * Pass type_uri for TYPE if PATH1 and PATH2 are URIs, and type_dirent if
466 * PATH1 and PATH2 are regular paths.
468 * If the two paths do not share a common ancestor, return 0.
470 * New strings are allocated in POOL.
471 * From libsvn_sbur/dirent_uri.c.
474 get_longest_ancestor_length(path_type_t types
,
479 apr_size_t path1_len
, path2_len
;
481 apr_size_t last_dirsep
= 0;
482 #ifdef SVN_USE_DOS_PATHS
483 svn_boolean_t unc
= FALSE
;
486 path1_len
= strlen(path1
);
487 path2_len
= strlen(path2
);
489 if (SVN_PATH_IS_EMPTY(path1
) || SVN_PATH_IS_EMPTY(path2
))
492 while (path1
[i
] == path2
[i
])
494 /* Keep track of the last directory separator we hit. */
500 /* If we get to the end of either path, break out. */
501 if ((i
== path1_len
) || (i
== path2_len
))
505 /* two special cases:
506 1. '/' is the longest common ancestor of '/' and '/foo' */
507 if (i
== 1 && path1
[0] == '/' && path2
[0] == '/')
509 /* 2. '' is the longest common ancestor of any non-matching
510 * strings 'foo' and 'bar' */
511 if (types
== type_dirent
&& i
== 0)
514 /* Handle some windows specific cases */
515 #ifdef SVN_USE_DOS_PATHS
516 if (types
== type_dirent
)
518 /* don't count the '//' from UNC paths */
519 if (last_dirsep
== 1 && path1
[0] == '/' && path1
[1] == '/')
526 if (i
== 3 && path1
[2] == '/' && path1
[1] == ':')
529 /* Cannot use SVN_ERR_ASSERT here, so we'll have to crash, sorry.
530 * Note that this assertion triggers only if the code above has
531 * been broken. The code below relies on this assertion, because
532 * it uses [i - 1] as index. */
536 if ((path1
[i
- 1] == ':' && path2
[i
] == '/') ||
537 (path2
[i
- 1] == ':' && path1
[i
] == '/'))
540 if (path1
[i
- 1] == ':' || path2
[i
- 1] == ':')
543 #endif /* SVN_USE_DOS_PATHS */
545 /* last_dirsep is now the offset of the last directory separator we
546 crossed before reaching a non-matching byte. i is the offset of
547 that non-matching byte, and is guaranteed to be <= the length of
548 whichever path is shorter.
549 If one of the paths is the common part return that. */
550 if (((i
== path1_len
) && (path2
[i
] == '/'))
551 || ((i
== path2_len
) && (path1
[i
] == '/'))
552 || ((i
== path1_len
) && (i
== path2_len
)))
556 /* Nothing in common but the root folder '/' or 'X:/' for Windows
558 #ifdef SVN_USE_DOS_PATHS
561 /* X:/foo and X:/bar returns X:/ */
562 if ((types
== type_dirent
) &&
563 last_dirsep
== 2 && path1
[1] == ':' && path1
[2] == '/'
564 && path2
[1] == ':' && path2
[2] == '/')
566 #endif /* SVN_USE_DOS_PATHS */
567 if (last_dirsep
== 0 && path1
[0] == '/' && path2
[0] == '/')
569 #ifdef SVN_USE_DOS_PATHS
577 /* From libsvn_subr/dirent_uri.c. */
579 svn_relpath_get_longest_ancestor(const char *relpath1
,
580 const char *relpath2
,
583 return apr_pstrndup(pool
, relpath1
,
584 get_longest_ancestor_length(type_relpath
, relpath1
,
588 /* From libsvn_subr/dirent_uri.c. */
590 svn_relpath_skip_ancestor(const char *parent_relpath
,
591 const char *child_relpath
)
593 apr_size_t len
= strlen(parent_relpath
);
595 if (0 != memcmp(parent_relpath
, child_relpath
, len
))
596 return child_relpath
; /* parent_relpath is no ancestor of child_relpath */
598 if (child_relpath
[len
] == 0)
599 return ""; /* parent_relpath == child_relpath */
601 if (len
== 1 && child_relpath
[0] == '/')
602 return child_relpath
+ 1;
604 if (child_relpath
[len
] == '/')
605 return child_relpath
+ len
+ 1;
607 return child_relpath
;
610 /* From libsvn_subr/dirent_uri.c. */
612 svn_relpath_join(const char *base
,
613 const char *component
,
616 apr_size_t blen
= strlen(base
);
617 apr_size_t clen
= strlen(component
);
620 assert(svn_relpath_is_canonical(base
, pool
));
621 assert(svn_relpath_is_canonical(component
, pool
));
623 /* If either is empty return the other */
625 return apr_pmemdup(pool
, component
, clen
+ 1);
627 return apr_pmemdup(pool
, base
, blen
+ 1);
629 path
= apr_palloc(pool
, blen
+ 1 + clen
+ 1);
630 memcpy(path
, base
, blen
);
632 memcpy(path
+ blen
+ 1, component
, clen
+ 1);
637 /* Locale insensitive tolower() for converting parts of dirents and urls
638 while canonicalizing. From libsvn_subr/dirent_uri.c. */
640 canonicalize_to_lower(char c
)
642 if (c
< 'A' || c
> 'Z')
645 return c
- 'A' + 'a';
648 /* Locale insensitive toupper() for converting parts of dirents and urls
649 while canonicalizing. From libsvn_subr/dirent_uri.c. */
651 canonicalize_to_upper(char c
)
653 if (c
< 'a' || c
> 'z')
656 return c
- 'a' + 'A';
660 /* Return the canonicalized version of PATH, of type TYPE, allocated in
661 * POOL. From libsvn_subr/dirent_uri.c.
664 canonicalize(path_type_t type
, const char *path
, apr_pool_t
*pool
)
669 apr_size_t schemelen
= 0;
670 apr_size_t canon_segments
= 0;
671 svn_boolean_t url
= FALSE
;
672 char *schema_data
= NULL
;
674 /* "" is already canonical, so just return it; note that later code
675 depends on path not being zero-length. */
676 if (SVN_PATH_IS_EMPTY(path
))
679 dst
= canon
= apr_pcalloc(pool
, strlen(path
) + 1);
681 /* If this is supposed to be an URI and it starts with "scheme://", then
682 copy the scheme, host name, etc. to DST and set URL = TRUE. */
684 if (type
== type_uri
&& *src
!= '/')
686 while (*src
&& (*src
!= '/') && (*src
!= ':'))
689 if (*src
== ':' && *(src
+1) == '/' && *(src
+2) == '/')
695 /* Found a scheme, convert to lowercase and copy to dst. */
699 *(dst
++) = canonicalize_to_lower((*src
++));
708 /* This might be the hostname */
710 while (*src
&& (*src
!= '/') && (*src
!= '@'))
715 /* Copy the username & password. */
716 seglen
= src
- seg
+ 1;
717 memcpy(dst
, seg
, seglen
);
724 /* Found a hostname, convert to lowercase and copy to dst. */
725 while (*src
&& (*src
!= '/'))
726 *(dst
++) = canonicalize_to_lower((*src
++));
728 /* Copy trailing slash, or null-terminator. */
731 /* Move src and dst forward only if we are not
732 * at null-terminator yet. */
744 /* Copy to DST any separator or drive letter that must come before the
745 first regular path segment. */
746 if (! url
&& type
!= type_relpath
)
749 /* If this is an absolute path, then just copy over the initial
750 separator character. */
755 #ifdef SVN_USE_DOS_PATHS
756 /* On Windows permit two leading separator characters which means an
758 if ((type
== type_dirent
) && *src
== '/')
760 #endif /* SVN_USE_DOS_PATHS */
762 #ifdef SVN_USE_DOS_PATHS
763 /* On Windows the first segment can be a drive letter, which we normalize
765 else if (type
== type_dirent
&&
766 ((*src
>= 'a' && *src
<= 'z') ||
767 (*src
>= 'A' && *src
<= 'Z')) &&
770 *(dst
++) = canonicalize_to_upper(*(src
++));
771 /* Leave the ':' to be processed as (or as part of) a path segment
772 by the following code block, so we need not care whether it has
775 #endif /* SVN_USE_DOS_PATHS */
780 /* Parse each segment, find the closing '/' */
781 const char *next
= src
;
782 while (*next
&& (*next
!= '/'))
787 if (seglen
== 0 || (seglen
== 1 && src
[0] == '.'))
789 /* Noop segment, so do nothing. */
791 #ifdef SVN_USE_DOS_PATHS
792 /* If this is the first path segment of a file:// URI and it contains a
793 windows drive letter, convert the drive letter to upper case. */
794 else if (url
&& canon_segments
== 1 && seglen
== 2 &&
795 (strncmp(canon
, "file:", 5) == 0) &&
796 src
[0] >= 'a' && src
[0] <= 'z' && src
[1] == ':')
798 *(dst
++) = canonicalize_to_upper(src
[0]);
804 #endif /* SVN_USE_DOS_PATHS */
807 /* An actual segment, append it to the destination path */
810 memcpy(dst
, src
, seglen
);
815 /* Skip over trailing slash to the next segment. */
821 /* Remove the trailing slash if there was at least one
822 * canonical segment and the last segment ends with a slash.
824 * But keep in mind that, for URLs, the scheme counts as a
825 * canonical segment -- so if path is ONLY a scheme (such
826 * as "https://") we should NOT remove the trailing slash. */
827 if ((canon_segments
> 0 && *(dst
- 1) == '/')
828 && ! (url
&& path
[schemelen
] == '\0'))
835 #ifdef SVN_USE_DOS_PATHS
836 /* Skip leading double slashes when there are less than 2
837 * canon segments. UNC paths *MUST* have two segments. */
838 if ((type
== type_dirent
) && canon
[0] == '/' && canon
[1] == '/')
840 if (canon_segments
< 2)
844 /* Now we're sure this is a valid UNC path, convert the server name
845 (the first path segment) to lowercase as Windows treats it as case
847 Note: normally the share name is treated as case insensitive too,
848 but it seems to be possible to configure Samba to treat those as
849 case sensitive, so better leave that alone. */
851 while (*dst
&& *dst
!= '/')
852 *(dst
++) = canonicalize_to_lower(*dst
);
855 #endif /* SVN_USE_DOS_PATHS */
857 /* Check the normalization of characters in a uri */
870 if (!apr_isxdigit(*(src
+1)) || !apr_isxdigit(*(src
+2)))
876 if (!svn_uri__char_validity
[(unsigned char)*src
])
885 apr_size_t pre_schema_size
= (apr_size_t
)(schema_data
- canon
);
887 dst
= apr_palloc(pool
, (apr_size_t
)(src
- canon
) + need_extra
+ 1);
888 memcpy(dst
, canon
, pre_schema_size
);
891 dst
+= pre_schema_size
;
906 if (!apr_isxdigit(*(src
+1)) || !apr_isxdigit(*(src
+2)))
917 digitz
[0] = *(++src
);
918 digitz
[1] = *(++src
);
921 val
= (int)strtol(digitz
, NULL
, 16);
923 if (svn_uri__char_validity
[(unsigned char)val
])
924 *(dst
++) = (char)val
;
928 *(dst
++) = canonicalize_to_upper(digitz
[0]);
929 *(dst
++) = canonicalize_to_upper(digitz
[1]);
934 if (!svn_uri__char_validity
[(unsigned char)*src
])
936 apr_snprintf(dst
, 4, "%%%02X", (unsigned char)*src
);
951 /* From libsvn_subr/dirent_uri.c. */
953 svn_uri_canonicalize(const char *uri
, apr_pool_t
*pool
)
955 return canonicalize(type_uri
, uri
, pool
);
958 /* From libsvn_subr/dirent_uri.c. */
960 svn_relpath_canonicalize(const char *relpath
, apr_pool_t
*pool
)
962 return canonicalize(type_relpath
, relpath
, pool
);
965 /* New code (public domain). */
967 svn_io_remove_file2(const char *path
,
968 svn_boolean_t ignore_enoent
,
969 apr_pool_t
*scratch_pool
)
971 svn_error_t
*err
= svn_io_remove_file(path
, scratch_pool
);
972 if (ignore_enoent
&& err
&& APR_STATUS_IS_ENOENT(err
->apr_err
))
974 svn_error_clear(err
);
980 /* From libsvn_subr/cmdline.c. */
982 svn_cmdline__apply_config_options(apr_hash_t
*config
,
983 const apr_array_header_t
*config_options
,
985 const char *argument_name
)
989 for (i
= 0; i
< config_options
->nelts
; i
++)
992 svn_cmdline__config_argument_t
*arg
=
993 APR_ARRAY_IDX(config_options
, i
,
994 svn_cmdline__config_argument_t
*);
996 cfg
= apr_hash_get(config
, arg
->file
, APR_HASH_KEY_STRING
);
1000 svn_config_set(cfg
, arg
->section
, arg
->option
, arg
->value
);
1004 svn_error_t
*err
= svn_error_createf(SVN_ERR_CL_ARG_PARSING_ERROR
, NULL
,
1005 _("Unrecognized file in argument of %s"), argument_name
);
1007 svn_handle_warning2(stderr
, err
, prefix
);
1008 svn_error_clear(err
);
1012 return SVN_NO_ERROR
;
1015 /* From libsvn_subr/cmdline.c. */
1017 svn_cmdline__parse_config_option(apr_array_header_t
*config_options
,
1018 const char *opt_arg
,
1021 svn_cmdline__config_argument_t
*config_option
;
1022 const char *first_colon
, *second_colon
, *equals_sign
;
1023 apr_size_t len
= strlen(opt_arg
);
1024 if ((first_colon
= strchr(opt_arg
, ':')) && (first_colon
!= opt_arg
))
1026 if ((second_colon
= strchr(first_colon
+ 1, ':')) &&
1027 (second_colon
!= first_colon
+ 1))
1029 if ((equals_sign
= strchr(second_colon
+ 1, '=')) &&
1030 (equals_sign
!= second_colon
+ 1))
1032 config_option
= apr_pcalloc(pool
, sizeof(*config_option
));
1033 config_option
->file
= apr_pstrndup(pool
, opt_arg
,
1034 first_colon
- opt_arg
);
1035 config_option
->section
= apr_pstrndup(pool
, first_colon
+ 1,
1036 second_colon
- first_colon
- 1);
1037 config_option
->option
= apr_pstrndup(pool
, second_colon
+ 1,
1038 equals_sign
- second_colon
-
1041 if (! (strchr(config_option
->option
, ':')))
1043 config_option
->value
= apr_pstrndup(pool
, equals_sign
+ 1,
1044 opt_arg
+ len
- equals_sign
- 1);
1045 APR_ARRAY_PUSH(config_options
, svn_cmdline__config_argument_t
1048 return SVN_NO_ERROR
;
1053 return svn_error_create(SVN_ERR_CL_ARG_PARSING_ERROR
, NULL
,
1054 _("Invalid syntax of argument of --config-option"));