<commit_before>/*
 * main.c:  Subversion command line client.
 *
 * ====================================================================
 * Copyright (c) 2000-2002 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/.
 * ====================================================================
 */

/* ==================================================================== */




/*** Includes. ***/

#include <string.h>
#include <assert.h>
#include <locale.h>

#include <apr_strings.h>
#include <apr_tables.h>
#include <apr_general.h>
#include <apr_lib.h>

#include "svn_pools.h"
#include "svn_wc.h"
#include "svn_client.h"
#include "svn_config.h"
#include "svn_string.h"
#include "svn_path.h"
#include "svn_delta.h"
#include "svn_error.h"
#include "svn_io.h"
#include "svn_time.h"
#include "cl.h"



/*** Option Processing ***/

const apr_getopt_option_t svn_cl__options[] =
  {
    {"destination",   'd', 1, "put results in new directory ARG"},
    {"force",         svn_cl__force_opt, 0, "force operation to run"},
    {"help",          'h', 0, "show help on a subcommand"},
    {"message",       'm', 1, "specify commit message \"ARG\""},
    {"quiet",         'q', 0, "print as little as possible"},
    {"recursive",     svn_cl__recursive_opt, 0, "descend recursively"},
    {"nonrecursive",  'n', 0, "operate on single directory only"},
    {"revision",      'r', 1, "specify revision number ARG (or X:Y range)"},
    {"date",          'D', 1, "specify a date ARG (instead of a revision)"},
    {"file",          'F', 1, "read data from file ARG"},
    {"xml-file",      svn_cl__xml_file_opt, 1, "read/write xml to specified file ARG"},
    {"locale",        svn_cl__locale_opt, 1, "specify a locale ARG"},
    {"version",       svn_cl__version_opt, 0, "print client version info"},
    {"verbose",       'v', 0, "print extra information"},
    {"very-verbose",  'V', 0, "print maxmimum information"},
    {"show-updates",  'u', 0, "display update information"},
    /* Here begin authentication args, add more as needed: */
    {"username",      svn_cl__auth_username_opt, 1, "specify a username ARG"},
    {"password",      svn_cl__auth_password_opt, 1, "specify a password ARG"},
    {"extensions",    'x', 1, "pass \"ARG\" as bundled options to GNU diff"},
    {"targets",       svn_cl__targets_opt, 1, "pass contents of file \"ARG\" as additional args"},
    {0,               0, 0}
  };


/* The maximum number of options that can be accepted by a subcommand;
   this is simply the number of unique switches that exist in the
   table above.  */
#define SVN_CL__MAX_OPTS sizeof(svn_cl__options)/sizeof(svn_cl__options[0])




/*** Command dispatch. ***/

/* The maximum number of aliases a subcommand can have. */
#define SVN_CL__MAX_ALIASES 3


/* One element of the command dispatch table. */
typedef struct svn_cl__cmd_desc_t
{
  /* The full name of this command. */
  const char *name;

  /* The function this command invokes. */
  svn_cl__cmd_proc_t *cmd_func;

  /* A list of alias names for this command. */
  const char *aliases[SVN_CL__MAX_ALIASES];

  /* A brief string describing this command, for usage messages. */
  const char *help;

  /* A list of options accepted by this command.  Each value in the
     array is a unique enum (the 2nd field in apr_getopt_option_t) */
  int valid_options[SVN_CL__MAX_OPTS];

} svn_cl__cmd_desc_t;



/* Our array of available subcommands.
 *
 * The entire list must be terminated with a entry of nulls.
 */
