📄 diff_file.c
字号:
file_baton->path[idx[i]],
bufp[i], length[i], offset[i],
file_baton->pool));
}
}
len = length[0] > length[1] ? length[1] : length[0];
offset[0] += len;
offset[1] += len;
/* Compare two chunks (that could be entire tokens if they both reside
* in memory).
*/
*compare = memcmp(bufp[0], bufp[1], len);
if (*compare != 0)
return SVN_NO_ERROR;
total_length -= len;
}
while(total_length > 0);
*compare = 0;
return SVN_NO_ERROR;
}
static
void
svn_diff__file_token_discard(void *baton,
void *token)
{
svn_diff__file_baton_t *file_baton = baton;
svn_diff__file_token_t *file_token = token;
file_token->next = file_baton->tokens;
file_baton->tokens = file_token;
}
static
void
svn_diff__file_token_discard_all(void *baton)
{
svn_diff__file_baton_t *file_baton = baton;
/* Discard all memory in use by the tokens, and close all open files. */
svn_pool_clear(file_baton->pool);
}
static const svn_diff_fns_t svn_diff__file_vtable =
{
svn_diff__file_datasource_open,
svn_diff__file_datasource_close,
svn_diff__file_datasource_get_next_token,
svn_diff__file_token_compare,
svn_diff__file_token_discard,
svn_diff__file_token_discard_all
};
svn_error_t *
svn_diff_file_diff(svn_diff_t **diff,
const char *original,
const char *modified,
apr_pool_t *pool)
{
svn_diff__file_baton_t baton;
memset(&baton, 0, sizeof(baton));
baton.path[0] = original;
baton.path[1] = modified;
baton.pool = svn_pool_create(pool);
SVN_ERR(svn_diff_diff(diff, &baton, &svn_diff__file_vtable, pool));
svn_pool_destroy(baton.pool);
return SVN_NO_ERROR;
}
svn_error_t *
svn_diff_file_diff3(svn_diff_t **diff,
const char *original,
const char *modified,
const char *latest,
apr_pool_t *pool)
{
svn_diff__file_baton_t baton;
memset(&baton, 0, sizeof(baton));
baton.path[0] = original;
baton.path[1] = modified;
baton.path[2] = latest;
baton.pool = svn_pool_create(pool);
SVN_ERR(svn_diff_diff3(diff, &baton, &svn_diff__file_vtable, pool));
svn_pool_destroy(baton.pool);
return SVN_NO_ERROR;
}
svn_error_t *
svn_diff_file_diff4(svn_diff_t **diff,
const char *original,
const char *modified,
const char *latest,
const char *ancestor,
apr_pool_t *pool)
{
svn_diff__file_baton_t baton;
memset(&baton, 0, sizeof(baton));
baton.path[0] = original;
baton.path[1] = modified;
baton.path[2] = latest;
baton.path[3] = ancestor;
baton.pool = svn_pool_create(pool);
SVN_ERR(svn_diff_diff4(diff, &baton, &svn_diff__file_vtable, pool));
svn_pool_destroy(baton.pool);
return SVN_NO_ERROR;
}
/** Display unified context diffs **/
#define SVN_DIFF__UNIFIED_CONTEXT_SIZE 3
typedef struct svn_diff__file_output_baton_t
{
svn_stream_t *output_stream;
const char *path[2];
apr_file_t *file[2];
apr_off_t current_line[2];
char buffer[2][4096];
apr_size_t length[2];
char *curp[2];
apr_off_t hunk_start[2];
apr_off_t hunk_length[2];
svn_stringbuf_t *hunk;
apr_pool_t *pool;
} svn_diff__file_output_baton_t;
typedef enum svn_diff__file_output_unified_type_e
{
svn_diff__file_output_unified_skip,
svn_diff__file_output_unified_context,
svn_diff__file_output_unified_delete,
svn_diff__file_output_unified_insert
} svn_diff__file_output_unified_type_e;
static
svn_error_t *
svn_diff__file_output_unified_line(svn_diff__file_output_baton_t *baton,
svn_diff__file_output_unified_type_e type,
int idx)
{
char *curp;
char *eol;
apr_size_t length;
svn_error_t *err;
svn_boolean_t bytes_processed = FALSE;
length = baton->length[idx];
curp = baton->curp[idx];
/* Lazily update the current line even if we're at EOF.
* This way we fake output of context at EOF
*/
baton->current_line[idx]++;
if (length == 0 && apr_file_eof(baton->file[idx]))
{
return SVN_NO_ERROR;
}
do
{
if (length > 0)
{
if (!bytes_processed)
{
switch (type)
{
case svn_diff__file_output_unified_context:
svn_stringbuf_appendbytes(baton->hunk, " ", 1);
baton->hunk_length[0]++;
baton->hunk_length[1]++;
break;
case svn_diff__file_output_unified_delete:
svn_stringbuf_appendbytes(baton->hunk, "-", 1);
baton->hunk_length[0]++;
break;
case svn_diff__file_output_unified_insert:
svn_stringbuf_appendbytes(baton->hunk, "+", 1);
baton->hunk_length[1]++;
break;
default:
break;
}
}
/* XXX: '\n' doesn't really cut it. We need to be able to detect
* XXX: '\n', '\r' and '\r\n'.
*/
eol = memchr(curp, '\n', length);
if (eol != NULL)
{
apr_size_t len;
eol++;
len = (apr_size_t)(eol - curp);
length -= len;
if (type != svn_diff__file_output_unified_skip)
{
svn_stringbuf_appendbytes(baton->hunk, curp, len);
}
baton->curp[idx] = eol;
baton->length[idx] = length;
err = SVN_NO_ERROR;
break;
}
if (type != svn_diff__file_output_unified_skip)
{
svn_stringbuf_appendbytes(baton->hunk, curp, length);
}
bytes_processed = TRUE;
}
curp = baton->buffer[idx];
length = sizeof(baton->buffer[idx]);
err = svn_io_file_read(baton->file[idx], curp, &length, baton->pool);
}
while (! err);
if (err && ! APR_STATUS_IS_EOF(err->apr_err))
return err;
if (err && APR_STATUS_IS_EOF(err->apr_err))
{
svn_error_clear (err);
/* Special case if we reach the end of file AND the last line is in the
changed range AND the file doesn't end with a newline */
if (bytes_processed && (type != svn_diff__file_output_unified_skip))
{
svn_stringbuf_appendcstr(baton->hunk,
APR_EOL_STR "\\ No newline at end of file" APR_EOL_STR);
}
baton->length[idx] = 0;
}
return SVN_NO_ERROR;
}
static
svn_error_t *
svn_diff__file_output_unified_flush_hunk(svn_diff__file_output_baton_t *baton)
{
apr_off_t target_line;
apr_size_t hunk_len;
int i;
if (svn_stringbuf_isempty(baton->hunk))
{
/* Nothing to flush */
return SVN_NO_ERROR;
}
target_line = baton->hunk_start[0] + baton->hunk_length[0]
+ SVN_DIFF__UNIFIED_CONTEXT_SIZE;
/* Add trailing context to the hunk */
while (baton->current_line[0] < target_line)
{
SVN_ERR(svn_diff__file_output_unified_line(baton,
svn_diff__file_output_unified_context, 0));
}
/* If the file is non-empty, convert the line indexes from
zero based to one based */
for (i = 0; i < 2; i++)
{
if (baton->hunk_length[i] > 0)
baton->hunk_start[i]++;
}
/* Output the hunk header. If the hunk length is 1, the file is a one line
file. In this case, surpress the number of lines in the hunk (it is
1 implicitly)
*/
SVN_ERR(svn_stream_printf(baton->output_stream, baton->pool,
"@@ -%" APR_OFF_T_FMT,
baton->hunk_start[0]));
if (baton->hunk_length[0] != 1)
{
SVN_ERR(svn_stream_printf(baton->output_stream, baton->pool,
",%" APR_OFF_T_FMT,
baton->hunk_length[0]));
}
SVN_ERR(svn_stream_printf(baton->output_stream, baton->pool,
" +%" APR_OFF_T_FMT,
baton->hunk_start[1]));
if (baton->hunk_length[1] != 1)
{
SVN_ERR(svn_stream_printf(baton->output_stream, baton->pool,
",%" APR_OFF_T_FMT,
baton->hunk_length[1]));
}
SVN_ERR(svn_stream_printf(baton->output_stream, baton->pool,
" @@" APR_EOL_STR));
/* Output the hunk content */
hunk_len = baton->hunk->len;
SVN_ERR(svn_stream_write(baton->output_stream, baton->hunk->data,
&hunk_len));
/* Prepare for the next hunk */
baton->hunk_length[0] = 0;
baton->hunk_length[1] = 0;
svn_stringbuf_setempty(baton->hunk);
return SVN_NO_ERROR;
}
static
svn_error_t *
svn_diff__file_output_unified_diff_modified(void *baton,
apr_off_t original_start, apr_off_t original_length,
apr_off_t modified_start, apr_off_t modified_length,
apr_off_t latest_start, apr_off_t latest_length)
{
svn_diff__file_output_baton_t *output_baton = baton;
apr_off_t target_line[2];
int i;
target_line[0] = original_start >= SVN_DIFF__UNIFIED_CONTEXT_SIZE
? original_start - SVN_DIFF__UNIFIED_CONTEXT_SIZE : 0;
target_line[1] = modified_start;
/* If the changed ranges are far enough apart (no overlapping or connecting
context), flush the current hunk, initialize the next hunk and skip the
lines not in context. Also do this when this is the first hunk.
*/
if (output_baton->current_line[0] < target_line[0]
&& (output_baton->hunk_start[0] + output_baton->hunk_length[0]
+ SVN_DIFF__UNIFIED_CONTEXT_SIZE < target_line[0]
|| output_baton->hunk_length[0] == 0))
{
SVN_ERR(svn_diff__file_output_unified_flush_hunk(output_baton));
output_baton->hunk_start[0] = target_line[0];
output_baton->hunk_start[1] = target_line[1] + target_line[0]
- original_start;
/* Skip lines until we are at the beginning of the context we want to
display */
while (output_baton->current_line[0] < target_line[0])
{
SVN_ERR(svn_diff__file_output_unified_line(output_baton,
svn_diff__file_output_unified_skip, 0));
}
}
/* Skip lines until we are at the start of the changed range */
while (output_baton->current_line[1] < target_line[1])
{
SVN_ERR(svn_diff__file_output_unified_line(output_baton,
svn_diff__file_output_unified_skip, 1));
}
/* Output the context preceding the changed range */
while (output_baton->current_line[0] < original_start)
{
SVN_ERR(svn_diff__file_output_unified_line(output_baton,
svn_diff__file_output_unified_context, 0));
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -