⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 diff.c

📁 linux subdivision ying gai ke yi le ba
💻 C
📖 第 1 页 / 共 5 页
字号:
/*
 * diff.c: comparing and merging
 *
 * ====================================================================
 * 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/.
 * ====================================================================
 */

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



/*** Includes. ***/

#include <apr_strings.h>
#include <apr_pools.h>
#include <apr_hash.h>
#include "svn_wc.h"
#include "svn_delta.h"
#include "svn_diff.h"
#include "svn_client.h"
#include "svn_string.h"
#include "svn_error.h"
#include "svn_path.h"
#include "svn_test.h"
#include "svn_io.h"
#include "svn_utf.h"
#include "svn_pools.h"
#include "svn_config.h"
#include "client.h"
#include <assert.h>

#include "svn_private_config.h"

/*
 * Constant separator strings
 */
static const char equal_string[] = 
  "===================================================================";
static const char under_string[] =
  "___________________________________________________________________";


/*-----------------------------------------------------------------*/

/* Utilities */

/* Wrapper for @c apr_file_printf(), which see.  @a format is a utf8-encoded
   string after it is formatted, so this function can convert it to
   native encoding before printing. */
static svn_error_t *
file_printf_from_utf8 (apr_file_t *fptr, const char *format, ...)
{
  va_list ap;
  const char *buf, *buf_apr;

  va_start (ap, format);
  buf = apr_pvsprintf (apr_file_pool_get (fptr), format, ap); 
  va_end(ap);

  SVN_ERR (svn_path_cstring_from_utf8 (&buf_apr, buf,
                                       apr_file_pool_get (fptr)));

  return svn_io_file_write_full (fptr, buf_apr, strlen (buf_apr), 
                                 NULL, apr_file_pool_get (fptr));
}


/* A helper func that writes out verbal descriptions of property diffs
   to FILE.   Of course, the apr_file_t will probably be the 'outfile'
   passed to svn_client_diff, which is probably stdout. */
static svn_error_t *
display_prop_diffs (const apr_array_header_t *propchanges,
                    apr_hash_t *original_props,
                    const char *path,
                    apr_file_t *file,
                    apr_pool_t *pool)
{
  int i;

  SVN_ERR (file_printf_from_utf8 (file,
                                  _("%sProperty changes on: %s%s"),
                                  APR_EOL_STR, path, APR_EOL_STR));

  /* ### todo [issue #1533]: Use file_printf_from_utf8() to convert this
     line of dashes to native encoding, at least conditionally?  Or is
     it better to have under_string always output the same, so
     programs can find it?  Also, what about checking for error? */
  apr_file_printf (file, "%s" APR_EOL_STR, under_string);

  for (i = 0; i < propchanges->nelts; i++)
    {
      const svn_prop_t *propchange
        = &APR_ARRAY_IDX(propchanges, i, svn_prop_t);

      const svn_string_t *original_value;

      if (original_props)
        original_value = apr_hash_get (original_props, 
                                       propchange->name, APR_HASH_KEY_STRING);
      else
        original_value = NULL;
      
      SVN_ERR (file_printf_from_utf8 (file, _("Name: %s%s"),
                                      propchange->name, APR_EOL_STR));

      /* For now, we have a rather simple heuristic: if this is an
         "svn:" property, then assume the value is UTF-8 and must
         therefore be converted before printing.  Otherwise, just
         print whatever's there and hope for the best. */
      {
        svn_boolean_t val_is_utf8 = svn_prop_is_svn_prop (propchange->name);
        
        if (original_value != NULL)
          {
            if (val_is_utf8)
              {
                SVN_ERR (file_printf_from_utf8
                         (file, "   - %s" APR_EOL_STR, original_value->data));
              }
            else
              {
                /* ### todo: check for error? */
                apr_file_printf
                  (file, "   - %s" APR_EOL_STR, original_value->data);
              }
          }
        
        if (propchange->value != NULL)
          {
            if (val_is_utf8)
              {
                SVN_ERR (file_printf_from_utf8
                         (file, "   + %s" APR_EOL_STR,
                          propchange->value->data));
              }
            else
              {
                /* ### todo: check for error? */
                apr_file_printf (file, "   + %s" APR_EOL_STR,
                                 propchange->value->data);
              }
          }
      }
    }

  /* ### todo [issue #1533]: Use file_printf_from_utf8() to convert this
     to native encoding, at least conditionally?  Or is it better to
     have under_string always output the same eol, so programs can
     find it consistently?  Also, what about checking for error? */
  apr_file_printf (file, APR_EOL_STR);

  return SVN_NO_ERROR;
}


/* Return SVN_ERR_UNSUPPORTED_FEATURE if @a url's schema does not
   match the schema of the url for @a adm_access's path; return
   SVN_ERR_BAD_URL if no schema can be found for one or both urls;
   otherwise return SVN_NO_ERROR.  Use @a adm_access's pool for
   temporary allocation. */