const svn_cl__cmd_desc_t svn_cl__cmd_table[] =
{
  { "add", svn_cl__add, {0},
    "Put files and directories under revision control, scheduling\n"
    "them for addition to repository.  They will be added in next commit.\n"
    "usage: svn add [OPTIONS] [TARGETS]\n",
    {svn_cl__targets_opt, svn_cl__recursive_opt} },

  { "checkout", svn_cl__checkout, {"co"},
    "Check out a working copy from a repository.\n"
    "usage: svn checkout REPOS_URL\n",
    {'d', 'r', 'D', 'q', 'n',
     svn_cl__auth_username_opt, svn_cl__auth_password_opt,
     svn_cl__xml_file_opt }  },

  { "cleanup", svn_cl__cleanup, {0},
    "Recursively clean up the working copy, removing locks, resuming\n"
    "unfinished operations, etc.\n"
    "usage: svn cleanup [TARGETS]\n",
    {0} },

  { "commit", svn_cl__commit, {"ci"},
    "Send changes from your working copy to the repository.\n"
    "usage: svn commit [TARGETS]\n\n"
    "   Be sure to use one of -m or -F to send a log message;\n"
    "   the -r switch is only for use with --xml-file.\n",
    {'m', 'F', 'q', svn_cl__targets_opt,
     svn_cl__force_opt, svn_cl__auth_username_opt, svn_cl__auth_password_opt,
     svn_cl__xml_file_opt, 'r'} },

  { "copy", svn_cl__copy, {"cp"},
    "Duplicate something in working copy or repos, remembering history.\n"
    "usage: svn copy SRC DST.\n\n"
    "  SRC and DST can each be either a working copy (WC) path or URL:\n"
    "    WC  -> WC:   copy and schedule for addition (with history)\n"
    "    WC  -> URL:  immediately commit a copy of WC to URL\n"
    "    URL -> WC:   check out URL into WC, schedule for addition\n"
    "    URL -> URL:  complete server-side copy;  used to branch & tag\n",
    {'m', 'F', 'r', svn_cl__auth_username_opt, svn_cl__auth_password_opt} },

  { "delete", svn_cl__delete, {"del", "remove", "rm"},
    "Remove files and directories from version control.\n"
    "usage: svn delete [TARGET | URL]\n\n"
    "    If run on a working-copy TARGET, item is scheduled for deletion\n"
    "    upon next commit.  (The working item itself will only be removed\n"
    "    if --force is passed.)  If run on URL, item is deleted from\n"
    "    repository via an immediate commit.\n",
    {svn_cl__force_opt, 'm', 'F', svn_cl__targets_opt,
     svn_cl__auth_username_opt, svn_cl__auth_password_opt} },

  { "diff", svn_cl__diff, {"di"},
    "Display local changes in the working copy, or changes between the\n"
    "working copy and the repository if a revision is given.\n"
    "usage: svn diff [-r REV1[:REV2]] [TARGETS]\n",
    {'r', 'D', 'x', 'n',
     svn_cl__auth_username_opt, svn_cl__auth_password_opt} },

  { "help", svn_cl__help, {"?", "h"},
    "Display this usage message.\n"
    "usage: svn help [SUBCOMMAND1 [SUBCOMMAND2] ...]\n",
    {svn_cl__version_opt} },
  /* We need to support "--help", "-?", and all that good stuff, of
     course.  But those options, since unknown, will result in the
     help message being printed out anyway, so there's no need to
     support them explicitly. */

  { "import", svn_cl__import, {0},
    "Commit an unversioned file or tree into the repository.\n"
    "usage: svn import REPOS_URL [PATH] [NEW_ENTRY_IN_REPOS]\n\n"
    "    Recursively commit a copy of PATH to REPOS_URL.\n"
    "    If no 3rd arg, copy top-level contents of PATH into REPOS_URL\n"
    "    directly.  Otherwise, create NEW_ENTRY underneath REPOS_URL and\n"
    "    begin copy there.  (-r is only needed if importing to --xml-file)\n",
    {'F', 'm', 'q', svn_cl__auth_username_opt, svn_cl__auth_password_opt,
     svn_cl__xml_file_opt, 'r'} },

  { "log", svn_cl__log, {0},
    "Show the log messages for a set of revision(s) and/or file(s).\n"
    "usage: svn log [URL] [PATH1 [PATH2] ...] \n"
    "    Either get the log messages for local PATHs or PATHs at the\n"
    "    URL. If URL is given by itself, then log messages are output for\n"
    "    that specific path. The -v option will include a list of affected\n"
    "    files for each log message. Examples are:\n"
    "\n"
    "    svn log\n"
    "\n"
    "    svn log foo.c\n"
    "\n"
    "    svn log http://www.example.com/repo/project/foo.c\n"
    "\n"
    "    svn log http://www.example.com/repo/project foo.c bar.c\n",
    {'r', 'D', 'v', svn_cl__targets_opt, svn_cl__auth_username_opt,
     svn_cl__auth_password_opt} },

  { "merge", svn_cl__merge, {0},
    "merge:  apply the differences between two paths to a working copy path.\n"
    "usage:  svn merge PATH1[@N] PATH2[@M] [WCPATH]\n\n"
    "  * PATH1 and PATH2 are either working-copy paths or URLs, specified at\n"
    "    revisions N and M.  These are the two sources to be compared.\n"
    "  * WCPATH is the working-copy path that will receive the changes.\n\n"
    "    - If either N or M are omitted, HEAD revision is assumed.\n"
    "    - If WCPATH is omitted, a value of '.' is assumed.\n"
    "    - If PATH1 and PATH2 are identical, an alternate syntax is allowed:\n"
    "            svn merge -rN:M PATH [WCPATH]\n",
    {'r', 'n', svn_cl__auth_username_opt, svn_cl__auth_password_opt} },

  { "mkdir", svn_cl__mkdir, {0},
    "Create a new directory under revision control.\n"
    "usage: mkdir [NEW_DIR | REPOS_URL].\n\n"
    "    Either create NEW_DIR in working copy scheduled for addition,\n"
    "    or create REPOS_URL via immediate commit.\n",
    {'m', 'F', svn_cl__auth_username_opt, svn_cl__auth_password_opt} },

  { "move", svn_cl__move, {"mv", "rename", "ren"},
    "Move/rename something in working copy or repository.\n"
    "usage: move SRC DST.\n\n"
    "  NOTE:  this command is equivalent to a 'copy' and 'delete'.\n\n"
    "  SRC and DST can both be working copy (WC) paths or URLs:\n"
    "    WC  -> WC:   move and schedule for addition (with history)\n"
    "    URL -> URL:  complete server-side rename.\n",
    {'m', 'F', 'r', svn_cl__auth_username_opt, svn_cl__auth_password_opt} },

  { "propdel", svn_cl__propdel, {"pdel"},
    "Remove property PROPNAME on files and directories.\n"
    "usage: propdel PROPNAME [TARGETS]\n",
    {'q', svn_cl__recursive_opt} },

  { "propedit", svn_cl__propedit, {"pedit", "pe"},
    "Edit property PROPNAME with $EDITOR on targets.\n"
    "usage: propedit PROPNAME [TARGETS]\n",
    {0} },

  { "propget", svn_cl__propget, {"pget", "pg"},
    "Print value of property PROPNAME on files or directories.\n"
    "usage: propget PROPNAME [TARGETS]\n",
    {svn_cl__recursive_opt} },

  { "proplist", svn_cl__proplist, {"plist", "pl"},
    "List all properties attached to files or directories.\n"
    "usage: proplist [TARGETS]\n",
    {'v', svn_cl__recursive_opt} },

  { "propset", svn_cl__propset, {"pset", "ps"},
    "Set property PROPNAME to PROPVAL on files or directories.\n"
    "usage: propset PROPNAME PROPVAL [TARGETS]\n\n"
    "    Use -F (instead of PROPVAL) to get the value from a file.\n",
    {'F', 'q', svn_cl__targets_opt, svn_cl__recursive_opt} },

  { "revert", svn_cl__revert, {0},
    "Restore pristine working copy file (undo all local edits)\n"
    "usage: revert TARGET1 [TARGET2 [TARGET3 ... ]]\n\n"
    "    Note:  this routine does not require network access, and \n"
    "    resolves any conflicted states.\n",
    {svn_cl__targets_opt, svn_cl__recursive_opt} },

  { "resolve", svn_cl__resolve, {0},
    "Remove 'conflicted' state on working copy files or directories.\n"
    "usage: resolve TARGET1 [TARGET2 [TARGET3 ... ]]\n\n"
    "    Note:  this routine does not semantically resolve conflict markers;\n"
    "    it merely removes conflict-related artifact files and allows TARGET\n"
    "    to be committed again.\n",
    {svn_cl__targets_opt} },

  { "status", svn_cl__status, {"stat", "st"},
    "Print the status of working copy files and directories.\n"
    "usage: svn status [TARGETS]\n\n"
    "   With no args, print only locally modified files (no network access).\n"
    "   With -u, add out-of-date information from server.\n"
    "   With -v, print excessive information on every file.\n\n"
    "Decoding --verbose output:\n"
    "Status| Out-of-date? | Local Rev | Last changed info |  Path\n"
    "    _                    965       938     kfogel      ./autogen.sh\n"
    "    _      *             965       970    sussman      ./build.conf\n"
    "    M                    965       687        joe      ./buildcheck.sh\n",
    { 'u', 'v', 'n', 'q',
      svn_cl__auth_username_opt, svn_cl__auth_password_opt } },

  { "switch", svn_cl__switch, {"sw"},
    "Update working copy to mirror a new URL\n"
    "usage: switch [TARGET] REPOS_URL\n\n" /* ### should args be reversed? */
    "   Note:  this is the way to move a working copy to a new branch.\n",
    {'r', 'n', svn_cl__force_opt} },

  { "update", svn_cl__update, {"up"},
    "Bring changes from the repository into the working copy.\n"
    "usage: update [TARGETS]\n\n"
    "  If no revision given, bring working copy up-to-date with HEAD rev.\n"
    "  Else synchronize working copy to revision given by -r or -D.\n",
    {'r', 'D', 'n', svn_cl__auth_username_opt,
     svn_cl__auth_password_opt, svn_cl__xml_file_opt} },

  { NULL, NULL, {0}, NULL, {0} }
};




/* Return the entry in svn_cl__cmd_table whose name matches CMD_NAME,
 * or NULL if none.  CMD_NAME may be an alias. */
static const svn_cl__cmd_desc_t *
svn_cl__get_canonical_command (const char *cmd_name)
{
  int i = 0;

  if (cmd_name == NULL)
    return NULL;

  while (svn_cl__cmd_table[i].name) {
    int j;
    if (strcmp (cmd_name, svn_cl__cmd_table[i].name) == 0)
      return svn_cl__cmd_table + i;
    for (j = 0;
         (j < SVN_CL__MAX_ALIASES) && svn_cl__cmd_table[i].aliases[j];
         j++)
      if (strcmp (cmd_name, svn_cl__cmd_table[i].aliases[j]) == 0)
        return svn_cl__cmd_table + i;

    i++;
  }

  /* If we get here, there was no matching command name or alias. */
  return NULL;
}





/*** 'help' processing ***/

/* Print an option OPT nicely into a STRING allocated in POOL.  If DOC
   is set, include generic documentation string of option.*/
static void
format_option (char **string,
               const apr_getopt_option_t *opt,
               svn_boolean_t doc,
               apr_pool_t *pool)
{
  char *opts;

  if (opt == NULL)
    {
      *string = apr_psprintf (pool, "?");
      return;
    }

  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_pstrcat (pool, opts, ":\t", opt->description, NULL);

  *string = opts;
}



