📄 opt.c
字号:
/*
* opt.c : option and argument parsing for Subversion command lines
*
* ====================================================================
* Copyright (c) 2000-2004 CollabNet. All rights reserved.
*
* This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms
* are also available at http://subversion.tigris.org/license-1.html.
* If newer versions of this license are posted there, you may use a
* newer version instead, at your option.
*
* This software consists of voluntary contributions made by many
* individuals. For exact contribution history, see the revision
* history and logs, available at http://subversion.tigris.org/.
* ====================================================================
*/
#include <stdio.h>
#include <string.h>
#include <assert.h>
#include <apr_pools.h>
#include <apr_general.h>
#include <apr_lib.h>
#include "svn_cmdline.h"
#include "svn_version.h"
#include "svn_types.h"
#include "svn_wc.h"
#include "svn_opt.h"
#include "svn_error.h"
#include "svn_pools.h"
#include "svn_path.h"
#include "svn_utf.h"
#include "svn_time.h"
#include "svn_private_config.h"
/*** Code. ***/
const svn_opt_subcommand_desc_t *
svn_opt_get_canonical_subcommand (const svn_opt_subcommand_desc_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_code (int code,
const apr_getopt_option_t *option_table)
{
apr_size_t i;
for (i = 0; option_table[i].optch; i++)
if (option_table[i].optch == code)
return &(option_table[i]);
return NULL;
}
svn_boolean_t
svn_opt_subcommand_takes_option (const svn_opt_subcommand_desc_t *command,
int option_code)
{
apr_size_t i;
for (i = 0; i < SVN_OPT_MAX_OPTIONS; i++)
if (command->valid_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. */
static svn_error_t *
print_command_info (const svn_opt_subcommand_desc_t *cmd,
const apr_getopt_option_t *options_table,
svn_boolean_t help,
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;
svn_boolean_t have_options = FALSE;
SVN_ERR (svn_cmdline_fprintf (stream, pool, ": %s",
dgettext (PACKAGE_NAME, cmd->help)));
/* 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 == FALSE)
{
SVN_ERR (svn_cmdline_fputs (_("\nValid options:\n"),
stream, pool));
have_options = TRUE;
}
/* convert each option code into an option */
option =
svn_opt_get_option_from_code (cmd->valid_options[i],
options_table);
/* print the option's docstring */
if (option)
{
const char *optstr;
svn_opt_format_option (&optstr, option, TRUE, pool);
SVN_ERR (svn_cmdline_fprintf (stream, pool, " %s\n",
optstr));
}
}
}
if (have_options)
SVN_ERR (svn_cmdline_fprintf (stream, pool, "\n"));
}
return SVN_NO_ERROR;
}
void
svn_opt_print_generic_help (const char *header,
const svn_opt_subcommand_desc_t *cmd_table,
const apr_getopt_option_t *opt_table,
const char *footer,
apr_pool_t *pool, FILE *stream)
{
int i = 0;
svn_error_t *err;
if (header)
if ((err = svn_cmdline_fputs (header, stream, pool)))
goto print_error;
while (cmd_table[i].name)
{
if ((err = svn_cmdline_fputs (" ", stream, pool))
|| (err = print_command_info (cmd_table + i, opt_table, FALSE,
pool, stream))
|| (err = svn_cmdline_fputs ("\n", stream, pool)))
goto print_error;
i++;
}
if ((err = svn_cmdline_fputs ("\n", stream, pool)))
goto print_error;
if (footer)
if ((err = svn_cmdline_fputs (footer, stream, pool)))
goto print_error;
return;
print_error:
svn_handle_error (err, stderr, FALSE);
svn_error_clear (err);
}
void
svn_opt_format_option (const char **string,
const apr_getopt_option_t *opt,
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
opts = apr_psprintf (pool, "--%s", opt->name);
if (opt->has_arg)
opts = apr_pstrcat (pool, opts, " arg", NULL);
if (doc)
opts = apr_psprintf (pool, "%-24s : %s", opts,
dgettext( PACKAGE_NAME, opt->description));
*string = opts;
}
void
svn_opt_subcommand_help (const char *subcommand,
const svn_opt_subcommand_desc_t *table,
const apr_getopt_option_t *options_table,
apr_pool_t *pool)
{
const svn_opt_subcommand_desc_t *cmd =
svn_opt_get_canonical_subcommand (table, subcommand);
svn_error_t *err;
if (cmd)
err = print_command_info (cmd, options_table, TRUE, pool, stdout);
else
err = svn_cmdline_fprintf (stderr, pool,
_("\"%s\": unknown command.\n\n"), subcommand);
if (err) {
svn_handle_error (err, stderr, FALSE);
svn_error_clear (err);
}
}
/*** 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 (strcasecmp (word, "head") == 0)
{
revision->kind = svn_opt_revision_head;
}
else if (strcasecmp (word, "prev") == 0)
{
revision->kind = svn_opt_revision_previous;
}
else if (strcasecmp (word, "base") == 0)
{
revision->kind = svn_opt_revision_base;
}
else if (strcasecmp (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;
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 (apr_isdigit (*str))
{
/* It's a number. */
end = str + 1;
while (apr_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 (apr_isalpha (*str))
{
end = str + 1;
while (apr_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)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -