diff options
Diffstat (limited to 'subversion/libsvn_diff/diff.c')
-rw-r--r-- | subversion/libsvn_diff/diff.c | 199 |
1 files changed, 199 insertions, 0 deletions
diff --git a/subversion/libsvn_diff/diff.c b/subversion/libsvn_diff/diff.c new file mode 100644 index 0000000..f43a3be --- /dev/null +++ b/subversion/libsvn_diff/diff.c @@ -0,0 +1,199 @@ +/* + * diff.c : routines for doing diffs + * + * ==================================================================== + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * ==================================================================== + */ + + +#include <apr.h> +#include <apr_pools.h> +#include <apr_general.h> + +#include "svn_pools.h" +#include "svn_error.h" +#include "svn_diff.h" +#include "svn_types.h" + +#include "diff.h" + + +svn_diff__token_index_t* +svn_diff__get_token_counts(svn_diff__position_t *loop_start, + svn_diff__token_index_t num_tokens, + apr_pool_t *pool) +{ + svn_diff__token_index_t *token_counts; + svn_diff__token_index_t token_index; + svn_diff__position_t *current; + + token_counts = apr_palloc(pool, num_tokens * sizeof(*token_counts)); + for (token_index = 0; token_index < num_tokens; token_index++) + token_counts[token_index] = 0; + + current = loop_start; + if (current != NULL) + { + do + { + token_counts[current->token_index]++; + current = current->next; + } + while (current != loop_start); + } + + return token_counts; +} + + +svn_diff_t * +svn_diff__diff(svn_diff__lcs_t *lcs, + apr_off_t original_start, apr_off_t modified_start, + svn_boolean_t want_common, + apr_pool_t *pool) +{ + svn_diff_t *diff; + svn_diff_t **diff_ref = &diff; + + while (1) + { + if (original_start < lcs->position[0]->offset + || modified_start < lcs->position[1]->offset) + { + (*diff_ref) = apr_palloc(pool, sizeof(**diff_ref)); + + (*diff_ref)->type = svn_diff__type_diff_modified; + (*diff_ref)->original_start = original_start - 1; + (*diff_ref)->original_length = + lcs->position[0]->offset - original_start; + (*diff_ref)->modified_start = modified_start - 1; + (*diff_ref)->modified_length = + lcs->position[1]->offset - modified_start; + (*diff_ref)->latest_start = 0; + (*diff_ref)->latest_length = 0; + + diff_ref = &(*diff_ref)->next; + } + + /* Detect the EOF */ + if (lcs->length == 0) + break; + + original_start = lcs->position[0]->offset; + modified_start = lcs->position[1]->offset; + + if (want_common) + { + (*diff_ref) = apr_palloc(pool, sizeof(**diff_ref)); + + (*diff_ref)->type = svn_diff__type_common; + (*diff_ref)->original_start = original_start - 1; + (*diff_ref)->original_length = lcs->length; + (*diff_ref)->modified_start = modified_start - 1; + (*diff_ref)->modified_length = lcs->length; + (*diff_ref)->latest_start = 0; + (*diff_ref)->latest_length = 0; + + diff_ref = &(*diff_ref)->next; + } + + original_start += lcs->length; + modified_start += lcs->length; + + lcs = lcs->next; + } + + *diff_ref = NULL; + + return diff; +} + + +svn_error_t * +svn_diff_diff_2(svn_diff_t **diff, + void *diff_baton, + const svn_diff_fns2_t *vtable, + apr_pool_t *pool) +{ + svn_diff__tree_t *tree; + svn_diff__position_t *position_list[2]; + svn_diff__token_index_t num_tokens; + svn_diff__token_index_t *token_counts[2]; + svn_diff_datasource_e datasource[] = {svn_diff_datasource_original, + svn_diff_datasource_modified}; + svn_diff__lcs_t *lcs; + apr_pool_t *subpool; + apr_pool_t *treepool; + apr_off_t prefix_lines = 0; + apr_off_t suffix_lines = 0; + + *diff = NULL; + + subpool = svn_pool_create(pool); + treepool = svn_pool_create(pool); + + svn_diff__tree_create(&tree, treepool); + + SVN_ERR(vtable->datasources_open(diff_baton, &prefix_lines, &suffix_lines, + datasource, 2)); + + /* Insert the data into the tree */ + SVN_ERR(svn_diff__get_tokens(&position_list[0], + tree, + diff_baton, vtable, + svn_diff_datasource_original, + prefix_lines, + subpool)); + + SVN_ERR(svn_diff__get_tokens(&position_list[1], + tree, + diff_baton, vtable, + svn_diff_datasource_modified, + prefix_lines, + subpool)); + + num_tokens = svn_diff__get_node_count(tree); + + /* The cool part is that we don't need the tokens anymore. + * Allow the app to clean them up if it wants to. + */ + if (vtable->token_discard_all != NULL) + vtable->token_discard_all(diff_baton); + + /* We don't need the nodes in the tree either anymore, nor the tree itself */ + svn_pool_destroy(treepool); + + token_counts[0] = svn_diff__get_token_counts(position_list[0], num_tokens, + subpool); + token_counts[1] = svn_diff__get_token_counts(position_list[1], num_tokens, + subpool); + + /* Get the lcs */ + lcs = svn_diff__lcs(position_list[0], position_list[1], token_counts[0], + token_counts[1], num_tokens, prefix_lines, + suffix_lines, subpool); + + /* Produce the diff */ + *diff = svn_diff__diff(lcs, 1, 1, TRUE, pool); + + /* Get rid of all the data we don't have a use for anymore */ + svn_pool_destroy(subpool); + + return SVN_NO_ERROR; +} |