const apr_getopt_option_t *
svn_cl__get_option_from_enum (int code,
                              const apr_getopt_option_t *option_table)
{
  int i;
  const apr_getopt_option_t *opt = NULL;

  for (i = 0; i < SVN_CL__MAX_OPTS; i++)
    {
      if (option_table[i].optch == code)
        {
          opt = &(option_table[i]);
          break;
        }
    }

  return opt;
}


/* Return TRUE iff subcommand COMMAND has OPTION_CODE listed within
   it.  Else return FALSE. */<commit_msg>Wow, it took a lot of people to come up with something simple like this ;)<commit_after>/*
 * main.c:  Subversion command line client.
 *
 * ====================================================================
 * Copyright (c) 2000-2002 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/.
 * ====================================================================
 */

/* ==================================================================== */




/*** Includes. ***/

#include <string.h>
#include <assert.h>
#include <locale.h>

#include <apr_strings.h>
#include <apr_tables.h>
#include <apr_general.h>
#include <apr_lib.h>

#include "svn_pools.h"
#include "svn_wc.h"
#include "svn_client.h"
#include "svn_config.h"
#include "svn_string.h"
#include "svn_path.h"
#include "svn_delta.h"
#include "svn_error.h"
#include "svn_io.h"
#include "svn_time.h"
#include "cl.h"



/*** Option Processing ***/

const apr_getopt_option_t svn_cl__options[] =
  {
    {"destination",   'd', 1, "put results in new directory ARG"},
    {"force",         svn_cl__force_opt, 0, "force operation to run"},
    {"help",          'h', 0, "show help on a subcommand"},
    {"message",       'm', 1, "specify commit message \"ARG\""},
    {"quiet",         'q', 0, "print as little as possible"},
    {"recursive",     svn_cl__recursive_opt, 0, "descend recursively"},
    {"nonrecursive",  'n', 0, "operate on single directory only"},
    {"revision",      'r', 1, "specify revision number ARG (or X:Y range)"},
    {"date",          'D', 1, "specify a date ARG (instead of a revision)"},
    {"file",          'F', 1, "read data from file ARG"},
    {"xml-file",      svn_cl__xml_file_opt, 1, "read/write xml to specified file ARG"},
    {"locale",        svn_cl__locale_opt, 1, "specify a locale ARG"},
    {"version",       svn_cl__version_opt, 0, "print client version info"},
    {"verbose",       'v', 0, "print extra information"},
    {"very-verbose",  'V', 0, "print maxmimum information"},
    {"show-updates",  'u', 0, "display update information"},
    /* Here begin authentication args, add more as needed: */
    {"username",      svn_cl__auth_username_opt, 1, "specify a username ARG"},
    {"password",      svn_cl__auth_password_opt, 1, "specify a password ARG"},
    {"extensions",    'x', 1, "pass \"ARG\" as bundled options to GNU diff"},
    {"targets",       svn_cl__targets_opt, 1, "pass contents of file \"ARG\" as additional args"},
    {0,               0, 0}
  };


/* The maximum number of options that can be accepted by a subcommand;
   this is simply the number of unique switches that exist in the
   table above.  */
#define SVN_CL__MAX_OPTS sizeof(svn_cl__options)/sizeof(svn_cl__options[0])




/*** Command dispatch. ***/

/* The maximum number of aliases a subcommand can have. */
#define SVN_CL__MAX_ALIASES 3


/* One element of the command dispatch table. */
typedef struct svn_cl__cmd_desc_t
{
  /* The full name of this command. */
  const char *name;

  /* The function this command invokes. */
  svn_cl__cmd_proc_t *cmd_func;

  /* A list of alias names for this command. */
  const char *aliases[SVN_CL__MAX_ALIASES];

  /* A brief string describing this command, for usage messages. */
  const char *help;

  /* A list of options accepted by this command.  Each value in the
     array is a unique enum (the 2nd field in apr_getopt_option_t) */
  int valid_options[SVN_CL__MAX_OPTS];

} svn_cl__cmd_desc_t;



/* Our array of available subcommands.
 *
 * The entire list must be terminated with a entry of nulls.
 */
