diff.c

来自「subversion-1.4.3-1.tar.gz 配置svn的源码」· C语言 代码 · 共 1,827 行 · 第 1/4 页

C
1,827
字号
  struct edit_baton *eb = dir_baton->edit_baton;  const char *textbase, *empty_file;  svn_boolean_t modified;  enum svn_wc_schedule_t schedule = entry->schedule;  svn_boolean_t copied = entry->copied;  svn_wc_adm_access_t *adm_access;  const char *base_mimetype, *working_mimetype;  const char *translated = NULL;  apr_array_header_t *propchanges = NULL;  apr_hash_t *baseprops = NULL;  assert(! eb->use_text_base);  SVN_ERR(svn_wc_adm_retrieve(&adm_access, dir_baton->edit_baton->anchor,                              dir_baton->path, pool));  /* If the item is schedule-add *with history*, then we don't want to     see a comparison to the empty file;  we want the usual working     vs. text-base comparision. */  if (copied)    schedule = svn_wc_schedule_normal;  /* If this was scheduled replace and we are ignoring ancestry,     report it as a normal file modification. */  if (eb->ignore_ancestry && (schedule == svn_wc_schedule_replace))    schedule = svn_wc_schedule_normal;  /* Prep these two paths early. */  textbase = svn_wc__text_base_path(path, FALSE, pool);  SVN_ERR(get_empty_file(eb, &empty_file));  /* Get property diffs if this is not schedule delete. */  if (schedule != svn_wc_schedule_delete)    {      SVN_ERR(svn_wc_props_modified_p(&modified, path, adm_access, pool));      if (modified)        SVN_ERR(svn_wc_get_prop_diffs(&propchanges, &baseprops, path,                                      adm_access, pool));      else        propchanges = apr_array_make(pool, 1, sizeof(svn_prop_t));    }  else    {      SVN_ERR(svn_wc_get_prop_diffs(NULL, &baseprops, path,                                    adm_access, pool));    }  switch (schedule)    {      /* Replace is treated like a delete plus an add: two         comparisons are generated, first one for the delete and         then one for the add. */    case svn_wc_schedule_replace:    case svn_wc_schedule_delete:      /* Delete compares text-base against empty file, modifications to the         working-copy version of the deleted file are not wanted. */      /* Get svn:mime-type from BASE props of PATH. */      SVN_ERR(get_base_mimetype(&base_mimetype, &baseprops,                                adm_access, path, pool));      SVN_ERR(dir_baton->edit_baton->callbacks->file_deleted              (NULL, NULL, path,                textbase,               empty_file,               base_mimetype,               NULL,               baseprops,               dir_baton->edit_baton->callback_baton));      /* Replace will fallthrough! */      if (schedule == svn_wc_schedule_delete)        break;    case svn_wc_schedule_add:      /* Get svn:mime-type from working props of PATH. */      SVN_ERR(get_working_mimetype(&working_mimetype, NULL,                                   adm_access, path, pool));      SVN_ERR(svn_wc_translated_file2              (&translated, path, path, adm_access,               SVN_WC_TRANSLATE_TO_NF               | SVN_WC_TRANSLATE_USE_GLOBAL_TMP,               pool));      SVN_ERR(dir_baton->edit_baton->callbacks->file_added              (NULL, NULL, NULL, path,               empty_file,               translated,               0, entry->revision,               NULL,               working_mimetype,               propchanges, baseprops,               dir_baton->edit_baton->callback_baton));      break;    default:      SVN_ERR(svn_wc_text_modified_p(&modified, path, FALSE,                                     adm_access, pool));      if (modified)        {          /* Note that this might be the _second_ time we translate             the file, as svn_wc_text_modified_p() might have used a             tmp translated copy too.  But what the heck, diff is             already expensive, translating twice for the sake of code             modularity is liveable. */          SVN_ERR(svn_wc_translated_file2                  (&translated, path,                   path, adm_access,                   SVN_WC_TRANSLATE_TO_NF                   | SVN_WC_TRANSLATE_USE_GLOBAL_TMP,                   pool));        }      if (modified || propchanges->nelts > 0)        {          /* Get svn:mime-type for both base and working file. */          SVN_ERR(get_base_mimetype(&base_mimetype, &baseprops,                                    adm_access, path, pool));          SVN_ERR(get_working_mimetype(&working_mimetype, NULL,                                       adm_access, path, pool));          SVN_ERR(dir_baton->edit_baton->callbacks->file_changed                  (NULL, NULL, NULL,                   path,                   modified ? textbase : NULL,                   translated,                   entry->revision,                   SVN_INVALID_REVNUM,                   base_mimetype,                   working_mimetype,                   propchanges, baseprops,                   dir_baton->edit_baton->callback_baton));        }    }  return SVN_NO_ERROR;}/* Called when the directory is closed to compare any elements that have * not yet been compared.  This identifies local, working copy only * changes.  At this stage we are dealing with files/directories that do * exist in the working copy. * * DIR_BATON is the baton for the directory. */static svn_error_t *directory_elements_diff(struct dir_baton *dir_baton){  apr_hash_t *entries;  apr_hash_index_t *hi;  svn_boolean_t in_anchor_not_target;  apr_pool_t *subpool;  svn_wc_adm_access_t *adm_access;  /* This directory should have been unchanged or replaced, not added,     since an added directory can only contain added files and these will     already have been compared. */  assert(!dir_baton->added);  /* Everything we do below is useless if we are comparing to BASE. */  if (dir_baton->edit_baton->use_text_base)    return SVN_NO_ERROR;  /* Determine if this is the anchor directory if the anchor is different     to the target. When the target is a file, the anchor is the parent     directory and if this is that directory the non-target entries must be     skipped. */  in_anchor_not_target =    (*dir_baton->edit_baton->target     && (! svn_path_compare_paths         (dir_baton->path,          svn_wc_adm_access_path(dir_baton->edit_baton->anchor))));  SVN_ERR(svn_wc_adm_retrieve(&adm_access, dir_baton->edit_baton->anchor,                              dir_baton->path, dir_baton->pool));  /* Check for local property mods on this directory, if we haven't     already reported them. */  if (!in_anchor_not_target && !apr_hash_get(dir_baton->compared, "", 0))    {      svn_boolean_t modified;      SVN_ERR(svn_wc_props_modified_p(&modified,                                      dir_baton->path, adm_access,                                      dir_baton->pool));      if (modified)        {          apr_array_header_t *propchanges;          apr_hash_t *baseprops;          SVN_ERR(svn_wc_get_prop_diffs(&propchanges, &baseprops,                                        dir_baton->path, adm_access,                                        dir_baton->pool));          SVN_ERR(dir_baton->edit_baton->callbacks->dir_props_changed                  (adm_access, NULL,                   dir_baton->path,                   propchanges, baseprops,                   dir_baton->edit_baton->callback_baton));        }    }  SVN_ERR(svn_wc_entries_read(&entries, adm_access, FALSE, dir_baton->pool));  subpool = svn_pool_create(dir_baton->pool);  for (hi = apr_hash_first(dir_baton->pool, entries); hi;       hi = apr_hash_next(hi))    {      const void *key;      void *val;      const svn_wc_entry_t *entry;      struct dir_baton *subdir_baton;      const char *name, *path;      svn_pool_clear(subpool);      apr_hash_this(hi, &key, NULL, &val);      name = key;      entry = val;            /* Skip entry for the directory itself. */      if (strcmp(key, SVN_WC_ENTRY_THIS_DIR) == 0)        continue;      /* In the anchor directory, if the anchor is not the target then all         entries other than the target should not be diff'd. Running diff         on one file in a directory should not diff other files in that         directory. */      if (in_anchor_not_target          && strcmp(dir_baton->edit_baton->target, name))        continue;      path = svn_path_join(dir_baton->path, name, subpool);      /* Skip entry if it is in the list of entries already diff'd. */      if (apr_hash_get(dir_baton->compared, path, APR_HASH_KEY_STRING))        continue;      switch (entry->kind)        {        case svn_node_file:          SVN_ERR(file_diff(dir_baton, path, entry, subpool));          break;        case svn_node_dir:          if (entry->schedule == svn_wc_schedule_replace)            {              /* ### TODO: Don't know how to do this bit. How do I get                 information about what is being replaced? If it was a                 directory then the directory elements are also going to be                 deleted. We need to show deletion diffs for these                 files. If it was a file we need to show a deletion diff                 for that file. */            }          /* Check the subdir if in the anchor (the subdir is the target), or             if recursive */          if (in_anchor_not_target || dir_baton->edit_baton->recurse)            {              subdir_baton = make_dir_baton(path, dir_baton,                                            dir_baton->edit_baton,                                            FALSE,                                            subpool);              SVN_ERR(directory_elements_diff(subdir_baton));            }          break;        default:          break;        }    }  svn_pool_destroy(subpool);  return SVN_NO_ERROR;}/* Report an existing file in the working copy (either in BASE or WORKING) * as having been added. * * DIR_BATON is the parent directory baton, ADM_ACCESS/PATH is the path * to the file to be compared. ENTRY is the working copy entry for * the file. * * Do all allocation in POOL. */static svn_error_t *report_wc_file_as_added(struct dir_baton *dir_baton,                        svn_wc_adm_access_t *adm_access,                        const char *path,                        const svn_wc_entry_t *entry,                        apr_pool_t *pool){  struct edit_baton *eb = dir_baton->edit_baton;  apr_hash_t *emptyprops;  const char *mimetype;  apr_hash_t *wcprops = NULL;  apr_array_header_t *propchanges;  const char *empty_file;  const char *source_file;  const char *translated_file;  SVN_ERR(get_empty_file(eb, &empty_file));  /* We can't show additions for files that don't exist. */  assert(!(entry->schedule == svn_wc_schedule_delete && !eb->use_text_base));  /* If the file was added *with history*, then we don't want to     see a comparison to the empty file;  we want the usual working     vs. text-base comparision. */  if (entry->copied)    {      /* Don't show anything if we're comparing to BASE, since by         definition there can't be any local modifications. */      if (eb->use_text_base)        return SVN_NO_ERROR;      /* Otherwise show just the local modifications. */      return file_diff(dir_baton, path, entry, pool);    }  emptyprops = apr_hash_make(pool);  if (eb->use_text_base)    SVN_ERR(get_base_mimetype(&mimetype, &wcprops,                              adm_access, path, pool));  else    SVN_ERR(get_working_mimetype(&mimetype, &wcprops,                                 adm_access, path, pool));  SVN_ERR(svn_prop_diffs(&propchanges,                         wcprops, emptyprops, pool));  if (eb->use_text_base)    source_file = svn_wc__text_base_path(path, FALSE, pool);  else    source_file = path;  SVN_ERR(svn_wc_translated_file2          (&translated_file,           source_file, path, adm_access,           SVN_WC_TRANSLATE_TO_NF           | SVN_WC_TRANSLATE_USE_GLOBAL_TMP,           pool));  SVN_ERR(eb->callbacks->file_added          (adm_access, NULL, NULL,           path,           empty_file, translated_file,           0, entry->revision,           NULL, mimetype,           propchanges, emptyprops,           eb->callback_baton));  return SVN_NO_ERROR;}/* Report an existing directory in the working copy (either in BASE * or WORKING) as having been added.  If recursing, also report any * subdirectories as added. * * DIR_BATON is the baton for the directory. * * Do all allocation in POOL. */static svn_error_t *report_wc_directory_as_added(struct dir_baton *dir_baton,                             apr_pool_t *pool){  struct edit_baton *eb = dir_baton->edit_baton;  svn_wc_adm_access_t *adm_access;  apr_hash_t *emptyprops = apr_hash_make(pool),             *wcprops = NULL;  apr_array_header_t *propchanges;  apr_hash_t *entries;  apr_hash_index_t *hi;  apr_pool_t *subpool;  SVN_ERR(svn_wc_adm_retrieve(&adm_access, eb->anchor,                              dir_baton->path, pool));  /* Get the BASE or WORKING properties, as appropriate, and simulate     their addition. */  if (eb->use_text_base)    SVN_ERR(svn_wc_get_prop_diffs(NULL, &wcprops,                                  dir_baton->path, adm_access, pool));  else    SVN_ERR(svn_wc_prop_list(&wcprops,                             dir_baton->path, adm_access, pool));  SVN_ERR(svn_prop_diffs(&propchanges,                         wcprops, emptyprops, pool));  if (propchanges->nelts > 0)    SVN_ERR(eb->callbacks->dir_props_changed            (adm_access, NULL,             dir_baton->path,             propchanges, emptyprops,             eb->callback_baton));  /* Report the addition of the directory's contents. */  SVN_ERR(svn_wc_entries_read(&entries, adm_access, FALSE, pool));  subpool = svn_pool_create(pool);  for (hi = apr_hash_first(pool, entries); hi;       hi = apr_hash_next(hi))    {      const void *key;      void *val;      const char *name, *path;      const svn_wc_entry_t *entry;      svn_pool_clear(subpool);      apr_hash_this(hi, &key, NULL, &val);      name = key;      entry = val;      /* Skip entry for the directory itself. */      if (strcmp(key, SVN_WC_ENTRY_THIS_DIR) == 0)        continue;      /* If comparing against WORKING, skip entries that are         schedule-deleted - they don't really exist. */      if (!eb->use_text_base && entry->schedule == svn_wc_schedule_delete)        continue;      path = svn_path_join(dir_baton->path, name, subpool);      switch (entry->kind)        {        case svn_node_file:          SVN_ERR(report_wc_file_as_added(dir_baton,                                          adm_access, path, entry, subpool));          break;        case svn_node_dir:          if (eb->recurse)            {              struct dir_baton *subdir_baton = make_dir_baton(path,                                                              dir_baton,                                                              eb,                                                              FALSE,                                                              subpool);              SVN_ERR(report_wc_directory_as_added(subdir_baton, subpool));            }          break;

⌨️ 快捷键说明

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