Index: subversion/clients/cmdline/props.c
===================================================================
--- subversion/clients/cmdline/props.c (revision 17)
+++ subversion/clients/cmdline/props.c (working copy)
@@ -42,41 +42,3 @@
_("Must specify revision explicitly when operating on a "
"revision property"));
}
-
-
-svn_error_t *
-svn_cl__print_prop_hash (apr_hash_t *prop_hash,
- svn_boolean_t names_only,
- apr_pool_t *pool)
-{
- apr_hash_index_t *hi;
-
- for (hi = apr_hash_first (pool, prop_hash); hi; hi = apr_hash_next (hi))
- {
- const void *key;
- void *val;
- const char *pname;
- svn_string_t *propval;
- const char *pname_stdout;
-
- apr_hash_this (hi, &key, NULL, &val);
- pname = key;
- propval = val;
-
- if (svn_prop_needs_translation (pname))
- SVN_ERR (svn_subst_detranslate_string (&propval, propval,
- TRUE, pool));
-
- SVN_ERR (svn_cmdline_cstring_from_utf8 (&pname_stdout, pname, pool));
-
- /* ### We leave these printfs for now, since if propval wasn't translated
- * above, we don't know anything about its encoding. In fact, it
- * might be binary data... */
- if (names_only)
- printf (" %s\n", pname_stdout);
- else
- printf (" %s : %s\n", pname_stdout, propval->data);
- }
-
- return SVN_NO_ERROR;
-}
Index: subversion/clients/cmdline/cl.h
===================================================================
--- subversion/clients/cmdline/cl.h (revision 17)
+++ subversion/clients/cmdline/cl.h (working copy)
@@ -254,18 +254,6 @@
svn_boolean_t repos_locks,
apr_pool_t *pool);
-/* Print a hash that maps property names (char *) to property values
- (svn_string_t *). The names are assumed to be in UTF-8 format;
- the values are either in UTF-8 (the special Subversion props) or
- plain binary values.
-
- If NAMES_ONLY is true, print just names, else print names and
- values. */
-svn_error_t *
-svn_cl__print_prop_hash (apr_hash_t *prop_hash,
- svn_boolean_t names_only,
- apr_pool_t *pool);
-
/* Return a SVN_ERR_CL_ARG_PARSING_ERROR error, with a message stating
that one must give an explicit revision when operating on a
revision property. */
Index: subversion/clients/cmdline/proplist-cmd.c
===================================================================
--- subversion/clients/cmdline/proplist-cmd.c (revision 17)
+++ subversion/clients/cmdline/proplist-cmd.c (working copy)
@@ -26,7 +26,10 @@
#include "svn_pools.h"
#include "svn_client.h"
#include "svn_error.h"
+#include "svn_subst.h"
#include "svn_path.h"
+#include "svn_xml.h"
+#include "svn_base64.h"
#include "cl.h"
#include "svn_private_config.h"
@@ -34,6 +37,225 @@
/*** Code. ***/
+/* A function that will print the given property. The property name is in pname,
+ value in propval. */
+typedef svn_error_t* (*prop_print_function_t) (const char* pname,
+ svn_string_t *propval,
+ void *refcon,
+ apr_pool_t *pool);
+
+/* A function that will print grouping information/separators if we're printing
+ properties for more than one file/directory. The properties are contained in
+ prop_hash and should probably be passed to print_prop_hash along with a
+ prop_print_function_t. */
+typedef svn_error_t* (*prop_group_function_t) (apr_hash_t *prop_hash,
+ const char *path,
+ void *baton,
+ apr_pool_t *pool);
+
+/* Tell print_prop_array how to compute the path it will send for printing.
+ The first two values also double as boolean for whether the path is url. */
+typedef enum {
+ print_path_local,
+ print_path_url,
+ print_path_absolute,
+} print_path_style_t;
+
+/* Print a hash that maps property names (char *) to property values
+ (svn_string_t *). The names are assumed to be in UTF-8 format;
+ the values are either in UTF-8 (the special Subversion props) or
+ plain binary values.
+
+ Pass the property name and a (possibly de-translated) value
+ to the print function. */
+static svn_error_t *
+print_prop_hash (apr_hash_t *prop_hash,
+ prop_print_function_t print_func,
+ void *baton,
+ apr_pool_t *pool)
+{
+ apr_hash_index_t *hi;
+
+ for (hi = apr_hash_first (pool, prop_hash); hi; hi = apr_hash_next (hi))
+ {
+ const void *key;
+ void *val;
+ const char *pname;
+ svn_string_t *propval;
+
+ apr_hash_this (hi, &key, NULL, &val);
+ pname = key;
+ propval = val;
+
+ if (svn_prop_needs_translation (pname))
+ SVN_ERR (svn_subst_detranslate_string (&propval, propval,
+ TRUE, pool));
+
+ SVN_ERR (print_func (pname, propval, baton, pool));
+ }
+
+ return SVN_NO_ERROR;
+}
+
+/* Iterate an array of props, where each element is a hash that maps
+ property names (char *) to property values (svn_string_t *).
+
+ Pass one hash and the current property's path to the given print-function.
+ The path is computed as either local, url, or absolute depending on path_style. */
+static svn_error_t*
+print_prop_array (apr_array_header_t *props,
+ print_path_style_t path_style,
+ prop_group_function_t group_func,
+ void *baton,
+ apr_pool_t *pool)
+{
+ int j;
+ for (j = 0; j < props->nelts; ++j)
+ {
+ svn_client_proplist_item_t *item
+ = ((svn_client_proplist_item_t **)props->elts)[j];
+ const char *name_local;
+
+ switch (path_style)
+ {
+ case print_path_absolute:
+ SVN_ERR (svn_path_get_absolute (&name_local,
+ item->node_name->data, pool));
+ break;
+
+ case print_path_local:
+ name_local = svn_path_local_style (item->node_name->data,
+ pool);
+ break;
+
+ case print_path_url:
+ default:
+ name_local = item->node_name->data;
+ break;
+ }
+
+ SVN_ERR (group_func (item->prop_hash, name_local, baton, pool));
+ }
+ return SVN_NO_ERROR;
+}
+
+/* Print a property in xml. Append the svn_stringbuf_t
+ passed in baton.
+ This function is an prop_print_function_t*/
+static svn_error_t *
+print_prop_xml (const char *pname,
+ svn_string_t *propval,
+ void *baton,
+ apr_pool_t *pool)
+{
+ svn_stringbuf_t *sb = (svn_stringbuf_t*) baton;
+ svn_xml_make_open_tag (&sb, pool, svn_xml_protect_pcdata, "key",
+ NULL);
+ svn_xml_escape_cdata_cstring (&sb, pname, pool);
+ svn_xml_make_close_tag (&sb, pool, "key");
+
+ if (!svn_xml_is_xml_safe (propval->data, propval->len))
+ {
+ svn_xml_make_open_tag (&sb, pool, svn_xml_protect_pcdata, "data", NULL);
+ const svn_string_t *bin_prop = svn_base64_encode_string (propval, pool);
+ svn_xml_escape_cdata_cstring (&sb, bin_prop->data, pool);
+ svn_xml_make_close_tag (&sb, pool, "data");
+ }
+ else
+ {
+ svn_xml_make_open_tag (&sb, pool, svn_xml_protect_pcdata, "string",
+ NULL);
+ svn_xml_escape_cdata_cstring (&sb, propval->data, pool);
+ svn_xml_make_close_tag (&sb, pool, "string");
+ }
+
+ return SVN_NO_ERROR;
+}
+
+/* Print the property name and, if names_only is non-null, it's value.
+ This function is an prop_print_function_t*/
+static svn_error_t *
+print_prop_cl (const char *pname,
+ svn_string_t *propval,
+ void *names_only,
+ apr_pool_t *pool)
+{
+ const char *pname_stdout;
+ SVN_ERR (svn_cmdline_cstring_from_utf8 (&pname_stdout, pname, pool));
+ /* ### We leave these printfs for now, since if propval wasn't translated
+ * above, we don't know anything about its encoding. In fact, it
+ * might be binary data... */
+ if (names_only)
+ printf (" %s\n", pname_stdout);
+ else
+ printf (" %s : %s\n", pname_stdout, propval->data);
+
+ return SVN_NO_ERROR;
+}
+
+/* Groups the properties from prop_hash. Appends
+ the svn_stringbuf_t passed in baton.
+
+ call print_prop_hash
+
+
+ This function is a prop_group_function_t. */
+static svn_error_t*
+group_props_xml (apr_hash_t *prop_hash,
+ const char *path,
+ void *baton,
+ apr_pool_t *pool)
+{
+ svn_stringbuf_t *sb = (svn_stringbuf_t*) baton;
+
+ /* */
+ svn_stringbuf_t *escpath = svn_stringbuf_create ("", pool);
+ svn_xml_escape_attr_cstring (&escpath, path, pool);
+ svn_xml_make_open_tag (&sb, pool, svn_xml_protect_pcdata, "dict",
+ "path", escpath->data, NULL);
+
+ svn_stringbuf_appendcstr (sb, "\n");
+ SVN_ERR (print_prop_hash (prop_hash, print_prop_xml, sb, pool));
+
+ /* */
+ svn_xml_make_close_tag (&sb, pool, "dict");
+}
+
+/* Prints the filepath or url for the property, then the property itself.
+ This function is a prop_group_function_t. */
+static svn_error_t*
+group_props_cl (apr_hash_t *prop_hash,
+ const char *path,
+ void *baton,
+ apr_pool_t *pool)
+ {
+ SVN_ERR (svn_cmdline_printf (pool, "Properties on '%s':\n", path));
+ SVN_ERR (print_prop_hash (prop_hash, print_prop_cl, baton, pool));
+ return SVN_NO_ERROR;
+}
+
+/* Create the xml stringbuf, writes header, and
+ open the first tag (). */
+static svn_error_t *
+begin_xml_proplist (svn_stringbuf_t **sb,
+ apr_pool_t *pool)
+{
+ *sb = svn_stringbuf_create ("", pool);
+ svn_xml_make_header (sb, pool);
+ svn_xml_make_open_tag (sb, pool, svn_xml_normal, "plist", NULL);
+}
+
+/* Writes the end tag () to sb, then prints to stdout*/
+static svn_error_t *
+end_xml_proplist (svn_stringbuf_t *sb,
+ apr_pool_t *pool)
+{
+ svn_xml_make_close_tag (&sb, pool, "plist");
+ SVN_ERR (svn_cl__error_checked_fputs (sb->data, stdout));
+ return SVN_NO_ERROR;
+}
+
+
/* This implements the `svn_opt_subcommand_t' interface. */
svn_error_t *
svn_cl__proplist (apr_getopt_t *os,
@@ -43,11 +265,12 @@
svn_cl__opt_state_t *opt_state = ((svn_cl__cmd_baton_t *) baton)->opt_state;
svn_client_ctx_t *ctx = ((svn_cl__cmd_baton_t *) baton)->ctx;
apr_array_header_t *targets;
+ svn_stringbuf_t *sb;
int i;
/* Suck up all remaining args in the target array. */
SVN_ERR (svn_opt_args_to_target_array2 (&targets, os,
- opt_state->targets, pool));
+ opt_state->targets, pool));
/* Add "." if user passed 0 arguments */
svn_opt_push_implicit_dot_target (targets, pool);
@@ -68,7 +291,7 @@
/* Either we have a URL target, or an implicit wc-path ('.')
which needs to be converted to a URL. */
if (targets->nelts <= 0)
- return svn_error_create(SVN_ERR_CL_INSUFFICIENT_ARGS, NULL,
+ return svn_error_create (SVN_ERR_CL_INSUFFICIENT_ARGS, NULL,
_("No URL target available"));
target = ((const char **) (targets->elts))[0];
SVN_ERR (svn_client_url_from_path (&URL, target, pool));
@@ -81,14 +304,22 @@
SVN_ERR (svn_client_revprop_list (&proplist,
URL, &(opt_state->start_revision),
&rev, ctx, pool));
-
- SVN_ERR
- (svn_cmdline_printf (pool,
+
+ if (opt_state->xml)
+ {
+ begin_xml_proplist (&sb, pool);
+ SVN_ERR (group_props_xml (proplist, URL, sb, pool));
+ SVN_ERR (end_xml_proplist (sb, pool));
+ }
+ else
+ {
+ SVN_ERR (svn_cmdline_printf (pool,
_("Unversioned properties on revision %ld:\n"),
rev));
- SVN_ERR (svn_cl__print_prop_hash
- (proplist, (! opt_state->verbose), pool));
+ SVN_ERR (print_prop_hash
+ (proplist, print_prop_cl, (void*)(! opt_state->verbose), pool));
+ }
}
else /* operate on normal, versioned properties (not revprops) */
{
@@ -98,7 +329,6 @@
{
const char *target = ((const char **) (targets->elts))[i];
apr_array_header_t *props;
- int j;
svn_error_t *err;
svn_boolean_t is_url = svn_path_is_url (target);
const char *truepath;
@@ -129,23 +359,20 @@
return err;
}
- for (j = 0; j < props->nelts; ++j)
+ if (opt_state->xml)
{
- svn_client_proplist_item_t *item
- = ((svn_client_proplist_item_t **)props->elts)[j];
- const char *name_local;
+ begin_xml_proplist (&sb, pool);
+ svn_xml_make_open_tag (&sb, pool, svn_xml_normal, "array", NULL);
+ SVN_ERR (print_prop_array (props, (is_url ? print_path_url :
+ (opt_state->verbose ? print_path_absolute : print_path_local)),
+ group_props_xml, sb, pool));
+ svn_xml_make_close_tag (&sb, pool, "array");
+ SVN_ERR (end_xml_proplist (sb, pool));
+ }
+ else
+ SVN_ERR (print_prop_array (props, (print_path_style_t)is_url, group_props_cl,
+ (void*)opt_state->verbose, pool));
- if (! is_url)
- name_local = svn_path_local_style (item->node_name->data,
- subpool);
- else
- name_local = item->node_name->data;
-
- SVN_ERR (svn_cmdline_printf(subpool, "Properties on '%s':\n",
- name_local));
- SVN_ERR (svn_cl__print_prop_hash
- (item->prop_hash, (! opt_state->verbose), subpool));
- }
}
svn_pool_destroy (subpool);
}
Index: subversion/clients/cmdline/main.c
===================================================================
--- subversion/clients/cmdline/main.c (revision 17)
+++ subversion/clients/cmdline/main.c (working copy)
@@ -533,7 +533,7 @@
" 1. Lists versioned props. If specified, REV determines in which\n"
" revision the target is first looked up.\n"
" 2. Lists unversioned remote props on repos revision.\n"),
- {'v', 'R', 'r', 'q', svn_cl__revprop_opt, SVN_CL__AUTH_OPTIONS,
+ {'v', 'R', 'r', 'q', svn_cl__revprop_opt, svn_cl__xml_opt, SVN_CL__AUTH_OPTIONS,
svn_cl__config_dir_opt} },
{ "propset", svn_cl__propset, {"pset", "ps"},