📄 diff_file.c
字号:
idx = svn_diff__file_datasource_to_index(datasource); curp = file_baton->curp[idx]; endp = file_baton->endp[idx]; last_chunk = offset_to_chunk(file_baton->size[idx]); if (curp == endp && last_chunk == file_baton->chunk[idx]) { return SVN_NO_ERROR; } /* Get a new token */ file_token = file_baton->tokens; if (file_token) { file_baton->tokens = file_token->next; } else { file_token = apr_palloc(file_baton->pool, sizeof(*file_token)); } file_token->datasource = datasource; file_token->offset = chunk_to_offset(file_baton->chunk[idx]) + (curp - file_baton->buffer[idx]); file_token->raw_length = 0; file_token->length = 0; while (1) { eol = find_eol_start(curp, endp - curp); if (eol) { had_cr = (*eol == '\r'); eol++; /* If we have the whole eol sequence in the chunk... */ if (!had_cr || eol != endp) { if (had_cr && *eol == '\n') ++eol; break; } } if (file_baton->chunk[idx] == last_chunk) { eol = endp; break; } length = endp - curp; file_token->raw_length += length; normalize(curp, &length, &file_baton->normalize_state[idx], file_baton->options); file_token->length += length; h = svn_diff__adler32(h, curp, length); curp = endp = file_baton->buffer[idx]; file_baton->chunk[idx]++; length = file_baton->chunk[idx] == last_chunk ? offset_in_chunk(file_baton->size[idx]) : CHUNK_SIZE; endp += length; file_baton->endp[idx] = endp; SVN_ERR(read_chunk(file_baton->file[idx], file_baton->path[idx], curp, length, chunk_to_offset(file_baton->chunk[idx]), file_baton->pool)); /* If the last chunk ended in a CR, we're done. */ if (had_cr) { eol = curp; if (*curp == '\n') ++eol; break; } } length = eol - curp; file_token->raw_length += length; file_baton->curp[idx] = eol; /* If the file length is exactly a multiple of CHUNK_SIZE, we will end up * with a spurious empty token. Avoid returning it. * Note that we use the unnormalized length; we don't want a line containing * only spaces (and no trailing newline) to appear like a non-existent * line. */ if (file_token->raw_length > 0) { normalize(curp, &length, &file_baton->normalize_state[idx], file_baton->options); file_token->length += length; *hash = svn_diff__adler32(h, curp, length); *token = file_token; } return SVN_NO_ERROR;}#define COMPARE_CHUNK_SIZE 4096/* Implements svn_diff_fns_t::token_compare */static svn_error_t *svn_diff__file_token_compare(void *baton, void *token1, void *token2, int *compare){ svn_diff__file_baton_t *file_baton = baton; svn_diff__file_token_t *file_token[2]; char buffer[2][COMPARE_CHUNK_SIZE]; char *bufp[2]; apr_off_t offset[2]; int idx[2]; apr_off_t length[2]; apr_off_t total_length; /* How much is left to read of each token from the file. */ apr_off_t raw_length[2]; int i; int chunk[2]; normalize_state_t state[2]; file_token[0] = token1; file_token[1] = token2; if (file_token[0]->length < file_token[1]->length) { *compare = -1; return SVN_NO_ERROR; } if (file_token[0]->length > file_token[1]->length) { *compare = 1; return SVN_NO_ERROR; } total_length = file_token[0]->length; if (total_length == 0) { *compare = 0; return SVN_NO_ERROR; } for (i = 0; i < 2; ++i) { idx[i] = svn_diff__file_datasource_to_index(file_token[i]->datasource); offset[i] = file_token[i]->offset; chunk[i] = file_baton->chunk[idx[i]]; state[i] = state_normal; if (offset_to_chunk(offset[i]) == chunk[i]) { /* If the start of the token is in memory, the entire token is * in memory. */ bufp[i] = file_baton->buffer[idx[i]]; bufp[i] += offset_in_chunk(offset[i]); length[i] = total_length; raw_length[i] = 0; } else { length[i] = 0; raw_length[i] = file_token[i]->raw_length; } } do { apr_off_t len; for (i = 0; i < 2; i++) { if (length[i] == 0) { /* Error if raw_length is 0, that's an unexpected change * of the file that can happen when ingoring whitespace * and that can lead to an infinite loop. */ if (raw_length[i] == 0) return svn_error_createf(SVN_ERR_DIFF_DATASOURCE_MODIFIED, NULL, _("The file '%s' changed unexpectedly" " during diff"), file_baton->path[idx[i]]); /* Read a chunk from disk into a buffer */ bufp[i] = buffer[i]; length[i] = raw_length[i] > COMPARE_CHUNK_SIZE ? COMPARE_CHUNK_SIZE : raw_length[i]; SVN_ERR(read_chunk(file_baton->file[idx[i]], file_baton->path[idx[i]], bufp[i], length[i], offset[i], file_baton->pool)); offset[i] += length[i]; raw_length[i] -= length[i]; normalize(bufp[i], &length[i], &state[i], file_baton->options); } } len = length[0] > length[1] ? length[1] : length[0]; /* 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; length[0] -= len; length[1] -= len; bufp[0] += len; bufp[1] += len; } while(total_length > 0); *compare = 0; return SVN_NO_ERROR;}/* Implements svn_diff_fns_t::token_discard */static voidsvn_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;}/* Implements svn_diff_fns_t::token_discard_all */static voidsvn_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};/* Id for the --ignore-eol-style option, which doesn't have a short name. */#define SVN_DIFF__OPT_IGNORE_EOL_STYLE 256/* Options supported by svn_diff_file_options_parse(). */static const apr_getopt_option_t diff_options[] ={ { "ignore-space-change", 'b', 0, NULL }, { "ignore-all-space", 'w', 0, NULL }, { "ignore-eol-style", SVN_DIFF__OPT_IGNORE_EOL_STYLE, 0, NULL }, /* ### For compatibility; we don't support the argument to -u, because * ### we don't have optional argument support. */ { "unified", 'u', 0, NULL }, { NULL, 0, 0, NULL }};svn_diff_file_options_t *svn_diff_file_options_create(apr_pool_t *pool){ return apr_pcalloc(pool, sizeof(svn_diff_file_options_t));}svn_error_t *svn_diff_file_options_parse(svn_diff_file_options_t *options, const apr_array_header_t *args, apr_pool_t *pool){ apr_getopt_t *os; /* Make room for each option (starting at index 1) plus trailing NULL. */ const char **argv = apr_palloc(pool, sizeof(char*) * (args->nelts + 2)); argv[0] = ""; memcpy(argv + 1, args->elts, sizeof(char*) * args->nelts); argv[args->nelts + 1] = NULL; apr_getopt_init(&os, pool, args->nelts + 1, argv); /* No printing of error messages, please! */ os->errfn = NULL; while (1) { const char *opt_arg; int opt_id; apr_status_t err = apr_getopt_long(os, diff_options, &opt_id, &opt_arg); if (APR_STATUS_IS_EOF(err)) break; if (err) return svn_error_wrap_apr(err, _("Error parsing diff options")); switch (opt_id) { case 'b': /* -w takes precedence over -b. */ if (! options->ignore_space) options->ignore_space = svn_diff_file_ignore_space_change; break; case 'w': options->ignore_space = svn_diff_file_ignore_space_all; break; case SVN_DIFF__OPT_IGNORE_EOL_STYLE: options->ignore_eol_style = TRUE; break; default: break; } } /* Check for spurious arguments. */ if (os->ind < os->argc) return svn_error_createf(SVN_ERR_INVALID_DIFF_OPTION, NULL, _("Invalid argument '%s' in diff options"), os->argv[os->ind]); return SVN_NO_ERROR;}svn_error_t *svn_diff_file_diff_2(svn_diff_t **diff, const char *original, const char *modified, const svn_diff_file_options_t *options, apr_pool_t *pool){ svn_diff__file_baton_t baton; memset(&baton, 0, sizeof(baton)); baton.options = options; 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_diff(svn_diff_t **diff, const char *original, const char *modified, apr_pool_t *pool){ return svn_diff_file_diff_2(diff, original, modified, svn_diff_file_options_create(pool), pool);}svn_error_t *svn_diff_file_diff3_2(svn_diff_t **diff, const char *original, const char *modified, const char *latest, const svn_diff_file_options_t *options, apr_pool_t *pool){ svn_diff__file_baton_t baton; memset(&baton, 0, sizeof(baton)); baton.options = options; 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_diff3(svn_diff_t **diff, const char *original, const char *modified, const char *latest, apr_pool_t *pool){ return svn_diff_file_diff3_2(diff, original, modified, latest, svn_diff_file_options_create(pool), pool);}svn_error_t *svn_diff_file_diff4_2(svn_diff_t **diff, const char *original, const char *modified, const char *latest,
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -