Author: rinrab
Date: Wed May 28 20:45:52 2025
New Revision: 1925920
URL: http://svn.apache.org/viewvc?rev=1925920&view=rev
Log:
Move opt-revision stuff into a separate file, opt_revision.c.
In this file, functions related to revision option parsing, formatting,
and other operations will be implemented.
Affected symbols:
- revision_from_word
- parse_one_rev
- svn_opt_parse_revision
- svn_opt_parse_revision_to_range
- svn_opt_parse_change_to_range
- svn_opt_parse_revnum
- svn_opt_resolve_revisions
- svn_opt__revision_to_string
- svn_opt__revision_range_create
- svn_opt__revision_range_from_revnums
* subversion/libsvn_subr/opt.c: Remove those funcs.
* subversion/libsvn_subr/opt_revision.c: Copy file from opt.c and keep only
the funcs listed above. Also cleanup includes and adjust file header.
Added:
subversion/trunk/subversion/libsvn_subr/opt_revision.c
- copied, changed from r1925919,
subversion/trunk/subversion/libsvn_subr/opt.c
Modified:
subversion/trunk/subversion/libsvn_subr/opt.c
Modified: subversion/trunk/subversion/libsvn_subr/opt.c
URL:
http://svn.apache.org/viewvc/subversion/trunk/subversion/libsvn_subr/opt.c?rev=1925920&r1=1925919&r2=1925920&view=diff
==============================================================================
--- subversion/trunk/subversion/libsvn_subr/opt.c (original)
+++ subversion/trunk/subversion/libsvn_subr/opt.c Wed May 28 20:45:52 2025
@@ -464,345 +464,6 @@ svn_opt_subcommand_help4(const char *sub
-/*** Parsing revision and date options. ***/
-
-
-/** Parsing "X:Y"-style arguments. **/
-
-/* If WORD matches one of the special revision descriptors,
- * case-insensitively, set *REVISION accordingly:
- *
- * - For "head", set REVISION->kind to svn_opt_revision_head.
- *
- * - For "prev", set REVISION->kind to svn_opt_revision_previous.
- *
- * - For "base", set REVISION->kind to svn_opt_revision_base.
- *
- * - For "committed", set REVISION->kind to svn_opt_revision_committed.
- *
- * If match, return 0, else return -1 and don't touch REVISION.
- */
-static int
-revision_from_word(svn_opt_revision_t *revision, const char *word)
-{
- if (svn_cstring_casecmp(word, "head") == 0)
- {
- revision->kind = svn_opt_revision_head;
- }
- else if (svn_cstring_casecmp(word, "prev") == 0)
- {
- revision->kind = svn_opt_revision_previous;
- }
- else if (svn_cstring_casecmp(word, "base") == 0)
- {
- revision->kind = svn_opt_revision_base;
- }
- else if (svn_cstring_casecmp(word, "committed") == 0)
- {
- revision->kind = svn_opt_revision_committed;
- }
- else
- return -1;
-
- return 0;
-}
-
-
-/* Parse one revision specification. Return pointer to character
- after revision, or NULL if the revision is invalid. Modifies
- str, so make sure to pass a copy of anything precious. Uses
- POOL for temporary allocation. */
-static char *parse_one_rev(svn_opt_revision_t *revision, char *str,
- apr_pool_t *pool)
-{
- char *end, save;
-
- /* Allow any number of 'r's to prefix a revision number, because
- that way if a script pastes svn output into another svn command
- (like "svn log -r${REV_COPIED_FROM_OUTPUT}"), it'll Just Work,
- even when compounded.
-
- As it happens, none of our special revision words begins with
- "r". If any ever do, then this code will have to get smarter.
-
- Incidentally, this allows "r{DATE}". We could avoid that with
- some trivial code rearrangement, but it's not clear what would
- be gained by doing so. */
- while (*str == 'r')
- str++;
-
- if (*str == '{')
- {
- svn_boolean_t matched;
- apr_time_t tm;
- svn_error_t *err;
-
- /* Brackets denote a date. */
- str++;
- end = strchr(str, '}');
- if (!end)
- return NULL;
- *end = '\0';
- err = svn_parse_date(&matched, &tm, str, apr_time_now(), pool);
- if (err)
- {
- svn_error_clear(err);
- return NULL;
- }
- if (!matched)
- return NULL;
- revision->kind = svn_opt_revision_date;
- revision->value.date = tm;
- return end + 1;
- }
- else if (svn_ctype_isdigit(*str))
- {
- /* It's a number. */
- end = str + 1;
- while (svn_ctype_isdigit(*end))
- end++;
- save = *end;
- *end = '\0';
- revision->kind = svn_opt_revision_number;
- revision->value.number = SVN_STR_TO_REV(str);
- *end = save;
- return end;
- }
- else if (svn_ctype_isalpha(*str))
- {
- end = str + 1;
- while (svn_ctype_isalpha(*end))
- end++;
- save = *end;
- *end = '\0';
- if (revision_from_word(revision, str) != 0)
- return NULL;
- *end = save;
- return end;
- }
- else
- return NULL;
-}
-
-
-int
-svn_opt_parse_revision(svn_opt_revision_t *start_revision,
- svn_opt_revision_t *end_revision,
- const char *arg,
- apr_pool_t *pool)
-{
- char *left_rev, *right_rev, *end;
-
- /* Operate on a copy of the argument. */
- left_rev = apr_pstrdup(pool, arg);
-
- right_rev = parse_one_rev(start_revision, left_rev, pool);
- if (right_rev && *right_rev == ':')
- {
- right_rev++;
- end = parse_one_rev(end_revision, right_rev, pool);
- if (!end || *end != '\0')
- return -1;
- }
- else if (!right_rev || *right_rev != '\0')
- return -1;
-
- return 0;
-}
-
-
-int
-svn_opt_parse_revision_to_range(apr_array_header_t *opt_ranges,
- const char *arg,
- apr_pool_t *pool)
-{
- svn_opt_revision_range_t *range = apr_palloc(pool, sizeof(*range));
-
- range->start.kind = svn_opt_revision_unspecified;
- range->end.kind = svn_opt_revision_unspecified;
-
- if (svn_opt_parse_revision(&(range->start), &(range->end),
- arg, pool) == -1)
- return -1;
-
- APR_ARRAY_PUSH(opt_ranges, svn_opt_revision_range_t *) = range;
- return 0;
-}
-
-int svn_opt_parse_change_to_range(apr_array_header_t *opt_ranges,
- const char *arg,
- apr_pool_t *result_pool)
-{
- char *end;
- svn_revnum_t changeno, changeno_end;
- const char *s = arg;
- svn_boolean_t is_negative;
-
- /* Check for a leading minus to allow "-c -r42".
- * The is_negative flag is used to handle "-c -42" and "-c -r42".
- * The "-c r-42" case is handled by strtol() returning a
- * negative number. */
- is_negative = (*s == '-');
- if (is_negative)
- s++;
-
- /* Allow any number of 'r's to prefix a revision number. */
- while (*s == 'r')
- s++;
- changeno = changeno_end = strtol(s, &end, 10);
- if (end != s && *end == '-')
- {
- /* Negative number in range not supported with -c */
- if (changeno < 0 || is_negative)
- return -1;
-
- s = end + 1;
- while (*s == 'r')
- s++;
- changeno_end = strtol(s, &end, 10);
-
- /* Negative number in range not supported with -c */
- if (changeno_end < 0)
- return -1;
- }
-
- /* Non-numeric change argument given to -c? */
- if (end == arg || *end != '\0')
- return -1;
-
- /* There is no change 0 */
- if (changeno == 0 || changeno_end == 0)
- return -1;
-
- /* The revision number cannot contain a double minus */
- if (changeno < 0 && is_negative)
- return -1;
-
- if (is_negative)
- changeno = -changeno;
-
- /* Figure out the range:
- -c N -> -r N-1:N
- -c -N -> -r N:N-1
- -c M-N -> -r M-1:N for M < N
- -c M-N -> -r M:N-1 for M > N
- -c -M-N -> error (too confusing/no valid use case)
- */
- if (changeno > 0)
- {
- if (changeno <= changeno_end)
- changeno--;
- else
- changeno_end--;
- }
- else
- {
- changeno = -changeno;
- changeno_end = changeno - 1;
- }
-
- APR_ARRAY_PUSH(opt_ranges,
- svn_opt_revision_range_t *)
- = svn_opt__revision_range_from_revnums(changeno, changeno_end,
- result_pool);
-
- return 0;
-}
-
-svn_error_t *
-svn_opt_parse_revnum(svn_revnum_t *rev, const char *str)
-{
- /* Allow any number of 'r's to prefix a revision number. */
- while (*str == 'r')
- str++;
-
- return svn_error_trace(svn_revnum_parse(rev, str, NULL));
-}
-
-svn_error_t *
-svn_opt_resolve_revisions(svn_opt_revision_t *peg_rev,
- svn_opt_revision_t *op_rev,
- svn_boolean_t is_url,
- svn_boolean_t notice_local_mods,
- apr_pool_t *pool)
-{
- if (peg_rev->kind == svn_opt_revision_unspecified)
- {
- if (is_url)
- {
- peg_rev->kind = svn_opt_revision_head;
- }
- else
- {
- if (notice_local_mods)
- peg_rev->kind = svn_opt_revision_working;
- else
- peg_rev->kind = svn_opt_revision_base;
- }
- }
-
- if (op_rev->kind == svn_opt_revision_unspecified)
- *op_rev = *peg_rev;
-
- return SVN_NO_ERROR;
-}
-
-const char *
-svn_opt__revision_to_string(const svn_opt_revision_t *revision,
- apr_pool_t *result_pool)
-{
- switch (revision->kind)
- {
- case svn_opt_revision_unspecified:
- return "unspecified";
- case svn_opt_revision_number:
- return apr_psprintf(result_pool, "%ld", revision->value.number);
- case svn_opt_revision_date:
- /* ### svn_time_to_human_cstring()? */
- return svn_time_to_cstring(revision->value.date, result_pool);
- case svn_opt_revision_committed:
- return "committed";
- case svn_opt_revision_previous:
- return "previous";
- case svn_opt_revision_base:
- return "base";
- case svn_opt_revision_working:
- return "working";
- case svn_opt_revision_head:
- return "head";
- default:
- return NULL;
- }
-}
-
-svn_opt_revision_range_t *
-svn_opt__revision_range_create(const svn_opt_revision_t *start_revision,
- const svn_opt_revision_t *end_revision,
- apr_pool_t *result_pool)
-{
- svn_opt_revision_range_t *range = apr_palloc(result_pool, sizeof(*range));
-
- range->start = *start_revision;
- range->end = *end_revision;
- return range;
-}
-
-svn_opt_revision_range_t *
-svn_opt__revision_range_from_revnums(svn_revnum_t start_revnum,
- svn_revnum_t end_revnum,
- apr_pool_t *result_pool)
-{
- svn_opt_revision_range_t *range = apr_palloc(result_pool, sizeof(*range));
-
- range->start.kind = svn_opt_revision_number;
- range->start.value.number = start_revnum;
- range->end.kind = svn_opt_revision_number;
- range->end.value.number = end_revnum;
- return range;
-}
-
-
-
/*** Parsing arguments. ***/
#define DEFAULT_ARRAY_SIZE 5
Copied: subversion/trunk/subversion/libsvn_subr/opt_revision.c (from r1925919,
subversion/trunk/subversion/libsvn_subr/opt.c)
URL:
http://svn.apache.org/viewvc/subversion/trunk/subversion/libsvn_subr/opt_revision.c?p2=subversion/trunk/subversion/libsvn_subr/opt_revision.c&p1=subversion/trunk/subversion/libsvn_subr/opt.c&r1=1925919&r2=1925920&rev=1925920&view=diff
==============================================================================
--- subversion/trunk/subversion/libsvn_subr/opt.c (original)
+++ subversion/trunk/subversion/libsvn_subr/opt_revision.c Wed May 28 20:45:52
2025
@@ -1,5 +1,5 @@
/*
- * opt.c : option and argument parsing for Subversion command lines
+ * opt.c : parsing revision and date options.
*
* ====================================================================
* Licensed to the Apache Software Foundation (ASF) under one
@@ -26,447 +26,22 @@
#define APR_WANT_STRFUNC
#include <apr_want.h>
-#include <stdio.h>
#include <string.h>
-#include <assert.h>
-#include <apr_pools.h>
+
#include <apr_general.h>
-#include <apr_lib.h>
-#include <apr_file_info.h>
-#include "svn_hash.h"
-#include "svn_cmdline.h"
-#include "svn_version.h"
#include "svn_types.h"
#include "svn_opt.h"
#include "svn_error.h"
-#include "svn_dirent_uri.h"
-#include "svn_path.h"
#include "svn_utf.h"
#include "svn_time.h"
-#include "svn_props.h"
#include "svn_ctype.h"
#include "private/svn_opt_private.h"
-#include "opt.h"
#include "svn_private_config.h"
-/*** Code. ***/
-
-const svn_opt_subcommand_desc3_t *
-svn_opt_get_canonical_subcommand3(const svn_opt_subcommand_desc3_t *table,
- const char *cmd_name)
-{
- int i = 0;
-
- if (cmd_name == NULL)
- return NULL;
-
- while (table[i].name) {
- int j;
- if (strcmp(cmd_name, table[i].name) == 0)
- return table + i;
- for (j = 0; (j < SVN_OPT_MAX_ALIASES) && table[i].aliases[j]; j++)
- if (strcmp(cmd_name, table[i].aliases[j]) == 0)
- return table + i;
-
- i++;
- }
-
- /* If we get here, there was no matching subcommand name or alias. */
- return NULL;
-}
-
-const apr_getopt_option_t *
-svn_opt_get_option_from_code3(int code,
- const apr_getopt_option_t *option_table,
- const svn_opt_subcommand_desc3_t *command,
- apr_pool_t *pool)
-{
- apr_size_t i;
-
- for (i = 0; option_table[i].optch; i++)
- if (option_table[i].optch == code)
- {
- if (command)
- {
- int j;
-
- for (j = 0; ((j < SVN_OPT_MAX_OPTIONS) &&
- command->desc_overrides[j].optch); j++)
- if (command->desc_overrides[j].optch == code)
- {
- apr_getopt_option_t *tmpopt =
- apr_palloc(pool, sizeof(*tmpopt));
- *tmpopt = option_table[i];
- tmpopt->description = command->desc_overrides[j].desc;
- return tmpopt;
- }
- }
- return &(option_table[i]);
- }
-
- return NULL;
-}
-
-/* Like svn_opt_get_option_from_code3(), but also, if CODE appears a second
- * time in OPTION_TABLE with a different name, then set *LONG_ALIAS to that
- * second name, else set it to NULL. */
-static const apr_getopt_option_t *
-get_option_from_code3(const char **long_alias,
- int code,
- const apr_getopt_option_t *option_table,
- const svn_opt_subcommand_desc3_t *command,
- apr_pool_t *pool)
-{
- const apr_getopt_option_t *i;
- const apr_getopt_option_t *opt
- = svn_opt_get_option_from_code3(code, option_table, command, pool);
-
- /* Find a long alias in the table, if there is one. */
- *long_alias = NULL;
- for (i = option_table; i->optch; i++)
- {
- if (i->optch == code && i->name != opt->name)
- {
- *long_alias = i->name;
- break;
- }
- }
-
- return opt;
-}
-
-
-/* Print an option OPT nicely into a STRING allocated in POOL.
- * If OPT has a single-character short form, then print OPT->name (if not
- * NULL) as an alias, else print LONG_ALIAS (if not NULL) as an alias.
- * If DOC is set, include the generic documentation string of OPT,
- * localized to the current locale if a translation is available.
- */
-static void
-format_option(const char **string,
- const apr_getopt_option_t *opt,
- const char *long_alias,
- svn_boolean_t doc,
- apr_pool_t *pool)
-{
- char *opts;
-
- if (opt == NULL)
- {
- *string = "?";
- return;
- }
-
- /* We have a valid option which may or may not have a "short
- name" (a single-character alias for the long option). */
- if (opt->optch <= 255)
- opts = apr_psprintf(pool, "-%c [--%s]", opt->optch, opt->name);
- else if (long_alias)
- opts = apr_psprintf(pool, "--%s [--%s]", opt->name, long_alias);
- else
- opts = apr_psprintf(pool, "--%s", opt->name);
-
- if (opt->has_arg)
- opts = apr_pstrcat(pool, opts, _(" ARG"), SVN_VA_NULL);
-
- if (doc)
- opts = apr_psprintf(pool, "%-24s : %s", opts, _(opt->description));
-
- *string = opts;
-}
-
-void
-svn_opt_format_option(const char **string,
- const apr_getopt_option_t *opt,
- svn_boolean_t doc,
- apr_pool_t *pool)
-{
- format_option(string, opt, NULL, doc, pool);
-}
-
-
-svn_boolean_t
-svn_opt_subcommand_takes_option4(const svn_opt_subcommand_desc3_t *command,
- int option_code,
- const int *global_options)
-{
- apr_size_t i;
-
- for (i = 0; i < SVN_OPT_MAX_OPTIONS; i++)
- if (command->valid_options[i] == option_code)
- return TRUE;
-
- if (global_options)
- for (i = 0; global_options[i]; i++)
- if (global_options[i] == option_code)
- return TRUE;
-
- return FALSE;
-}
-
-
-/* Print the canonical command name for CMD, and all its aliases, to
- STREAM. If HELP is set, print CMD's help string too, in which case
- obtain option usage from OPTIONS_TABLE.
-
- Include global and experimental options iff VERBOSE is true.
- */
-static svn_error_t *
-print_command_info3(const svn_opt_subcommand_desc3_t *cmd,
- const apr_getopt_option_t *options_table,
- const int *global_options,
- svn_boolean_t help,
- svn_boolean_t verbose,
- apr_pool_t *pool,
- FILE *stream)
-{
- svn_boolean_t first_time;
- apr_size_t i;
-
- /* Print the canonical command name. */
- SVN_ERR(svn_cmdline_fputs(cmd->name, stream, pool));
-
- /* Print the list of aliases. */
- first_time = TRUE;
- for (i = 0; i < SVN_OPT_MAX_ALIASES; i++)
- {
- if (cmd->aliases[i] == NULL)
- break;
-
- if (first_time) {
- SVN_ERR(svn_cmdline_fputs(" (", stream, pool));
- first_time = FALSE;
- }
- else
- SVN_ERR(svn_cmdline_fputs(", ", stream, pool));
-
- SVN_ERR(svn_cmdline_fputs(cmd->aliases[i], stream, pool));
- }
-
- if (! first_time)
- SVN_ERR(svn_cmdline_fputs(")", stream, pool));
-
- if (help)
- {
- const apr_getopt_option_t *option;
- const char *long_alias;
- svn_boolean_t have_options = FALSE;
- svn_boolean_t have_experimental = FALSE;
-
- SVN_ERR(svn_cmdline_fprintf(stream, pool, ": "));
-
- for (i = 0; i < SVN_OPT_MAX_PARAGRAPHS && cmd->help[i]; i++)
- {
- SVN_ERR(svn_cmdline_fprintf(stream, pool, "%s", _(cmd->help[i])));
- }
-
- /* Loop over all valid option codes attached to the subcommand */
- for (i = 0; i < SVN_OPT_MAX_OPTIONS; i++)
- {
- if (cmd->valid_options[i])
- {
- if (!have_options)
- {
- SVN_ERR(svn_cmdline_fputs(_("\nValid options:\n"),
- stream, pool));
- have_options = TRUE;
- }
-
- /* convert each option code into an option */
- option = get_option_from_code3(&long_alias,
cmd->valid_options[i],
- options_table, cmd, pool);
-
- /* print the option's docstring */
- if (option && option->description)
- {
- const char *optstr;
-
- if (option->name && strncmp(option->name, "x-", 2) == 0)
- {
- if (verbose && !have_experimental)
- SVN_ERR(svn_cmdline_fputs(_("\nExperimental
options:\n"),
- stream, pool));
- have_experimental = TRUE;
- if (!verbose)
- continue;
- }
-
- format_option(&optstr, option, long_alias, TRUE, pool);
- SVN_ERR(svn_cmdline_fprintf(stream, pool, " %s\n",
- optstr));
- }
- }
- }
- /* And global options too */
- if (verbose && global_options && *global_options)
- {
- SVN_ERR(svn_cmdline_fputs(_("\nGlobal options:\n"),
- stream, pool));
- have_options = TRUE;
-
- for (i = 0; global_options[i]; i++)
- {
-
- /* convert each option code into an option */
- option = get_option_from_code3(&long_alias, global_options[i],
- options_table, cmd, pool);
-
- /* print the option's docstring */
- if (option && option->description)
- {
- const char *optstr;
- format_option(&optstr, option, long_alias, TRUE, pool);
- SVN_ERR(svn_cmdline_fprintf(stream, pool, " %s\n",
- optstr));
- }
- }
- }
-
- if (!verbose && global_options && *global_options)
- SVN_ERR(svn_cmdline_fputs(_("\n(Use '-v' to show global and
experimental options.)\n"),
- stream, pool));
- if (have_options)
- SVN_ERR(svn_cmdline_fprintf(stream, pool, "\n"));
- }
-
- return SVN_NO_ERROR;
-}
-
-/* The body for svn_opt_print_generic_help3() function with standard error
- * handling semantic. Handling of errors implemented at caller side. */
-static svn_error_t *
-print_generic_help_body3(const char *header,
- const svn_opt_subcommand_desc3_t *cmd_table,
- const apr_getopt_option_t *opt_table,
- const char *footer,
- svn_boolean_t with_experimental,
- apr_pool_t *pool, FILE *stream)
-{
- svn_boolean_t have_experimental = FALSE;
- int i;
-
- if (header)
- SVN_ERR(svn_cmdline_fputs(header, stream, pool));
-
- for (i = 0; cmd_table[i].name; i++)
- {
- if (strncmp(cmd_table[i].name, "x-", 2) == 0)
- {
- if (with_experimental && !have_experimental)
- SVN_ERR(svn_cmdline_fputs(_("\nExperimental subcommands:\n"),
- stream, pool));
- have_experimental = TRUE;
- if (!with_experimental)
- continue;
- }
- SVN_ERR(svn_cmdline_fputs(" ", stream, pool));
- SVN_ERR(print_command_info3(cmd_table + i, opt_table,
- NULL, FALSE, FALSE,
- pool, stream));
- SVN_ERR(svn_cmdline_fputs("\n", stream, pool));
- }
-
- if (have_experimental && !with_experimental)
- SVN_ERR(svn_cmdline_fputs(_("\n(Use '-v' to show experimental
subcommands.)\n"),
- stream, pool));
-
- SVN_ERR(svn_cmdline_fputs("\n", stream, pool));
-
- if (footer)
- SVN_ERR(svn_cmdline_fputs(footer, stream, pool));
-
- return SVN_NO_ERROR;
-}
-
-static void
-print_generic_help(const char *header,
- const svn_opt_subcommand_desc3_t *cmd_table,
- const apr_getopt_option_t *opt_table,
- const char *footer,
- svn_boolean_t with_experimental,
- apr_pool_t *pool, FILE *stream)
-{
- svn_error_t *err;
-
- err = print_generic_help_body3(header, cmd_table, opt_table, footer,
- with_experimental,
- pool, stream);
-
- /* Issue #3014:
- * Don't print anything on broken pipes. The pipe was likely
- * closed by the process at the other end. We expect that
- * process to perform error reporting as necessary.
- *
- * ### This assumes that there is only one error in a chain for
- * ### SVN_ERR_IO_PIPE_WRITE_ERROR. See svn_cmdline_fputs(). */
- if (err && err->apr_err != SVN_ERR_IO_PIPE_WRITE_ERROR)
- svn_handle_error2(err, stderr, FALSE, "svn: ");
- svn_error_clear(err);
-}
-
-void
-svn_opt_print_generic_help3(const char *header,
- const svn_opt_subcommand_desc3_t *cmd_table,
- const apr_getopt_option_t *opt_table,
- const char *footer,
- apr_pool_t *pool, FILE *stream)
-{
- print_generic_help(header, cmd_table, opt_table, footer,
- TRUE, pool, stream);
-}
-
-
-/* The body of svn_opt_subcommand_help4(), which see.
- *
- * VERBOSE means show also the subcommand's global and experimental options.
- */
-static void
-subcommand_help(const char *subcommand,
- const svn_opt_subcommand_desc3_t *table,
- const apr_getopt_option_t *options_table,
- const int *global_options,
- svn_boolean_t verbose,
- apr_pool_t *pool)
-{
- const svn_opt_subcommand_desc3_t *cmd =
- svn_opt_get_canonical_subcommand3(table, subcommand);
- svn_error_t *err;
-
- if (cmd)
- err = print_command_info3(cmd, options_table, global_options,
- TRUE, verbose, pool, stdout);
- else
- err = svn_cmdline_fprintf(stderr, pool,
- _("\"%s\": unknown command.\n\n"), subcommand);
-
- if (err) {
- /* Issue #3014: Don't print anything on broken pipes. */
- if (err->apr_err != SVN_ERR_IO_PIPE_WRITE_ERROR)
- svn_handle_error2(err, stderr, FALSE, "svn: ");
- svn_error_clear(err);
- }
-}
-
-void
-svn_opt_subcommand_help4(const char *subcommand,
- const svn_opt_subcommand_desc3_t *table,
- const apr_getopt_option_t *options_table,
- const int *global_options,
- apr_pool_t *pool)
-{
- subcommand_help(subcommand, table, options_table, global_options,
- TRUE, pool);
-}
-
-
-
-/*** Parsing revision and date options. ***/
-
-
/** Parsing "X:Y"-style arguments. **/
/* If WORD matches one of the special revision descriptors,
@@ -800,561 +375,3 @@ svn_opt__revision_range_from_revnums(svn
range->end.value.number = end_revnum;
return range;
}
-
-
-
-/*** Parsing arguments. ***/
-#define DEFAULT_ARRAY_SIZE 5
-
-
-/* Copy STR into POOL and push the copy onto ARRAY. */
-static void
-array_push_str(apr_array_header_t *array,
- const char *str,
- apr_pool_t *pool)
-{
- /* ### Not sure if this function is still necessary. It used to
- convert str to svn_stringbuf_t * and push it, but now it just
- dups str in pool and pushes the copy. So its only effect is
- transfer str's lifetime to pool. Is that something callers are
- depending on? */
-
- APR_ARRAY_PUSH(array, const char *) = apr_pstrdup(pool, str);
-}
-
-
-void
-svn_opt_push_implicit_dot_target(apr_array_header_t *targets,
- apr_pool_t *pool)
-{
- if (targets->nelts == 0)
- APR_ARRAY_PUSH(targets, const char *) = ""; /* Ha! "", not ".", is the
canonical */
- assert(targets->nelts);
-}
-
-
-svn_error_t *
-svn_opt_parse_num_args(apr_array_header_t **args_p,
- apr_getopt_t *os,
- int num_args,
- apr_pool_t *pool)
-{
- int i;
- apr_array_header_t *args
- = apr_array_make(pool, DEFAULT_ARRAY_SIZE, sizeof(const char *));
-
- /* loop for num_args and add each arg to the args array */
- for (i = 0; i < num_args; i++)
- {
- if (os->ind >= os->argc)
- {
- return svn_error_create(SVN_ERR_CL_INSUFFICIENT_ARGS, 0, NULL);
- }
- array_push_str(args, os->argv[os->ind++], pool);
- }
-
- *args_p = args;
- return SVN_NO_ERROR;
-}
-
-svn_error_t *
-svn_opt_parse_all_args(apr_array_header_t **args_p,
- apr_getopt_t *os,
- apr_pool_t *pool)
-{
- apr_array_header_t *args
- = apr_array_make(pool, DEFAULT_ARRAY_SIZE, sizeof(const char *));
-
- if (os->ind > os->argc)
- {
- return svn_error_create(SVN_ERR_CL_ARG_PARSING_ERROR, 0, NULL);
- }
- while (os->ind < os->argc)
- {
- array_push_str(args, os->argv[os->ind++], pool);
- }
-
- *args_p = args;
- return SVN_NO_ERROR;
-}
-
-
-svn_error_t *
-svn_opt_parse_path(svn_opt_revision_t *rev,
- const char **truepath,
- const char *path /* UTF-8! */,
- apr_pool_t *pool)
-{
- const char *peg_rev;
-
- SVN_ERR(svn_opt__split_arg_at_peg_revision(truepath, &peg_rev, path, pool));
-
- /* Parse the peg revision, if one was found */
- if (strlen(peg_rev))
- {
- int ret;
- svn_opt_revision_t start_revision, end_revision;
-
- end_revision.kind = svn_opt_revision_unspecified;
-
- if (peg_rev[1] == '\0') /* looking at empty peg revision */
- {
- ret = 0;
- start_revision.kind = svn_opt_revision_unspecified;
- start_revision.value.number = 0;
- }
- else /* looking at non-empty peg revision */
- {
- const char *rev_str = &peg_rev[1];
-
- /* URLs get treated differently from wc paths. */
- if (svn_path_is_url(path))
- {
- /* URLs are URI-encoded, so we look for dates with
- URI-encoded delimiters. */
- size_t rev_len = strlen(rev_str);
- if (rev_len > 6
- && rev_str[0] == '%'
- && rev_str[1] == '7'
- && (rev_str[2] == 'B'
- || rev_str[2] == 'b')
- && rev_str[rev_len-3] == '%'
- && rev_str[rev_len-2] == '7'
- && (rev_str[rev_len-1] == 'D'
- || rev_str[rev_len-1] == 'd'))
- {
- rev_str = svn_path_uri_decode(rev_str, pool);
- }
- }
- ret = svn_opt_parse_revision(&start_revision,
- &end_revision,
- rev_str, pool);
- }
-
- if (ret || end_revision.kind != svn_opt_revision_unspecified)
- {
- /* If an svn+ssh URL was used and it contains only one @,
- * provide an error message that presents a possible solution
- * to the parsing error (issue #2349). */
- if (strncmp(path, "svn+ssh://", 10) == 0)
- {
- const char *at;
-
- at = strchr(path, '@');
- if (at && strrchr(path, '@') == at)
- return svn_error_createf(SVN_ERR_CL_ARG_PARSING_ERROR, NULL,
- _("Syntax error parsing peg revision "
- "'%s'; did you mean '%s@'?"),
- &peg_rev[1], path);
- }
-
- return svn_error_createf(SVN_ERR_CL_ARG_PARSING_ERROR, NULL,
- _("Syntax error parsing peg revision '%s'"),
- &peg_rev[1]);
- }
- rev->kind = start_revision.kind;
- rev->value = start_revision.value;
- }
- else
- {
- /* Didn't find a peg revision. */
- rev->kind = svn_opt_revision_unspecified;
- }
-
- return SVN_NO_ERROR;
-}
-
-
-/* Note: This is substantially copied into svn_client_args_to_target_array() in
- * order to move to libsvn_client while maintaining backward compatibility. */
-svn_error_t *
-svn_opt__args_to_target_array(apr_array_header_t **targets_p,
- apr_getopt_t *os,
- const apr_array_header_t *known_targets,
- apr_pool_t *pool)
-{
- int i;
- 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 *));
-
- /* Step 1: create a master array of targets that are in UTF-8
- encoding, and come from concatenating the targets left by apr_getopt,
- plus any extra targets (e.g., from the --targets switch.) */
-
- for (; os->ind < os->argc; os->ind++)
- {
- /* The apr_getopt targets are still in native encoding. */
- const char *raw_target = os->argv[os->ind];
- SVN_ERR(svn_utf_cstring_to_utf8
- ((const char **) apr_array_push(input_targets),
- raw_target, pool));
- }
-
- if (known_targets)
- {
- for (i = 0; i < known_targets->nelts; i++)
- {
- /* The --targets array have already been converted to UTF-8,
- because we needed to split up the list with svn_cstring_split. */
- const char *utf8_target = APR_ARRAY_IDX(known_targets,
- i, const char *);
- APR_ARRAY_PUSH(input_targets, const char *) = utf8_target;
- }
- }
-
- /* Step 2: process each target. */
-
- for (i = 0; i < input_targets->nelts; i++)
- {
- const char *utf8_target = APR_ARRAY_IDX(input_targets, i, const char *);
- const char *true_target;
- const char *target; /* after all processing is finished */
- const char *peg_rev;
-
- /*
- * This is needed so that the target can be properly canonicalized,
- * otherwise the canonicalization does not treat a ".@BASE" as a "."
- * with a BASE peg revision, and it is not canonicalized to "@BASE".
- * If any peg revision exists, it is appended to the final
- * canonicalized path or URL. Do not use svn_opt_parse_path()
- * because the resulting peg revision is a structure that would have
- * to be converted back into a string. Converting from a string date
- * to the apr_time_t field in the svn_opt_revision_value_t and back to
- * a string would not necessarily preserve the exact bytes of the
- * input date, so its easier just to keep it in string form.
- */
- SVN_ERR(svn_opt__split_arg_at_peg_revision(&true_target, &peg_rev,
- utf8_target, pool));
-
- /* URLs and wc-paths get treated differently. */
- if (svn_path_is_url(true_target))
- {
- SVN_ERR(svn_opt__arg_canonicalize_url(&true_target, true_target,
- pool));
- }
- else /* not a url, so treat as a path */
- {
- const char *base_name;
-
- SVN_ERR(svn_opt__arg_canonicalize_path(&true_target, true_target,
- pool));
-
- /* If the target has the same name as a Subversion
- working copy administrative dir, skip it. */
- base_name = svn_dirent_basename(true_target, pool);
-
- /* FIXME:
- The canonical list of administrative directory names is
- maintained in libsvn_wc/adm_files.c:svn_wc_set_adm_dir().
- That list can't be used here, because that use would
- create a circular dependency between libsvn_wc and
- libsvn_subr. Make sure changes to the lists are always
- synchronized! */
- if (0 == strcmp(base_name, ".svn")
- || 0 == strcmp(base_name, "_svn"))
- {
- 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, SVN_VA_NULL);
-
- APR_ARRAY_PUSH(output_targets, const char *) = target;
- }
-
-
- /* kff todo: need to remove redundancies from targets before
- passing it to the cmd_func. */
-
- *targets_p = output_targets;
-
- return err;
-}
-
-svn_error_t *
-svn_opt_parse_revprop(apr_hash_t **revprop_table_p, const char *revprop_spec,
- apr_pool_t *pool)
-{
- const char *sep, *propname;
- svn_string_t *propval;
-
- if (! *revprop_spec)
- return svn_error_create(SVN_ERR_CL_ARG_PARSING_ERROR, NULL,
- _("Revision property pair is empty"));
-
- if (! *revprop_table_p)
- *revprop_table_p = apr_hash_make(pool);
-
- sep = strchr(revprop_spec, '=');
- if (sep)
- {
- propname = apr_pstrndup(pool, revprop_spec, sep - revprop_spec);
- SVN_ERR(svn_utf_cstring_to_utf8(&propname, propname, pool));
- propval = svn_string_create(sep + 1, pool);
- }
- else
- {
- SVN_ERR(svn_utf_cstring_to_utf8(&propname, revprop_spec, pool));
- propval = svn_string_create_empty(pool);
- }
-
- if (!svn_prop_name_is_valid(propname))
- return svn_error_createf(SVN_ERR_CLIENT_PROPERTY_NAME, NULL,
- _("'%s' is not a valid Subversion property name"),
- propname);
-
- svn_hash_sets(*revprop_table_p, propname, propval);
-
- return SVN_NO_ERROR;
-}
-
-svn_error_t *
-svn_opt__split_arg_at_peg_revision(const char **true_target,
- const char **peg_revision,
- const char *utf8_target,
- apr_pool_t *pool)
-{
- const char *peg_start = NULL; /* pointer to the peg revision, if any */
- const char *ptr;
-
- for (ptr = (utf8_target + strlen(utf8_target) - 1); ptr >= utf8_target;
- --ptr)
- {
- /* If we hit a path separator, stop looking. This is OK
- only because our revision specifiers can't contain '/'. */
- if (*ptr == '/')
- break;
-
- if (*ptr == '@')
- {
- peg_start = ptr;
- break;
- }
- }
-
- if (peg_start)
- {
- *true_target = apr_pstrmemdup(pool, utf8_target, ptr - utf8_target);
- if (peg_revision)
- *peg_revision = apr_pstrdup(pool, peg_start);
- }
- else
- {
- *true_target = utf8_target;
- if (peg_revision)
- *peg_revision = "";
- }
-
- return SVN_NO_ERROR;
-}
-
-svn_error_t *
-svn_opt__arg_canonicalize_url(const char **url_out, const char *url_in,
- apr_pool_t *pool)
-{
- const char *target;
-
- /* Convert to URI. */
- target = svn_path_uri_from_iri(url_in, pool);
- /* Auto-escape some ASCII characters. */
- target = svn_path_uri_autoescape(target, pool);
-
-#if '/' != SVN_PATH_LOCAL_SEPARATOR
- /* Allow using file:///C:\users\me/repos on Windows, like we did in 1.6 */
- if (strchr(target, SVN_PATH_LOCAL_SEPARATOR))
- {
- char *p = apr_pstrdup(pool, target);
- target = p;
-
- /* Convert all local-style separators to the canonical ones. */
- for (; *p != '\0'; ++p)
- if (*p == SVN_PATH_LOCAL_SEPARATOR)
- *p = '/';
- }
-#endif
-
- /* Verify that no backpaths are present in the URL. */
- if (svn_path_is_backpath_present(target))
- return svn_error_createf(SVN_ERR_BAD_URL, 0,
- _("URL '%s' contains a '..' element"),
- target);
-
- /* Strip any trailing '/' and collapse other redundant elements. */
- target = svn_uri_canonicalize(target, pool);
-
- *url_out = target;
- return SVN_NO_ERROR;
-}
-
-svn_error_t *
-svn_opt__arg_canonicalize_path(const char **path_out, const char *path_in,
- apr_pool_t *pool)
-{
- const char *apr_target;
- char *truenamed_target; /* APR-encoded */
- apr_status_t apr_err;
-
- /* canonicalize case, and change all separators to '/'. */
- SVN_ERR(svn_path_cstring_from_utf8(&apr_target, path_in, pool));
- apr_err = apr_filepath_merge(&truenamed_target, "", apr_target,
- APR_FILEPATH_TRUENAME, pool);
-
- if (!apr_err)
- /* We have a canonicalized APR-encoded target now. */
- apr_target = truenamed_target;
- else if (APR_STATUS_IS_ENOENT(apr_err))
- /* It's okay for the file to not exist, that just means we
- have to accept the case given to the client. We'll use
- the original APR-encoded target. */
- ;
- else
- return svn_error_createf(apr_err, NULL,
- _("Error resolving case of '%s'"),
- svn_dirent_local_style(path_in, pool));
-
- /* convert back to UTF-8. */
- SVN_ERR(svn_path_cstring_to_utf8(path_out, apr_target, pool));
- *path_out = svn_dirent_canonicalize(*path_out, pool);
-
- return SVN_NO_ERROR;
-}
-
-
-svn_error_t *
-svn_opt__print_version_info(const char *pgm_name,
- const char *footer,
- const svn_version_extended_t *info,
- svn_boolean_t quiet,
- svn_boolean_t verbose,
- apr_pool_t *pool)
-{
- if (quiet)
- return svn_cmdline_printf(pool, "%s\n", SVN_VER_NUMBER);
-
- SVN_ERR(svn_cmdline_printf(pool, _("%s, version %s\n"
- " compiled %s, %s on %s\n\n"),
- pgm_name, SVN_VERSION,
- svn_version_ext_build_date(info),
- svn_version_ext_build_time(info),
- svn_version_ext_build_host(info)));
- SVN_ERR(svn_cmdline_printf(pool, "%s\n", svn_version_ext_copyright(info)));
-
- if (footer)
- {
- SVN_ERR(svn_cmdline_printf(pool, "%s\n", footer));
- }
-
- if (verbose)
- {
- const apr_array_header_t *libs;
-
- SVN_ERR(svn_cmdline_fputs(_("System information:\n\n"), stdout, pool));
- SVN_ERR(svn_cmdline_printf(pool, _("* running on %s\n"),
- svn_version_ext_runtime_host(info)));
- if (svn_version_ext_runtime_osname(info))
- {
- SVN_ERR(svn_cmdline_printf(pool, _(" - %s\n"),
- svn_version_ext_runtime_osname(info)));
- }
-
- libs = svn_version_ext_linked_libs(info);
- if (libs && libs->nelts)
- {
- const svn_version_ext_linked_lib_t *lib;
- int i;
-
- SVN_ERR(svn_cmdline_fputs(_("* linked dependencies:\n"),
- stdout, pool));
- for (i = 0; i < libs->nelts; ++i)
- {
- lib = &APR_ARRAY_IDX(libs, i, svn_version_ext_linked_lib_t);
- if (lib->runtime_version)
- SVN_ERR(svn_cmdline_printf(pool,
- " - %s %s (compiled with %s)\n",
- lib->name,
- lib->runtime_version,
- lib->compiled_version));
- else
- SVN_ERR(svn_cmdline_printf(pool,
- " - %s %s (static)\n",
- lib->name,
- lib->compiled_version));
- }
- }
-
- libs = svn_version_ext_loaded_libs(info);
- if (libs && libs->nelts)
- {
- const svn_version_ext_loaded_lib_t *lib;
- int i;
-
- SVN_ERR(svn_cmdline_fputs(_("* loaded shared libraries:\n"),
- stdout, pool));
- for (i = 0; i < libs->nelts; ++i)
- {
- lib = &APR_ARRAY_IDX(libs, i, svn_version_ext_loaded_lib_t);
- if (lib->version)
- SVN_ERR(svn_cmdline_printf(pool,
- " - %s (%s)\n",
- lib->name, lib->version));
- else
- SVN_ERR(svn_cmdline_printf(pool, " - %s\n", lib->name));
- }
- }
- }
-
- return SVN_NO_ERROR;
-}
-
-svn_error_t *
-svn_opt_print_help5(apr_getopt_t *os,
- const char *pgm_name,
- svn_boolean_t print_version,
- svn_boolean_t quiet,
- svn_boolean_t verbose,
- const char *version_footer,
- const char *header,
- const svn_opt_subcommand_desc3_t *cmd_table,
- const apr_getopt_option_t *option_table,
- const int *global_options,
- const char *footer,
- apr_pool_t *pool)
-{
- apr_array_header_t *targets = NULL;
-
- if (os)
- SVN_ERR(svn_opt_parse_all_args(&targets, os, pool));
-
- if (os && targets->nelts) /* help on subcommand(s) requested */
- {
- int i;
-
- for (i = 0; i < targets->nelts; i++)
- {
- subcommand_help(APR_ARRAY_IDX(targets, i, const char *),
- cmd_table, option_table, global_options,
- verbose, pool);
- }
- }
- else if (print_version) /* just --version */
- {
- SVN_ERR(svn_opt__print_version_info(pgm_name, version_footer,
- svn_version_extended(verbose, pool),
- quiet, verbose, pool));
- }
- else if (os && !targets->nelts) /* `-h', `--help', or `help' */
- print_generic_help(header, cmd_table, option_table, footer,
- verbose,
- pool, stdout);
- else /* unknown option or cmd */
- SVN_ERR(svn_cmdline_fprintf(stderr, pool,
- _("Type '%s help' for usage.\n"), pgm_name));
-
- return SVN_NO_ERROR;
-}