const svn_cl__cmd_desc_t svn_cl__cmd_table[] =
{
  { "add", svn_cl__add, {0},
    "Put files and directories under revision control, scheduling\n"
    "them for addition to repository.  They will be added in next commit.\n"
    "usage: svn add [OPTIONS] [TARGETS]\n",
    {svn_cl__targets_opt, svn_cl__recursive_opt} },

  { "checkout", svn_cl__checkout, {"co"},
    "Check out a working copy from a repository.\n"
    "usage: svn checkout REPOS_URL\n",
    {'d', 'r', 'D', 'q', 'n',
     svn_cl__auth_username_opt, svn_cl__auth_password_opt,
     svn_cl__xml_file_opt }  },

  { "cleanup", svn_cl__cleanup, {0},
    "Recursively clean up the working copy, removing locks, resuming\n"
    "unfinished operations, etc.\n"
    "usage: svn cleanup [TARGETS]\n",
    {0} },

  { "commit", svn_cl__commit, {"ci"},
    "Send changes from your working copy to the repository.\n"
    "usage: svn commit [TARGETS]\n\n"
    "   Be sure to use one of -m or -F to send a log message;\n"
    "   the -r switch is only for use with --xml-file.\n",
    {'m', 'F', 'q', svn_cl__targets_opt,
     svn_cl__force_opt, svn_cl__auth_username_opt, svn_cl__auth_password_opt,
     svn_cl__xml_file_opt, 'r'} },

  { "copy", svn_cl__copy, {"cp"},
    "Duplicate something in working copy or repos, remembering history.\n"
    "usage: svn copy SRC DST.\n\n"
    "  SRC and DST can each be either a working copy (WC) path or URL:\n"
    "    WC  -> WC:   copy and schedule for addition (with history)\n"
    "    WC  -> URL:  immediately commit a copy of WC to URL\n"
    "    URL -> WC:   check out URL into WC, schedule for addition\n"
    "    URL -> URL:  complete server-side copy;  used to branch & tag\n",
    {'m', 'F', 'r', svn_cl__auth_username_opt, svn_cl__auth_password_opt} },

  { "delete", svn_cl__delete, {"del", "remove", "rm"},
    "Remove files and directories from version control.\n"
    "usage: svn delete [TARGET | URL]\n\n"
    "    If run on a working-copy TARGET, item is scheduled for deletion\n"
    "    upon next commit.  (The working item itself will only be removed\n"
    "    if --force is passed.)  If run on URL, item is deleted from\n"
    "    repository via an immediate commit.\n",
    {svn_cl__force_opt, 'm', 'F', svn_cl__targets_opt,
     svn_cl__auth_username_opt, svn_cl__auth_password_opt} },

  { "diff", svn_cl__diff, {"di"},
    "Display local changes in the working copy, or changes between the\n"
    "working copy and the repository if a revision is given.\n"
    "usage: svn diff [-r REV1[:REV2]] [TARGETS]\n",
    {'r', 'D', 'x', 'n',
     svn_cl__auth_username_opt, svn_cl__auth_password_opt} },

  { "help", svn_cl__help, {"?", "h"},
    "Display this usage message.\n"
    "usage: svn help [SUBCOMMAND1 [SUBCOMMAND2] ...]\n",
    {svn_cl__version_opt} },
  /* We need to support "--help", "-?", and all that good stuff, of
     course.  But those options, since unknown, will result in the
     help message being printed out anyway, so there's no need to
     support them explicitly. */

  { "import", svn_cl__import, {0},
    "Commit an unversioned file or tree into the repository.\n"
    "usage: svn import REPOS_URL [PATH] [NEW_ENTRY_IN_REPOS]\n\n"
    "    Recursively commit a copy of PATH to REPOS_URL.\n"
    "    If no 3rd arg, copy top-level contents of PATH into REPOS_URL\n"
    "    directly.  Otherwise, create NEW_ENTRY underneath REPOS_URL and\n"
    "    begin copy there.  (-r is only needed if importing to --xml-file)\n",
    {'F', 'm', 'q', svn_cl__auth_username_opt, svn_cl__auth_password_opt,
     svn_cl__xml_file_opt, 'r'} },

  { "log", svn_cl__log, {0},
    "Show the log messages for a set of revision(s) and/or file(s).\n"
    "usage: svn log [URL] [PATH1 [PATH2] ...] \n"
    "    Either get the log messages for local PATHs or PATHs at the\n"
    "    URL. If URL is given by itself, then log messages are output for\n"
    "    that specific path. The -v option will include a list of affected\n"
    "    files for each log message. Examples are:\n"
    "\n"
    "    svn log\n"
    "\n"
    "    svn log foo.c\n"
    "\n"
    "    svn log http://www.example.com/repo/project/foo.c\n"
    "\n"
    "    svn log http://www.example.com/repo/project foo.c bar.c\n",
    {'r', 'D', 'v', svn_cl__targets_opt, svn_cl__auth_username_opt,
     svn_cl__auth_password_opt} },

  { "merge", svn_cl__merge, {0},
    "merge:  apply the differences between two paths to a working copy path.\n"
    "usage:  svn merge PATH1[@N] PATH2[@M] [WCPATH]\n\n"
    "  * PATH1 and PATH2 are either working-copy paths or URLs, specified at\n"
    "    revisions N and M.  These are the two sources to be compared.\n"
    "  * WCPATH is the working-copy path that will receive the changes.\n\n"
    "    - If either N or M are omitted, HEAD revision is assumed.\n"
    "    - If WCPATH is omitted, a value of '.' is assumed.\n"
    "    - If PATH1 and PATH2 are identical, an alternate syntax is allowed:\n"
    "            svn merge -rN:M PATH [WCPATH]\n",
    {'r', 'n', svn_cl__auth_username_opt, svn_cl__auth_password_opt} },

  { "mkdir", svn_cl__mkdir, {0},
    "Create a new directory under revision control.\n"
    "usage: mkdir [NEW_DIR | REPOS_URL].\n\n"
    "    Either create NEW_DIR in working copy scheduled for addition,\n"
    "    or create REPOS_URL via immediate commit.\n",
    {'m', 'F', svn_cl__auth_username_opt, svn_cl__auth_password_opt} },

  { "move", svn_cl__move, {"mv", "rename", "ren"},
    "Move/rename something in working copy or repository.\n"
    "usage: move SRC DST.\n\n"
    "  NOTE:  this command is equivalent to a 'copy' and 'delete'.\n\n"
    "  SRC and DST can both be working copy (WC) paths or URLs:\n"
    "    WC  -> WC:   move and schedule for addition (with history)\n"
    "    URL -> URL:  complete server-side rename.\n",
    {'m', 'F', 'r', svn_cl__auth_username_opt, svn_cl__auth_password_opt} },

  { "propdel", svn_cl__propdel, {"pdel"},
    "Remove property PROPNAME on files and directories.\n"
    "usage: propdel PROPNAME [TARGETS]\n",
    {'q', svn_cl__recursive_opt} },

  { "propedit", svn_cl__propedit, {"pedit", "pe"},
    "Edit property PROPNAME with $EDITOR on targets.\n"
    "usage: propedit PROPNAME [TARGETS]\n",
    {0} },

  { "propget", svn_cl__propget, {"pget", "pg"},
    "Print value of property PROPNAME on files or directories.\n"
    "usage: propget PROPNAME [TARGETS]\n",
    {svn_cl__recursive_opt} },

  { "proplist", svn_cl__proplist, {"plist", "pl"},
    "List all properties attached to files or directories.\n"
    "usage: proplist [TARGETS]\n",
    {'v', svn_cl__recursive_opt} },

  { "propset", svn_cl__propset, {"pset", "ps"},
    "Set property PROPNAME to PROPVAL on files or directories.\n"
    "usage: propset PROPNAME PROPVAL [TARGETS]\n\n"
    "    Use -F (instead of PROPVAL) to get the value from a file.\n",
    {'F', 'q', svn_cl__targets_opt, svn_cl__recursive_opt} },

  { "revert", svn_cl__revert, {0},
    "Restore pristine working copy file (undo all local edits)\n"
    "usage: revert TARGET1 [TARGET2 [TARGET3 ... ]]\n\n"
    "    Note:  this routine does not require network access, and \n"
    "    resolves any conflicted states.\n",
    {svn_cl__targets_opt, svn_cl__recursive_opt} },

  { "resolve", svn_cl__resolve, {0},
    "Remove 'conflicted' state on working copy files or directories.\n"
    "usage: resolve TARGET1 [TARGET2 [TARGET3 ... ]]\n\n"
    "    Note:  this routine does not semantically resolve conflict markers;\n"
    "    it merely removes conflict-related artifact files and allows TARGET\n"
    "    to be committed again.\n",
    {svn_cl__targets_opt} },

  { "status", svn_cl__status, {"stat", "st"},
    "Print the status of working copy files and directories.\n"
    "usage: svn status [TARGETS]\n\n"
    "   With no args, print only locally modified files (no network access).\n"
    "   With -u, add out-of-date information from server.\n"
    "   With -v, print excessive information on every file.\n\n"
    "Decoding --verbose output:\n"
    "Status| Out-of-date? | Local Rev | Last changed info |  Path\n"
    "    _                    965       938     kfogel      ./autogen.sh\n"
    "    _      *             965       970    sussman      ./build.conf\n"
    "    M                    965       687        joe      ./buildcheck.sh\n",
    { 'u', 'v', 'n', 'q',
      svn_cl__auth_username_opt, svn_cl__auth_password_opt } },

  { "switch", svn_cl__switch, {"sw"},
    "Update working copy to mirror a new URL\n"
    "usage: switch [TARGET] REPOS_URL\n\n" /* ### should args be reversed? */
    "   Note:  this is the way to move a working copy to a new branch.\n",
    {'r', 'n', svn_cl__force_opt} },

  { "update", svn_cl__update, {"up"},
    "Bring changes from the repository into the working copy.\n"
    "usage: update [TARGETS]\n\n"
    "  If no revision given, bring working copy up-to-date with HEAD rev.\n"
    "  Else synchronize working copy to revision given by -r or -D.\n",
    {'r', 'D', 'n', svn_cl__auth_username_opt,
     svn_cl__auth_password_opt, svn_cl__xml_file_opt} },

  { NULL, NULL, {0}, NULL, {0} }
};




