editor.c
来自「linux subdivision ying gai ke yi le ba」· C语言 代码 · 共 739 行 · 第 1/2 页
C
739 行
/*
* editor.c : Driving and consuming an editor across an svn connection
*
* ====================================================================
* 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/.
* ====================================================================
*/
#define APR_WANT_STRFUNC
#include <apr_want.h>
#include <apr_general.h>
#include <apr_lib.h>
#include <apr_strings.h>
#include <apr_md5.h>
#include <assert.h>
#include "svn_types.h"
#include "svn_string.h"
#include "svn_error.h"
#include "svn_path.h"
#include "svn_delta.h"
#include "svn_ra_svn.h"
#include "svn_pools.h"
#include "svn_md5.h"
#include "ra_svn.h"
/*
* Both the client and server in the svn protocol need to drive and
* consume editors. For a commit, the client drives and the server
* consumes; for an update/switch/status/diff, the server drives and
* the client consumes. This file provides a generic framework for
* marshalling and unmarshalling editor operations over an svn
* connection; both ends are useful for both server and client.
*/
typedef struct {
svn_ra_svn_conn_t *conn;
svn_ra_svn_edit_callback callback; /* Called on successful completion. */
void *callback_baton;
int next_token;
} ra_svn_edit_baton_t;
/* Works for both directories and files. */
typedef struct {
svn_ra_svn_conn_t *conn;
apr_pool_t *pool;
ra_svn_edit_baton_t *eb;
const char *token;
} ra_svn_baton_t;
typedef struct {
const svn_delta_editor_t *editor;
void *edit_baton;
apr_hash_t *tokens;
svn_boolean_t *aborted;
apr_pool_t *pool;
} ra_svn_driver_state_t;
typedef struct {
const char *token;
void *baton;
svn_error_t *err; /* Tracks delayed errors. */
apr_pool_t *pool;
} ra_svn_token_entry_t;
/* --- CONSUMING AN EDITOR BY PASSING EDIT OPERATIONS OVER THE NET --- */
static const char *make_token(char type, ra_svn_edit_baton_t *eb,
apr_pool_t *pool)
{
return apr_psprintf(pool, "%c%d", type, eb->next_token++);
}
static ra_svn_baton_t *ra_svn_make_baton(svn_ra_svn_conn_t *conn,
apr_pool_t *pool,
ra_svn_edit_baton_t *eb,
const char *token)
{
ra_svn_baton_t *b;
b = apr_palloc(pool, sizeof(*b));
b->conn = conn;
b->pool = pool;
b->eb = eb;
b->token = token;
return b;
}
static svn_error_t *ra_svn_target_rev(void *edit_baton, svn_revnum_t rev,
apr_pool_t *pool)
{
ra_svn_edit_baton_t *eb = edit_baton;
SVN_ERR(svn_ra_svn_write_cmd(eb->conn, pool, "target-rev", "r", rev));
SVN_ERR(svn_ra_svn_read_cmd_response(eb->conn, pool, ""));
return SVN_NO_ERROR;
}
static svn_error_t *ra_svn_open_root(void *edit_baton, svn_revnum_t rev,
apr_pool_t *pool, void **root_baton)
{
ra_svn_edit_baton_t *eb = edit_baton;
const char *token = make_token('d', eb, pool);
SVN_ERR(svn_ra_svn_write_cmd(eb->conn, pool, "open-root", "(?r)c", rev,
token));
SVN_ERR(svn_ra_svn_read_cmd_response(eb->conn, pool, ""));
*root_baton = ra_svn_make_baton(eb->conn, pool, eb, token);
return SVN_NO_ERROR;
}
static svn_error_t *ra_svn_delete_entry(const char *path, svn_revnum_t rev,
void *parent_baton, apr_pool_t *pool)
{
ra_svn_baton_t *b = parent_baton;
SVN_ERR(svn_ra_svn_write_cmd(b->conn, pool, "delete-entry", "c(?r)c",
path, rev, b->token));
SVN_ERR(svn_ra_svn_read_cmd_response(b->conn, pool, ""));
return SVN_NO_ERROR;
}
static svn_error_t *ra_svn_add_dir(const char *path, void *parent_baton,
const char *copy_path,
svn_revnum_t copy_rev,
apr_pool_t *pool, void **child_baton)
{
ra_svn_baton_t *b = parent_baton;
const char *token = make_token('d', b->eb, pool);
assert((copy_path && SVN_IS_VALID_REVNUM(copy_rev))
|| (!copy_path && !SVN_IS_VALID_REVNUM(copy_rev)));
SVN_ERR(svn_ra_svn_write_cmd(b->conn, pool, "add-dir", "ccc(?cr)", path,
b->token, token, copy_path, copy_rev));
SVN_ERR(svn_ra_svn_read_cmd_response(b->conn, pool, ""));
*child_baton = ra_svn_make_baton(b->conn, pool, b->eb, token);
return SVN_NO_ERROR;
}
static svn_error_t *ra_svn_open_dir(const char *path, void *parent_baton,
svn_revnum_t rev, apr_pool_t *pool,
void **child_baton)
{
ra_svn_baton_t *b = parent_baton;
const char *token = make_token('d', b->eb, pool);
SVN_ERR(svn_ra_svn_write_cmd(b->conn, pool, "open-dir", "ccc(?r)",
path, b->token, token, rev));
SVN_ERR(svn_ra_svn_read_cmd_response(b->conn, pool, ""));
*child_baton = ra_svn_make_baton(b->conn, pool, b->eb, token);
return SVN_NO_ERROR;
}
static svn_error_t *ra_svn_change_dir_prop(void *dir_baton, const char *name,
const svn_string_t *value,
apr_pool_t *pool)
{
ra_svn_baton_t *b = dir_baton;
SVN_ERR(svn_ra_svn_write_cmd(b->conn, pool, "change-dir-prop", "cc(?s)",
b->token, name, value));
return SVN_NO_ERROR;
}
static svn_error_t *ra_svn_close_dir(void *dir_baton, apr_pool_t *pool)
{
ra_svn_baton_t *b = dir_baton;
SVN_ERR(svn_ra_svn_write_cmd(b->conn, pool, "close-dir", "c", b->token));
SVN_ERR(svn_ra_svn_read_cmd_response(b->conn, pool, ""));
return SVN_NO_ERROR;
}
static svn_error_t *ra_svn_add_file(const char *path,
void *parent_baton,
const char *copy_path,
svn_revnum_t copy_rev,
apr_pool_t *pool,
void **file_baton)
{
ra_svn_baton_t *b = parent_baton;
const char *token = make_token('c', b->eb, pool);
assert((copy_path && SVN_IS_VALID_REVNUM(copy_rev))
|| (!copy_path && !SVN_IS_VALID_REVNUM(copy_rev)));
SVN_ERR(svn_ra_svn_write_cmd(b->conn, pool, "add-file", "ccc(?cr)", path,
b->token, token, copy_path, copy_rev));
*file_baton = ra_svn_make_baton(b->conn, pool, b->eb, token);
return SVN_NO_ERROR;
}
static svn_error_t *ra_svn_open_file(const char *path,
void *parent_baton,
svn_revnum_t rev,
apr_pool_t *pool,
void **file_baton)
{
ra_svn_baton_t *b = parent_baton;
const char *token = make_token('c', b->eb, pool);
SVN_ERR(svn_ra_svn_write_cmd(b->conn, pool, "open-file", "ccc(?r)",
path, b->token, token, rev));
*file_baton = ra_svn_make_baton(b->conn, pool, b->eb, token);
return SVN_NO_ERROR;
}
static svn_error_t *ra_svn_svndiff_handler(void *baton, const char *data,
apr_size_t *len)
{
ra_svn_baton_t *b = baton;
svn_string_t str;
str.data = data;
str.len = *len;
return svn_ra_svn_write_string(b->conn, b->pool, &str);
}
static svn_error_t *ra_svn_svndiff_close_handler(void *baton)
{
ra_svn_baton_t *b = baton;
SVN_ERR(svn_ra_svn_write_cstring(b->conn, b->pool, ""));
return SVN_NO_ERROR;
}
static svn_error_t *ra_svn_apply_textdelta(void *file_baton,
const char *base_checksum,
apr_pool_t *pool,
svn_txdelta_window_handler_t *wh,
void **wh_baton)
{
ra_svn_baton_t *b = file_baton;
svn_stream_t *diff_stream;
/* Tell the other side we're starting a text delta. */
SVN_ERR(svn_ra_svn_write_cmd(b->conn, pool, "apply-textdelta", "c(?c)",
b->token, base_checksum));
/* Transform the window stream to an svndiff stream. Reuse the
* file baton for the stream handler, since it has all the
* needed information. */
diff_stream = svn_stream_create(b, pool);
svn_stream_set_write(diff_stream, ra_svn_svndiff_handler);
svn_stream_set_close(diff_stream, ra_svn_svndiff_close_handler);
svn_txdelta_to_svndiff(diff_stream, pool, wh, wh_baton);
return SVN_NO_ERROR;
}
static svn_error_t *ra_svn_change_file_prop(void *file_baton,
const char *name,
const svn_string_t *value,
apr_pool_t *pool)
{
ra_svn_baton_t *b = file_baton;
SVN_ERR(svn_ra_svn_write_cmd(b->conn, pool, "change-file-prop", "cc(?s)",
b->token, name, value));
return SVN_NO_ERROR;
}
static svn_error_t *ra_svn_close_file(void *file_baton,
const char *text_checksum,
apr_pool_t *pool)
{
ra_svn_baton_t *b = file_baton;
SVN_ERR(svn_ra_svn_write_cmd(b->conn, pool, "close-file", "c(?c)",
b->token, text_checksum));
SVN_ERR(svn_ra_svn_read_cmd_response(b->conn, pool, ""));
return SVN_NO_ERROR;
}
static svn_error_t *ra_svn_close_edit(void *edit_baton, apr_pool_t *pool)
{
ra_svn_edit_baton_t *eb = edit_baton;
SVN_ERR(svn_ra_svn_write_cmd(eb->conn, pool, "close-edit", ""));
SVN_ERR(svn_ra_svn_read_cmd_response(eb->conn, pool, ""));
if (eb->callback)
SVN_ERR(eb->callback(eb->callback_baton));
return SVN_NO_ERROR;
}
static svn_error_t *ra_svn_abort_edit(void *edit_baton, apr_pool_t *pool)
{
ra_svn_edit_baton_t *eb = edit_baton;
SVN_ERR(svn_ra_svn_write_cmd(eb->conn, pool, "abort-edit", ""));
SVN_ERR(svn_ra_svn_read_cmd_response(eb->conn, pool, ""));
return SVN_NO_ERROR;
}
void svn_ra_svn_get_editor(const svn_delta_editor_t **editor,
void **edit_baton, svn_ra_svn_conn_t *conn,
apr_pool_t *pool, svn_ra_svn_edit_callback callback,
void *callback_baton)
{
svn_delta_editor_t *ra_svn_editor;
ra_svn_edit_baton_t *eb;
if (svn_ra_svn_has_capability(conn, SVN_RA_SVN_CAP_EDIT_PIPELINE))
{
svn_ra_svn__get_editorp(editor, edit_baton, conn, pool, callback,
callback_baton);
return;
}
eb = apr_palloc(pool, sizeof(*eb));
eb->conn = conn;
eb->callback = callback;
eb->callback_baton = callback_baton;
eb->next_token = 0;
ra_svn_editor = svn_delta_default_editor(pool);
ra_svn_editor->set_target_revision = ra_svn_target_rev;
ra_svn_editor->open_root = ra_svn_open_root;
ra_svn_editor->delete_entry = ra_svn_delete_entry;
ra_svn_editor->add_directory = ra_svn_add_dir;
ra_svn_editor->open_directory = ra_svn_open_dir;
ra_svn_editor->change_dir_prop = ra_svn_change_dir_prop;
ra_svn_editor->close_directory = ra_svn_close_dir;
ra_svn_editor->add_file = ra_svn_add_file;
ra_svn_editor->open_file = ra_svn_open_file;
ra_svn_editor->apply_textdelta = ra_svn_apply_textdelta;
ra_svn_editor->change_file_prop = ra_svn_change_file_prop;
ra_svn_editor->close_file = ra_svn_close_file;
ra_svn_editor->close_edit = ra_svn_close_edit;
ra_svn_editor->abort_edit = ra_svn_abort_edit;
*editor = ra_svn_editor;
*edit_baton = eb;
}
/* --- DRIVING AN EDITOR --- */
static apr_status_t clear_token_err(void *arg)
{
ra_svn_token_entry_t *entry = arg;
svn_error_clear(entry->err);
return APR_SUCCESS;
}
/* Store a token entry. The token string will be copied into pool. */
static ra_svn_token_entry_t *store_token(ra_svn_driver_state_t *ds,
void *baton, const char *token,
apr_pool_t *pool)
{
ra_svn_token_entry_t *entry;
entry = apr_palloc(pool, sizeof(*entry));
entry->token = apr_pstrdup(pool, token);
entry->baton = baton;
entry->err = NULL;
entry->pool = pool;
apr_hash_set(ds->tokens, entry->token, APR_HASH_KEY_STRING, entry);
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?