summaryrefslogtreecommitdiff
path: root/subversion/svndumpfilter/svndumpfilter.c
diff options
context:
space:
mode:
Diffstat (limited to 'subversion/svndumpfilter/svndumpfilter.c')
-rw-r--r--subversion/svndumpfilter/svndumpfilter.c408
1 files changed, 175 insertions, 233 deletions
diff --git a/subversion/svndumpfilter/svndumpfilter.c b/subversion/svndumpfilter/svndumpfilter.c
index 0e5bbc6..922482b 100644
--- a/subversion/svndumpfilter/svndumpfilter.c
+++ b/subversion/svndumpfilter/svndumpfilter.c
@@ -43,9 +43,10 @@
#include "svn_mergeinfo.h"
#include "svn_version.h"
+#include "private/svn_repos_private.h"
#include "private/svn_mergeinfo_private.h"
#include "private/svn_cmdline_private.h"
-#include "private/svn_subr_private.h"
+#include "private/svn_sorts_private.h"
#ifdef _WIN32
typedef apr_status_t (__stdcall *open_fn_t)(apr_file_t **, apr_pool_t *);
@@ -240,7 +241,6 @@ struct revision_baton_t
/* Does this revision have node or prop changes? */
svn_boolean_t has_nodes;
- svn_boolean_t has_props;
/* Did we drop any nodes? */
svn_boolean_t had_dropped_nodes;
@@ -253,7 +253,7 @@ struct revision_baton_t
svn_revnum_t rev_actual;
/* Pointers to dumpfile data. */
- svn_stringbuf_t *header;
+ apr_hash_t *original_headers;
apr_hash_t *props;
};
@@ -278,7 +278,7 @@ struct node_baton_t
svn_filesize_t tcl;
/* Pointers to dumpfile data. */
- svn_stringbuf_t *header;
+ svn_repos__dumpfile_headers_t *headers;
svn_stringbuf_t *props;
/* Expect deltas? */
@@ -287,6 +287,8 @@ struct node_baton_t
/* We might need the node path in a parse error message. */
char *node_path;
+
+ apr_pool_t *node_pool;
};
@@ -310,6 +312,24 @@ magic_header_record(int version, void *parse_baton, apr_pool_t *pool)
}
+/* Return a deep copy of a (char * -> char *) hash. */
+static apr_hash_t *
+headers_dup(apr_hash_t *headers,
+ apr_pool_t *pool)
+{
+ apr_hash_t *new_hash = apr_hash_make(pool);
+ apr_hash_index_t *hi;
+
+ for (hi = apr_hash_first(pool, headers); hi; hi = apr_hash_next(hi))
+ {
+ const char *key = apr_hash_this_key(hi);
+ const char *val = apr_hash_this_val(hi);
+
+ svn_hash_sets(new_hash, apr_pstrdup(pool, key), apr_pstrdup(pool, val));
+ }
+ return new_hash;
+}
+
/* New revision: set up revision_baton, decide if we skip it. */
static svn_error_t *
new_revision_record(void **revision_baton,
@@ -318,21 +338,16 @@ new_revision_record(void **revision_baton,
apr_pool_t *pool)
{
struct revision_baton_t *rb;
- apr_hash_index_t *hi;
const char *rev_orig;
- svn_stream_t *header_stream;
*revision_baton = apr_palloc(pool, sizeof(struct revision_baton_t));
rb = *revision_baton;
rb->pb = parse_baton;
rb->has_nodes = FALSE;
- rb->has_props = FALSE;
rb->had_dropped_nodes = FALSE;
rb->writing_begun = FALSE;
- rb->header = svn_stringbuf_create_empty(pool);
rb->props = apr_hash_make(pool);
-
- header_stream = svn_stream_from_stringbuf(rb->header, pool);
+ rb->original_headers = headers_dup(headers, pool);
rev_orig = svn_hash_gets(headers, SVN_REPOS_DUMPFILE_REVISION_NUMBER);
rb->rev_orig = SVN_STR_TO_REV(rev_orig);
@@ -342,28 +357,6 @@ new_revision_record(void **revision_baton,
else
rb->rev_actual = rb->rev_orig;
- SVN_ERR(svn_stream_printf(header_stream, pool,
- SVN_REPOS_DUMPFILE_REVISION_NUMBER ": %ld\n",
- rb->rev_actual));
-
- for (hi = apr_hash_first(pool, headers); hi; hi = apr_hash_next(hi))
- {
- const char *key = svn__apr_hash_index_key(hi);
- const char *val = svn__apr_hash_index_val(hi);
-
- if ((!strcmp(key, SVN_REPOS_DUMPFILE_CONTENT_LENGTH))
- || (!strcmp(key, SVN_REPOS_DUMPFILE_PROP_CONTENT_LENGTH))
- || (!strcmp(key, SVN_REPOS_DUMPFILE_REVISION_NUMBER)))
- continue;
-
- /* passthru: put header into header stringbuf. */
-
- SVN_ERR(svn_stream_printf(header_stream, pool, "%s: %s\n",
- key, val));
- }
-
- SVN_ERR(svn_stream_close(header_stream));
-
return SVN_NO_ERROR;
}
@@ -375,12 +368,8 @@ new_revision_record(void **revision_baton,
static svn_error_t *
output_revision(struct revision_baton_t *rb)
{
- int bytes_used;
- char buf[SVN_KEYLINE_MAXLEN];
- apr_hash_index_t *hi;
svn_boolean_t write_out_rev = FALSE;
apr_pool_t *hash_pool = apr_hash_pool_get(rb->props);
- svn_stringbuf_t *props = svn_stringbuf_create_empty(hash_pool);
apr_pool_t *subpool = svn_pool_create(hash_pool);
rb->writing_begun = TRUE;
@@ -398,7 +387,6 @@ output_revision(struct revision_baton_t *rb)
&& (! rb->pb->drop_all_empty_revs))
{
apr_hash_t *old_props = rb->props;
- rb->has_props = TRUE;
rb->props = apr_hash_make(hash_pool);
svn_hash_sets(rb->props, SVN_PROP_REVISION_DATE,
svn_hash_gets(old_props, SVN_PROP_REVISION_DATE));
@@ -407,39 +395,6 @@ output_revision(struct revision_baton_t *rb)
"padding."), hash_pool));
}
- /* Now, "rasterize" the props to a string, and append the property
- information to the header string. */
- if (rb->has_props)
- {
- for (hi = apr_hash_first(subpool, rb->props);
- hi;
- hi = apr_hash_next(hi))
- {
- const char *pname = svn__apr_hash_index_key(hi);
- const svn_string_t *pval = svn__apr_hash_index_val(hi);
-
- write_prop_to_stringbuf(props, pname, pval);
- }
- svn_stringbuf_appendcstr(props, "PROPS-END\n");
- svn_stringbuf_appendcstr(rb->header,
- SVN_REPOS_DUMPFILE_PROP_CONTENT_LENGTH);
- bytes_used = apr_snprintf(buf, sizeof(buf), ": %" APR_SIZE_T_FMT,
- props->len);
- svn_stringbuf_appendbytes(rb->header, buf, bytes_used);
- svn_stringbuf_appendbyte(rb->header, '\n');
- }
-
- svn_stringbuf_appendcstr(rb->header, SVN_REPOS_DUMPFILE_CONTENT_LENGTH);
- bytes_used = apr_snprintf(buf, sizeof(buf), ": %" APR_SIZE_T_FMT, props->len);
- svn_stringbuf_appendbytes(rb->header, buf, bytes_used);
- svn_stringbuf_appendbyte(rb->header, '\n');
-
- /* put an end to headers */
- svn_stringbuf_appendbyte(rb->header, '\n');
-
- /* put an end to revision */
- svn_stringbuf_appendbyte(props, '\n');
-
/* write out the revision */
/* Revision is written out in the following cases:
1. If the revision has nodes or
@@ -459,10 +414,12 @@ output_revision(struct revision_baton_t *rb)
if (write_out_rev)
{
/* This revision is a keeper. */
- SVN_ERR(svn_stream_write(rb->pb->out_stream,
- rb->header->data, &(rb->header->len)));
- SVN_ERR(svn_stream_write(rb->pb->out_stream,
- props->data, &(props->len)));
+ SVN_ERR(svn_repos__dump_revision_record(rb->pb->out_stream,
+ rb->rev_actual,
+ rb->original_headers,
+ rb->props,
+ FALSE /*props_section_always*/,
+ subpool));
/* Stash the oldest original rev not dropped. */
if (rb->rev_orig > 0
@@ -544,6 +501,7 @@ new_node_record(void **node_baton,
*node_baton = apr_palloc(pool, sizeof(struct node_baton_t));
nb = *node_baton;
nb->rb = rev_baton;
+ nb->node_pool = pool;
pb = nb->rb->pb;
node_path = svn_hash_gets(headers, SVN_REPOS_DUMPFILE_NODE_PATH);
@@ -551,9 +509,9 @@ new_node_record(void **node_baton,
/* Ensure that paths start with a leading '/'. */
if (node_path[0] != '/')
- node_path = apr_pstrcat(pool, "/", node_path, (char *)NULL);
+ node_path = apr_pstrcat(pool, "/", node_path, SVN_VA_NULL);
if (copyfrom_path && copyfrom_path[0] != '/')
- copyfrom_path = apr_pstrcat(pool, "/", copyfrom_path, (char *)NULL);
+ copyfrom_path = apr_pstrcat(pool, "/", copyfrom_path, SVN_VA_NULL);
nb->do_skip = skip_path(node_path, pb->prefixes,
pb->do_exclude, pb->glob);
@@ -615,7 +573,7 @@ new_node_record(void **node_baton,
nb->has_text_delta = FALSE;
nb->writing_begun = FALSE;
nb->tcl = tcl ? svn__atoui64(tcl) : 0;
- nb->header = svn_stringbuf_create_empty(pool);
+ nb->headers = svn_repos__dumpfile_headers_create(pool);
nb->props = svn_stringbuf_create_empty(pool);
nb->node_path = apr_pstrdup(pool, node_path);
@@ -627,23 +585,20 @@ new_node_record(void **node_baton,
/* A node record is required to begin with 'Node-path', skip the
leading '/' to match the form used by 'svnadmin dump'. */
- SVN_ERR(svn_stream_printf(nb->rb->pb->out_stream,
- pool, "%s: %s\n",
- SVN_REPOS_DUMPFILE_NODE_PATH, node_path + 1));
+ svn_repos__dumpfile_header_push(
+ nb->headers, SVN_REPOS_DUMPFILE_NODE_PATH, node_path + 1);
/* Node-kind is next and is optional. */
kind = svn_hash_gets(headers, SVN_REPOS_DUMPFILE_NODE_KIND);
if (kind)
- SVN_ERR(svn_stream_printf(nb->rb->pb->out_stream,
- pool, "%s: %s\n",
- SVN_REPOS_DUMPFILE_NODE_KIND, kind));
+ svn_repos__dumpfile_header_push(
+ nb->headers, SVN_REPOS_DUMPFILE_NODE_KIND, kind);
/* Node-action is next and required. */
action = svn_hash_gets(headers, SVN_REPOS_DUMPFILE_NODE_ACTION);
if (action)
- SVN_ERR(svn_stream_printf(nb->rb->pb->out_stream,
- pool, "%s: %s\n",
- SVN_REPOS_DUMPFILE_NODE_ACTION, action));
+ svn_repos__dumpfile_header_push(
+ nb->headers, SVN_REPOS_DUMPFILE_NODE_ACTION, action);
else
return svn_error_createf(SVN_ERR_INCOMPLETE_DATA, 0,
_("Missing Node-action for path '%s'"),
@@ -651,8 +606,8 @@ new_node_record(void **node_baton,
for (hi = apr_hash_first(pool, headers); hi; hi = apr_hash_next(hi))
{
- const char *key = svn__apr_hash_index_key(hi);
- const char *val = svn__apr_hash_index_val(hi);
+ const char *key = apr_hash_this_key(hi);
+ const char *val = apr_hash_this_val(hi);
if ((!strcmp(key, SVN_REPOS_DUMPFILE_PROP_DELTA))
&& (!strcmp(val, "true")))
@@ -690,18 +645,14 @@ new_node_record(void **node_baton,
return svn_error_createf
(SVN_ERR_NODE_UNEXPECTED_KIND, NULL,
_("No valid copyfrom revision in filtered stream"));
- SVN_ERR(svn_stream_printf
- (nb->rb->pb->out_stream, pool,
- SVN_REPOS_DUMPFILE_NODE_COPYFROM_REV ": %ld\n",
- cf_renum_val->rev));
+ svn_repos__dumpfile_header_pushf(
+ nb->headers, SVN_REPOS_DUMPFILE_NODE_COPYFROM_REV,
+ "%ld", cf_renum_val->rev);
continue;
}
/* passthru: put header straight to output */
-
- SVN_ERR(svn_stream_printf(nb->rb->pb->out_stream,
- pool, "%s: %s\n",
- key, val));
+ svn_repos__dumpfile_header_push(nb->headers, key, val);
}
}
@@ -709,65 +660,6 @@ new_node_record(void **node_baton,
}
-/* Output node header and props to dumpstream
- This will be called by set_fulltext() after setting nb->has_text to TRUE,
- if the node has any text, or by close_node() otherwise. This must only
- be called if nb->writing_begun is FALSE. */
-static svn_error_t *
-output_node(struct node_baton_t *nb)
-{
- int bytes_used;
- char buf[SVN_KEYLINE_MAXLEN];
-
- nb->writing_begun = TRUE;
-
- /* when there are no props nb->props->len would be zero and won't mess up
- Content-Length. */
- if (nb->has_props)
- svn_stringbuf_appendcstr(nb->props, "PROPS-END\n");
-
- /* 1. recalculate & check text-md5 if present. Passed through right now. */
-
- /* 2. recalculate and add content-lengths */
-
- if (nb->has_props)
- {
- svn_stringbuf_appendcstr(nb->header,
- SVN_REPOS_DUMPFILE_PROP_CONTENT_LENGTH);
- bytes_used = apr_snprintf(buf, sizeof(buf), ": %" APR_SIZE_T_FMT,
- nb->props->len);
- svn_stringbuf_appendbytes(nb->header, buf, bytes_used);
- svn_stringbuf_appendbyte(nb->header, '\n');
- }
- if (nb->has_text)
- {
- svn_stringbuf_appendcstr(nb->header,
- SVN_REPOS_DUMPFILE_TEXT_CONTENT_LENGTH);
- bytes_used = apr_snprintf(buf, sizeof(buf), ": %" SVN_FILESIZE_T_FMT,
- nb->tcl);
- svn_stringbuf_appendbytes(nb->header, buf, bytes_used);
- svn_stringbuf_appendbyte(nb->header, '\n');
- }
- svn_stringbuf_appendcstr(nb->header, SVN_REPOS_DUMPFILE_CONTENT_LENGTH);
- bytes_used = apr_snprintf(buf, sizeof(buf), ": %" SVN_FILESIZE_T_FMT,
- (svn_filesize_t) (nb->props->len + nb->tcl));
- svn_stringbuf_appendbytes(nb->header, buf, bytes_used);
- svn_stringbuf_appendbyte(nb->header, '\n');
-
- /* put an end to headers */
- svn_stringbuf_appendbyte(nb->header, '\n');
-
- /* 3. output all the stuff */
-
- SVN_ERR(svn_stream_write(nb->rb->pb->out_stream,
- nb->header->data , &(nb->header->len)));
- SVN_ERR(svn_stream_write(nb->rb->pb->out_stream,
- nb->props->data , &(nb->props->len)));
-
- return SVN_NO_ERROR;
-}
-
-
/* Examine the mergeinfo in INITIAL_VAL, omitting missing merge
sources or renumbering revisions in rangelists as appropriate, and
return the (possibly new) mergeinfo in *FINAL_VAL (allocated from
@@ -794,6 +686,13 @@ adjust_mergeinfo(svn_string_t **final_val, const svn_string_t *initial_val,
want filtered.
If the oldest rev is r0 then there is nothing to filter. */
+
+ /* ### This seems to cater only for use cases where the revisions being
+ processed are not following on from revisions that will already
+ exist in the destination repository. If the revisions being
+ processed do follow on, then we might want to keep the mergeinfo
+ that refers to those older revisions. */
+
if (rb->pb->skip_missing_merge_sources && rb->pb->oldest_original_rev > 0)
SVN_ERR(svn_mergeinfo__filter_mergeinfo_by_ranges(
&mergeinfo, mergeinfo,
@@ -802,8 +701,8 @@ adjust_mergeinfo(svn_string_t **final_val, const svn_string_t *initial_val,
for (hi = apr_hash_first(subpool, mergeinfo); hi; hi = apr_hash_next(hi))
{
- const char *merge_source = svn__apr_hash_index_key(hi);
- svn_rangelist_t *rangelist = svn__apr_hash_index_val(hi);
+ const char *merge_source = apr_hash_this_key(hi);
+ svn_rangelist_t *rangelist = apr_hash_this_val(hi);
struct parse_baton_t *pb = rb->pb;
/* Determine whether the merge_source is a part of the prefix. */
@@ -867,7 +766,6 @@ set_revision_property(void *revision_baton,
struct revision_baton_t *rb = revision_baton;
apr_pool_t *hash_pool = apr_hash_pool_get(rb->props);
- rb->has_props = TRUE;
svn_hash_sets(rb->props,
apr_pstrdup(hash_pool, name),
svn_string_dup(value, hash_pool));
@@ -886,6 +784,9 @@ set_node_property(void *node_baton,
if (nb->do_skip)
return SVN_NO_ERROR;
+ /* Try to detect if a delta-mode property occurs unexpectedly. HAS_PROPS
+ can be false here only if the parser didn't call remove_node_props(),
+ so this may indicate a bug rather than bad data. */
if (! (nb->has_props || nb->has_prop_delta))
return svn_error_createf(SVN_ERR_STREAM_MALFORMED_DATA, NULL,
_("Delta property block detected, but deltas "
@@ -931,14 +832,17 @@ delete_node_property(void *node_baton, const char *name)
}
+/* The parser calls this method if the node record has a non-delta
+ * property content section, before any calls to set_node_property().
+ * If the node record uses property deltas, this is not called.
+ */
static svn_error_t *
remove_node_props(void *node_baton)
{
struct node_baton_t *nb = node_baton;
/* In this case, not actually indicating that the node *has* props,
- rather that we know about all the props that it has, since it now
- has none. */
+ rather that it has a property content section. */
nb->has_props = TRUE;
return SVN_NO_ERROR;
@@ -954,7 +858,20 @@ set_fulltext(svn_stream_t **stream, void *node_baton)
{
nb->has_text = TRUE;
if (! nb->writing_begun)
- SVN_ERR(output_node(nb));
+ {
+ nb->writing_begun = TRUE;
+ if (nb->has_props)
+ {
+ svn_stringbuf_appendcstr(nb->props, "PROPS-END\n");
+ }
+ SVN_ERR(svn_repos__dump_node_record(nb->rb->pb->out_stream,
+ nb->headers,
+ nb->has_props ? nb->props : NULL,
+ nb->has_text,
+ nb->tcl,
+ TRUE /*content_length_always*/,
+ nb->node_pool));
+ }
*stream = nb->rb->pb->out_stream;
}
@@ -975,7 +892,20 @@ close_node(void *node_baton)
/* If the node was not flushed already to output its text, do it now. */
if (! nb->writing_begun)
- SVN_ERR(output_node(nb));
+ {
+ nb->writing_begun = TRUE;
+ if (nb->has_props)
+ {
+ svn_stringbuf_appendcstr(nb->props, "PROPS-END\n");
+ }
+ SVN_ERR(svn_repos__dump_node_record(nb->rb->pb->out_stream,
+ nb->headers,
+ nb->has_props ? nb->props : NULL,
+ nb->has_text,
+ nb->tcl,
+ TRUE /*content_length_always*/,
+ nb->node_pool));
+ }
/* put an end to node. */
SVN_ERR(svn_stream_write(nb->rb->pb->out_stream, "\n\n", &len));
@@ -999,7 +929,7 @@ close_revision(void *revision_baton)
/* Filtering vtable */
-svn_repos_parse_fns3_t filtering_vtable =
+static svn_repos_parse_fns3_t filtering_vtable =
{
magic_header_record,
uuid_record,
@@ -1175,6 +1105,7 @@ subcommand_help(apr_getopt_t *os, void *baton, apr_pool_t *pool)
struct svndumpfilter_opt_state *opt_state = baton;
const char *header =
_("general usage: svndumpfilter SUBCOMMAND [ARGS & OPTIONS ...]\n"
+ "Subversion repository dump filtering tool.\n"
"Type 'svndumpfilter help <subcommand>' for help on a "
"specific subcommand.\n"
"Type 'svndumpfilter --version' to see the program version.\n"
@@ -1301,12 +1232,11 @@ do_filter(apr_getopt_t *os,
hi;
hi = apr_hash_next(hi))
{
- const svn_revnum_t *revnum = svn__apr_hash_index_key(hi);
+ const svn_revnum_t *revnum = apr_hash_this_key(hi);
APR_ARRAY_PUSH(keys, svn_revnum_t) = *revnum;
}
- qsort(keys->elts, keys->nelts,
- keys->elt_size, svn_sort_compare_revisions);
+ svn_sort__array(keys, svn_sort_compare_revisions);
for (i = 0; i < keys->nelts; i++)
{
svn_revnum_t this_key;
@@ -1345,11 +1275,11 @@ do_filter(apr_getopt_t *os,
hi;
hi = apr_hash_next(hi))
{
- const char *path = svn__apr_hash_index_key(hi);
+ const char *path = apr_hash_this_key(hi);
APR_ARRAY_PUSH(keys, const char *) = path;
}
- qsort(keys->elts, keys->nelts, keys->elt_size, svn_sort_compare_paths);
+ svn_sort__array(keys, svn_sort_compare_paths);
for (i = 0; i < keys->nelts; i++)
{
svn_pool_clear(subpool);
@@ -1383,12 +1313,16 @@ subcommand_include(apr_getopt_t *os, void *baton, apr_pool_t *pool)
/** Main. **/
-int
-main(int argc, const char *argv[])
+/*
+ * On success, leave *EXIT_CODE untouched and return SVN_NO_ERROR. On error,
+ * either return an error to be displayed, or set *EXIT_CODE to non-zero and
+ * return SVN_NO_ERROR.
+ */
+static svn_error_t *
+sub_main(int *exit_code, int argc, const char *argv[], apr_pool_t *pool)
{
svn_error_t *err;
apr_status_t apr_err;
- apr_pool_t *pool;
const svn_opt_subcommand_desc2_t *subcommand = NULL;
struct svndumpfilter_opt_state opt_state;
@@ -1397,33 +1331,19 @@ main(int argc, const char *argv[])
apr_array_header_t *received_opts;
int i;
-
- /* Initialize the app. */
- if (svn_cmdline_init("svndumpfilter", stderr) != EXIT_SUCCESS)
- return EXIT_FAILURE;
-
- /* Create our top-level pool. Use a separate mutexless allocator,
- * given this application is single threaded.
- */
- pool = apr_allocator_owner_get(svn_pool_create_allocator(FALSE));
-
/* Check library versions */
- err = check_lib_versions();
- if (err)
- return svn_cmdline_handle_exit_error(err, pool, "svndumpfilter: ");
+ SVN_ERR(check_lib_versions());
received_opts = apr_array_make(pool, SVN_OPT_MAX_OPTIONS, sizeof(int));
/* Initialize the FS library. */
- err = svn_fs_initialize(pool);
- if (err)
- return svn_cmdline_handle_exit_error(err, pool, "svndumpfilter: ");
+ SVN_ERR(svn_fs_initialize(pool));
if (argc <= 1)
{
- SVN_INT_ERR(subcommand_help(NULL, NULL, pool));
- svn_pool_destroy(pool);
- return EXIT_FAILURE;
+ SVN_ERR(subcommand_help(NULL, NULL, pool));
+ *exit_code = EXIT_FAILURE;
+ return SVN_NO_ERROR;
}
/* Initialize opt_state. */
@@ -1432,9 +1352,7 @@ main(int argc, const char *argv[])
opt_state.end_revision.kind = svn_opt_revision_unspecified;
/* Parse options. */
- err = svn_cmdline__getopt_init(&os, argc, argv, pool);
- if (err)
- return svn_cmdline_handle_exit_error(err, pool, "svndumpfilter: ");
+ SVN_ERR(svn_cmdline__getopt_init(&os, argc, argv, pool));
os->interleave = 1;
while (1)
@@ -1447,9 +1365,9 @@ main(int argc, const char *argv[])
break;
else if (apr_err)
{
- SVN_INT_ERR(subcommand_help(NULL, NULL, pool));
- svn_pool_destroy(pool);
- return EXIT_FAILURE;
+ SVN_ERR(subcommand_help(NULL, NULL, pool));
+ *exit_code = EXIT_FAILURE;
+ return SVN_NO_ERROR;
}
/* Stash the option code in an array before parsing it. */
@@ -1490,9 +1408,9 @@ main(int argc, const char *argv[])
break;
default:
{
- SVN_INT_ERR(subcommand_help(NULL, NULL, pool));
- svn_pool_destroy(pool);
- return EXIT_FAILURE;
+ SVN_ERR(subcommand_help(NULL, NULL, pool));
+ *exit_code = EXIT_FAILURE;
+ return SVN_NO_ERROR;
}
} /* close `switch' */
} /* close `while' */
@@ -1501,10 +1419,10 @@ main(int argc, const char *argv[])
--drop-all-empty-revs. */
if (opt_state.drop_empty_revs && opt_state.drop_all_empty_revs)
{
- err = svn_error_create(SVN_ERR_CL_MUTUALLY_EXCLUSIVE_ARGS, NULL,
- _("--drop-empty-revs cannot be used with "
- "--drop-all-empty-revs"));
- return svn_cmdline_handle_exit_error(err, pool, "svndumpfilter: ");
+ return svn_error_create(SVN_ERR_CL_MUTUALLY_EXCLUSIVE_ARGS,
+ NULL,
+ _("--drop-empty-revs cannot be used with "
+ "--drop-all-empty-revs"));
}
/* If the user asked for help, then the rest of the arguments are
@@ -1536,9 +1454,9 @@ main(int argc, const char *argv[])
svn_error_clear(svn_cmdline_fprintf
(stderr, pool,
_("Subcommand argument required\n")));
- SVN_INT_ERR(subcommand_help(NULL, NULL, pool));
- svn_pool_destroy(pool);
- return EXIT_FAILURE;
+ SVN_ERR(subcommand_help(NULL, NULL, pool));
+ *exit_code = EXIT_FAILURE;
+ return SVN_NO_ERROR;
}
}
else
@@ -1548,18 +1466,16 @@ main(int argc, const char *argv[])
if (subcommand == NULL)
{
const char* first_arg_utf8;
- if ((err = svn_utf_cstring_to_utf8(&first_arg_utf8, first_arg,
- pool)))
- return svn_cmdline_handle_exit_error(err, pool,
- "svndumpfilter: ");
+ SVN_ERR(svn_utf_cstring_to_utf8(&first_arg_utf8, first_arg,
+ pool));
svn_error_clear(
svn_cmdline_fprintf(stderr, pool,
_("Unknown subcommand: '%s'\n"),
first_arg_utf8));
- SVN_INT_ERR(subcommand_help(NULL, NULL, pool));
- svn_pool_destroy(pool);
- return EXIT_FAILURE;
+ SVN_ERR(subcommand_help(NULL, NULL, pool));
+ *exit_code = EXIT_FAILURE;
+ return SVN_NO_ERROR;
}
}
}
@@ -1579,10 +1495,10 @@ main(int argc, const char *argv[])
/* Ensure that each prefix is UTF8-encoded, in internal
style, and absolute. */
- SVN_INT_ERR(svn_utf_cstring_to_utf8(&prefix, os->argv[i], pool));
+ SVN_ERR(svn_utf_cstring_to_utf8(&prefix, os->argv[i], pool));
prefix = svn_relpath__internal_style(prefix, pool);
if (prefix[0] != '/')
- prefix = apr_pstrcat(pool, "/", prefix, (char *)NULL);
+ prefix = apr_pstrcat(pool, "/", prefix, SVN_VA_NULL);
APR_ARRAY_PUSH(opt_state.prefixes, const char *) = prefix;
}
@@ -1597,12 +1513,12 @@ main(int argc, const char *argv[])
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_targets_file,
- opt_state.targets_file, pool));
+ SVN_ERR(svn_utf_cstring_to_utf8(&utf8_targets_file,
+ opt_state.targets_file, pool));
- SVN_INT_ERR(svn_stringbuf_from_file2(&buffer, utf8_targets_file,
- pool));
- SVN_INT_ERR(svn_utf_stringbuf_to_utf8(&buffer_utf8, buffer, pool));
+ SVN_ERR(svn_stringbuf_from_file2(&buffer, utf8_targets_file,
+ pool));
+ SVN_ERR(svn_utf_stringbuf_to_utf8(&buffer_utf8, buffer, pool));
targets = apr_array_append(pool,
svn_cstring_split(buffer_utf8->data, "\n\r",
@@ -1613,7 +1529,7 @@ main(int argc, const char *argv[])
{
const char *prefix = APR_ARRAY_IDX(targets, i, const char *);
if (prefix[0] != '/')
- prefix = apr_pstrcat(pool, "/", prefix, (char *)NULL);
+ prefix = apr_pstrcat(pool, "/", prefix, SVN_VA_NULL);
APR_ARRAY_PUSH(opt_state.prefixes, const char *) = prefix;
}
}
@@ -1623,8 +1539,8 @@ main(int argc, const char *argv[])
svn_error_clear(svn_cmdline_fprintf
(stderr, pool,
_("\nError: no prefixes supplied.\n")));
- svn_pool_destroy(pool);
- return EXIT_FAILURE;
+ *exit_code = EXIT_FAILURE;
+ return SVN_NO_ERROR;
}
}
@@ -1649,15 +1565,15 @@ main(int argc, const char *argv[])
pool);
svn_opt_format_option(&optstr, badopt, FALSE, pool);
if (subcommand->name[0] == '-')
- SVN_INT_ERR(subcommand_help(NULL, NULL, pool));
+ SVN_ERR(subcommand_help(NULL, NULL, pool));
else
svn_error_clear(svn_cmdline_fprintf
(stderr, pool,
_("Subcommand '%s' doesn't accept option '%s'\n"
"Type 'svndumpfilter help %s' for usage.\n"),
subcommand->name, optstr, subcommand->name));
- svn_pool_destroy(pool);
- return EXIT_FAILURE;
+ *exit_code = EXIT_FAILURE;
+ return SVN_NO_ERROR;
}
}
@@ -1674,14 +1590,40 @@ main(int argc, const char *argv[])
_("Try 'svndumpfilter help' for more "
"info"));
}
- return svn_cmdline_handle_exit_error(err, pool, "svndumpfilter: ");
+ return err;
}
- else
- {
- svn_pool_destroy(pool);
- /* Flush stdout, making sure the user will see any print errors. */
- SVN_INT_ERR(svn_cmdline_fflush(stdout));
- return EXIT_SUCCESS;
+ return SVN_NO_ERROR;
+}
+
+int
+main(int argc, const char *argv[])
+{
+ apr_pool_t *pool;
+ int exit_code = EXIT_SUCCESS;
+ svn_error_t *err;
+
+ /* Initialize the app. */
+ if (svn_cmdline_init("svndumpfilter", stderr) != EXIT_SUCCESS)
+ return EXIT_FAILURE;
+
+ /* Create our top-level pool. Use a separate mutexless allocator,
+ * given this application is single threaded.
+ */
+ pool = apr_allocator_owner_get(svn_pool_create_allocator(FALSE));
+
+ err = sub_main(&exit_code, argc, argv, pool);
+
+ /* Flush stdout and report if it fails. It would be flushed on exit anyway
+ but this makes sure that output is not silently lost if it fails. */
+ err = svn_error_compose_create(err, svn_cmdline_fflush(stdout));
+
+ if (err)
+ {
+ exit_code = EXIT_FAILURE;
+ svn_cmdline_handle_exit_error(err, NULL, "svndumpfilter: ");
}
+
+ svn_pool_destroy(pool);
+ return exit_code;
}