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 + -
显示快捷键?