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

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




/*** Includes. ***/

#include <string.h>

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

#include "svn_wc.h"
#include "svn_client.h"
#include "svn_string.h"
#include "svn_path.h"
#include "svn_delta.h"
#include "svn_error.h"
#include "cl.h"



/*** Command dispatch. ***/

/* Map names to command routine, etc. 
 *
 * Canonical name entries must come immediately before their aliases.
 * For example, "add" must be the first of the add commands listed,
 * followed immediately by its aliases "ad" and "new".
 *
 * Alias entries should have null or 0 for every field except `name'
 * and `is_alias'.  The canonical entry will be used for everything
 * else.
 *
 * The entire list must be terminated with a entry of nulls.
 */
static const svn_cl__cmd_desc_t cmd_table[] = 
{
  { "add",        FALSE,  svn_cl__add_command,      svn_cl__add,
    "Add new files and directories to version control.\n"
    "usage: add [TARGETS]\n" },
  { "ad",         TRUE, 0, NULL, NULL },
  { "new",        TRUE, 0, NULL, NULL },

  { "checkout",   FALSE,  svn_cl__checkout_command, svn_cl__checkout,
    "Check out a working directory from a repository.\n"
    "usage: checkout REPOSPATH\n" },
  { "co",         TRUE, 0, NULL, NULL },

  { "commit",     FALSE,  svn_cl__commit_command,   svn_cl__commit,
    "Commit changes from your working copy to the repository.\n"
    "usage: commit [TARGETS]\n" },
  { "ci",         TRUE, 0, NULL, NULL },

  { "delete",     FALSE,  svn_cl__delete_command,   svn_cl__delete,
    "Remove files and directories from version control.\n"
    "usage: delete [TARGETS]\n" },
  { "del",        TRUE, 0, NULL, NULL },
  { "remove",     TRUE, 0, NULL, NULL },
  { "rm",         TRUE, 0, NULL, NULL },

  { "help",       FALSE,  svn_cl__help_command,   svn_cl__help,
    "Display this usage message.\n"
    "usage: help [SUBCOMMAND1 [SUBCOMMAND2] ...]\n" },
  { "?",          TRUE, 0, NULL, NULL },
  { "h",          TRUE, 0, NULL, NULL },
  /* 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. */

  { "proplist",   FALSE,  svn_cl__proplist_command, svn_cl__proplist,
    "List all properties for given files and directories.\n"
    "usage: proplist [TARGETS]\n" },
  { "plist",      TRUE, 0, NULL, NULL },
  { "pl",         TRUE, 0, NULL, NULL },

  { "propget",    FALSE,  svn_cl__propget_command,  svn_cl__propget,
    "Get the value of property PROPNAME on files and directories.\n"
    "usage: propget PROPNAME [TARGETS]\n" },
  { "pget",       TRUE,   svn_cl__propget_command,  svn_cl__propget, NULL },
  { "pg",         TRUE,   svn_cl__propget_command,  svn_cl__propget, NULL },

  { "propset",    FALSE,  svn_cl__propset_command,  svn_cl__propset,
    "Set property PROPNAME to PROPVAL on the named files and directories.\n"
    "usage: propset PROPNAME [PROPVAL | --valfile VALFILE] "
    "[TARGET1 [TARGET2] ...]\n"},
  { "pset",       TRUE, 0, NULL, NULL },
  { "ps",         TRUE, 0, NULL, NULL },

  { "status",     FALSE,  svn_cl__status_command,   svn_cl__status,
    "Print the status of working copy files and directories.\n"
    "usage: status [TARGETS]\n" },
  { "stat",       TRUE, 0, NULL, NULL },
  { "st",         TRUE, 0, NULL, NULL },

  { "diff",     FALSE,  svn_cl__diff_command,   svn_cl__diff,
    "Display local file changes as contextual diffs.\n"
    "usage: diff [TARGETS]\n" },
  { "df",         TRUE, 0, NULL, NULL },

  { "update",     FALSE,  svn_cl__update_command,   svn_cl__update,
    "Bring changes from the repository into the working copy.\n"
    "usage: update [TARGETS]\n" },
  { "up",         TRUE, 0, NULL, NULL },
  { NULL,         FALSE,  0, NULL, NULL }
};


/* Return the entry in cmd_table whose name matches CMD_NAME, or null
 * if none.  CMD_NAME may be an alias, in which case the alias entry
 * will be returned (so caller may need to canonicalize result).
 */
static const svn_cl__cmd_desc_t *
get_cmd_table_entry (const char *cmd_name)
{
  int max = (sizeof (cmd_table) / sizeof (cmd_table[0])) - 1;
  int i;

  if (cmd_name == NULL)
    return NULL;

  for (i = 0; i < max; i++)
    if (strcmp (cmd_name, cmd_table[i].name) == 0)
      return cmd_table + i;

  /* Else command not found. */
  return NULL;
}


