Index: subversion/include/svn_opt.h =================================================================== --- subversion/include/svn_opt.h (revision 29392) +++ subversion/include/svn_opt.h (working copy) @@ -346,7 +346,10 @@ enum svn_opt_revision_kind { svn_opt_revision_working, /** repository youngest */ - svn_opt_revision_head + svn_opt_revision_head, + + /** repository prior to youngest */ + svn_opt_revision_prior }; /** Index: subversion/libsvn_subr/opt.c =================================================================== --- subversion/libsvn_subr/opt.c (revision 29392) +++ subversion/libsvn_subr/opt.c (working copy) @@ -622,6 +622,19 @@ static char *parse_one_rev(svn_opt_revision_t *rev *end = save; return end; } + else if (*str == '-' && apr_isdigit(*(str + 1))) + { + /* We're dealing with a negative number here. */ + end = str + 2; + while (apr_isdigit(*end)) + end++; + save = *end; + *end = '\0'; + revision->kind = svn_opt_revision_number; + revision->value.number = SVN_STR_TO_REV(str); + *end = save; + return end; + } else if (apr_isalpha(*str)) { end = str + 1; @@ -634,6 +647,7 @@ static char *parse_one_rev(svn_opt_revision_t *rev *end = save; return end; } + else return NULL; } Index: subversion/libsvn_client/revisions.c =================================================================== --- subversion/libsvn_client/revisions.c (revision 29392) +++ subversion/libsvn_client/revisions.c (working copy) @@ -49,6 +49,7 @@ svn_client__get_revision_number(svn_revnum_t *revn *revnum = revision->value.number; break; + case svn_opt_revision_prior: case svn_opt_revision_head: /* If our caller provided a value for HEAD that he wants us to use, we'll use it. Otherwise, we have to query the @@ -67,6 +68,11 @@ svn_client__get_revision_number(svn_revnum_t *revn if (youngest_rev) *youngest_rev = *revnum; } + + /* We want HEAD - 1 when 'prior' */ + if (revision->kind == svn_opt_revision_prior) + --(*revnum); + break; case svn_opt_revision_committed: Index: subversion/tests/cmdline/diff_tests.py =================================================================== --- subversion/tests/cmdline/diff_tests.py (revision 29392) +++ subversion/tests/cmdline/diff_tests.py (working copy) @@ -3343,6 +3343,27 @@ def diff_file_depth_empty(sbox): if len(out) < 4: raise svntest.Failure +def diff_change_head_keyword(sbox): + "diff using -cHEAD" + + sbox.build() + os.chdir(sbox.wc_dir) + + add_a_file_in_a_subdir() + update_a_file() + + svntest.main.run_svn(None, 'ci', '-m', 'log msg') + + diff_output, err_output = svntest.main.run_svn(None, 'diff', + '-c', 'HEAD') + + diff_output2, err_output2 = svntest.main.run_svn(None, 'diff', + '-r', '1:2') + + if diff_output != diff_output2: + raise svntest.Failure + + ######################################################################## #Run the tests @@ -3396,6 +3417,7 @@ test_list = [ None, diff_backward_repos_wc_copy, diff_summarize_xml, diff_file_depth_empty, + diff_change_head_keyword, ] if __name__ == '__main__': Index: subversion/svn/main.c =================================================================== --- subversion/svn/main.c (revision 29392) +++ subversion/svn/main.c (working copy) @@ -1193,9 +1193,8 @@ main(int argc, const char *argv[]) break; case 'c': { - char *end; - svn_revnum_t changeno; - svn_opt_revision_range_t *range; + svn_opt_revision_range_t *range = apr_palloc(pool, + sizeof(*range)); if (opt_state.old_target) { @@ -1204,41 +1203,73 @@ main(int argc, const char *argv[]) _("Can't specify -c with --old")); return svn_cmdline_handle_exit_error(err, pool, "svn: "); } - changeno = strtol(opt_arg, &end, 10); - if (end == opt_arg || *end != '\0') + + /* The first move is to use svn_opt_parse_revision() to + * extract the revision argument into the range structure. */ + if (svn_opt_parse_revision(&range->start, &range->end, + opt_arg, pool) != 0) { - err = svn_error_create(SVN_ERR_CL_ARG_PARSING_ERROR, NULL, - _("Non-numeric change argument " - "given to -c")); + err = svn_utf_cstring_to_utf8(&utf8_opt_arg, opt_arg, pool); + if (! err) + err = svn_error_createf + (SVN_ERR_CL_ARG_PARSING_ERROR, NULL, + _("Syntax error in revision argument '%s'"), + utf8_opt_arg); return svn_cmdline_handle_exit_error(err, pool, "svn: "); } - if (changeno == 0) + + /* Sanity check: only range->start should be set with -c. */ + if (range->end.kind != svn_opt_revision_unspecified) { - err = svn_error_create(SVN_ERR_CL_ARG_PARSING_ERROR, NULL, - _("There is no change 0")); + err = svn_error_create + (SVN_ERR_CL_ARG_PARSING_ERROR, NULL, + _("Multiple revision arguments encountered; " + "can't specify N:M range with -c, " + "try '-r N:M' instead")); return svn_cmdline_handle_exit_error(err, pool, "svn: "); } - /* Figure out the range: - -c N -> -r N-1:N - -c -N -> -r N:N-1 */ - range = apr_palloc(pool, sizeof(*range)); - if (changeno > 0) + /* Then we check for the type, is it a number or HEAD? */ + if (range->start.kind == svn_opt_revision_number) { - range->start.value.number = changeno - 1; - range->end.value.number = changeno; + svn_revnum_t change_rev = range->start.value.number; + + /* Figure out the range: + -c 0 -> invalid + -c N -> -r N-1:N + -c -N -> -r N:N-1 */ + if (change_rev == 0) + { + err = svn_error_create(SVN_ERR_CL_ARG_PARSING_ERROR, NULL, + _("There is no change 0")); + return svn_cmdline_handle_exit_error(err, pool, "svn: "); + } + else if (change_rev > 0) + { + range->start.value.number = change_rev - 1; + range->end.value.number = change_rev; + } + else + { + change_rev = -change_rev; + range->start.value.number = change_rev; + range->end.value.number = change_rev - 1; + } + + range->end.kind = svn_opt_revision_number; } - else + else if (range->start.kind == svn_opt_revision_head) { - changeno = -changeno; - range->start.value.number = changeno; - range->end.value.number = changeno - 1; + range->start.kind = svn_opt_revision_prior; + range->end.kind = svn_opt_revision_head; + range->start.value.number = SVN_IGNORED_REVNUM; + range->end.value.number = SVN_IGNORED_REVNUM; } - opt_state.used_change_arg = TRUE; - range->start.kind = svn_opt_revision_number; - range->end.kind = svn_opt_revision_number; + APR_ARRAY_PUSH(opt_state.revision_ranges, svn_opt_revision_range_t *) = range; + + opt_state.used_change_arg = TRUE; } break; case 'r':