/* Return the entry in svn_cl__cmd_table whose name matches CMD_NAME,
 * or NULL if none.  CMD_NAME may be an alias. */
static const svn_cl__cmd_desc_t *
svn_cl__get_canonical_command (const char *cmd_name)
{
  int i = 0;

  if (cmd_name == NULL)
    return NULL;

  while (svn_cl__cmd_table[i].name) {
    int j;
    if (strcmp (cmd_name, svn_cl__cmd_table[i].name) == 0)
      return svn_cl__cmd_table + i;
    for (j = 0;
         (j < SVN_CL__MAX_ALIASES) && svn_cl__cmd_table[i].aliases[j];
         j++)
      if (strcmp (cmd_name, svn_cl__cmd_table[i].aliases[j]) == 0)
        return svn_cl__cmd_table + i;

    i++;
  }

  /* If we get here, there was no matching command name or alias. */
  return NULL;
}





/*** 'help' processing ***/

/* Print an option OPT nicely into a STRING allocated in POOL.  If DOC
   is set, include generic documentation string of option.*/
static void
format_option (char **string,
               const apr_getopt_option_t *opt,
               svn_boolean_t doc,
               apr_pool_t *pool)
{
  char *opts;

  if (opt == NULL)
    {
      *string = apr_psprintf (pool, "?");
      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, opt->description);

  *string = opts;
}



const apr_getopt_option_t *
svn_cl__get_option_from_enum (int code,
                              const apr_getopt_option_t *option_table)
{
  int i;
  const apr_getopt_option_t *opt = NULL;

  for (i = 0; i < SVN_CL__MAX_OPTS; i++)
    {
      if (option_table[i].optch == code)
        {
          opt = &(option_table[i]);
          break;
        }
    }

  return opt;
}


/* Return TRUE iff subcommand COMMAND has OPTION_CODE listed within
   it.  Else return FALSE. */
{'fraction_non_alphanumeric': 0.14307417927207874, 'fraction_numerical': 0.006143074179272079, 'mean_word_length': 2.979366539624129, 'pattern_counts': {'":': 1, '<': 23, '<?xml version=': 0, '>': 41, 'https://': 0, 'lorem ipsum': 0, 'www.': 4, 'xml': 18}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 6, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '1765259', 'n_tokens_mistral': 10746, 'n_tokens_neox': 10328, 'n_words': 3302}