/* Return the canonical command table entry for CMD (which may be the
 * entry for CMD itself, or some other entry if CMD is an alias).
 * If CMD is not found, return null.
 */
static const svn_cl__cmd_desc_t *
get_canonical_command (const char *cmd)
{
  const svn_cl__cmd_desc_t *cmd_desc = get_cmd_table_entry (cmd);

  if (cmd_desc == NULL)
    return NULL;

  while (cmd_desc->is_alias)
    cmd_desc--;

  return cmd_desc;
}




/*** Help. ***/

/* Print the canonical command name for CMD, all its aliases,
   and if HELP is set, print the help string for the command too. */
static void
print_command_info (const svn_cl__cmd_desc_t *cmd_desc,
                    svn_boolean_t help, 
                    apr_pool_t *pool)
{
  const svn_cl__cmd_desc_t *this_cmd = get_canonical_command (cmd_desc->name);
  const svn_cl__cmd_desc_t *canonical_cmd = this_cmd;
  svn_boolean_t first_time;

  /* Print the canonical command name. */
  fputs (canonical_cmd->name, stdout);

  /* Print the list of aliases. */
  first_time = TRUE;
  for (this_cmd++; (this_cmd->name && this_cmd->is_alias); this_cmd++)
    {
      if (first_time) {
        printf (" (");
        first_time = FALSE;
      }
      else
        printf (", ");

      printf ("%s", this_cmd->name);
    }
  if (! first_time)
    printf (")");

  if (help)
    printf (": %s\n", canonical_cmd->help);
}


/* Print a generic (non-command-specific) usage message. */
static void
print_generic_help (apr_pool_t *pool)
{
  size_t max = (sizeof (cmd_table) / sizeof (cmd_table[0])) - 1;
  static const char usage[] =
    "usage: svn <subcommand> [options] [args]\n"
    "Type \"svn help <subcommand>\" for help on a specific subcommand.\n"
    "\n"
    "Most subcommands take file and/or directory arguments, recursing\n"
    "on the directories.  If no arguments are supplied to such a\n"
    "command, it will recurse on the current directory (inclusive) by\n" 
    "default.\n"
    "\n"
    "Available subcommands:\n";
  int i;

  printf ("%s", usage);
  for (i = 0; i < max; i++)
    if (! cmd_table[i].is_alias)
      {
        printf ("   ");
        print_command_info (cmd_table + i, FALSE, pool);
        printf ("\n");
      }
}


/* Print either generic help, or command-specific help for each
 * command in ARGV.  OPT_STATE is unused and may be null.
 * 
 * Unlike all the other command routines, ``help'' has its own
 * option processing.  Of course, it does not accept any options :-),
 * just command line args.
 */
svn_error_t *
svn_cl__help (svn_cl__opt_state_t *opt_state,
              apr_array_header_t *targets,
              apr_pool_t *pool)
{
  int i;

  if (targets->nelts)
    for (i = 0; i < targets->nelts; i++)
      {
        svn_string_t *this = (((svn_string_t **) (targets)->elts))[i];
        const svn_cl__cmd_desc_t *cmd = get_canonical_command (this->data);
        if (cmd)
          print_command_info (cmd, TRUE, pool);
        else
          fprintf (stderr, "\"%s\": unknown command.\n\n", this->data);
      }
  else
    print_generic_help (pool);

  return SVN_NO_ERROR;
}




