/* * 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 #include #include #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; }