Author: rinrab
Date: Sun Apr 5 17:02:57 2026
New Revision: 1932857
Log:
svnbrowse: Separate tool's code onto separate files; header, model, and the
"main".
* subversion/svnbrowse/svnbrowse.h: svncopy from svnbrowse.c
(includes): Cleanup.
(opt_): Declare enum.
(svn_browse__opt_state_t, svn_browse__item_t, svn_browse__state_t,
svn_browse__model_t): Declare structs.
(svn_browse__state_create, svn_browse__model_enter_path,
svn_browse__model_get_selected_item, svn_browse__model_go_enter,
svn_browse__model_go_up, svn_browse__model_move_selection,
svn_browse__model_create): Declare functions.
* subversion/svnbrowse/model.c: svncopy from svnbrowse.c
(includes): Cleanup.
(svn_browse__state_create, svn_browse__model_enter_path,
svn_browse__model_get_selected_item, svn_browse__model_go_enter,
svn_browse__model_go_up, svn_browse__model_move_selection,
svn_browse__model_create): Leave those functions in this file.
(everywhere): Update references to model and state function becuase they
were renamed to include svn_browse__ prefix in it.
* subversion/svnbrowse/svnbrowse.c
(svn_browse__state_create, svn_browse__model_enter_path,
svn_browse__model_get_selected_item, svn_browse__model_go_enter,
svn_browse__model_go_up, svn_browse__model_move_selection,
svn_browse__model_create, svn_browse__opt_state_t, svn_browse__item_t,
svn_browse__state_t, svn_browse__model_t, opt_): Those symbols have been
moved away from here.
(everywhere): Update references to model and state function becuase they
were renamed to include svn_browse__ prefix in it.
Added:
subversion/trunk/subversion/svnbrowse/model.c
- copied, changed from r1932856,
subversion/trunk/subversion/svnbrowse/svnbrowse.c
subversion/trunk/subversion/svnbrowse/svnbrowse.h
- copied, changed from r1932856,
subversion/trunk/subversion/svnbrowse/svnbrowse.c
Modified:
subversion/trunk/subversion/svnbrowse/svnbrowse.c
Copied and modified: subversion/trunk/subversion/svnbrowse/model.c (from
r1932856, subversion/trunk/subversion/svnbrowse/svnbrowse.c)
==============================================================================
--- subversion/trunk/subversion/svnbrowse/svnbrowse.c Sun Apr 5 12:49:23
2026 (r1932856, copy source)
+++ subversion/trunk/subversion/svnbrowse/model.c Sun Apr 5 17:02:57
2026 (r1932857)
@@ -1,6 +1,5 @@
/*
- * svnbrowse.c: TUI (terminal user interface) client for browsing and
- * exploring remote Subversion targets.
+ * model.c: the application state
*
* ====================================================================
* Licensed to the Apache Software Foundation (ASF) under one
@@ -24,164 +23,22 @@
#include <apr.h>
-#include "svn_cmdline.h"
#include "svn_client.h"
-#include "svn_opt.h"
+#include "svn_cmdline.h"
+#include "svn_dirent_uri.h"
#include "svn_ra.h"
-#include "svn_path.h"
#include "svn_pools.h"
-#include "svn_cmdline.h"
#include "svn_error.h"
-#include "private/svn_cmdline_private.h"
+#include "svnbrowse.h"
-#include <ncurses.h>
-
-#include "svn_private_config.h"
-
-enum {
- opt_auth_password = SVN_OPT_FIRST_LONGOPT_ID,
- opt_auth_password_from_stdin,
- opt_auth_username,
- opt_config_dir,
- opt_config_option,
- opt_no_auth_cache,
- opt_version,
- opt_trust_server_cert,
- opt_trust_server_cert_failures,
- opt_password_from_stdin,
-};
-
-typedef struct svn_browse__opt_state_t {
- svn_boolean_t version; /* print version information */
- svn_boolean_t verbose; /* for svnbrowse --version */
- svn_boolean_t quiet; /* for svnbrowse --version */
- svn_boolean_t help; /* print usage message */
-
- const char *auth_username; /* auth username */
- const char *auth_password; /* auth password */
- apr_array_header_t *targets; /* target list from file */
- svn_boolean_t no_auth_cache; /* do not cache authentication information */
- const char *config_dir; /* over-riding configuration directory */
- apr_array_header_t *config_options; /* over-riding configuration options */
- svn_opt_revision_t revision;
-
- /* trust server SSL certs that would otherwise be rejected as "untrusted" */
- svn_boolean_t trust_server_cert_unknown_ca;
- svn_boolean_t trust_server_cert_cn_mismatch;
- svn_boolean_t trust_server_cert_expired;
- svn_boolean_t trust_server_cert_not_yet_valid;
- svn_boolean_t trust_server_cert_other_failure;
-} svn_browse__opt_state_t;
-
-/* Option codes and descriptions for the command line client.
- * The entire list must be terminated with an entry of nulls. */
-const apr_getopt_option_t svn_browse__options[] =
-{
- {"username", opt_auth_username, 1, N_("specify a username ARG")},
- {"password", opt_auth_password, 1,
- N_("specify a password ARG (caution: on many operating\n"
- " "
- "systems, other users will be able to see this)")},
- {"password-from-stdin",
- opt_auth_password_from_stdin, 0,
- N_("read password from stdin")},
- {"revision", 'r', 1,
- N_("ARG\n"
- " "
- "A revision argument can be one of:\n"
- " "
- " NUMBER revision number\n"
- " "
- " '{' DATE '}' revision at start of the date\n"
- " "
- " 'HEAD' latest in repository\n"
- " "
- " 'BASE' base rev of item's working copy\n"
- " "
- " 'COMMITTED' last commit at or before BASE\n"
- " "
- " 'PREV' revision just before COMMITTED")},
- {"help", 'h', 0, N_("show help on a subcommand")},
- {NULL, '?', 0, N_("show help on a subcommand")},
- {"trust-server-cert", opt_trust_server_cert, 0,
- N_("deprecated; same as\n"
- " "
- "--trust-server-cert-failures=unknown-ca")},
- {"trust-server-cert-failures", opt_trust_server_cert_failures, 1,
- N_("with --non-interactive, accept SSL server\n"
- " "
- "certificates with failures; ARG is comma-separated\n"
- " "
- "list of 'unknown-ca' (Unknown Authority),\n"
- " "
- "'cn-mismatch' (Hostname mismatch), 'expired'\n"
- " "
- "(Expired certificate), 'not-yet-valid' (Not yet\n"
- " "
- "valid certificate) and 'other' (all other not\n"
- " "
- "separately classified certificate errors).")},
- {"config-dir", opt_config_dir, 1,
- N_("read user configuration files from directory ARG")},
- {"config-option", opt_config_option, 1,
- N_("set user configuration option in the format:\n"
- " "
- " FILE:SECTION:OPTION=[VALUE]\n"
- " "
- "For example:\n"
- " "
- " servers:global:http-library=serf")},
- {"no-auth-cache", opt_no_auth_cache, 0,
- N_("do not cache authentication tokens")},
- {"version", opt_version, 0, N_("show program version information")},
- {"verbose", 'v', 0, N_("print extra information")},
- { NULL, 0, 0, NULL }
-};
-
-/* Control+ASCII character are represented as values 1-26 according to their
- * alphabetical order. */
-#define CTRL(ch) ((ch) - 'a' + 1)
-
-typedef struct svn_browse__item_t {
- const char *name;
- const svn_dirent_t *dirent;
-} svn_browse__item_t;
-
-/* a state of a single directory */
-typedef struct svn_browse__state_t {
- /* information about this node */
- const char *relpath;
- svn_revnum_t revision;
-
- /* stores the list of nodes in this state; an array of svn_browse__item_t */
- apr_array_header_t *list;
-
- /* the index of hovered item */
- int selection;
-
- /* a pool where the structure is allocated */
- apr_pool_t *pool;
-} svn_browse__state_t;
-
-typedef struct svn_browse__model_t {
- const char *root;
- svn_revnum_t revision;
-
- svn_client_ctx_t *client;
- svn_ra_session_t *session;
-
- svn_browse__state_t *current;
- apr_pool_t *pool;
-} svn_browse__model_t;
-
-static svn_error_t *
-state_create(svn_browse__state_t **state_p,
- svn_ra_session_t *session,
- const char *relpath,
- svn_revnum_t revision,
- apr_pool_t *result_pool,
- apr_pool_t *scratch_pool)
+svn_error_t *
+svn_browse__state_create(svn_browse__state_t **state_p,
+ svn_ra_session_t *session,
+ const char *relpath,
+ svn_revnum_t revision,
+ apr_pool_t *result_pool,
+ apr_pool_t *scratch_pool)
{
svn_browse__state_t *state = apr_pcalloc(result_pool, sizeof(*state));
svn_revnum_t fetched_revnum;
@@ -213,15 +70,15 @@ state_create(svn_browse__state_t **state
return SVN_NO_ERROR;
}
-static svn_error_t *
-model_enter_path(svn_browse__model_t *ctx, const char *relpath,
+svn_error_t *
+svn_browse__model_enter_path(svn_browse__model_t *ctx, const char *relpath,
apr_pool_t *scratch_pool)
{
svn_browse__state_t *newstate;
apr_pool_t *state_pool = svn_pool_create(ctx->pool);
- SVN_ERR(state_create(&newstate, ctx->session, relpath, ctx->revision,
- state_pool, scratch_pool));
+ SVN_ERR(svn_browse__state_create(&newstate, ctx->session, relpath,
+ ctx->revision, state_pool, scratch_pool));
/* switch to the next state and nuke the previous one */
apr_pool_destroy(ctx->current->pool);
@@ -230,32 +87,34 @@ model_enter_path(svn_browse__model_t *ct
return SVN_NO_ERROR;
}
-static svn_browse__item_t *
-model_get_selected_item(svn_browse__model_t *model)
+svn_browse__item_t *
+svn_browse__model_get_selected_item(svn_browse__model_t *model)
{
return APR_ARRAY_IDX(model->current->list, model->current->selection,
svn_browse__item_t *);
}
-static svn_error_t *
-model_go_enter(svn_browse__model_t *model, apr_pool_t *scratch_pool)
+svn_error_t *
+svn_browse__model_go_enter(svn_browse__model_t *model, apr_pool_t
*scratch_pool)
{
- svn_browse__item_t *item = model_get_selected_item(model);
+ svn_browse__item_t *item = svn_browse__model_get_selected_item(model);
const char *new_url = svn_relpath_join(model->current->relpath, item->name,
scratch_pool);
- return svn_error_trace(model_enter_path(model, new_url, scratch_pool));
+ return svn_error_trace(svn_browse__model_enter_path(model, new_url,
+ scratch_pool));
}
-static svn_error_t *
-model_go_up(svn_browse__model_t *model, apr_pool_t *scratch_pool)
+svn_error_t *
+svn_browse__model_go_up(svn_browse__model_t *model, apr_pool_t *scratch_pool)
{
const char *new_url = svn_relpath_dirname(model->current->relpath,
scratch_pool);
- return svn_error_trace(model_enter_path(model, new_url, scratch_pool));
+ return svn_error_trace(svn_browse__model_enter_path(model, new_url,
+ scratch_pool));
}
-static svn_error_t *
-model_move_selection(svn_browse__model_t *model, int delta)
+svn_error_t *
+svn_browse__model_move_selection(svn_browse__model_t *model, int delta)
{
model->current->selection += delta;
@@ -268,12 +127,12 @@ model_move_selection(svn_browse__model_t
return SVN_NO_ERROR;
}
-static svn_error_t *
-model_create(svn_browse__model_t **model_p,
- const char *url,
- svn_revnum_t revision,
- apr_pool_t *result_pool,
- apr_pool_t *scratch_pool)
+svn_error_t *
+svn_browse__model_create(svn_browse__model_t **model_p,
+ const char *url,
+ svn_revnum_t revision,
+ apr_pool_t *result_pool,
+ apr_pool_t *scratch_pool)
{
svn_browse__model_t *model = apr_pcalloc(result_pool, sizeof(*model));
svn_auth_baton_t *auth;
@@ -301,8 +160,8 @@ model_create(svn_browse__model_t **model
/* the state should be in a separate pool so it's safe to free it */
state_pool = svn_pool_create(result_pool);
- SVN_ERR(state_create(&state, session, relpath, revision, state_pool,
- scratch_pool));
+ SVN_ERR(svn_browse__state_create(&state, session, relpath, revision,
+ state_pool, scratch_pool));
model->root = apr_pstrdup(result_pool, root);
model->revision = revision;
@@ -314,311 +173,3 @@ model_create(svn_browse__model_t **model
*model_p = model;
return SVN_NO_ERROR;
}
-
-typedef struct svn_browse__view_t {
- /* TODO: store information about terminal screen (a WINDOW* in curses world)
*/
- svn_browse__model_t *model;
-} svn_browse__view_t;
-
-static svn_browse__view_t *
-view_make(svn_browse__model_t *model, apr_pool_t *result_pool)
-{
- svn_browse__view_t *view = apr_pcalloc(result_pool, sizeof(*view));
- view->model = model;
- return view;
-}
-
-static void
-view_draw(svn_browse__view_t *view, apr_pool_t *pool)
-{
- int i;
- const char *abspath = svn_path_url_add_component2(
- view->model->root, view->model->current->relpath, pool);
-
- mvprintw(0, 4, "Browsing: %s", abspath);
-
- for (i = 0; i < view->model->current->list->nelts; i++)
- {
- svn_browse__item_t *item = APR_ARRAY_IDX(view->model->current->list, i,
- svn_browse__item_t *);
-
- if (i == view->model->current->selection)
- standout();
-
- if (item->dirent->kind == svn_node_dir)
- mvprintw(i + 1, 0, "%s/", item->name);
- else if (item->dirent->kind == svn_node_file)
- mvprintw(i + 1, 0, "%s", item->name);
- else
- abort();
-
- mvprintw(i + 1, COLS - 40, "%8ld KiB r%-8ld %s",
- item->dirent->size / 1024,
- item->dirent->created_rev,
- item->dirent->last_author);
-
- if (i == view->model->current->selection)
- standend();
- }
-}
-
-static svn_error_t *
-show_usage(apr_pool_t *scratch_pool)
-{
- fprintf(stderr, "Type 'svnbrowse --help' for usage.\n");
- return SVN_NO_ERROR;
-}
-
-static svn_error_t *
-show_help(apr_pool_t *scratch_pool,
- const svn_browse__opt_state_t *opt_state)
-{
- svn_stringbuf_t *buf = svn_stringbuf_create_empty(scratch_pool);
- const apr_getopt_option_t *opt;
-
- svn_stringbuf_appendcstr(buf, N_(
- "usage: svnbrowse <target> [options]\n"
- "Interactively browse Subversion repositories\n"
- "\n"
- ));
-
- svn_stringbuf_appendcstr(buf, N_("Valid options:\n"));
- for (opt = svn_browse__options; opt->description; opt++)
- {
- if (opt->name)
- {
- const char *opts;
- svn_opt_format_option(&opts, opt, TRUE /* doc */, scratch_pool);
- svn_stringbuf_appendcstr(buf, " ");
- svn_stringbuf_appendcstr(buf, opts);
- svn_stringbuf_appendbyte(buf, '\n');
- }
- }
-
- return svn_error_trace(svn_cmdline_fputs(buf->data, stderr, scratch_pool));
-}
-
-static svn_error_t *
-show_version(apr_pool_t *scratch_pool,
- const svn_browse__opt_state_t *opt_state)
-{
- const char *ra_desc_start
- = "The following repository access (RA) modules are available:\n\n";
- svn_stringbuf_t *version_footer;
-
- version_footer = svn_stringbuf_create(ra_desc_start, scratch_pool);
- SVN_ERR(svn_ra_print_modules(version_footer, scratch_pool));
-
- SVN_ERR(svn_opt_print_help5(NULL,
- "svnbrowse",
- TRUE /* print_version */,
- opt_state->quiet,
- opt_state->verbose,
- version_footer->data,
- NULL, NULL, NULL, NULL, NULL,
- scratch_pool));
-
- return SVN_NO_ERROR;
-}
-
-static svn_error_t *
-sub_main(int *code, int argc, const char *argv[], apr_pool_t *pool)
-{
- const char *url;
- svn_browse__model_t *ctx;
- svn_browse__view_t *view;
- svn_browse__opt_state_t opt_state = { 0 };
- svn_boolean_t read_pass_from_stdin = FALSE;
- apr_pool_t *iterpool;
- apr_getopt_t *os;
-
- opt_state.revision.kind = svn_opt_revision_head;
- opt_state.config_options =
- apr_array_make(pool, 0, sizeof(svn_cmdline__config_argument_t *));
-
- SVN_ERR(svn_cmdline__getopt_init(&os, argc, argv, pool));
- os->interleave = 1;
-
- while (TRUE)
- {
- const char *opt_arg;
- int opt_id;
-
- /* Parse the next option. */
- apr_status_t status = apr_getopt_long(os, svn_browse__options, &opt_id,
- &opt_arg);
-
- if (APR_STATUS_IS_EOF(status))
- break;
- else if (status != APR_SUCCESS)
- {
- SVN_ERR(show_usage(pool));
- *code = EXIT_FAILURE;
- return SVN_NO_ERROR;
- }
-
- switch (opt_id)
- {
- case 'r':
- SVN_ERR(svn_opt_parse_one_revision(&opt_state.revision, opt_arg,
pool));
- break;
- case 'h':
- case '?':
- opt_state.help = TRUE;
- break;
- case opt_version:
- opt_state.version = TRUE;
- break;
- case opt_auth_username:
- opt_state.auth_username = apr_pstrdup(pool, opt_arg);
- break;
- case opt_auth_password:
- opt_state.auth_password = apr_pstrdup(pool, opt_arg);
- break;
- case opt_auth_password_from_stdin:
- read_pass_from_stdin = TRUE;
- break;
- case opt_no_auth_cache:
- opt_state.no_auth_cache = TRUE;
- break;
- /* ### can we drop it in a 1.16 tool? */
- case opt_trust_server_cert: /* backwards compat to 1.8 */
- opt_state.trust_server_cert_unknown_ca = TRUE;
- break;
- case opt_trust_server_cert_failures:
- SVN_ERR(svn_cmdline__parse_trust_options(
- &opt_state.trust_server_cert_unknown_ca,
- &opt_state.trust_server_cert_cn_mismatch,
- &opt_state.trust_server_cert_expired,
- &opt_state.trust_server_cert_not_yet_valid,
- &opt_state.trust_server_cert_other_failure,
- opt_arg, pool));
- break;
- case opt_config_dir:
- opt_state.config_dir = svn_dirent_internal_style(opt_arg, pool);
- break;
- case opt_config_option:
- SVN_ERR(svn_cmdline__parse_config_option(opt_state.config_options,
- opt_arg, "svnbrowse: ",
pool));
- break;
- default:
- break;
- }
- }
-
- if (opt_state.version)
- {
- SVN_ERR(show_version(pool, &opt_state));
- return SVN_NO_ERROR;
- }
-
- if (opt_state.help)
- {
- SVN_ERR(show_help(pool, &opt_state));
- return SVN_NO_ERROR;
- }
-
- /* TODO: WC paths are not implemented; svn_uri_canonicalize_safe() will just
- * fail in case of one */
- url = (os->ind < argc) ? os->argv[os->ind++] : ".";
- SVN_ERR(svn_uri_canonicalize_safe(&url, NULL, url, pool, pool));
-
- /* we must fail if there are extra arguments */
- if (os->ind < argc - 1)
- {
- printf("%d\n", os->ind);
- *code = EXIT_FAILURE;
- SVN_ERR(show_usage(pool));
- return SVN_NO_ERROR;
- }
-
- SVN_ERR(svn_config_ensure(opt_state.config_dir, pool));
-
- SVN_ERR(model_create(&ctx, url, SVN_INVALID_REVNUM, pool, pool));
-
- /* init the display */
- initscr();
-
- /* put ncurses into keypad mode to handle arrow inputs */
- intrflush(stdscr, FALSE);
- keypad(stdscr, TRUE);
- nonl();
-
- view = view_make(ctx, pool);
-
- iterpool = svn_pool_create(pool);
-
- while (TRUE)
- {
- svn_browse__item_t *item;
- const char *new_url;
-
- svn_pool_clear(iterpool);
-
- clear();
- view_draw(view, iterpool);
- refresh();
-
- /* getch() reads the next character/key with the following additional
- * rules:
- * 1. as we configured it to use keypad(), arrows and other special keys
- * are handled as KEY_XXX.
- * 2. Control (CTRL) version are handled as literal 1-26 values of ch
where
- * 1 is <C-A> and 26 is <C-Z>.
- * 3. The rest of keys remain as their equivalents on the current layout.
- * 4. If shift is held, they just become uppercased.
- */
- switch (getch())
- {
- case KEY_UP:
- case 'k':
- SVN_ERR(model_move_selection(ctx, -1));
- break;
- case KEY_DOWN:
- case 'j':
- SVN_ERR(model_move_selection(ctx, 1));
- break;
- case '\n':
- case '\r':
- SVN_ERR(model_go_enter(ctx, iterpool));
- break;
- case KEY_BACKSPACE:
- case '-':
- case 'u':
- SVN_ERR(model_go_up(ctx, iterpool));
- break;
- /* TODO: quit via escape. some say just check for 27, but it I think
it's
- * a bit ugly. */
- case 'q':
- goto quit;
- }
- }
-
-quit:
- endwin();
-
- return SVN_NO_ERROR;
-}
-
-int main(int argc, const char *argv[])
-{
- apr_pool_t *pool;
- int exit_code = EXIT_SUCCESS;
- svn_error_t *err;
-
- if (svn_cmdline_init("svnbrowse", stderr) != EXIT_SUCCESS)
- return EXIT_FAILURE;
-
- pool = apr_allocator_owner_get(svn_pool_create_allocator(FALSE));
-
- err = sub_main(&exit_code, argc, argv, pool);
-
- if (err)
- {
- exit_code = EXIT_FAILURE;
- svn_cmdline_handle_exit_error(err, NULL, "svnbrowse: ");
- }
-
- svn_pool_destroy(pool);
- return exit_code;
-}
Modified: subversion/trunk/subversion/svnbrowse/svnbrowse.c
==============================================================================
--- subversion/trunk/subversion/svnbrowse/svnbrowse.c Sun Apr 5 12:49:23
2026 (r1932856)
+++ subversion/trunk/subversion/svnbrowse/svnbrowse.c Sun Apr 5 17:02:57
2026 (r1932857)
@@ -25,7 +25,6 @@
#include <apr.h>
#include "svn_cmdline.h"
-#include "svn_client.h"
#include "svn_opt.h"
#include "svn_ra.h"
#include "svn_path.h"
@@ -38,41 +37,7 @@
#include <ncurses.h>
#include "svn_private_config.h"
-
-enum {
- opt_auth_password = SVN_OPT_FIRST_LONGOPT_ID,
- opt_auth_password_from_stdin,
- opt_auth_username,
- opt_config_dir,
- opt_config_option,
- opt_no_auth_cache,
- opt_version,
- opt_trust_server_cert,
- opt_trust_server_cert_failures,
- opt_password_from_stdin,
-};
-
-typedef struct svn_browse__opt_state_t {
- svn_boolean_t version; /* print version information */
- svn_boolean_t verbose; /* for svnbrowse --version */
- svn_boolean_t quiet; /* for svnbrowse --version */
- svn_boolean_t help; /* print usage message */
-
- const char *auth_username; /* auth username */
- const char *auth_password; /* auth password */
- apr_array_header_t *targets; /* target list from file */
- svn_boolean_t no_auth_cache; /* do not cache authentication information */
- const char *config_dir; /* over-riding configuration directory */
- apr_array_header_t *config_options; /* over-riding configuration options */
- svn_opt_revision_t revision;
-
- /* trust server SSL certs that would otherwise be rejected as "untrusted" */
- svn_boolean_t trust_server_cert_unknown_ca;
- svn_boolean_t trust_server_cert_cn_mismatch;
- svn_boolean_t trust_server_cert_expired;
- svn_boolean_t trust_server_cert_not_yet_valid;
- svn_boolean_t trust_server_cert_other_failure;
-} svn_browse__opt_state_t;
+#include "svnbrowse.h"
/* Option codes and descriptions for the command line client.
* The entire list must be terminated with an entry of nulls. */
@@ -143,178 +108,6 @@ const apr_getopt_option_t svn_browse__op
* alphabetical order. */
#define CTRL(ch) ((ch) - 'a' + 1)
-typedef struct svn_browse__item_t {
- const char *name;
- const svn_dirent_t *dirent;
-} svn_browse__item_t;
-
-/* a state of a single directory */
-typedef struct svn_browse__state_t {
- /* information about this node */
- const char *relpath;
- svn_revnum_t revision;
-
- /* stores the list of nodes in this state; an array of svn_browse__item_t */
- apr_array_header_t *list;
-
- /* the index of hovered item */
- int selection;
-
- /* a pool where the structure is allocated */
- apr_pool_t *pool;
-} svn_browse__state_t;
-
-typedef struct svn_browse__model_t {
- const char *root;
- svn_revnum_t revision;
-
- svn_client_ctx_t *client;
- svn_ra_session_t *session;
-
- svn_browse__state_t *current;
- apr_pool_t *pool;
-} svn_browse__model_t;
-
-static svn_error_t *
-state_create(svn_browse__state_t **state_p,
- svn_ra_session_t *session,
- const char *relpath,
- svn_revnum_t revision,
- apr_pool_t *result_pool,
- apr_pool_t *scratch_pool)
-{
- svn_browse__state_t *state = apr_pcalloc(result_pool, sizeof(*state));
- svn_revnum_t fetched_revnum;
- apr_hash_t *dirents;
- apr_hash_index_t *hi;
-
- SVN_ERR(svn_ra_get_dir2(session, &dirents, &fetched_revnum, NULL, relpath,
- revision, SVN_DIRENT_ALL, scratch_pool));
-
- state->relpath = apr_pstrdup(result_pool, relpath);
- state->revision = fetched_revnum;
- state->selection = 0;
- state->pool = result_pool;
-
- state->list = apr_array_make(result_pool, 0, sizeof(svn_browse__item_t *));
- for (hi = apr_hash_first(scratch_pool, dirents); hi; hi = apr_hash_next(hi))
- {
- const char *name = apr_hash_this_key(hi);
- const svn_dirent_t *dirent = apr_hash_this_val(hi);
-
- svn_browse__item_t *item = apr_pcalloc(result_pool, sizeof(*item));
- item->name = apr_pstrdup(result_pool, name);
- item->dirent = svn_dirent_dup(dirent, result_pool);
-
- APR_ARRAY_PUSH(state->list, svn_browse__item_t *) = item;
- }
-
- *state_p = state;
- return SVN_NO_ERROR;
-}
-
-static svn_error_t *
-model_enter_path(svn_browse__model_t *ctx, const char *relpath,
- apr_pool_t *scratch_pool)
-{
- svn_browse__state_t *newstate;
- apr_pool_t *state_pool = svn_pool_create(ctx->pool);
-
- SVN_ERR(state_create(&newstate, ctx->session, relpath, ctx->revision,
- state_pool, scratch_pool));
-
- /* switch to the next state and nuke the previous one */
- apr_pool_destroy(ctx->current->pool);
- ctx->current = newstate;
-
- return SVN_NO_ERROR;
-}
-
-static svn_browse__item_t *
-model_get_selected_item(svn_browse__model_t *model)
-{
- return APR_ARRAY_IDX(model->current->list, model->current->selection,
- svn_browse__item_t *);
-}
-
-static svn_error_t *
-model_go_enter(svn_browse__model_t *model, apr_pool_t *scratch_pool)
-{
- svn_browse__item_t *item = model_get_selected_item(model);
- const char *new_url = svn_relpath_join(model->current->relpath, item->name,
- scratch_pool);
- return svn_error_trace(model_enter_path(model, new_url, scratch_pool));
-}
-
-static svn_error_t *
-model_go_up(svn_browse__model_t *model, apr_pool_t *scratch_pool)
-{
- const char *new_url = svn_relpath_dirname(model->current->relpath,
- scratch_pool);
- return svn_error_trace(model_enter_path(model, new_url, scratch_pool));
-}
-
-static svn_error_t *
-model_move_selection(svn_browse__model_t *model, int delta)
-{
- model->current->selection += delta;
-
- if (model->current->selection >= model->current->list->nelts)
- model->current->selection = model->current->list->nelts - 1;
-
- if (model->current->selection < 0)
- model->current->selection = 0;
-
- return SVN_NO_ERROR;
-}
-
-static svn_error_t *
-model_create(svn_browse__model_t **model_p,
- const char *url,
- svn_revnum_t revision,
- apr_pool_t *result_pool,
- apr_pool_t *scratch_pool)
-{
- svn_browse__model_t *model = apr_pcalloc(result_pool, sizeof(*model));
- svn_auth_baton_t *auth;
- svn_client_ctx_t *client;
- svn_ra_session_t *session;
- apr_pool_t *state_pool;
- svn_browse__state_t *state;
- const char *root, *relpath;
-
- /* Set up Authentication stuff. */
- SVN_ERR(svn_cmdline_create_auth_baton2(&auth, FALSE, NULL, NULL, NULL, FALSE,
- FALSE, FALSE, FALSE, FALSE, FALSE,
- NULL, NULL, NULL, result_pool));
-
- SVN_ERR(svn_client_create_context2(&client, NULL, result_pool));
- client->auth_baton = auth;
-
- SVN_ERR(svn_client_open_ra_session2(&session, url, NULL, client, result_pool,
- scratch_pool));
-
- SVN_ERR(svn_ra_get_repos_root2(session, &root, scratch_pool));
- SVN_ERR(svn_ra_reparent(session, root, scratch_pool));
-
- relpath = svn_uri_skip_ancestor(root, url, scratch_pool);
-
- /* the state should be in a separate pool so it's safe to free it */
- state_pool = svn_pool_create(result_pool);
- SVN_ERR(state_create(&state, session, relpath, revision, state_pool,
- scratch_pool));
-
- model->root = apr_pstrdup(result_pool, root);
- model->revision = revision;
- model->client = client;
- model->session = session;
- model->current = state;
- model->pool = result_pool;
-
- *model_p = model;
- return SVN_NO_ERROR;
-}
-
typedef struct svn_browse__view_t {
/* TODO: store information about terminal screen (a WINDOW* in curses world)
*/
svn_browse__model_t *model;
@@ -534,7 +327,7 @@ sub_main(int *code, int argc, const char
SVN_ERR(svn_config_ensure(opt_state.config_dir, pool));
- SVN_ERR(model_create(&ctx, url, SVN_INVALID_REVNUM, pool, pool));
+ SVN_ERR(svn_browse__model_create(&ctx, url, SVN_INVALID_REVNUM, pool, pool));
/* init the display */
initscr();
@@ -572,20 +365,20 @@ sub_main(int *code, int argc, const char
{
case KEY_UP:
case 'k':
- SVN_ERR(model_move_selection(ctx, -1));
+ SVN_ERR(svn_browse__model_move_selection(ctx, -1));
break;
case KEY_DOWN:
case 'j':
- SVN_ERR(model_move_selection(ctx, 1));
+ SVN_ERR(svn_browse__model_move_selection(ctx, 1));
break;
case '\n':
case '\r':
- SVN_ERR(model_go_enter(ctx, iterpool));
+ SVN_ERR(svn_browse__model_go_enter(ctx, iterpool));
break;
case KEY_BACKSPACE:
case '-':
case 'u':
- SVN_ERR(model_go_up(ctx, iterpool));
+ SVN_ERR(svn_browse__model_go_up(ctx, iterpool));
break;
/* TODO: quit via escape. some say just check for 27, but it I think
it's
* a bit ugly. */
Copied and modified: subversion/trunk/subversion/svnbrowse/svnbrowse.h (from
r1932856, subversion/trunk/subversion/svnbrowse/svnbrowse.c)
==============================================================================
--- subversion/trunk/subversion/svnbrowse/svnbrowse.c Sun Apr 5 12:49:23
2026 (r1932856, copy source)
+++ subversion/trunk/subversion/svnbrowse/svnbrowse.h Sun Apr 5 17:02:57
2026 (r1932857)
@@ -1,6 +1,5 @@
/*
- * svnbrowse.c: TUI (terminal user interface) client for browsing and
- * exploring remote Subversion targets.
+ * svnbrowse.h: shared stuff for svnbrowse application
*
* ====================================================================
* Licensed to the Apache Software Foundation (ASF) under one
@@ -24,20 +23,9 @@
#include <apr.h>
-#include "svn_cmdline.h"
#include "svn_client.h"
#include "svn_opt.h"
#include "svn_ra.h"
-#include "svn_path.h"
-#include "svn_pools.h"
-#include "svn_cmdline.h"
-#include "svn_error.h"
-
-#include "private/svn_cmdline_private.h"
-
-#include <ncurses.h>
-
-#include "svn_private_config.h"
enum {
opt_auth_password = SVN_OPT_FIRST_LONGOPT_ID,
@@ -74,75 +62,6 @@ typedef struct svn_browse__opt_state_t {
svn_boolean_t trust_server_cert_other_failure;
} svn_browse__opt_state_t;
-/* Option codes and descriptions for the command line client.
- * The entire list must be terminated with an entry of nulls. */
-const apr_getopt_option_t svn_browse__options[] =
-{
- {"username", opt_auth_username, 1, N_("specify a username ARG")},
- {"password", opt_auth_password, 1,
- N_("specify a password ARG (caution: on many operating\n"
- " "
- "systems, other users will be able to see this)")},
- {"password-from-stdin",
- opt_auth_password_from_stdin, 0,
- N_("read password from stdin")},
- {"revision", 'r', 1,
- N_("ARG\n"
- " "
- "A revision argument can be one of:\n"
- " "
- " NUMBER revision number\n"
- " "
- " '{' DATE '}' revision at start of the date\n"
- " "
- " 'HEAD' latest in repository\n"
- " "
- " 'BASE' base rev of item's working copy\n"
- " "
- " 'COMMITTED' last commit at or before BASE\n"
- " "
- " 'PREV' revision just before COMMITTED")},
- {"help", 'h', 0, N_("show help on a subcommand")},
- {NULL, '?', 0, N_("show help on a subcommand")},
- {"trust-server-cert", opt_trust_server_cert, 0,
- N_("deprecated; same as\n"
- " "
- "--trust-server-cert-failures=unknown-ca")},
- {"trust-server-cert-failures", opt_trust_server_cert_failures, 1,
- N_("with --non-interactive, accept SSL server\n"
- " "
- "certificates with failures; ARG is comma-separated\n"
- " "
- "list of 'unknown-ca' (Unknown Authority),\n"
- " "
- "'cn-mismatch' (Hostname mismatch), 'expired'\n"
- " "
- "(Expired certificate), 'not-yet-valid' (Not yet\n"
- " "
- "valid certificate) and 'other' (all other not\n"
- " "
- "separately classified certificate errors).")},
- {"config-dir", opt_config_dir, 1,
- N_("read user configuration files from directory ARG")},
- {"config-option", opt_config_option, 1,
- N_("set user configuration option in the format:\n"
- " "
- " FILE:SECTION:OPTION=[VALUE]\n"
- " "
- "For example:\n"
- " "
- " servers:global:http-library=serf")},
- {"no-auth-cache", opt_no_auth_cache, 0,
- N_("do not cache authentication tokens")},
- {"version", opt_version, 0, N_("show program version information")},
- {"verbose", 'v', 0, N_("print extra information")},
- { NULL, 0, 0, NULL }
-};
-
-/* Control+ASCII character are represented as values 1-26 according to their
- * alphabetical order. */
-#define CTRL(ch) ((ch) - 'a' + 1)
-
typedef struct svn_browse__item_t {
const char *name;
const svn_dirent_t *dirent;
@@ -175,450 +94,37 @@ typedef struct svn_browse__model_t {
apr_pool_t *pool;
} svn_browse__model_t;
-static svn_error_t *
-state_create(svn_browse__state_t **state_p,
- svn_ra_session_t *session,
- const char *relpath,
- svn_revnum_t revision,
- apr_pool_t *result_pool,
- apr_pool_t *scratch_pool)
-{
- svn_browse__state_t *state = apr_pcalloc(result_pool, sizeof(*state));
- svn_revnum_t fetched_revnum;
- apr_hash_t *dirents;
- apr_hash_index_t *hi;
-
- SVN_ERR(svn_ra_get_dir2(session, &dirents, &fetched_revnum, NULL, relpath,
- revision, SVN_DIRENT_ALL, scratch_pool));
-
- state->relpath = apr_pstrdup(result_pool, relpath);
- state->revision = fetched_revnum;
- state->selection = 0;
- state->pool = result_pool;
-
- state->list = apr_array_make(result_pool, 0, sizeof(svn_browse__item_t *));
- for (hi = apr_hash_first(scratch_pool, dirents); hi; hi = apr_hash_next(hi))
- {
- const char *name = apr_hash_this_key(hi);
- const svn_dirent_t *dirent = apr_hash_this_val(hi);
-
- svn_browse__item_t *item = apr_pcalloc(result_pool, sizeof(*item));
- item->name = apr_pstrdup(result_pool, name);
- item->dirent = svn_dirent_dup(dirent, result_pool);
-
- APR_ARRAY_PUSH(state->list, svn_browse__item_t *) = item;
- }
-
- *state_p = state;
- return SVN_NO_ERROR;
-}
-
-static svn_error_t *
-model_enter_path(svn_browse__model_t *ctx, const char *relpath,
- apr_pool_t *scratch_pool)
-{
- svn_browse__state_t *newstate;
- apr_pool_t *state_pool = svn_pool_create(ctx->pool);
-
- SVN_ERR(state_create(&newstate, ctx->session, relpath, ctx->revision,
- state_pool, scratch_pool));
-
- /* switch to the next state and nuke the previous one */
- apr_pool_destroy(ctx->current->pool);
- ctx->current = newstate;
-
- return SVN_NO_ERROR;
-}
-
-static svn_browse__item_t *
-model_get_selected_item(svn_browse__model_t *model)
-{
- return APR_ARRAY_IDX(model->current->list, model->current->selection,
- svn_browse__item_t *);
-}
-
-static svn_error_t *
-model_go_enter(svn_browse__model_t *model, apr_pool_t *scratch_pool)
-{
- svn_browse__item_t *item = model_get_selected_item(model);
- const char *new_url = svn_relpath_join(model->current->relpath, item->name,
- scratch_pool);
- return svn_error_trace(model_enter_path(model, new_url, scratch_pool));
-}
-
-static svn_error_t *
-model_go_up(svn_browse__model_t *model, apr_pool_t *scratch_pool)
-{
- const char *new_url = svn_relpath_dirname(model->current->relpath,
- scratch_pool);
- return svn_error_trace(model_enter_path(model, new_url, scratch_pool));
-}
-
-static svn_error_t *
-model_move_selection(svn_browse__model_t *model, int delta)
-{
- model->current->selection += delta;
-
- if (model->current->selection >= model->current->list->nelts)
- model->current->selection = model->current->list->nelts - 1;
-
- if (model->current->selection < 0)
- model->current->selection = 0;
-
- return SVN_NO_ERROR;
-}
-
-static svn_error_t *
-model_create(svn_browse__model_t **model_p,
- const char *url,
- svn_revnum_t revision,
- apr_pool_t *result_pool,
- apr_pool_t *scratch_pool)
-{
- svn_browse__model_t *model = apr_pcalloc(result_pool, sizeof(*model));
- svn_auth_baton_t *auth;
- svn_client_ctx_t *client;
- svn_ra_session_t *session;
- apr_pool_t *state_pool;
- svn_browse__state_t *state;
- const char *root, *relpath;
-
- /* Set up Authentication stuff. */
- SVN_ERR(svn_cmdline_create_auth_baton2(&auth, FALSE, NULL, NULL, NULL, FALSE,
- FALSE, FALSE, FALSE, FALSE, FALSE,
- NULL, NULL, NULL, result_pool));
-
- SVN_ERR(svn_client_create_context2(&client, NULL, result_pool));
- client->auth_baton = auth;
-
- SVN_ERR(svn_client_open_ra_session2(&session, url, NULL, client, result_pool,
- scratch_pool));
-
- SVN_ERR(svn_ra_get_repos_root2(session, &root, scratch_pool));
- SVN_ERR(svn_ra_reparent(session, root, scratch_pool));
-
- relpath = svn_uri_skip_ancestor(root, url, scratch_pool);
-
- /* the state should be in a separate pool so it's safe to free it */
- state_pool = svn_pool_create(result_pool);
- SVN_ERR(state_create(&state, session, relpath, revision, state_pool,
- scratch_pool));
-
- model->root = apr_pstrdup(result_pool, root);
- model->revision = revision;
- model->client = client;
- model->session = session;
- model->current = state;
- model->pool = result_pool;
-
- *model_p = model;
- return SVN_NO_ERROR;
-}
-
-typedef struct svn_browse__view_t {
- /* TODO: store information about terminal screen (a WINDOW* in curses world)
*/
- svn_browse__model_t *model;
-} svn_browse__view_t;
-
-static svn_browse__view_t *
-view_make(svn_browse__model_t *model, apr_pool_t *result_pool)
-{
- svn_browse__view_t *view = apr_pcalloc(result_pool, sizeof(*view));
- view->model = model;
- return view;
-}
-
-static void
-view_draw(svn_browse__view_t *view, apr_pool_t *pool)
-{
- int i;
- const char *abspath = svn_path_url_add_component2(
- view->model->root, view->model->current->relpath, pool);
-
- mvprintw(0, 4, "Browsing: %s", abspath);
-
- for (i = 0; i < view->model->current->list->nelts; i++)
- {
- svn_browse__item_t *item = APR_ARRAY_IDX(view->model->current->list, i,
- svn_browse__item_t *);
-
- if (i == view->model->current->selection)
- standout();
-
- if (item->dirent->kind == svn_node_dir)
- mvprintw(i + 1, 0, "%s/", item->name);
- else if (item->dirent->kind == svn_node_file)
- mvprintw(i + 1, 0, "%s", item->name);
- else
- abort();
-
- mvprintw(i + 1, COLS - 40, "%8ld KiB r%-8ld %s",
- item->dirent->size / 1024,
- item->dirent->created_rev,
- item->dirent->last_author);
-
- if (i == view->model->current->selection)
- standend();
- }
-}
-
-static svn_error_t *
-show_usage(apr_pool_t *scratch_pool)
-{
- fprintf(stderr, "Type 'svnbrowse --help' for usage.\n");
- return SVN_NO_ERROR;
-}
-
-static svn_error_t *
-show_help(apr_pool_t *scratch_pool,
- const svn_browse__opt_state_t *opt_state)
-{
- svn_stringbuf_t *buf = svn_stringbuf_create_empty(scratch_pool);
- const apr_getopt_option_t *opt;
-
- svn_stringbuf_appendcstr(buf, N_(
- "usage: svnbrowse <target> [options]\n"
- "Interactively browse Subversion repositories\n"
- "\n"
- ));
-
- svn_stringbuf_appendcstr(buf, N_("Valid options:\n"));
- for (opt = svn_browse__options; opt->description; opt++)
- {
- if (opt->name)
- {
- const char *opts;
- svn_opt_format_option(&opts, opt, TRUE /* doc */, scratch_pool);
- svn_stringbuf_appendcstr(buf, " ");
- svn_stringbuf_appendcstr(buf, opts);
- svn_stringbuf_appendbyte(buf, '\n');
- }
- }
-
- return svn_error_trace(svn_cmdline_fputs(buf->data, stderr, scratch_pool));
-}
-
-static svn_error_t *
-show_version(apr_pool_t *scratch_pool,
- const svn_browse__opt_state_t *opt_state)
-{
- const char *ra_desc_start
- = "The following repository access (RA) modules are available:\n\n";
- svn_stringbuf_t *version_footer;
-
- version_footer = svn_stringbuf_create(ra_desc_start, scratch_pool);
- SVN_ERR(svn_ra_print_modules(version_footer, scratch_pool));
-
- SVN_ERR(svn_opt_print_help5(NULL,
- "svnbrowse",
- TRUE /* print_version */,
- opt_state->quiet,
- opt_state->verbose,
- version_footer->data,
- NULL, NULL, NULL, NULL, NULL,
- scratch_pool));
-
- return SVN_NO_ERROR;
-}
-
-static svn_error_t *
-sub_main(int *code, int argc, const char *argv[], apr_pool_t *pool)
-{
- const char *url;
- svn_browse__model_t *ctx;
- svn_browse__view_t *view;
- svn_browse__opt_state_t opt_state = { 0 };
- svn_boolean_t read_pass_from_stdin = FALSE;
- apr_pool_t *iterpool;
- apr_getopt_t *os;
-
- opt_state.revision.kind = svn_opt_revision_head;
- opt_state.config_options =
- apr_array_make(pool, 0, sizeof(svn_cmdline__config_argument_t *));
-
- SVN_ERR(svn_cmdline__getopt_init(&os, argc, argv, pool));
- os->interleave = 1;
-
- while (TRUE)
- {
- const char *opt_arg;
- int opt_id;
-
- /* Parse the next option. */
- apr_status_t status = apr_getopt_long(os, svn_browse__options, &opt_id,
- &opt_arg);
-
- if (APR_STATUS_IS_EOF(status))
- break;
- else if (status != APR_SUCCESS)
- {
- SVN_ERR(show_usage(pool));
- *code = EXIT_FAILURE;
- return SVN_NO_ERROR;
- }
-
- switch (opt_id)
- {
- case 'r':
- SVN_ERR(svn_opt_parse_one_revision(&opt_state.revision, opt_arg,
pool));
- break;
- case 'h':
- case '?':
- opt_state.help = TRUE;
- break;
- case opt_version:
- opt_state.version = TRUE;
- break;
- case opt_auth_username:
- opt_state.auth_username = apr_pstrdup(pool, opt_arg);
- break;
- case opt_auth_password:
- opt_state.auth_password = apr_pstrdup(pool, opt_arg);
- break;
- case opt_auth_password_from_stdin:
- read_pass_from_stdin = TRUE;
- break;
- case opt_no_auth_cache:
- opt_state.no_auth_cache = TRUE;
- break;
- /* ### can we drop it in a 1.16 tool? */
- case opt_trust_server_cert: /* backwards compat to 1.8 */
- opt_state.trust_server_cert_unknown_ca = TRUE;
- break;
- case opt_trust_server_cert_failures:
- SVN_ERR(svn_cmdline__parse_trust_options(
- &opt_state.trust_server_cert_unknown_ca,
- &opt_state.trust_server_cert_cn_mismatch,
- &opt_state.trust_server_cert_expired,
- &opt_state.trust_server_cert_not_yet_valid,
- &opt_state.trust_server_cert_other_failure,
- opt_arg, pool));
- break;
- case opt_config_dir:
- opt_state.config_dir = svn_dirent_internal_style(opt_arg, pool);
- break;
- case opt_config_option:
- SVN_ERR(svn_cmdline__parse_config_option(opt_state.config_options,
- opt_arg, "svnbrowse: ",
pool));
- break;
- default:
- break;
- }
- }
-
- if (opt_state.version)
- {
- SVN_ERR(show_version(pool, &opt_state));
- return SVN_NO_ERROR;
- }
-
- if (opt_state.help)
- {
- SVN_ERR(show_help(pool, &opt_state));
- return SVN_NO_ERROR;
- }
-
- /* TODO: WC paths are not implemented; svn_uri_canonicalize_safe() will just
- * fail in case of one */
- url = (os->ind < argc) ? os->argv[os->ind++] : ".";
- SVN_ERR(svn_uri_canonicalize_safe(&url, NULL, url, pool, pool));
-
- /* we must fail if there are extra arguments */
- if (os->ind < argc - 1)
- {
- printf("%d\n", os->ind);
- *code = EXIT_FAILURE;
- SVN_ERR(show_usage(pool));
- return SVN_NO_ERROR;
- }
-
- SVN_ERR(svn_config_ensure(opt_state.config_dir, pool));
-
- SVN_ERR(model_create(&ctx, url, SVN_INVALID_REVNUM, pool, pool));
-
- /* init the display */
- initscr();
-
- /* put ncurses into keypad mode to handle arrow inputs */
- intrflush(stdscr, FALSE);
- keypad(stdscr, TRUE);
- nonl();
-
- view = view_make(ctx, pool);
-
- iterpool = svn_pool_create(pool);
-
- while (TRUE)
- {
- svn_browse__item_t *item;
- const char *new_url;
-
- svn_pool_clear(iterpool);
-
- clear();
- view_draw(view, iterpool);
- refresh();
-
- /* getch() reads the next character/key with the following additional
- * rules:
- * 1. as we configured it to use keypad(), arrows and other special keys
- * are handled as KEY_XXX.
- * 2. Control (CTRL) version are handled as literal 1-26 values of ch
where
- * 1 is <C-A> and 26 is <C-Z>.
- * 3. The rest of keys remain as their equivalents on the current layout.
- * 4. If shift is held, they just become uppercased.
- */
- switch (getch())
- {
- case KEY_UP:
- case 'k':
- SVN_ERR(model_move_selection(ctx, -1));
- break;
- case KEY_DOWN:
- case 'j':
- SVN_ERR(model_move_selection(ctx, 1));
- break;
- case '\n':
- case '\r':
- SVN_ERR(model_go_enter(ctx, iterpool));
- break;
- case KEY_BACKSPACE:
- case '-':
- case 'u':
- SVN_ERR(model_go_up(ctx, iterpool));
- break;
- /* TODO: quit via escape. some say just check for 27, but it I think
it's
- * a bit ugly. */
- case 'q':
- goto quit;
- }
- }
-
-quit:
- endwin();
-
- return SVN_NO_ERROR;
-}
-
-int main(int argc, const char *argv[])
-{
- apr_pool_t *pool;
- int exit_code = EXIT_SUCCESS;
- svn_error_t *err;
-
- if (svn_cmdline_init("svnbrowse", stderr) != EXIT_SUCCESS)
- return EXIT_FAILURE;
-
- pool = apr_allocator_owner_get(svn_pool_create_allocator(FALSE));
-
- err = sub_main(&exit_code, argc, argv, pool);
-
- if (err)
- {
- exit_code = EXIT_FAILURE;
- svn_cmdline_handle_exit_error(err, NULL, "svnbrowse: ");
- }
-
- svn_pool_destroy(pool);
- return exit_code;
-}
+svn_error_t *
+svn_browse__state_create(svn_browse__state_t **state_p,
+ svn_ra_session_t *session,
+ const char *relpath,
+ svn_revnum_t revision,
+ apr_pool_t *result_pool,
+ apr_pool_t *scratch_pool);
+
+svn_error_t *
+svn_browse__model_enter_path(svn_browse__model_t *ctx,
+ const char *relpath,
+ apr_pool_t *scratch_pool);
+
+svn_browse__item_t *
+svn_browse__model_get_selected_item(svn_browse__model_t *model);
+
+svn_error_t *
+svn_browse__model_go_enter(svn_browse__model_t *model,
+ apr_pool_t *scratch_pool);
+
+svn_error_t *
+svn_browse__model_go_up(svn_browse__model_t *model,
+ apr_pool_t *scratch_pool);
+
+svn_error_t *
+svn_browse__model_move_selection(svn_browse__model_t *model,
+ int delta);
+
+svn_error_t *
+svn_browse__model_create(svn_browse__model_t **model_p,
+ const char *url,
+ svn_revnum_t revision,
+ apr_pool_t *result_pool,
+ apr_pool_t *scratch_pool);