#include "svn_client.h"
#include "svn_error.h"
#include "svn_path.h"
#include "svn_opt.h"
#include "svn_utf.h"
#include "client.h"
#include "private/svn_opt_private.h"
#include "svn_private_config.h"
#define DEFAULT_ARRAY_SIZE 5
static svn_boolean_t
arg_is_repos_relative_url(const char *arg)
{
return (0 == strncmp("^/", arg, 2));
}
static svn_error_t *
resolve_repos_relative_url(const char **absolute_url,
const char *relative_url,
const char *repos_root_url,
apr_pool_t *pool)
{
if (! arg_is_repos_relative_url(relative_url))
return svn_error_createf(SVN_ERR_BAD_URL, NULL,
_("Improper relative URL '%s'"),
relative_url);
*absolute_url = apr_pstrcat(pool, repos_root_url, relative_url + 1, NULL);
return SVN_NO_ERROR;
}
static svn_error_t *
check_root_url_of_target(const char **root_url,
const char *target,
svn_client_ctx_t *ctx,
apr_pool_t *pool)
{
svn_error_t *error;
const char *tmp_root_url;
const char *truepath;
svn_opt_revision_t opt_rev;
SVN_ERR(svn_opt_parse_path(&opt_rev, &truepath, target, pool));
if ((error = svn_client__get_repos_root(&tmp_root_url,
truepath,
&opt_rev,
NULL, ctx, pool)))
{
if ((error->apr_err == SVN_ERR_ENTRY_NOT_FOUND)
|| (error->apr_err == SVN_ERR_WC_NOT_DIRECTORY))
{
svn_error_clear(error);
return SVN_NO_ERROR;
}
else
return error;
}
else if (*root_url != NULL)
{
if (strcmp(*root_url, tmp_root_url) != 0)
return svn_error_createf(SVN_ERR_ILLEGAL_TARGET, NULL,
_("All non-relative targets must have "
"the same root URL"));
}
else
*root_url = tmp_root_url;
return SVN_NO_ERROR;
}
svn_error_t *
svn_client_args_to_target_array(apr_array_header_t **targets_p,
apr_getopt_t *os,
const apr_array_header_t *known_targets,
svn_client_ctx_t *ctx,
apr_pool_t *pool)
{
int i;
svn_boolean_t rel_url_found = FALSE;
const char *root_url = NULL;
svn_error_t *err = SVN_NO_ERROR;
apr_array_header_t *input_targets =
apr_array_make(pool, DEFAULT_ARRAY_SIZE, sizeof(const char *));
apr_array_header_t *output_targets =
apr_array_make(pool, DEFAULT_ARRAY_SIZE, sizeof(const char *));
for (; os->ind < os->argc; os->ind++)
{
const char *raw_target = os->argv[os->ind];
const char *utf8_target;
SVN_ERR(svn_utf_cstring_to_utf8(&utf8_target,
raw_target, pool));
if (arg_is_repos_relative_url(utf8_target))
rel_url_found = TRUE;
APR_ARRAY_PUSH(input_targets, const char *) = utf8_target;
}
if (known_targets)
{
for (i = 0; i < known_targets->nelts; i++)
{
const char *utf8_target = APR_ARRAY_IDX(known_targets,
i, const char *);
if (arg_is_repos_relative_url(utf8_target))
rel_url_found = TRUE;
APR_ARRAY_PUSH(input_targets, const char *) = utf8_target;
}
}
for (i = 0; i < input_targets->nelts; i++)
{
const char *utf8_target = APR_ARRAY_IDX(input_targets, i, const char *);
if (arg_is_repos_relative_url(utf8_target))
{
APR_ARRAY_PUSH(output_targets, const char *) = utf8_target;
}
else
{
const char *true_target;
const char *peg_rev;
const char *target;
SVN_ERR(svn_opt__split_arg_at_peg_revision(&true_target, &peg_rev,
utf8_target, pool));
if (svn_path_is_url(true_target))
{
SVN_ERR(svn_opt__arg_canonicalize_url(&true_target,
true_target, pool));
}
else
{
char *base_name;
SVN_ERR(svn_opt__arg_canonicalize_path(&true_target,
true_target, pool));
base_name = svn_path_basename(true_target, pool);
if (svn_wc_is_adm_dir(base_name, pool))
{
err = svn_error_createf(SVN_ERR_RESERVED_FILENAME_SPECIFIED,
err,
_("'%s' ends in a reserved name"),
utf8_target);
continue;
}
}
target = apr_pstrcat(pool, true_target, peg_rev, NULL);
if (rel_url_found)
{
SVN_ERR(check_root_url_of_target(&root_url, target,
ctx, pool));
}
APR_ARRAY_PUSH(output_targets, const char *) = target;
}
}
if (rel_url_found)
{
if (root_url == NULL)
SVN_ERR(svn_client_root_url_from_path(&root_url, "", ctx, pool));
*targets_p = apr_array_make(pool, output_targets->nelts,
sizeof(const char *));
for (i = 0; i < output_targets->nelts; i++)
{
const char *target = APR_ARRAY_IDX(output_targets, i,
const char *);
if (arg_is_repos_relative_url(target))
{
const char *abs_target;
const char *true_target;
const char *peg_rev;
SVN_ERR(svn_opt__split_arg_at_peg_revision(&true_target, &peg_rev,
target, pool));
SVN_ERR(resolve_repos_relative_url(&abs_target, true_target,
root_url, pool));
SVN_ERR(svn_opt__arg_canonicalize_url(&true_target, abs_target,
pool));
target = apr_pstrcat(pool, true_target, peg_rev, NULL);
}
APR_ARRAY_PUSH(*targets_p, const char *) = target;
}
}
else
*targets_p = output_targets;
return err;
}