1251881Speter/*
2251881Speter * diff.c :  routines for doing diffs
3251881Speter *
4251881Speter * ====================================================================
5251881Speter *    Licensed to the Apache Software Foundation (ASF) under one
6251881Speter *    or more contributor license agreements.  See the NOTICE file
7251881Speter *    distributed with this work for additional information
8251881Speter *    regarding copyright ownership.  The ASF licenses this file
9251881Speter *    to you under the Apache License, Version 2.0 (the
10251881Speter *    "License"); you may not use this file except in compliance
11251881Speter *    with the License.  You may obtain a copy of the License at
12251881Speter *
13251881Speter *      http://www.apache.org/licenses/LICENSE-2.0
14251881Speter *
15251881Speter *    Unless required by applicable law or agreed to in writing,
16251881Speter *    software distributed under the License is distributed on an
17251881Speter *    "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
18251881Speter *    KIND, either express or implied.  See the License for the
19251881Speter *    specific language governing permissions and limitations
20251881Speter *    under the License.
21251881Speter * ====================================================================
22251881Speter */
23251881Speter
24251881Speter
25251881Speter#include <apr.h>
26251881Speter#include <apr_pools.h>
27251881Speter#include <apr_general.h>
28251881Speter
29251881Speter#include "svn_pools.h"
30251881Speter#include "svn_error.h"
31251881Speter#include "svn_diff.h"
32251881Speter#include "svn_types.h"
33251881Speter
34251881Speter#include "diff.h"
35251881Speter
36251881Speter
37251881Spetersvn_diff__token_index_t*
38251881Spetersvn_diff__get_token_counts(svn_diff__position_t *loop_start,
39251881Speter                           svn_diff__token_index_t num_tokens,
40251881Speter                           apr_pool_t *pool)
41251881Speter{
42251881Speter  svn_diff__token_index_t *token_counts;
43251881Speter  svn_diff__token_index_t token_index;
44251881Speter  svn_diff__position_t *current;
45251881Speter
46251881Speter  token_counts = apr_palloc(pool, num_tokens * sizeof(*token_counts));
47251881Speter  for (token_index = 0; token_index < num_tokens; token_index++)
48251881Speter    token_counts[token_index] = 0;
49251881Speter
50251881Speter  current = loop_start;
51251881Speter  if (current != NULL)
52251881Speter    {
53251881Speter      do
54251881Speter        {
55251881Speter          token_counts[current->token_index]++;
56251881Speter          current = current->next;
57251881Speter        }
58251881Speter      while (current != loop_start);
59251881Speter    }
60251881Speter
61251881Speter  return token_counts;
62251881Speter}
63251881Speter
64251881Speter
65251881Spetersvn_diff_t *
66251881Spetersvn_diff__diff(svn_diff__lcs_t *lcs,
67251881Speter               apr_off_t original_start, apr_off_t modified_start,
68251881Speter               svn_boolean_t want_common,
69251881Speter               apr_pool_t *pool)
70251881Speter{
71251881Speter  svn_diff_t *diff;
72251881Speter  svn_diff_t **diff_ref = &diff;
73251881Speter
74251881Speter  while (1)
75251881Speter    {
76251881Speter      if (original_start < lcs->position[0]->offset
77251881Speter          || modified_start < lcs->position[1]->offset)
78251881Speter      {
79251881Speter          (*diff_ref) = apr_palloc(pool, sizeof(**diff_ref));
80251881Speter
81251881Speter          (*diff_ref)->type = svn_diff__type_diff_modified;
82251881Speter          (*diff_ref)->original_start = original_start - 1;
83251881Speter          (*diff_ref)->original_length =
84251881Speter            lcs->position[0]->offset - original_start;
85251881Speter          (*diff_ref)->modified_start = modified_start - 1;
86251881Speter          (*diff_ref)->modified_length =
87251881Speter            lcs->position[1]->offset - modified_start;
88251881Speter          (*diff_ref)->latest_start = 0;
89251881Speter          (*diff_ref)->latest_length = 0;
90251881Speter
91251881Speter          diff_ref = &(*diff_ref)->next;
92251881Speter      }
93251881Speter
94251881Speter      /* Detect the EOF */
95251881Speter      if (lcs->length == 0)
96251881Speter          break;
97251881Speter
98251881Speter      original_start = lcs->position[0]->offset;
99251881Speter      modified_start = lcs->position[1]->offset;
100251881Speter
101251881Speter      if (want_common)
102251881Speter        {
103251881Speter          (*diff_ref) = apr_palloc(pool, sizeof(**diff_ref));
104251881Speter
105251881Speter          (*diff_ref)->type = svn_diff__type_common;
106251881Speter          (*diff_ref)->original_start = original_start - 1;
107251881Speter          (*diff_ref)->original_length = lcs->length;
108251881Speter          (*diff_ref)->modified_start = modified_start - 1;
109251881Speter          (*diff_ref)->modified_length = lcs->length;
110251881Speter          (*diff_ref)->latest_start = 0;
111251881Speter          (*diff_ref)->latest_length = 0;
112251881Speter
113251881Speter          diff_ref = &(*diff_ref)->next;
114251881Speter        }
115251881Speter
116251881Speter      original_start += lcs->length;
117251881Speter      modified_start += lcs->length;
118251881Speter
119251881Speter      lcs = lcs->next;
120251881Speter    }
121251881Speter
122251881Speter  *diff_ref = NULL;
123251881Speter
124251881Speter  return diff;
125251881Speter}
126251881Speter
127251881Speter
128251881Spetersvn_error_t *
129251881Spetersvn_diff_diff_2(svn_diff_t **diff,
130251881Speter                void *diff_baton,
131251881Speter                const svn_diff_fns2_t *vtable,
132251881Speter                apr_pool_t *pool)
133251881Speter{
134251881Speter  svn_diff__tree_t *tree;
135251881Speter  svn_diff__position_t *position_list[2];
136251881Speter  svn_diff__token_index_t num_tokens;
137251881Speter  svn_diff__token_index_t *token_counts[2];
138251881Speter  svn_diff_datasource_e datasource[] = {svn_diff_datasource_original,
139251881Speter                                        svn_diff_datasource_modified};
140251881Speter  svn_diff__lcs_t *lcs;
141251881Speter  apr_pool_t *subpool;
142251881Speter  apr_pool_t *treepool;
143251881Speter  apr_off_t prefix_lines = 0;
144251881Speter  apr_off_t suffix_lines = 0;
145251881Speter
146251881Speter  *diff = NULL;
147251881Speter
148251881Speter  subpool = svn_pool_create(pool);
149251881Speter  treepool = svn_pool_create(pool);
150251881Speter
151251881Speter  svn_diff__tree_create(&tree, treepool);
152251881Speter
153251881Speter  SVN_ERR(vtable->datasources_open(diff_baton, &prefix_lines, &suffix_lines,
154251881Speter                                   datasource, 2));
155251881Speter
156251881Speter  /* Insert the data into the tree */
157251881Speter  SVN_ERR(svn_diff__get_tokens(&position_list[0],
158251881Speter                               tree,
159251881Speter                               diff_baton, vtable,
160251881Speter                               svn_diff_datasource_original,
161251881Speter                               prefix_lines,
162251881Speter                               subpool));
163251881Speter
164251881Speter  SVN_ERR(svn_diff__get_tokens(&position_list[1],
165251881Speter                               tree,
166251881Speter                               diff_baton, vtable,
167251881Speter                               svn_diff_datasource_modified,
168251881Speter                               prefix_lines,
169251881Speter                               subpool));
170251881Speter
171251881Speter  num_tokens = svn_diff__get_node_count(tree);
172251881Speter
173251881Speter  /* The cool part is that we don't need the tokens anymore.
174251881Speter   * Allow the app to clean them up if it wants to.
175251881Speter   */
176251881Speter  if (vtable->token_discard_all != NULL)
177251881Speter    vtable->token_discard_all(diff_baton);
178251881Speter
179251881Speter  /* We don't need the nodes in the tree either anymore, nor the tree itself */
180251881Speter  svn_pool_destroy(treepool);
181251881Speter
182251881Speter  token_counts[0] = svn_diff__get_token_counts(position_list[0], num_tokens,
183251881Speter                                               subpool);
184251881Speter  token_counts[1] = svn_diff__get_token_counts(position_list[1], num_tokens,
185251881Speter                                               subpool);
186251881Speter
187251881Speter  /* Get the lcs */
188251881Speter  lcs = svn_diff__lcs(position_list[0], position_list[1], token_counts[0],
189251881Speter                      token_counts[1], num_tokens, prefix_lines,
190251881Speter                      suffix_lines, subpool);
191251881Speter
192251881Speter  /* Produce the diff */
193251881Speter  *diff = svn_diff__diff(lcs, 1, 1, TRUE, pool);
194251881Speter
195251881Speter  /* Get rid of all the data we don't have a use for anymore */
196251881Speter  svn_pool_destroy(subpool);
197251881Speter
198251881Speter  return SVN_NO_ERROR;
199251881Speter}
200