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

📄 blame.c

📁 subversion-1.4.3-1.tar.gz 配置svn的源码
💻 C
📖 第 1 页 / 共 2 页
字号:
/* * blame.c:  return blame messages * * ==================================================================== * Copyright (c) 2000-2006 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 <apr_pools.h>#include "client.h"#include "svn_client.h"#include "svn_subst.h"#include "svn_string.h"#include "svn_error.h"#include "svn_diff.h"#include "svn_pools.h"#include "svn_path.h"#include "svn_props.h"#include "svn_private_config.h"#include <assert.h>/* The metadata associated with a particular revision. */struct rev{  svn_revnum_t revision; /* the revision number */  const char *author;    /* the author of the revision */  const char *date;      /* the date of the revision */  /* Only used by the pre-1.1 code. */  const char *path;      /* the absolute repository path */  struct rev *next;      /* the next revision */};/* One chunk of blame */struct blame{  struct rev *rev;    /* the responsible revision */  apr_off_t start;    /* the starting diff-token (line) */  struct blame *next; /* the next chunk */};/* The baton used for a file revision.  Also used for the diff output   routine. */struct file_rev_baton {  svn_revnum_t start_rev, end_rev;  const char *target;  svn_client_ctx_t *ctx;  const svn_diff_file_options_t *diff_options;  svn_boolean_t ignore_mime_type;  /* name of file containing the previous revision of the file */  const char *last_filename;  struct rev *rev;     /* the rev for which blame is being assigned                          during a diff */  struct blame *blame; /* linked list of blame chunks */  struct blame *avail; /* linked list of free blame chunks */  const char *tmp_path; /* temp file name to feed svn_io_open_unique_file */  apr_pool_t *mainpool;  /* lives during the whole sequence of calls */  apr_pool_t *lastpool;  /* pool used during previous call */  apr_pool_t *currpool;  /* pool used during this call */};/* The baton used by the txdelta window handler. */struct delta_baton {  /* Our underlying handler/baton that we wrap */  svn_txdelta_window_handler_t wrapped_handler;  void *wrapped_baton;  struct file_rev_baton *file_rev_baton;  apr_file_t *source_file;  /* the delta source */  apr_file_t *file;  /* the result of the delta */  const char *filename;};/* Return a blame chunk associated with REV for a change starting   at token START, and allocated in BATON->mainpool. */static struct blame *blame_create(struct file_rev_baton *baton, struct rev *rev, apr_off_t start){  struct blame *blame;  if (baton->avail)    {      blame = baton->avail;      baton->avail = blame->next;    }  else    blame = apr_palloc(baton->mainpool, sizeof(*blame));  blame->rev = rev;  blame->start = start;         blame->next = NULL;  return blame;}/* Destroy a blame chunk. */static voidblame_destroy(struct file_rev_baton *baton, struct blame *blame){  blame->next = baton->avail;  baton->avail = blame;}/* Return the blame chunk that contains token OFF, starting the search at   BLAME. */static struct blame *blame_find(struct blame *blame, apr_off_t off){  struct blame *prev = NULL;  while (blame)    {      if (blame->start > off) break;      prev = blame;      blame = blame->next;    }  return prev;}/* Shift the start-point of BLAME and all subsequence blame-chunks   by ADJUST tokens */static voidblame_adjust(struct blame *blame, apr_off_t adjust){  while (blame)    {      blame->start += adjust;      blame = blame->next;    }}/* Delete the blame associated with the region from token START to   START + LENGTH */static svn_error_t *blame_delete_range(struct file_rev_baton *db, apr_off_t start,                   apr_off_t length){  struct blame *first = blame_find(db->blame, start);  struct blame *last = blame_find(db->blame, start + length);  struct blame *tail = last->next;  if (first != last)    {      struct blame *walk = first->next;      while (walk != last)        {          struct blame *next = walk->next;          blame_destroy(db, walk);          walk = next;        }      first->next = last;      last->start = start;      if (first->start == start)        {          *first = *last;          blame_destroy(db, last);          last = first;        }    }  if (tail && tail->start == last->start + length)    {      *last = *tail;      blame_destroy(db, tail);      tail = last->next;    }  blame_adjust(tail, -length);  return SVN_NO_ERROR;}/* Insert a chunk of blame associated with DB->rev starting   at token START and continuing for LENGTH tokens */static svn_error_t *blame_insert_range(struct file_rev_baton *db, apr_off_t start,                   apr_off_t length){  struct blame *head = db->blame;  struct blame *point = blame_find(head, start);  struct blame *insert;  if (point->start == start)    {      insert = blame_create(db, point->rev, point->start + length);      point->rev = db->rev;      insert->next = point->next;      point->next = insert;    }  else    {      struct blame *middle;      middle = blame_create(db, db->rev, start);      insert = blame_create(db, point->rev, start + length);      middle->next = insert;      insert->next = point->next;      point->next = middle;    }  blame_adjust(insert->next, length);  return SVN_NO_ERROR;}/* Callback for diff between subsequent revisions */static svn_error_t *output_diff_modified(void *baton,                     apr_off_t original_start,                     apr_off_t original_length,                     apr_off_t modified_start,                     apr_off_t modified_length,                     apr_off_t latest_start,                     apr_off_t latest_length){  struct file_rev_baton *db = baton;  if (original_length)    SVN_ERR(blame_delete_range(db, modified_start, original_length));  if (modified_length)    SVN_ERR(blame_insert_range(db, modified_start, modified_length));  return SVN_NO_ERROR;}/* Used only by the old code. *//* The baton used for RA->get_log */struct log_message_baton {  const char *path;        /* The path to be processed */  struct rev *eldest;      /* The eldest revision processed */  char action;             /* The action associated with the eldest */   svn_revnum_t copyrev;    /* The revision the eldest was copied from */  svn_cancel_func_t cancel_func; /* cancellation callback */   void *cancel_baton;            /* cancellation baton */  apr_pool_t *pool; };static const svn_diff_output_fns_t output_fns = {        NULL,        output_diff_modified};/* Callback for log messages: accumulates revision metadata into   a chronologically ordered list stored in the baton. */static svn_error_t *log_message_receiver(void *baton,                     apr_hash_t *changed_paths,                     svn_revnum_t revision,                     const char *author,                     const char *date,                     const char *message,                     apr_pool_t *pool){  struct log_message_baton *lmb = baton;  struct rev *rev;  if (lmb->cancel_func)    SVN_ERR(lmb->cancel_func(lmb->cancel_baton));  rev = apr_palloc(lmb->pool, sizeof(*rev));  rev->revision = revision;  rev->author = apr_pstrdup(lmb->pool, author);  rev->date = apr_pstrdup(lmb->pool, date);  rev->path = lmb->path;  rev->next = lmb->eldest;  lmb->eldest = rev;  SVN_ERR(svn_client__prev_log_path(&lmb->path, &lmb->action,                                    &lmb->copyrev, changed_paths,                                    lmb->path, svn_node_file, revision,                                    lmb->pool));  return SVN_NO_ERROR;}/* Add the blame for the diffs between LAST_FILE and CUR_FILE with the rev   specified in FRB.  LAST_FILE may be NULL in which   case blame is added for every line of CUR_FILE. */static svn_error_t *add_file_blame(const char *last_file, const char *cur_file,               struct file_rev_baton *frb){  if (!last_file)    {      assert(frb->blame == NULL);      frb->blame = blame_create(frb, frb->rev, 0);    }  else    {      svn_diff_t *diff;      /* We have a previous file.  Get the diff and adjust blame info. */      SVN_ERR(svn_diff_file_diff_2(&diff, last_file, cur_file,                                 frb->diff_options, frb->currpool));      SVN_ERR(svn_diff_output(diff, frb, &output_fns));    }  return SVN_NO_ERROR;}static svn_error_t *window_handler(svn_txdelta_window_t *window, void *baton){  struct delta_baton *dbaton = baton;  struct file_rev_baton *frb = dbaton->file_rev_baton;  /* Call the wrapped handler first. */  SVN_ERR(dbaton->wrapped_handler(window, dbaton->wrapped_baton));  /* We patiently wait for the NULL window marking the end. */  if (window)    return SVN_NO_ERROR;  /* Close the files used for the delta.     It is important to do this early, since otherwise, they will be deleted     before all handles are closed, which leads to failures on some platforms     when new tempfiles are to be created. */  if (dbaton->source_file)    SVN_ERR(svn_io_file_close(dbaton->source_file, frb->currpool));  SVN_ERR(svn_io_file_close(dbaton->file, frb->currpool));  /* Process this file. */  SVN_ERR(add_file_blame(frb->last_filename,                         dbaton->filename, frb));  /* Prepare for next revision. */  /* Remember the file name so we can diff it with the next revision. */  frb->last_filename = dbaton->filename;  /* Switch pools. */  {    apr_pool_t *tmp_pool = frb->lastpool;    frb->lastpool = frb->currpool;    frb->currpool = tmp_pool;  }  return SVN_NO_ERROR;}/* Throw an SVN_ERR_CLIENT_IS_BINARY_FILE error if PROP_DIFFS indicates a   binary MIME type.  Else, return SVN_NO_ERROR. */static svn_error_t *check_mimetype(apr_array_header_t *prop_diffs, const char *target,               apr_pool_t *pool){  int i;  for (i = 0; i < prop_diffs->nelts; ++i)    {      const svn_prop_t *prop = &APR_ARRAY_IDX(prop_diffs, i, svn_prop_t);      if (strcmp(prop->name, SVN_PROP_MIME_TYPE) == 0          && prop->value          && svn_mime_type_is_binary(prop->value->data))        return svn_error_createf           (SVN_ERR_CLIENT_IS_BINARY_FILE, 0,           _("Cannot calculate blame information for binary file '%s'"),           svn_path_local_style(target, pool));    }  return SVN_NO_ERROR;}static svn_error_t *file_rev_handler(void *baton, const char *path, svn_revnum_t revnum,                 apr_hash_t *rev_props,                 svn_txdelta_window_handler_t *content_delta_handler,                 void **content_delta_baton,                 apr_array_header_t *prop_diffs,                 apr_pool_t *pool){  struct file_rev_baton *frb = baton;  svn_stream_t *last_stream;  svn_stream_t *cur_stream;  struct delta_baton *delta_baton;  /* Clear the current pool. */  svn_pool_clear(frb->currpool);  /* If this file has a non-textual mime-type, bail out. */  if (! frb->ignore_mime_type)    SVN_ERR(check_mimetype(prop_diffs, frb->target, frb->currpool));  if (frb->ctx->notify_func2)    {      svn_wc_notify_t *notify        = svn_wc_create_notify(path, svn_wc_notify_blame_revision, pool);      notify->kind = svn_node_none;      notify->content_state = notify->prop_state        = svn_wc_notify_state_inapplicable;      notify->lock_state = svn_wc_notify_lock_state_inapplicable;      notify->revision = revnum;      frb->ctx->notify_func2(frb->ctx->notify_baton2, notify, pool);    }  if (frb->ctx->cancel_func)    SVN_ERR(frb->ctx->cancel_func(frb->ctx->cancel_baton));  /* If there were no content changes, we couldn't care less about this     revision now.  Note that we checked the mime type above, so things     work if the user just changes the mime type in a commit.     Also note that we don't switch the pools in this case.  This is important,     since the tempfile will be removed by the pool and we need the tempfile     from the last revision with content changes. */  if (!content_delta_handler)    return SVN_NO_ERROR;  /* Create delta baton. */  delta_baton = apr_palloc(frb->currpool, sizeof(*delta_baton));  /* Prepare the text delta window handler. */  if (frb->last_filename)    SVN_ERR(svn_io_file_open(&delta_baton->source_file, frb->last_filename,                             APR_READ, APR_OS_DEFAULT, frb->currpool));  else    /* Means empty stream below. */    delta_baton->source_file = NULL;  last_stream = svn_stream_from_aprfile(delta_baton->source_file, pool);  SVN_ERR(svn_io_open_unique_file2(&delta_baton->file,                                   &delta_baton->filename,                                   frb->tmp_path,                                   ".tmp", svn_io_file_del_on_pool_cleanup,                                   frb->currpool));  cur_stream = svn_stream_from_aprfile(delta_baton->file, frb->currpool);

⌨️ 快捷键说明

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