aboutsummaryrefslogtreecommitdiff
path: root/subversion/libsvn_subr
diff options
context:
space:
mode:
Diffstat (limited to 'subversion/libsvn_subr')
-rw-r--r--subversion/libsvn_subr/apr_escape.c135
-rw-r--r--subversion/libsvn_subr/cmdline.c101
-rw-r--r--subversion/libsvn_subr/iter.c26
-rw-r--r--subversion/libsvn_subr/opt.c2
-rw-r--r--subversion/libsvn_subr/version.c2
5 files changed, 252 insertions, 14 deletions
diff --git a/subversion/libsvn_subr/apr_escape.c b/subversion/libsvn_subr/apr_escape.c
new file mode 100644
index 000000000000..caa25d9fc573
--- /dev/null
+++ b/subversion/libsvn_subr/apr_escape.c
@@ -0,0 +1,135 @@
+/* Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/* The code in this file is copied from APR (initially from APR 1.7.0)
+ * to provide compatibility for building against APR < 1.5.0.
+ */
+
+#include "private/svn_dep_compat.h"
+
+#if !APR_VERSION_AT_LEAST(1,5,0)
+
+#include <apr_lib.h>
+#include <apr_strings.h>
+
+/* from apr_escape_test_char.h */
+#define T_ESCAPE_SHELL_CMD (1)
+#define T_ESCAPE_PATH_SEGMENT (2)
+#define T_OS_ESCAPE_PATH (4)
+#define T_ESCAPE_ECHO (8)
+#define T_ESCAPE_URLENCODED (16)
+#define T_ESCAPE_XML (32)
+#define T_ESCAPE_LDAP_DN (64)
+#define T_ESCAPE_LDAP_FILTER (128)
+
+static const unsigned char test_char_table[256] = {
+ 224,222,222,222,222,222,222,222,222,222,223,222,222,222,222,222,222,222,222,222,
+ 222,222,222,222,222,222,222,222,222,222,222,222,6,16,127,22,17,22,49,17,
+ 145,145,129,80,80,0,0,18,0,0,0,0,0,0,0,0,0,0,16,87,
+ 119,16,119,23,16,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+ 0,0,0,0,0,0,0,0,0,0,0,23,223,23,23,0,23,0,0,0,
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+ 0,0,0,23,23,23,17,222,222,222,222,222,222,222,222,222,222,222,222,222,
+ 222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,
+ 222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,
+ 222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,
+ 222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,
+ 222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,
+ 222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222
+};
+
+/* from apr_encode_private.h */
+#if APR_CHARSET_EBCDIC
+#error This Subversion compatibility code for APR<1.5 does not support EBCDIC.
+#else /* APR_CHARSET_EBCDIC */
+#define ENCODE_TO_ASCII(ch) (ch)
+#define ENCODE_TO_NATIVE(ch) (ch)
+#endif /* !APR_CHARSET_EBCDIC */
+
+/* we assume the folks using this ensure 0 <= c < 256... which means
+ * you need a cast to (unsigned char) first, you can't just plug a
+ * char in here and get it to work, because if char is signed then it
+ * will first be sign extended.
+ */
+#define TEST_CHAR(c, f) (test_char_table[(unsigned)(c)] & (f))
+
+APR_DECLARE(apr_status_t) apr_escape_shell(char *escaped, const char *str,
+ apr_ssize_t slen, apr_size_t *len)
+{
+ unsigned char *d;
+ const unsigned char *s;
+ apr_size_t size = 1;
+ int found = 0;
+
+ d = (unsigned char *) escaped;
+ s = (const unsigned char *) str;
+
+ if (s) {
+ if (d) {
+ for (; *s && slen; ++s, slen--) {
+#if defined(OS2) || defined(WIN32)
+ /*
+ * Newlines to Win32/OS2 CreateProcess() are ill advised.
+ * Convert them to spaces since they are effectively white
+ * space to most applications
+ */
+ if (*s == '\r' || *s == '\n') {
+ if (d) {
+ *d++ = ' ';
+ found = 1;
+ }
+ continue;
+ }
+#endif
+ if (TEST_CHAR(*s, T_ESCAPE_SHELL_CMD)) {
+ *d++ = '\\';
+ size++;
+ found = 1;
+ }
+ *d++ = *s;
+ size++;
+ }
+ *d = '\0';
+ }
+ else {
+ for (; *s && slen; ++s, slen--) {
+ if (TEST_CHAR(*s, T_ESCAPE_SHELL_CMD)) {
+ size++;
+ found = 1;
+ }
+ size++;
+ }
+ }
+ }
+
+ if (len) {
+ *len = size;
+ }
+ if (!found) {
+ return APR_NOTFOUND;
+ }
+
+ return APR_SUCCESS;
+}
+
+#else /* APR_VERSION_AT_LEAST(1,5,0) */
+
+/* Silence OSX ranlib warnings about object files with no symbols. */
+#include <apr.h>
+extern const apr_uint32_t svn__fake__apr_escape;
+const apr_uint32_t svn__fake__apr_escape = 0xdeadbeef;
+
+#endif /* !APR_VERSION_AT_LEAST(1,5,0) */
diff --git a/subversion/libsvn_subr/cmdline.c b/subversion/libsvn_subr/cmdline.c
index d1aad71b234a..bc27788ec03a 100644
--- a/subversion/libsvn_subr/cmdline.c
+++ b/subversion/libsvn_subr/cmdline.c
@@ -39,9 +39,15 @@
#include <apr.h> /* for STDIN_FILENO */
#include <apr_errno.h> /* for apr_strerror */
+#include <apr_version.h>
+#if APR_VERSION_AT_LEAST(1,5,0)
#include <apr_escape.h>
+#else
+#include "private/svn_dep_compat.h"
+#endif
#include <apr_general.h> /* for apr_initialize/apr_terminate */
#include <apr_strings.h> /* for apr_snprintf */
+#include <apr_env.h> /* for apr_env_get */
#include <apr_pools.h>
#include <apr_signal.h>
@@ -1235,38 +1241,84 @@ svn_cmdline__be_interactive(svn_boolean_t non_interactive,
/* Helper for the edit_externally functions. Set *EDITOR to some path to an
- editor binary. Sources to search include: the EDITOR_CMD argument
- (if not NULL), $SVN_EDITOR, the runtime CONFIG variable (if CONFIG
+ editor binary, in native C string on Unix/Linux platforms and in UTF-8
+ string on Windows platform. Sources to search include: the EDITOR_CMD
+ argument (if not NULL), $SVN_EDITOR, the runtime CONFIG variable (if CONFIG
is not NULL), $VISUAL, $EDITOR. Return
SVN_ERR_CL_NO_EXTERNAL_EDITOR if no binary can be found. */
static svn_error_t *
find_editor_binary(const char **editor,
const char *editor_cmd,
- apr_hash_t *config)
+ apr_hash_t *config,
+ apr_pool_t *pool)
{
const char *e;
+ const char *e_cfg;
struct svn_config_t *cfg;
+ apr_status_t status;
/* Use the editor specified on the command line via --editor-cmd, if any. */
+#ifdef WIN32
+ /* On Windows, editor_cmd is transcoded to the system active code page
+ because we use main() as a entry point without APR's (or our own) wrapper
+ in command line tools. */
+ if (editor_cmd)
+ {
+ SVN_ERR(svn_utf_cstring_to_utf8(&e, editor_cmd, pool));
+ }
+ else
+ {
+ e = NULL;
+ }
+#else
e = editor_cmd;
+#endif
/* Otherwise look for the Subversion-specific environment variable. */
if (! e)
- e = getenv("SVN_EDITOR");
+ {
+ status = apr_env_get((char **)&e, "SVN_EDITOR", pool);
+ if (status || ! *e)
+ {
+ e = NULL;
+ }
+ }
/* If not found then fall back on the config file. */
if (! e)
{
cfg = config ? svn_hash_gets(config, SVN_CONFIG_CATEGORY_CONFIG) : NULL;
- svn_config_get(cfg, &e, SVN_CONFIG_SECTION_HELPERS,
+ svn_config_get(cfg, &e_cfg, SVN_CONFIG_SECTION_HELPERS,
SVN_CONFIG_OPTION_EDITOR_CMD, NULL);
+#ifdef WIN32
+ if (e_cfg)
+ {
+ /* On Windows, we assume that config values are set in system active
+ code page, so we need transcode it here. */
+ SVN_ERR(svn_utf_cstring_to_utf8(&e, e_cfg, pool));
+ }
+#else
+ e = e_cfg;
+#endif
}
/* If not found yet then try general purpose environment variables. */
if (! e)
- e = getenv("VISUAL");
+ {
+ status = apr_env_get((char**)&e, "VISUAL", pool);
+ if (status || ! *e)
+ {
+ e = NULL;
+ }
+ }
if (! e)
- e = getenv("EDITOR");
+ {
+ status = apr_env_get((char**)&e, "EDITOR", pool);
+ if (status || ! *e)
+ {
+ e = NULL;
+ }
+ }
#ifdef SVN_CLIENT_EDITOR
/* If still not found then fall back on the hard-coded default. */
@@ -1400,13 +1452,17 @@ svn_cmdline__edit_file_externally(const char *path,
apr_pool_t *pool)
{
const char *editor, *cmd, *base_dir, *file_name, *base_dir_apr;
+ const char *file_name_local;
+#ifdef WIN32
+ const WCHAR *wcmd;
+#endif
char *old_cwd;
int sys_err;
apr_status_t apr_err;
svn_dirent_split(&base_dir, &file_name, path, pool);
- SVN_ERR(find_editor_binary(&editor, editor_cmd, config));
+ SVN_ERR(find_editor_binary(&editor, editor_cmd, config, pool));
apr_err = apr_filepath_get(&old_cwd, APR_FILEPATH_NATIVE, pool);
if (apr_err)
@@ -1423,10 +1479,18 @@ svn_cmdline__edit_file_externally(const char *path,
return svn_error_wrap_apr
(apr_err, _("Can't change working directory to '%s'"), base_dir);
+ SVN_ERR(svn_path_cstring_from_utf8(&file_name_local,
+ escape_path(pool, file_name), pool));
/* editor is explicitly documented as being interpreted by the user's shell,
and as such should already be quoted/escaped as needed. */
- cmd = apr_psprintf(pool, "%s %s", editor, escape_path(pool, file_name));
+#ifndef WIN32
+ cmd = apr_psprintf(pool, "%s %s", editor, file_name_local);
sys_err = system(cmd);
+#else
+ cmd = apr_psprintf(pool, "\"%s %s\"", editor, file_name_local);
+ SVN_ERR(svn_utf__win32_utf8_to_utf16(&wcmd, cmd, NULL, pool));
+ sys_err = _wsystem(wcmd);
+#endif
apr_err = apr_filepath_set(old_cwd, pool);
if (apr_err)
@@ -1458,6 +1522,9 @@ svn_cmdline__edit_string_externally(svn_string_t **edited_contents /* UTF-8! */,
{
const char *editor;
const char *cmd;
+#ifdef WIN32
+ const WCHAR *wcmd;
+#endif
apr_file_t *tmp_file;
const char *tmpfile_name;
const char *tmpfile_native;
@@ -1471,7 +1538,7 @@ svn_cmdline__edit_string_externally(svn_string_t **edited_contents /* UTF-8! */,
int sys_err;
svn_boolean_t remove_file = TRUE;
- SVN_ERR(find_editor_binary(&editor, editor_cmd, config));
+ SVN_ERR(find_editor_binary(&editor, editor_cmd, config, pool));
/* Convert file contents from UTF-8/LF if desired. */
if (as_text)
@@ -1581,13 +1648,18 @@ svn_cmdline__edit_string_externally(svn_string_t **edited_contents /* UTF-8! */,
goto cleanup;
/* Prepare the editor command line. */
- err = svn_utf_cstring_from_utf8(&tmpfile_native, tmpfile_name, pool);
+ err = svn_utf_cstring_from_utf8(&tmpfile_native,
+ escape_path(pool, tmpfile_name), pool);
if (err)
goto cleanup;
/* editor is explicitly documented as being interpreted by the user's shell,
and as such should already be quoted/escaped as needed. */
- cmd = apr_psprintf(pool, "%s %s", editor, escape_path(pool, tmpfile_native));
+#ifndef WIN32
+ cmd = apr_psprintf(pool, "%s %s", editor, tmpfile_native);
+#else
+ cmd = apr_psprintf(pool, "\"%s %s\"", editor, tmpfile_native);
+#endif
/* If the caller wants us to leave the file around, return the path
of the file we'll use, and make a note not to destroy it. */
@@ -1598,7 +1670,12 @@ svn_cmdline__edit_string_externally(svn_string_t **edited_contents /* UTF-8! */,
}
/* Now, run the editor command line. */
+#ifndef WIN32
sys_err = system(cmd);
+#else
+ SVN_ERR(svn_utf__win32_utf8_to_utf16(&wcmd, cmd, NULL, pool));
+ sys_err = _wsystem(wcmd);
+#endif
if (sys_err != 0)
{
/* Extracting any meaning from sys_err is platform specific, so just
diff --git a/subversion/libsvn_subr/iter.c b/subversion/libsvn_subr/iter.c
index 6d04846e8378..1a303b511945 100644
--- a/subversion/libsvn_subr/iter.c
+++ b/subversion/libsvn_subr/iter.c
@@ -143,3 +143,29 @@ svn_iter__break(void)
{
return &internal_break_error;
}
+
+#if !APR_VERSION_AT_LEAST(1, 5, 0)
+const void *apr_hash_this_key(apr_hash_index_t *hi)
+{
+ const void *key;
+
+ apr_hash_this((apr_hash_index_t *)hi, &key, NULL, NULL);
+ return key;
+}
+
+apr_ssize_t apr_hash_this_key_len(apr_hash_index_t *hi)
+{
+ apr_ssize_t klen;
+
+ apr_hash_this((apr_hash_index_t *)hi, NULL, &klen, NULL);
+ return klen;
+}
+
+void *apr_hash_this_val(apr_hash_index_t *hi)
+{
+ void *val;
+
+ apr_hash_this((apr_hash_index_t *)hi, NULL, NULL, &val);
+ return val;
+}
+#endif
diff --git a/subversion/libsvn_subr/opt.c b/subversion/libsvn_subr/opt.c
index 1a9beb646f89..2832553d1f41 100644
--- a/subversion/libsvn_subr/opt.c
+++ b/subversion/libsvn_subr/opt.c
@@ -326,7 +326,7 @@ print_command_info3(const svn_opt_subcommand_desc3_t *cmd,
}
}
- if (!verbose)
+ if (!verbose && global_options && *global_options)
SVN_ERR(svn_cmdline_fputs(_("\n(Use '-v' to show global and experimental options.)\n"),
stream, pool));
if (have_options)
diff --git a/subversion/libsvn_subr/version.c b/subversion/libsvn_subr/version.c
index 1c50ad0e7a5d..cbb09f55812d 100644
--- a/subversion/libsvn_subr/version.c
+++ b/subversion/libsvn_subr/version.c
@@ -143,7 +143,7 @@ svn_version_extended(svn_boolean_t verbose,
info->build_time = __TIME__;
info->build_host = SVN_BUILD_HOST;
info->copyright = apr_pstrdup
- (pool, _("Copyright (C) 2020 The Apache Software Foundation.\n"
+ (pool, _("Copyright (C) 2021 The Apache Software Foundation.\n"
"This software consists of contributions made by many people;\n"
"see the NOTICE file for more information.\n"
"Subversion is open source software, see "