static svn_error_t *
check_schema_match (svn_wc_adm_access_t *adm_access, const char *url)
{
  const char *path = svn_wc_adm_access_path (adm_access);
  apr_pool_t *pool = svn_wc_adm_access_pool (adm_access);
  const svn_wc_entry_t *ent;
  const char *idx1, *idx2;
  
  SVN_ERR (svn_wc_entry (&ent, path, adm_access, TRUE, pool));
  
  idx1 = strchr (url, ':');
  idx2 = strchr (ent->url, ':');

  if ((idx1 == NULL) && (idx2 == NULL))
    {
      return svn_error_createf
        (SVN_ERR_BAD_URL, NULL,
         _("URLs have no schema ('%s' and '%s')"), url, ent->url);
    }
  else if (idx1 == NULL)
    {
      return svn_error_createf
        (SVN_ERR_BAD_URL, NULL,
         _("URL has no schema: '%s'"), url);
    }
  else if (idx2 == NULL)
    {
      return svn_error_createf
        (SVN_ERR_BAD_URL, NULL,
         _("URL has no schema: '%s'"), ent->url);
    }
  else if (((idx1 - url) != (idx2 - ent->url))
           || (strncmp (url, ent->url, idx1 - url) != 0))
    {
      return svn_error_createf
        (SVN_ERR_UNSUPPORTED_FEATURE, NULL,
         _("Access schema mixtures not yet supported ('%s' and '%s')"),
	 url, ent->url);
    }

  /* else */

  return SVN_NO_ERROR;
}


/*-----------------------------------------------------------------*/

/*** Callbacks for 'svn diff', invoked by the repos-diff editor. ***/


struct diff_cmd_baton {
  const apr_array_header_t *options;
  apr_pool_t *pool;
  apr_file_t *outfile;
  apr_file_t *errfile;

  /* The original targets passed to the diff command.  We may need
     these to construct distinctive diff labels when comparing the
     same relative path in the same revision, under different anchors
     (for example, when comparing a trunk against a branch). */
  const char *orig_path_1;
  const char *orig_path_2;

  /* These are the numeric representations of the revisions passed to
     svn_client_diff, either may be SVN_INVALID_REVNUM.  We need these
     because some of the svn_wc_diff_callbacks_t don't get revision
     arguments.

     ### Perhaps we should change the callback signatures and eliminate
     ### these?
  */
  svn_revnum_t revnum1;
  svn_revnum_t revnum2;

  /* Client config hash (may be NULL). */
  apr_hash_t *config;

  /* Set this flag if you want diff_file_changed to output diffs
     unconditionally, even if the diffs are empty. */
  svn_boolean_t force_diff_output;

};


/* Generate a label for the diff output for file PATH at revision REVNUM.
   If REVNUM is invalid then it is assumed to be the current working
   copy. */
static const char *
diff_label (const char *path,
            svn_revnum_t revnum,
            apr_pool_t *pool)
{
  const char *label;
  if (revnum != SVN_INVALID_REVNUM)
    label = apr_psprintf (pool, _("%s\t(revision %ld)"),
                          path, revnum);
  else
    label = apr_psprintf (pool, _("%s\t(working copy)"), path);

  return label;
}

/* The main workhorse, which invokes an external 'diff' program on the
   two temporary files.   The path is the "true" label to use in the
   diff output. */
static svn_error_t *
diff_file_changed (svn_wc_adm_access_t *adm_access,
                   svn_wc_notify_state_t *state,
                   const char *path,
                   const char *tmpfile1,
                   const char *tmpfile2,
                   svn_revnum_t rev1,
                   svn_revnum_t rev2,
                   const char *mimetype1,
                   const char *mimetype2,
                   void *diff_baton)
{
  struct diff_cmd_baton *diff_cmd_baton = diff_baton;
  const char *diff_cmd = NULL;
  const char **args = NULL;
  int nargs, exitcode;
  apr_pool_t *subpool = svn_pool_create (diff_cmd_baton->pool);
  svn_stream_t *os;
  apr_file_t *errfile = diff_cmd_baton->errfile;
  const char *label1, *label2;
  svn_boolean_t mt1_binary = FALSE, mt2_binary = FALSE;
  const char *path1, *path2;
  int i;

  /* Get a stream from our output file. */
  os = svn_stream_from_aprfile(diff_cmd_baton->outfile, subpool); 

  /* Assemble any option args. */
  nargs = diff_cmd_baton->options->nelts;
  if (nargs)
    {
      args = apr_palloc (subpool, nargs * sizeof (char *));
      for (i = 0; i < diff_cmd_baton->options->nelts; i++)
        {
          args[i] = 
            ((const char **)(diff_cmd_baton->options->elts))[i];
        }
      assert (i == nargs);
    }

  /* Generate the diff headers. */

  /* ### Holy cow.  Due to anchor/target weirdness, we can't
     simply join diff_cmd_baton->orig_path_1 with path, ditto for
     orig_path_2.  That will work when they're directory URLs, but
     not for file URLs.  Nor can we just use anchor1 and anchor2
     from do_diff(), at least not without some more logic here.
     What a nightmare.
     
     For now, to distinguish the two paths, we'll just put the
     unique portions of the original targets in parentheses before
     the received path, with ellipses for handwaving.  This makes
     the labels a bit clumsy, but at least distinctive.  Better
     solutions are possible, they'll just take more thought. */

  path1 = diff_cmd_baton->orig_path_1;
  path2 = diff_cmd_baton->orig_path_2;
  
  for (i = 0; path1[i] && path2[i] && (path1[i] == path2[i]); i++)
    ;
  
  /* Make sure the prefix is made of whole components. (Issue #1771) */
  if (path1[i] || path2[i])
    {
      for ( ; (i > 0) && (path1[i] != '/'); i--)
        ;
    }
  
  path1 = path1 + i;
  path2 = path2 + i;
  
  if (path1[0] == '\0')
    path1 = apr_psprintf (subpool, "%s", path);
  else if (path1[0] == '/')
    path1 = apr_psprintf (subpool, "%s\t(...%s)", path, path1);
  else
    path1 = apr_psprintf (subpool, "%s\t(.../%s)", path, path1);
  
  if (path2[0] == '\0')
    path2 = apr_psprintf (subpool, "%s", path);
  else if (path2[0] == '/')

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -