blob: f43a3be405e28eedcbbf0ae4b6d5164edfe91963 [file] [log] [blame]
/*
* 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;
}