/* Read the contents of FILENAME into *RESULT. */
static svn_error_t *
read_from_file (svn_string_t **result, const char *filename, apr_pool_t *pool)
{
  /* Right now, there are two places in Subversion where we'd need to
     read a value from a file: when setting a property, and for log
     messages (like "cvs commit -f<filename>").  Since properties are
     implemented using prop-sized memory chunks anyway, it's no loss
     to just read the file into a string.  Someday, we may streamify
     properties, at which point it would be desirable to let the
     callee read streamily from the file. */

  svn_string_t *res;
  apr_status_t apr_err;
  char buf[BUFSIZ];
  apr_size_t len;
  apr_file_t *f = NULL;

  res = svn_string_create ("", pool);

  apr_err = apr_open (&f, filename, APR_READ, APR_OS_DEFAULT, pool);
  if (apr_err)<commit_msg>Add a comment about problems in read_from_file.<commit_after>/*
 * main.c:  Subversion command line client.
 *
 * ====================================================================
 * Copyright (c) 2000 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.
 * ====================================================================
 */

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




/*** Includes. ***/

#include <string.h>

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

#include "svn_wc.h"
#include "svn_client.h"
#include "svn_string.h"
#include "svn_path.h"
#include "svn_delta.h"
#include "svn_error.h"
#include "cl.h"



/*** Command dispatch. ***/

/* Map names to command routine, etc. 
 *
 * Canonical name entries must come immediately before their aliases.
 * For example, "add" must be the first of the add commands listed,
 * followed immediately by its aliases "ad" and "new".
 *
 * Alias entries should have null or 0 for every field except `name'
 * and `is_alias'.  The canonical entry will be used for everything
 * else.
 *
 * The entire list must be terminated with a entry of nulls.
 */
static const svn_cl__cmd_desc_t cmd_table[] = 
{
  { "add",        FALSE,  svn_cl__add_command,      svn_cl__add,
    "Add new files and directories to version control.\n"
    "usage: add [TARGETS]\n" },
  { "ad",         TRUE, 0, NULL, NULL },
  { "new",        TRUE, 0, NULL, NULL },

  { "checkout",   FALSE,  svn_cl__checkout_command, svn_cl__checkout,
    "Check out a working directory from a repository.\n"
    "usage: checkout REPOSPATH\n" },
  { "co",         TRUE, 0, NULL, NULL },

  { "commit",     FALSE,  svn_cl__commit_command,   svn_cl__commit,
    "Commit changes from your working copy to the repository.\n"
    "usage: commit [TARGETS]\n" },
  { "ci",         TRUE, 0, NULL, NULL },

  { "delete",     FALSE,  svn_cl__delete_command,   svn_cl__delete,
    "Remove files and directories from version control.\n"
    "usage: delete [TARGETS]\n" },
  { "del",        TRUE, 0, NULL, NULL },
  { "remove",     TRUE, 0, NULL, NULL },
  { "rm",         TRUE, 0, NULL, NULL },

  { "help",       FALSE,  svn_cl__help_command,   svn_cl__help,
    "Display this usage message.\n"
    "usage: help [SUBCOMMAND1 [SUBCOMMAND2] ...]\n" },
  { "?",          TRUE, 0, NULL, NULL },
  { "h",          TRUE, 0, NULL, NULL },
  /* 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. */

  { "proplist",   FALSE,  svn_cl__proplist_command, svn_cl__proplist,
    "List all properties for given files and directories.\n"
    "usage: proplist [TARGETS]\n" },
  { "plist",      TRUE, 0, NULL, NULL },
  { "pl",         TRUE, 0, NULL, NULL },

  { "propget",    FALSE,  svn_cl__propget_command,  svn_cl__propget,
    "Get the value of property PROPNAME on files and directories.\n"
    "usage: propget PROPNAME [TARGETS]\n" },
  { "pget",       TRUE,   svn_cl__propget_command,  svn_cl__propget, NULL },
  { "pg",         TRUE,   svn_cl__propget_command,  svn_cl__propget, NULL },

  { "propset",    FALSE,  svn_cl__propset_command,  svn_cl__propset,
    "Set property PROPNAME to PROPVAL on the named files and directories.\n"
    "usage: propset PROPNAME [PROPVAL | --valfile VALFILE] "
    "[TARGET1 [TARGET2] ...]\n"},
  { "pset",       TRUE, 0, NULL, NULL },
  { "ps",         TRUE, 0, NULL, NULL },

  { "status",     FALSE,  svn_cl__status_command,   svn_cl__status,
    "Print the status of working copy files and directories.\n"
    "usage: status [TARGETS]\n" },
  { "stat",       TRUE, 0, NULL, NULL },
  { "st",         TRUE, 0, NULL, NULL },

  { "diff",     FALSE,  svn_cl__diff_command,   svn_cl__diff,
    "Display local file changes as contextual diffs.\n"
    "usage: diff [TARGETS]\n" },
  { "df",         TRUE, 0, NULL, NULL },

  { "update",     FALSE,  svn_cl__update_command,   svn_cl__update,
    "Bring changes from the repository into the working copy.\n"
    "usage: update [TARGETS]\n" },
  { "up",         TRUE, 0, NULL, NULL },
  { NULL,         FALSE,  0, NULL, NULL }
};


/* Return the entry in cmd_table whose name matches CMD_NAME, or null
 * if none.  CMD_NAME may be an alias, in which case the alias entry
 * will be returned (so caller may need to canonicalize result).
 */
static const svn_cl__cmd_desc_t *
get_cmd_table_entry (const char *cmd_name)
{
  int max = (sizeof (cmd_table) / sizeof (cmd_table[0])) - 1;
  int i;

  if (cmd_name == NULL)
    return NULL;

  for (i = 0; i < max; i++)
    if (strcmp (cmd_name, cmd_table[i].name) == 0)
      return cmd_table + i;

  /* Else command not found. */
  return NULL;
}


/* Return the canonical command table entry for CMD (which may be the
 * entry for CMD itself, or some other entry if CMD is an alias).
 * If CMD is not found, return null.
 */
static const svn_cl__cmd_desc_t *
get_canonical_command (const char *cmd)
{
  const svn_cl__cmd_desc_t *cmd_desc = get_cmd_table_entry (cmd);

  if (cmd_desc == NULL)
    return NULL;

  while (cmd_desc->is_alias)
    cmd_desc--;

  return cmd_desc;
}




/*** Help. ***/

/* Print the canonical command name for CMD, all its aliases,
   and if HELP is set, print the help string for the command too. */
static void
print_command_info (const svn_cl__cmd_desc_t *cmd_desc,
                    svn_boolean_t help, 
                    apr_pool_t *pool)
{
  const svn_cl__cmd_desc_t *this_cmd = get_canonical_command (cmd_desc->name);
  const svn_cl__cmd_desc_t *canonical_cmd = this_cmd;
  svn_boolean_t first_time;

  /* Print the canonical command name. */
  fputs (canonical_cmd->name, stdout);

  /* Print the list of aliases. */
  first_time = TRUE;
  for (this_cmd++; (this_cmd->name && this_cmd->is_alias); this_cmd++)
    {
      if (first_time) {
        printf (" (");
        first_time = FALSE;
      }
      else
        printf (", ");

      printf ("%s", this_cmd->name);
    }
  if (! first_time)
    printf (")");

  if (help)
    printf (": %s\n", canonical_cmd->help);
}


/* Print a generic (non-command-specific) usage message. */
static void
print_generic_help (apr_pool_t *pool)
{
  size_t max = (sizeof (cmd_table) / sizeof (cmd_table[0])) - 1;
  static const char usage[] =
    "usage: svn <subcommand> [options] [args]\n"
    "Type \"svn help <subcommand>\" for help on a specific subcommand.\n"
    "\n"
    "Most subcommands take file and/or directory arguments, recursing\n"
    "on the directories.  If no arguments are supplied to such a\n"
    "command, it will recurse on the current directory (inclusive) by\n" 
    "default.\n"
    "\n"
    "Available subcommands:\n";
  int i;

  printf ("%s", usage);
  for (i = 0; i < max; i++)
    if (! cmd_table[i].is_alias)
      {
        printf ("   ");
        print_command_info (cmd_table + i, FALSE, pool);
        printf ("\n");
      }
}


/* Print either generic help, or command-specific help for each
 * command in ARGV.  OPT_STATE is unused and may be null.
 * 
 * Unlike all the other command routines, ``help'' has its own
 * option processing.  Of course, it does not accept any options :-),
 * just command line args.
 */
svn_error_t *
svn_cl__help (svn_cl__opt_state_t *opt_state,
              apr_array_header_t *targets,
              apr_pool_t *pool)
{
  int i;

  if (targets->nelts)
    for (i = 0; i < targets->nelts; i++)
      {
        svn_string_t *this = (((svn_string_t **) (targets)->elts))[i];
        const svn_cl__cmd_desc_t *cmd = get_canonical_command (this->data);
        if (cmd)
          print_command_info (cmd, TRUE, pool);
        else
          fprintf (stderr, "\"%s\": unknown command.\n\n", this->data);
      }
  else
    print_generic_help (pool);

  return SVN_NO_ERROR;
}




/* Read the contents of FILENAME into *RESULT. */
static svn_error_t *
read_from_file (svn_string_t **result, const char *filename, apr_pool_t *pool)
{
  /* Right now, there are two places in Subversion where we'd need to
     read a value from a file: when setting a property, and for log
     messages (like "cvs commit -f<filename>").  Since properties are
     implemented using prop-sized memory chunks anyway, it's no loss
     to just read the file into a string.  Someday, we may streamify
     properties, at which point it would be desirable to let the
     callee read streamily from the file. */

  /* ### this function must be fixed to do an apr_stat() for SIZE,
     ### alloc the buffer, then read the file into the buffer. Using
     ### an svn_string_t means quadratic memory usage: start with
     ### BUFSIZE, allocate 2*BUFSIZE, then alloc 4*BUFSIZE, etc. */

  svn_string_t *res;
  apr_status_t apr_err;
  char buf[BUFSIZ];
  apr_size_t len;
  apr_file_t *f = NULL;

  res = svn_string_create ("", pool);

  apr_err = apr_open (&f, filename, APR_READ, APR_OS_DEFAULT, pool);
  if (apr_err)
{'fraction_non_alphanumeric': 0.14193724420190995, 'fraction_numerical': 0.004038199181446112, 'mean_word_length': 2.977859778597786, 'pattern_counts': {'":': 4, '<': 25, '<?xml version=': 0, '>': 43, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '6685532', 'n_tokens_mistral': 6279, 'n_tokens_neox': 6034, 'n_words': 1986}