📄 util.c
字号:
/*
* util.c: Subversion command line client utility functions. Any
* functions that need to be shared across subcommands should be put
* in here.
*
* ====================================================================
* Copyright (c) 2000-2004 CollabNet. All rights reserved.
*
* This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms
* are also available at http://subversion.tigris.org/license-1.html.
* If newer versions of this license are posted there, you may use a
* newer version instead, at your option.
*
* This software consists of voluntary contributions made by many
* individuals. For exact contribution history, see the revision
* history and logs, available at http://subversion.tigris.org/.
* ====================================================================
*/
/* ==================================================================== */
/*** Includes. ***/
#include <string.h>
#include <ctype.h>
#include <assert.h>
#include <apr_strings.h>
#include <apr_tables.h>
#include <apr_general.h>
#include <apr_lib.h>
#include "svn_wc.h"
#include "svn_client.h"
#include "svn_cmdline.h"
#include "svn_string.h"
#include "svn_path.h"
#include "svn_delta.h"
#include "svn_error.h"
#include "svn_io.h"
#include "svn_pools.h"
#include "svn_utf.h"
#include "svn_subst.h"
#include "svn_config.h"
#include "svn_private_config.h"
#include "cl.h"
svn_error_t *
svn_cl__print_commit_info (svn_client_commit_info_t *commit_info,
apr_pool_t *pool)
{
if ((commit_info)
&& (SVN_IS_VALID_REVNUM (commit_info->revision)))
SVN_ERR (svn_cmdline_printf (pool, _("\nCommitted revision %ld.\n"),
commit_info->revision));
return SVN_NO_ERROR;
}
svn_error_t *
svn_cl__edit_externally (svn_string_t **edited_contents /* UTF-8! */,
const char **tmpfile_left /* UTF-8! */,
const char *editor_cmd,
const char *base_dir /* UTF-8! */,
const svn_string_t *contents /* UTF-8! */,
const char *prefix,
apr_hash_t *config,
svn_boolean_t as_text,
const char *encoding,
apr_pool_t *pool)
{
const char *editor = NULL;
const char *cmd;
apr_file_t *tmp_file;
const char *tmpfile_name;
const char *tmpfile_native;
const char *tmpfile_apr, *base_dir_apr;
svn_string_t *translated_contents;
apr_status_t apr_err, apr_err2;
apr_size_t written;
apr_finfo_t finfo_before, finfo_after;
svn_error_t *err = SVN_NO_ERROR, *err2;
char *old_cwd;
int sys_err;
svn_boolean_t remove_file = TRUE;
struct svn_config_t *cfg;
/* Look for the Subversion specific environment variable. */
editor = getenv ("SVN_EDITOR");
/* If not found then fall back on the config file. */
if (! editor)
{
cfg = config ? apr_hash_get (config, SVN_CONFIG_CATEGORY_CONFIG,
APR_HASH_KEY_STRING) : NULL;
svn_config_get (cfg, &editor, SVN_CONFIG_SECTION_HELPERS,
SVN_CONFIG_OPTION_EDITOR_CMD, NULL);
}
/* If not found yet then try general purpose environment variables. */
if (! editor)
editor = getenv ("VISUAL");
if (! editor)
editor = getenv ("EDITOR");
#ifdef SVN_CLIENT_EDITOR
/* If still not found then fall back on the hard-coded default. */
if (! editor)
editor = SVN_CLIENT_EDITOR;
#endif
/* Override further with the editor specified on the command line
via --editor-cmd, if any. */
if (editor_cmd)
editor = editor_cmd;
/* Abort if there is no editor specified */
if (! editor)
return svn_error_create
(SVN_ERR_CL_NO_EXTERNAL_EDITOR, NULL,
_("None of the environment variables SVN_EDITOR, VISUAL or EDITOR is "
"set, and no 'editor-cmd' run-time configuration option was found"));
/* Convert file contents from UTF-8/LF if desired. */
if (as_text)
{
const char *translated;
SVN_ERR (svn_subst_translate_cstring (contents->data, &translated,
APR_EOL_STR, FALSE,
NULL, FALSE, pool));
translated_contents = svn_string_create ("", pool);
if (encoding)
SVN_ERR (svn_utf_cstring_from_utf8_ex (&translated_contents->data,
translated, encoding, NULL,
pool));
else
SVN_ERR (svn_utf_cstring_from_utf8 (&translated_contents->data,
translated, pool));
translated_contents->len = strlen (translated_contents->data);
}
else
translated_contents = svn_string_dup (contents, pool);
/* Move to BASE_DIR to avoid getting characters that need quoting
into tmpfile_name */
apr_err = apr_filepath_get (&old_cwd, APR_FILEPATH_NATIVE, pool);
if (apr_err)
return svn_error_wrap_apr (apr_err, _("Can't get working directory"));
/* APR doesn't like "" directories */
if (base_dir[0] == '\0')
base_dir_apr = ".";
else
SVN_ERR (svn_path_cstring_from_utf8 (&base_dir_apr, base_dir, pool));
apr_err = apr_filepath_set (base_dir_apr, pool);
if (apr_err)
{
return svn_error_wrap_apr
(apr_err, _("Can't change working directory to '%s'"), base_dir);
}
/*** From here on, any problems that occur require us to cd back!! ***/
/* Ask the working copy for a temporary file that starts with
PREFIX. */
err = svn_io_open_unique_file (&tmp_file, &tmpfile_name,
prefix, ".tmp", FALSE, pool);
if (err)
goto cleanup2;
/*** From here on, any problems that occur require us to cleanup
the file we just created!! ***/
/* Dump initial CONTENTS to TMP_FILE. */
apr_err = apr_file_write_full (tmp_file, translated_contents->data,
translated_contents->len, &written);
apr_err2 = apr_file_close (tmp_file);
if (! apr_err)
apr_err = apr_err2;
/* Make sure the whole CONTENTS were written, else return an error. */
if (apr_err)
{
err = svn_error_wrap_apr (apr_err, _("Can't write to '%s'"),
tmpfile_name);
goto cleanup;
}
err = svn_path_cstring_from_utf8 (&tmpfile_apr, tmpfile_name, pool);
if (err)
goto cleanup;
/* Get information about the temporary file before the user has
been allowed to edit its contents. */
apr_err = apr_stat (&finfo_before, tmpfile_apr,
APR_FINFO_MTIME | APR_FINFO_SIZE, pool);
if (apr_err)
{
err = svn_error_wrap_apr (apr_err, _("Can't stat '%s'"), tmpfile_name);
goto cleanup;
}
/* Now, run the editor command line. */
err = svn_utf_cstring_from_utf8 (&tmpfile_native, tmpfile_name, pool);
if (err)
goto cleanup;
cmd = apr_psprintf (pool, "%s %s", editor, tmpfile_native);
sys_err = system (cmd);
if (sys_err != 0)
{
/* Extracting any meaning from sys_err is platform specific, so just
use the raw value. */
err = svn_error_createf (SVN_ERR_EXTERNAL_PROGRAM, NULL,
_("system('%s') returned %d"), cmd, sys_err);
goto cleanup;
}
/* Get information about the temporary file after the assumed editing. */
apr_err = apr_stat (&finfo_after, tmpfile_apr,
APR_FINFO_MTIME | APR_FINFO_SIZE, pool);
if (apr_err)
{
err = svn_error_wrap_apr (apr_err, _("Can't stat '%s'"), tmpfile_name);
goto cleanup;
}
/* If the file looks changed... */
if ((finfo_before.mtime != finfo_after.mtime) ||
(finfo_before.size != finfo_after.size))
{
svn_stringbuf_t *edited_contents_s;
err = svn_stringbuf_from_file (&edited_contents_s, tmpfile_name, pool);
if (err)
goto cleanup;
*edited_contents = svn_string_create_from_buf (edited_contents_s, pool);
/* Translate back to UTF8/LF if desired. */
if (as_text)
{
err = svn_subst_translate_string (edited_contents, *edited_contents,
encoding, pool);
if (err)
goto cleanup;
}
}
else
{
/* No edits seem to have been made */
*edited_contents = NULL;
}
/* If the caller wants us to leave the file around, return the path
of the file we used, and make a note not to destroy it. */
if (tmpfile_left)
{
*tmpfile_left = svn_path_join (base_dir, tmpfile_name, pool);
remove_file = FALSE;
}
cleanup:
if (remove_file)
{
/* Remove the file from disk. */
err2 = svn_io_remove_file (tmpfile_name, pool);
/* Only report remove error if there was no previous error. */
if (! err && err2)
err = err2;
}
cleanup2:
/* If we against all probability can't cd back, all further relative
file references would be screwed up, so we have to abort. */
apr_err = apr_filepath_set (old_cwd, pool);
if (apr_err)
{
svn_handle_error (svn_error_wrap_apr
(apr_err, _("Can't restore working directory")),
stderr, TRUE /* fatal */);
}
return err;
}
struct log_msg_baton
{
const char *editor_cmd; /* editor specified via --editor-cmd, else NULL */
const char *message; /* the message. */
const char *message_encoding; /* the locale/encoding of the message. */
const char *base_dir; /* the base directory for an external edit. UTF-8! */
const char *tmpfile_left; /* the tmpfile left by an external edit. UTF-8! */
apr_hash_t *config; /* client configuration hash */
apr_pool_t *pool; /* a pool. */
};
svn_error_t *
svn_cl__make_log_msg_baton (void **baton,
svn_cl__opt_state_t *opt_state,
const char *base_dir /* UTF-8! */,
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -