Author: julianfoad
Date: Sat Apr 27 01:19:38 2013
New Revision: 1476461
URL: http://svn.apache.org/r1476461
Log:
Fix non-ASCII character handling in several 'svn' command-line options, when
using a non-UTF-8 locale. In roughly decreasing order of importance:
--old, --new:
It did not convert the path to UTF-8. It would fail to find a non-ASCII
path, or conceivably could find the wrong path.
--search, --search-and:
It did not convert the search term to UTF-8. It would fail to match a
non-ASCII search term, or conceivably could find a wrong match.
--file:
The check for accidentally specifying a versioned file used the
unconverted path, and so a non-ASCII path would (most likely) not
trigger the check when it should.
--limit, --accept, --show-revs, --strip, --change:
It did not convert the value to UTF-8 before parsing it. Valid values
would work properly, but the error message displayed for an invalid
value would display the invalid value wrongly.
--native-eol
Conversion to UTF-8 has been moved before comparison against fixed ASCII
strings like 'CRLF'. This will only make a difference if there are
character encodings in use that are not compatible with ASCII; otherwise
it is just for consistency of coding style.
* subversion/svn/svn.c
(sub_main): Convert option arguments to UTF-8 before using them, in most
cases where we weren't already doing so.
* subversion/svn/cl.h
(svn_cl__opt_state_t): Document which fields are *not* converted to UTF-8,
instead of the previous incomplete annotation of which ones are. Remove
the unused 'changelist' field (which was long ago superseded by the
'changelists' array.
Modified:
subversion/trunk/subversion/svn/cl.h
subversion/trunk/subversion/svn/svn.c
Modified: subversion/trunk/subversion/svn/cl.h
URL:
http://svn.apache.org/viewvc/subversion/trunk/subversion/svn/cl.h?rev=1476461&r1=1476460&r2=1476461&view=diff
==============================================================================
--- subversion/trunk/subversion/svn/cl.h (original)
+++ subversion/trunk/subversion/svn/cl.h Sat Apr 27 01:19:38 2013
@@ -158,7 +158,7 @@ typedef struct svn_cl__opt_state_t
/* Was --no-unlock specified? */
svn_boolean_t no_unlock;
- const char *message; /* log message */
+ const char *message; /* log message (not converted to UTF-8) */
svn_boolean_t force; /* be more forceful, as in "svn rm -f ..." */
svn_boolean_t force_log; /* force validity of a suspect log msg file */
svn_boolean_t incremental; /* yield output suitable for concatenation */
@@ -168,19 +168,22 @@ typedef struct svn_cl__opt_state_t
svn_boolean_t verbose; /* be verbose */
svn_boolean_t update; /* contact the server for the full story */
svn_boolean_t strict; /* do strictly what was requested */
- svn_stringbuf_t *filedata; /* contents of file used as option data */
- const char *encoding; /* the locale/encoding of the data*/
+ svn_stringbuf_t *filedata; /* contents of file used as option data
+ (not converted to UTF-8) */
+ const char *encoding; /* the locale/encoding of 'message' and of
+ 'filedata' (not converted to UTF-8) */
svn_boolean_t help; /* print usage message */
- const char *auth_username; /* auth username */ /* UTF-8! */
- const char *auth_password; /* auth password */ /* UTF-8! */
- const char *extensions; /* subprocess extension args */ /* UTF-8! */
- apr_array_header_t *targets; /* target list from file */ /* UTF-8! */
+ const char *auth_username; /* auth username */
+ const char *auth_password; /* auth password */
+ const char *extensions; /* subprocess extension args */
+ apr_array_header_t *targets; /* target list from file */
svn_boolean_t xml; /* output in xml, e.g., "svn log --xml" */
svn_boolean_t no_ignore; /* disregard default ignores & svn:ignore's */
svn_boolean_t no_auth_cache; /* do not cache authentication information */
struct
{
- const char *diff_cmd; /* the external diff command to use */
+ const char *diff_cmd; /* the external diff command to use
+ (not converted to UTF-8) */
svn_boolean_t internal_diff; /* override diff_cmd in config file */
svn_boolean_t no_diff_added; /* do not show diffs for deleted files */
svn_boolean_t no_diff_deleted; /* do not show diffs for deleted files */
@@ -197,8 +200,10 @@ typedef struct svn_cl__opt_state_t
svn_boolean_t stop_on_copy; /* don't cross copies during processing */
svn_boolean_t dry_run; /* try operation but make no changes */
svn_boolean_t revprop; /* operate on a revision property */
- const char *merge_cmd; /* the external merge command to use */
- const char *editor_cmd; /* the external editor command to use */
+ const char *merge_cmd; /* the external merge command to use
+ (not converted to UTF-8) */
+ const char *editor_cmd; /* the external editor command to use
+ (not converted to UTF-8) */
svn_boolean_t record_only; /* whether to record mergeinfo */
const char *old_target; /* diff target */
const char *new_target; /* diff target */
@@ -210,13 +215,12 @@ typedef struct svn_cl__opt_state_t
const char *native_eol; /* override system standard eol marker */
svn_boolean_t remove; /* deassociate a changelist */
apr_array_header_t *changelists; /* changelist filters */
- const char *changelist; /* operate on this changelist
- THIS IS TEMPORARY (LAST OF CHANGELISTS) */
svn_boolean_t keep_changelists;/* don't remove changelists after commit */
svn_boolean_t keep_local; /* delete path only from repository */
svn_boolean_t all_revprops; /* retrieve all revprops */
svn_boolean_t no_revprops; /* retrieve no revprops */
- apr_hash_t *revprop_table; /* table of revision properties to get/set */
+ apr_hash_t *revprop_table; /* table of revision properties to get/set
+ (not converted to UTF-8) */
svn_boolean_t parents; /* create intermediate directories */
svn_boolean_t use_merge_history; /* use/display extra merge information */
svn_cl__accept_t accept_which; /* how to handle conflicts */
Modified: subversion/trunk/subversion/svn/svn.c
URL:
http://svn.apache.org/viewvc/subversion/trunk/subversion/svn/svn.c?rev=1476461&r1=1476460&r2=1476461&view=diff
==============================================================================
--- subversion/trunk/subversion/svn/svn.c (original)
+++ subversion/trunk/subversion/svn/svn.c Sat Apr 27 01:19:38 2013
@@ -1722,7 +1722,7 @@ sub_main(int argc, const char *argv[], a
apr_array_header_t *received_opts;
int i;
const svn_opt_subcommand_desc2_t *subcommand = NULL;
- const char *dash_m_arg = NULL, *dash_F_arg = NULL;
+ const char *dash_F_arg = NULL;
svn_cl__cmd_baton_t command_baton;
svn_auth_baton_t *ab;
svn_config_t *cfg_config;
@@ -1798,7 +1798,8 @@ sub_main(int argc, const char *argv[], a
switch (opt_id) {
case 'l':
{
- err = svn_cstring_atoi(&opt_state.limit, opt_arg);
+ SVN_INT_ERR(svn_utf_cstring_to_utf8(&utf8_opt_arg, opt_arg, pool));
+ err = svn_cstring_atoi(&opt_state.limit, utf8_opt_arg);
if (err)
{
err = svn_error_create(SVN_ERR_CL_ARG_PARSING_ERROR, err,
@@ -1814,16 +1815,17 @@ sub_main(int argc, const char *argv[], a
}
break;
case 'm':
- /* Note that there's no way here to detect if the log message
- contains a zero byte -- if it does, then opt_arg will just
- be shorter than the user intended. Oh well. */
+ /* We store the raw message here. We will convert it to UTF-8
+ * later, according to the value of the '--encoding' option. */
opt_state.message = apr_pstrdup(pool, opt_arg);
- dash_m_arg = opt_arg;
break;
case 'c':
{
- apr_array_header_t *change_revs =
- svn_cstring_split(opt_arg, ", \n\r\t\v", TRUE, pool);
+ apr_array_header_t *change_revs;
+
+ SVN_INT_ERR(svn_utf_cstring_to_utf8(&utf8_opt_arg, opt_arg, pool));
+ change_revs = svn_cstring_split(utf8_opt_arg, ", \n\r\t\v", TRUE,
+ pool);
if (opt_state.old_target)
{
@@ -1918,10 +1920,10 @@ sub_main(int argc, const char *argv[], a
break;
case 'r':
opt_state.used_revision_arg = TRUE;
+ SVN_INT_ERR(svn_utf_cstring_to_utf8(&utf8_opt_arg, opt_arg, pool));
if (svn_opt_parse_revision_to_range(opt_state.revision_ranges,
- opt_arg, pool) != 0)
+ utf8_opt_arg, pool) != 0)
{
- SVN_INT_ERR(svn_utf_cstring_to_utf8(&utf8_opt_arg, opt_arg, pool));
err = svn_error_createf
(SVN_ERR_CL_ARG_PARSING_ERROR, NULL,
_("Syntax error in revision argument '%s'"),
@@ -1946,20 +1948,19 @@ sub_main(int argc, const char *argv[], a
opt_state.incremental = TRUE;
break;
case 'F':
+ /* We read the raw file content here. We will convert it to UTF-8
+ * later (if it's a log/lock message or an svn:* prop value),
+ * according to the value of the '--encoding' option. */
SVN_INT_ERR(svn_utf_cstring_to_utf8(&utf8_opt_arg, opt_arg, pool));
SVN_INT_ERR(svn_stringbuf_from_file2(&(opt_state.filedata),
utf8_opt_arg, pool));
reading_file_from_stdin = (strcmp(utf8_opt_arg, "-") == 0);
- dash_F_arg = opt_arg;
+ dash_F_arg = utf8_opt_arg;
break;
case opt_targets:
{
svn_stringbuf_t *buffer, *buffer_utf8;
- /* We need to convert to UTF-8 now, even before we divide
- the targets into an array, because otherwise we wouldn't
- know what delimiter to use for svn_cstring_split(). */
-
SVN_INT_ERR(svn_utf_cstring_to_utf8(&utf8_opt_arg, opt_arg, pool));
SVN_INT_ERR(svn_stringbuf_from_file2(&buffer, utf8_opt_arg, pool));
SVN_INT_ERR(svn_utf_stringbuf_to_utf8(&buffer_utf8, buffer, pool));
@@ -2109,17 +2110,16 @@ sub_main(int argc, const char *argv[], a
_("Can't specify -c with --old"));
return EXIT_ERROR(err);
}
- opt_state.old_target = apr_pstrdup(pool, opt_arg);
+ SVN_INT_ERR(svn_utf_cstring_to_utf8(&utf8_opt_arg, opt_arg, pool));
+ opt_state.old_target = apr_pstrdup(pool, utf8_opt_arg);
break;
case opt_new_cmd:
- opt_state.new_target = apr_pstrdup(pool, opt_arg);
+ SVN_INT_ERR(svn_utf_cstring_to_utf8(&utf8_opt_arg, opt_arg, pool));
+ opt_state.new_target = apr_pstrdup(pool, utf8_opt_arg);
break;
case opt_config_dir:
- {
- const char *path_utf8;
- SVN_INT_ERR(svn_utf_cstring_to_utf8(&path_utf8, opt_arg, pool));
- opt_state.config_dir = svn_dirent_internal_style(path_utf8, pool);
- }
+ SVN_INT_ERR(svn_utf_cstring_to_utf8(&utf8_opt_arg, opt_arg, pool));
+ opt_state.config_dir = svn_dirent_internal_style(utf8_opt_arg, pool);
break;
case opt_config_options:
if (!opt_state.config_options)
@@ -2127,9 +2127,9 @@ sub_main(int argc, const char *argv[], a
apr_array_make(pool, 1,
sizeof(svn_cmdline__config_argument_t*));
- SVN_INT_ERR(svn_utf_cstring_to_utf8(&opt_arg, opt_arg, pool));
+ SVN_INT_ERR(svn_utf_cstring_to_utf8(&utf8_opt_arg, opt_arg, pool));
SVN_INT_ERR(svn_cmdline__parse_config_option(opt_state.config_options,
- opt_arg, pool));
+ utf8_opt_arg, pool));
break;
case opt_autoprops:
opt_state.autoprops = TRUE;
@@ -2138,12 +2138,12 @@ sub_main(int argc, const char *argv[], a
opt_state.no_autoprops = TRUE;
break;
case opt_native_eol:
- if ( !strcmp("LF", opt_arg) || !strcmp("CR", opt_arg) ||
- !strcmp("CRLF", opt_arg))
- opt_state.native_eol = apr_pstrdup(pool, opt_arg);
+ SVN_INT_ERR(svn_utf_cstring_to_utf8(&utf8_opt_arg, opt_arg, pool));
+ if ( !strcmp("LF", utf8_opt_arg) || !strcmp("CR", utf8_opt_arg) ||
+ !strcmp("CRLF", utf8_opt_arg))
+ opt_state.native_eol = utf8_opt_arg;
else
{
- SVN_INT_ERR(svn_utf_cstring_to_utf8(&utf8_opt_arg, opt_arg, pool));
err = svn_error_createf
(SVN_ERR_CL_ARG_PARSING_ERROR, NULL,
_("Syntax error in native-eol argument '%s'"),
@@ -2162,14 +2162,13 @@ sub_main(int argc, const char *argv[], a
break;
case opt_changelist:
SVN_INT_ERR(svn_utf_cstring_to_utf8(&utf8_opt_arg, opt_arg, pool));
- opt_state.changelist = utf8_opt_arg;
- if (opt_state.changelist[0] == '\0')
+ if (utf8_opt_arg[0] == '\0')
{
err = svn_error_create(SVN_ERR_CL_ARG_PARSING_ERROR, NULL,
_("Changelist names must not be empty"));
return EXIT_ERROR(err);
}
- svn_hash_sets(changelists, opt_state.changelist, (void *)1);
+ svn_hash_sets(changelists, utf8_opt_arg, (void *)1);
break;
case opt_keep_changelists:
opt_state.keep_changelists = TRUE;
@@ -2196,31 +2195,35 @@ sub_main(int argc, const char *argv[], a
opt_state.use_merge_history = TRUE;
break;
case opt_accept:
- opt_state.accept_which = svn_cl__accept_from_word(opt_arg);
+ SVN_INT_ERR(svn_utf_cstring_to_utf8(&utf8_opt_arg, opt_arg, pool));
+ opt_state.accept_which = svn_cl__accept_from_word(utf8_opt_arg);
if (opt_state.accept_which == svn_cl__accept_invalid)
return EXIT_ERROR
(svn_error_createf(SVN_ERR_CL_ARG_PARSING_ERROR, NULL,
_("'%s' is not a valid --accept value"),
- opt_arg));
+ utf8_opt_arg));
break;
case opt_show_revs:
- opt_state.show_revs = svn_cl__show_revs_from_word(opt_arg);
+ SVN_INT_ERR(svn_utf_cstring_to_utf8(&utf8_opt_arg, opt_arg, pool));
+ opt_state.show_revs = svn_cl__show_revs_from_word(utf8_opt_arg);
if (opt_state.show_revs == svn_cl__show_revs_invalid)
return EXIT_ERROR
(svn_error_createf(SVN_ERR_CL_ARG_PARSING_ERROR, NULL,
_("'%s' is not a valid --show-revs value"),
- opt_arg));
+ utf8_opt_arg));
break;
case opt_reintegrate:
opt_state.reintegrate = TRUE;
break;
case opt_strip:
{
- err = svn_cstring_atoi(&opt_state.strip, opt_arg);
+ SVN_INT_ERR(svn_utf_cstring_to_utf8(&utf8_opt_arg, opt_arg, pool));
+ err = svn_cstring_atoi(&opt_state.strip, utf8_opt_arg);
if (err)
{
err = svn_error_createf(SVN_ERR_CL_ARG_PARSING_ERROR, err,
- _("Invalid strip count '%s'"), opt_arg);
+ _("Invalid strip count '%s'"),
+ utf8_opt_arg);
return EXIT_ERROR(err);
}
if (opt_state.strip < 0)
@@ -2265,10 +2268,12 @@ sub_main(int argc, const char *argv[], a
opt_state.diff.properties_only = TRUE;
break;
case opt_search:
- add_search_pattern_group(&opt_state, opt_arg, pool);
+ SVN_INT_ERR(svn_utf_cstring_to_utf8(&utf8_opt_arg, opt_arg, pool));
+ add_search_pattern_group(&opt_state, utf8_opt_arg, pool);
break;
case opt_search_and:
- add_search_pattern_to_latest_group(&opt_state, opt_arg, pool);
+ SVN_INT_ERR(svn_utf_cstring_to_utf8(&utf8_opt_arg, opt_arg, pool));
+ add_search_pattern_to_latest_group(&opt_state, utf8_opt_arg, pool);
default:
/* Hmmm. Perhaps this would be a good place to squirrel away
opts that commands like svn diff might need. Hmmm indeed. */
@@ -2682,10 +2687,10 @@ sub_main(int argc, const char *argv[], a
/* If the -m argument is a file at all, that's probably not what
the user intended. */
- if (dash_m_arg)
+ if (opt_state.message)
{
apr_finfo_t finfo;
- if (apr_stat(&finfo, dash_m_arg,
+ if (apr_stat(&finfo, opt_state.message /* not converted to UTF-8 */,
APR_FINFO_MIN, pool) == APR_SUCCESS)
{
if (subcommand->cmd_func != svn_cl__lock)