📄 opt.c
字号:
{
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;
}
/*** 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? */
(*((const char **) apr_array_push (array))) = apr_pstrdup (pool, str);
}
void
svn_opt_push_implicit_dot_target (apr_array_header_t *targets,
apr_pool_t *pool)
{
if (targets->nelts == 0)
array_push_str (targets, "", pool); /* 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_ARG_PARSING_ERROR,
0, _("Too few arguments"));
}
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)
{
int i;
apr_pool_t *subpool = svn_pool_create (pool);
svn_opt_revision_t start_revision, end_revision;
/* scanning from right to left, just to be friendly to any
screwed-up filenames that might *actually* contain @-signs. :-) */
for (i = (strlen (path) - 1); i >= 0; i--)
{
/* If we hit a path separator, stop looking. */
if (path[i] == '/')
break;
if (path[i] == '@')
{
const char *native_rev;
SVN_ERR (svn_utf_cstring_from_utf8 (&native_rev, path + i + 1,
subpool));
if (svn_opt_parse_revision (&start_revision,
&end_revision,
native_rev, subpool))
return svn_error_createf (SVN_ERR_CL_ARG_PARSING_ERROR, NULL,
_("Syntax error parsing revision '%s'"),
path + i + 1);
*truepath = apr_pstrndup (pool, path, i);
rev->kind = start_revision.kind;
rev->value = start_revision.value;
svn_pool_destroy (subpool);
return SVN_NO_ERROR;
}
}
/* Didn't find an @-sign. */
*truepath = path;
rev->kind = svn_opt_revision_unspecified;
svn_pool_destroy (subpool);
return SVN_NO_ERROR;
}
svn_error_t *
svn_opt_args_to_target_array (apr_array_header_t **targets_p,
apr_getopt_t *os,
apr_array_header_t *known_targets,
svn_opt_revision_t *start_revision,
svn_opt_revision_t *end_revision,
svn_boolean_t extract_revisions,
apr_pool_t *pool)
{
int i;
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 *);
(*((const char **) apr_array_push (input_targets))) = 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 *target; /* after all processing is finished */
/* URLs and wc-paths get treated differently. */
if (svn_path_is_url (utf8_target))
{
/* No need to canonicalize a URL's case or path separators. */
/* Convert to URI. */
target = svn_path_uri_from_iri (utf8_target, pool);
/* Auto-escape some ASCII characters. */
target = svn_path_uri_autoescape (target, pool);
/* The above doesn't guarantee a valid URI. */
if (! svn_path_is_uri_safe (target))
return svn_error_createf (SVN_ERR_BAD_URL, 0,
_("URL '%s' is not properly URI-encoded"),
utf8_target);
/* 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"),
utf8_target);
/* strip any trailing '/' */
target = svn_path_canonicalize (target, pool);
}
else /* not a url, so treat as a path */
{
const char *apr_target;
const char *base_name;
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, utf8_target,
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'"),
utf8_target);
/* convert back to UTF-8. */
SVN_ERR (svn_path_cstring_to_utf8 (&target, apr_target, pool));
target = svn_path_canonicalize (target, pool);
/* If this target is a Subversion administrative directory,
skip it. TODO: Perhaps this check should not call the
target a SVN admin dir unless svn_wc_check_wc passes on
the target, too? */
base_name = svn_path_basename (target, pool);
if (! strcmp (base_name, SVN_WC_ADM_DIR_NAME))
continue;
}
(*((const char **) apr_array_push (output_targets))) = target;
}
/* kff todo: need to remove redundancies from targets before
passing it to the cmd_func. */
if (extract_revisions)
{
svn_opt_revision_t temprev;
const char *path;
if (output_targets->nelts > 0)
{
path = ((const char **) (output_targets->elts))[0];
SVN_ERR (svn_opt_parse_path (&temprev, &path, path, pool));
if (temprev.kind != svn_opt_revision_unspecified)
{
((const char **) (output_targets->elts))[0] =
svn_path_canonicalize (path, pool);
start_revision->kind = temprev.kind;
start_revision->value = temprev.value;
}
}
if (output_targets->nelts > 1)
{
path = ((const char **) (output_targets->elts))[1];
SVN_ERR (svn_opt_parse_path (&temprev, &path, path, pool));
if (temprev.kind != svn_opt_revision_unspecified)
{
((const char **) (output_targets->elts))[1] =
svn_path_canonicalize (path, pool);
end_revision->kind = temprev.kind;
end_revision->value = temprev.value;
}
}
}
*targets_p = output_targets;
return SVN_NO_ERROR;
}
/* Print version info for PGM_NAME. If QUIET is true, print in
* brief. Else if QUIET is not true, print the version more
* verbosely, and if FOOTER is non-null, print it following the
* version information.
*
* Use POOL for temporary allocations.
*/
static svn_error_t *
print_version_info (const char *pgm_name,
const char *footer,
svn_boolean_t quiet,
apr_pool_t *pool)
{
if (quiet)
{
SVN_ERR (svn_cmdline_printf (pool, "%s\n", SVN_VER_NUMBER));
return SVN_NO_ERROR;
}
SVN_ERR (svn_cmdline_printf (pool, _("%s, version %s\n"
" compiled %s, %s\n\n"), pgm_name,
SVN_VERSION, __DATE__, __TIME__));
SVN_ERR (svn_cmdline_fputs (_("Copyright (C) 2000-2004 CollabNet.\n"
"Subversion is open source software, see"
" http://subversion.tigris.org/\n"
"This product includes software developed by "
"CollabNet (http://www.Collab.Net/).\n\n"),
stdout, pool));
if (footer)
{
SVN_ERR (svn_cmdline_printf (pool, "%s\n", footer));
}
return SVN_NO_ERROR;
}
svn_error_t *
svn_opt_print_help (apr_getopt_t *os,
const char *pgm_name,
svn_boolean_t print_version,
svn_boolean_t quiet,
const char *version_footer,
const char *header,
const svn_opt_subcommand_desc_t *cmd_table,
const apr_getopt_option_t *option_table,
const char *footer,
apr_pool_t *pool)
{
apr_array_header_t *targets = NULL;
int i;
if (os)
SVN_ERR (svn_opt_parse_all_args (&targets, os, pool));
if (cmd_table
&& targets
&& targets->nelts) /* help on subcommand(s) requested */
for (i = 0; i < targets->nelts; i++)
{
svn_opt_subcommand_help (((const char **) (targets->elts))[i],
cmd_table, option_table, pool);
}
else if (print_version) /* just --version */
SVN_ERR (print_version_info (pgm_name, version_footer, quiet, pool));
else if (os && !targets->nelts) /* `-h', `--help', or `help' */
svn_opt_print_generic_help (header,
cmd_table,
option_table,
footer,
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;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -