{"thread":{"id":"30485","subject":"[PATCH 0/5] xdiff: replace emit_func() with type-safe","startedAt":"2012-05-09T20:19:10Z","lastAt":"2012-05-18T08:28:17Z","messageCount":7,"participants":["René Scharfe","Thomas Rast"],"isPatch":true,"patchVersion":1,"patchTotal":5},"messages":[{"id":"191225","messageId":"4FAAD13E.8030806@lsrfire.ath.cx","threadId":"30485","inReplyTo":null,"subject":"[PATCH 0/5] xdiff: replace emit_func() with type-safe","fromName":"René Scharfe","fromEmail":"rene.scharfe@lsrfire.ath.cx","sentAt":"2012-05-09T20:19:10Z","receivedAt":"2012-05-09T20:19:10Z","isPatch":true,"sender":{"key":"l.s.r@web.de","avatar":"https://avatars.githubusercontent.com/u/26122331?v=4"},"body":"Commit ef2e62fe added the ability to bypass the creation of textual diffs\nand to access diff data directly, through the added emit_func member of\nxdemitconf_t.  This function pointer has a type of \"void (*)()\", because\n\"int (*)(xdfenv_t *, xdchange_t *, xdemitcb_t *, xdemitconf_t const *)\"\n(its real type) would be difficult to export due to the many internal\ntypes in that signature.\n\nThis feature is currently used twice in git blame, through the function\nxdi_diff_hunks().  Both cases only need to know which lines are affected\nby the different hunks of a diff, i.e. the numbers shown in hunk headers\nof unified diffs.\n\nThis patch series adds a simpler mechanism to accommodate these two\ncallers, in a type-safe way, without exporting too many internal types\nof libxdiff.  The last patch removes the old functions.\n\n  xdiff: add hunk_func()\n  blame: use hunk_func(), part 1\n  blame: use hunk_func(), part 2\n  blame: factor out helper for calling xdi_diff()\n  xdiff: remove emit_func() and xdi_diff_hunks()\n\n builtin/blame.c   |   53 +++++++++++++++++++++++++++++++----------------------\n xdiff-interface.c |   44 --------------------------------------------\n xdiff-interface.h |    4 ----\n xdiff/xdiff.h     |    6 +++++-\n xdiff/xdiffi.c    |   17 +++++++++++++++--\n 5 files changed, 51 insertions(+), 73 deletions(-)\n\n-- \n1.7.10.1\n"},{"id":"191226","messageId":"4FAAD1A7.50206@lsrfire.ath.cx","threadId":"30485","inReplyTo":"4FAAD13E.8030806@lsrfire.ath.cx","subject":"[PATCH 1/5] xdiff: add hunk_func()","fromName":"René Scharfe","fromEmail":"rene.scharfe@lsrfire.ath.cx","sentAt":"2012-05-09T20:20:55Z","receivedAt":"2012-05-09T20:20:55Z","isPatch":true,"sender":{"key":"l.s.r@web.de","avatar":"https://avatars.githubusercontent.com/u/26122331?v=4"},"body":"Add a way to register a callback function that is gets passed the\nstart line and line count of each hunk of a diff.  Only standard\ntypes are used.\n\nSigned-off-by: Rene Scharfe <rene.scharfe@lsrfire.ath.cx>\n---\n xdiff/xdiff.h  |    5 +++++\n xdiff/xdiffi.c |   17 +++++++++++++++++\n 2 files changed, 22 insertions(+)\n\ndiff --git a/xdiff/xdiff.h b/xdiff/xdiff.h\nindex 09215af..33c010b 100644\n--- a/xdiff/xdiff.h\n+++ b/xdiff/xdiff.h\n@@ -86,6 +86,10 @@ typedef struct s_xdemitcb {\n \n typedef long (*find_func_t)(const char *line, long line_len, char *buffer, long buffer_size, void *priv);\n \n+typedef int (*xdl_emit_hunk_consume_func_t)(long start_a, long count_a,\n+\t\t\t\t\t    long start_b, long count_b,\n+\t\t\t\t\t    void *cb_data);\n+\n typedef struct s_xdemitconf {\n \tlong ctxlen;\n \tlong interhunkctxlen;\n@@ -93,6 +97,7 @@ typedef struct s_xdemitconf {\n \tfind_func_t find_func;\n \tvoid *find_func_priv;\n \tvoid (*emit_func)();\n+\txdl_emit_hunk_consume_func_t hunk_func;\n } xdemitconf_t;\n \n typedef struct s_bdiffparam {\ndiff --git a/xdiff/xdiffi.c b/xdiff/xdiffi.c\nindex bc889e8..4d671f4 100644\n--- a/xdiff/xdiffi.c\n+++ b/xdiff/xdiffi.c\n@@ -538,6 +538,20 @@ void xdl_free_script(xdchange_t *xscr) {\n \t}\n }\n \n+static int xdl_call_hunk_func(xdfenv_t *xe, xdchange_t *xscr, xdemitcb_t *ecb,\n+\t\t\t      xdemitconf_t const *xecfg)\n+{\n+\txdchange_t *xch, *xche;\n+\n+\tfor (xch = xscr; xch; xch = xche->next) {\n+\t\txche = xdl_get_hunk(xch, xecfg);\n+\t\tif (xecfg->hunk_func(xch->i1, xche->i1 + xche->chg1 - xch->i1,\n+\t\t\t\t     xch->i2, xche->i2 + xche->chg2 - xch->i2,\n+\t\t\t\t     ecb->priv) < 0)\n+\t\t\treturn -1;\n+\t}\n+\treturn 0;\n+}\n \n int xdl_diff(mmfile_t *mf1, mmfile_t *mf2, xpparam_t const *xpp,\n \t     xdemitconf_t const *xecfg, xdemitcb_t *ecb) {\n@@ -546,6 +560,9 @@ int xdl_diff(mmfile_t *mf1, mmfile_t *mf2, xpparam_t const *xpp,\n \temit_func_t ef = xecfg->emit_func ?\n \t\t(emit_func_t)xecfg->emit_func : xdl_emit_diff;\n \n+\tif (xecfg->hunk_func)\n+\t\tef = xdl_call_hunk_func;\n+\n \tif (xdl_do_diff(mf1, mf2, xpp, &xe) < 0) {\n \n \t\treturn -1;\n-- \n1.7.10.1\n"},{"id":"191227","messageId":"4FAAD1E4.30906@lsrfire.ath.cx","threadId":"30485","inReplyTo":"4FAAD13E.8030806@lsrfire.ath.cx","subject":"[PATCH 2/5] blame: use hunk_func(), part 1","fromName":"René Scharfe","fromEmail":"rene.scharfe@lsrfire.ath.cx","sentAt":"2012-05-09T20:21:56Z","receivedAt":"2012-05-09T20:21:56Z","isPatch":true,"sender":{"key":"l.s.r@web.de","avatar":"https://avatars.githubusercontent.com/u/26122331?v=4"},"body":"Use blame_chunk_cb() directly as hunk_func() callback, without detour\nthrough xdi_diff_hunks().\n\nSigned-off-by: Rene Scharfe <rene.scharfe@lsrfire.ath.cx>\n---\n builtin/blame.c |   17 ++++++++++++-----\n 1 file changed, 12 insertions(+), 5 deletions(-)\n\ndiff --git a/builtin/blame.c b/builtin/blame.c\nindex 324d476..9ae5cf3 100644\n--- a/builtin/blame.c\n+++ b/builtin/blame.c\n@@ -759,12 +759,14 @@ struct blame_chunk_cb_data {\n \tlong tlno;\n };\n \n-static void blame_chunk_cb(void *data, long same, long p_next, long t_next)\n+static int blame_chunk_cb(long start_a, long count_a,\n+\t\t\t  long start_b, long count_b, void *data)\n {\n \tstruct blame_chunk_cb_data *d = data;\n-\tblame_chunk(d->sb, d->tlno, d->plno, same, d->target, d->parent);\n-\td->plno = p_next;\n-\td->tlno = t_next;\n+\tblame_chunk(d->sb, d->tlno, d->plno, start_b, d->target, d->parent);\n+\td->plno = start_a + count_a;\n+\td->tlno = start_b + count_b;\n+\treturn 0;\n }\n \n /*\n@@ -781,6 +783,8 @@ static int pass_blame_to_parent(struct scoreboard *sb,\n \tstruct blame_chunk_cb_data d;\n \txpparam_t xpp;\n \txdemitconf_t xecfg;\n+\txdemitcb_t ecb;\n+\n \tmemset(&d, 0, sizeof(d));\n \td.sb = sb; d.target = target; d.parent = parent;\n \tlast_in_target = find_last_in_target(sb, target);\n@@ -795,7 +799,10 @@ static int pass_blame_to_parent(struct scoreboard *sb,\n \txpp.flags = xdl_opts;\n \tmemset(&xecfg, 0, sizeof(xecfg));\n \txecfg.ctxlen = 0;\n-\txdi_diff_hunks(&file_p, &file_o, blame_chunk_cb, &d, &xpp, &xecfg);\n+\txecfg.hunk_func = blame_chunk_cb;\n+\tmemset(&ecb, 0, sizeof(ecb));\n+\tecb.priv = &d;\n+\txdi_diff(&file_p, &file_o, &xpp, &xecfg, &ecb);\n \t/* The rest (i.e. anything after tlno) are the same as the parent */\n \tblame_chunk(sb, d.tlno, d.plno, last_in_target, target, parent);\n \n-- \n1.7.10.1\n"},{"id":"191229","messageId":"4FAAD217.6040702@lsrfire.ath.cx","threadId":"30485","inReplyTo":"4FAAD13E.8030806@lsrfire.ath.cx","subject":"[PATCH 3/5] blame: use hunk_func(), part 2","fromName":"René Scharfe","fromEmail":"rene.scharfe@lsrfire.ath.cx","sentAt":"2012-05-09T20:22:47Z","receivedAt":"2012-05-09T20:22:47Z","isPatch":true,"sender":{"key":"l.s.r@web.de","avatar":"https://avatars.githubusercontent.com/u/26122331?v=4"},"body":"Use handle_split_cb() directly as hunk_func() callback, without going\nthrough xdi_diff_hunks().\n\nSigned-off-by: Rene Scharfe <rene.scharfe@lsrfire.ath.cx>\n---\n builtin/blame.c |   18 +++++++++++++-----\n 1 file changed, 13 insertions(+), 5 deletions(-)\n\ndiff --git a/builtin/blame.c b/builtin/blame.c\nindex 9ae5cf3..c83fc7c 100644\n--- a/builtin/blame.c\n+++ b/builtin/blame.c\n@@ -906,12 +906,15 @@ struct handle_split_cb_data {\n \tlong tlno;\n };\n \n-static void handle_split_cb(void *data, long same, long p_next, long t_next)\n+static int handle_split_cb(long start_a, long count_a,\n+\t\t\t   long start_b, long count_b, void *data)\n {\n \tstruct handle_split_cb_data *d = data;\n-\thandle_split(d->sb, d->ent, d->tlno, d->plno, same, d->parent, d->split);\n-\td->plno = p_next;\n-\td->tlno = t_next;\n+\thandle_split(d->sb, d->ent, d->tlno, d->plno, start_b, d->parent,\n+\t\t     d->split);\n+\td->plno = start_a + count_a;\n+\td->tlno = start_b + count_b;\n+\treturn 0;\n }\n \n /*\n@@ -931,6 +934,8 @@ static void find_copy_in_blob(struct scoreboard *sb,\n \tstruct handle_split_cb_data d;\n \txpparam_t xpp;\n \txdemitconf_t xecfg;\n+\txdemitcb_t ecb;\n+\n \tmemset(&d, 0, sizeof(d));\n \td.sb = sb; d.ent = ent; d.parent = parent; d.split = split;\n \t/*\n@@ -954,8 +959,11 @@ static void find_copy_in_blob(struct scoreboard *sb,\n \txpp.flags = xdl_opts;\n \tmemset(&xecfg, 0, sizeof(xecfg));\n \txecfg.ctxlen = 1;\n+\txecfg.hunk_func = handle_split_cb;\n+\tmemset(&ecb, 0, sizeof(ecb));\n+\tecb.priv = &d;\n \tmemset(split, 0, sizeof(struct blame_entry [3]));\n-\txdi_diff_hunks(file_p, &file_o, handle_split_cb, &d, &xpp, &xecfg);\n+\txdi_diff(file_p, &file_o, &xpp, &xecfg, &ecb);\n \t/* remainder, if any, all match the preimage */\n \thandle_split(sb, ent, d.tlno, d.plno, ent->num_lines, parent, split);\n }\n-- \n1.7.10.1\n"},{"id":"191230","messageId":"4FAAD24B.3010901@lsrfire.ath.cx","threadId":"30485","inReplyTo":"4FAAD13E.8030806@lsrfire.ath.cx","subject":"[PATCH 4/5] blame: factor out helper for calling xdi_diff()","fromName":"René Scharfe","fromEmail":"rene.scharfe@lsrfire.ath.cx","sentAt":"2012-05-09T20:23:39Z","receivedAt":"2012-05-09T20:23:39Z","isPatch":true,"sender":{"key":"l.s.r@web.de","avatar":"https://avatars.githubusercontent.com/u/26122331?v=4"},"body":"Signed-off-by: Rene Scharfe <rene.scharfe@lsrfire.ath.cx>\n---\n builtin/blame.c |   38 ++++++++++++++++----------------------\n 1 file changed, 16 insertions(+), 22 deletions(-)\n\ndiff --git a/builtin/blame.c b/builtin/blame.c\nindex c83fc7c..778d661 100644\n--- a/builtin/blame.c\n+++ b/builtin/blame.c\n@@ -88,6 +88,20 @@ struct origin {\n \tchar path[FLEX_ARRAY];\n };\n \n+static int diff_hunks(mmfile_t *file_a, mmfile_t *file_b, long ctxlen,\n+\t\t      xdl_emit_hunk_consume_func_t hunk_func, void *cb_data)\n+{\n+\txpparam_t xpp = {0};\n+\txdemitconf_t xecfg = {0};\n+\txdemitcb_t ecb = {0};\n+\n+\txpp.flags = xdl_opts;\n+\txecfg.ctxlen = ctxlen;\n+\txecfg.hunk_func = hunk_func;\n+\tecb.priv = cb_data;\n+\treturn xdi_diff(file_a, file_b, &xpp, &xecfg, &ecb);\n+}\n+\n /*\n  * Prepare diff_filespec and convert it using diff textconv API\n  * if the textconv driver exists.\n@@ -781,9 +795,6 @@ static int pass_blame_to_parent(struct scoreboard *sb,\n \tint last_in_target;\n \tmmfile_t file_p, file_o;\n \tstruct blame_chunk_cb_data d;\n-\txpparam_t xpp;\n-\txdemitconf_t xecfg;\n-\txdemitcb_t ecb;\n \n \tmemset(&d, 0, sizeof(d));\n \td.sb = sb; d.target = target; d.parent = parent;\n@@ -795,14 +806,7 @@ static int pass_blame_to_parent(struct scoreboard *sb,\n \tfill_origin_blob(&sb->revs->diffopt, target, &file_o);\n \tnum_get_patch++;\n \n-\tmemset(&xpp, 0, sizeof(xpp));\n-\txpp.flags = xdl_opts;\n-\tmemset(&xecfg, 0, sizeof(xecfg));\n-\txecfg.ctxlen = 0;\n-\txecfg.hunk_func = blame_chunk_cb;\n-\tmemset(&ecb, 0, sizeof(ecb));\n-\tecb.priv = &d;\n-\txdi_diff(&file_p, &file_o, &xpp, &xecfg, &ecb);\n+\tdiff_hunks(&file_p, &file_o, 0, blame_chunk_cb, &d);\n \t/* The rest (i.e. anything after tlno) are the same as the parent */\n \tblame_chunk(sb, d.tlno, d.plno, last_in_target, target, parent);\n \n@@ -932,9 +936,6 @@ static void find_copy_in_blob(struct scoreboard *sb,\n \tint cnt;\n \tmmfile_t file_o;\n \tstruct handle_split_cb_data d;\n-\txpparam_t xpp;\n-\txdemitconf_t xecfg;\n-\txdemitcb_t ecb;\n \n \tmemset(&d, 0, sizeof(d));\n \td.sb = sb; d.ent = ent; d.parent = parent; d.split = split;\n@@ -955,15 +956,8 @@ static void find_copy_in_blob(struct scoreboard *sb,\n \t * file_o is a part of final image we are annotating.\n \t * file_p partially may match that image.\n \t */\n-\tmemset(&xpp, 0, sizeof(xpp));\n-\txpp.flags = xdl_opts;\n-\tmemset(&xecfg, 0, sizeof(xecfg));\n-\txecfg.ctxlen = 1;\n-\txecfg.hunk_func = handle_split_cb;\n-\tmemset(&ecb, 0, sizeof(ecb));\n-\tecb.priv = &d;\n \tmemset(split, 0, sizeof(struct blame_entry [3]));\n-\txdi_diff(file_p, &file_o, &xpp, &xecfg, &ecb);\n+\tdiff_hunks(file_p, &file_o, 1, handle_split_cb, &d);\n \t/* remainder, if any, all match the preimage */\n \thandle_split(sb, ent, d.tlno, d.plno, ent->num_lines, parent, split);\n }\n-- \n1.7.10.1\n"},{"id":"191231","messageId":"4FAAD282.1060105@lsrfire.ath.cx","threadId":"30485","inReplyTo":"4FAAD13E.8030806@lsrfire.ath.cx","subject":"[PATCH 5/5] xdiff: remove emit_func() and xdi_diff_hunks()","fromName":"René Scharfe","fromEmail":"rene.scharfe@lsrfire.ath.cx","sentAt":"2012-05-09T20:24:34Z","receivedAt":"2012-05-09T20:24:34Z","isPatch":true,"sender":{"key":"l.s.r@web.de","avatar":"https://avatars.githubusercontent.com/u/26122331?v=4"},"body":"The functions are unused now, remove them.\n\nSigned-off-by: Rene Scharfe <rene.scharfe@lsrfire.ath.cx>\n---\n xdiff-interface.c |   44 --------------------------------------------\n xdiff-interface.h |    4 ----\n xdiff/xdiff.h     |    1 -\n xdiff/xdiffi.c    |    6 +-----\n 4 files changed, 1 insertion(+), 54 deletions(-)\n\ndiff --git a/xdiff-interface.c b/xdiff-interface.c\nindex 0e2c169..ecfa05f 100644\n--- a/xdiff-interface.c\n+++ b/xdiff-interface.c\n@@ -156,50 +156,6 @@ int xdi_diff_outf(mmfile_t *mf1, mmfile_t *mf2,\n \treturn ret;\n }\n \n-struct xdiff_emit_hunk_state {\n-\txdiff_emit_hunk_consume_fn consume;\n-\tvoid *consume_callback_data;\n-};\n-\n-static int process_diff(xdfenv_t *xe, xdchange_t *xscr, xdemitcb_t *ecb,\n-\t\t\txdemitconf_t const *xecfg)\n-{\n-\tlong s1, s2, same, p_next, t_next;\n-\txdchange_t *xch, *xche;\n-\tstruct xdiff_emit_hunk_state *state = ecb->priv;\n-\txdiff_emit_hunk_consume_fn fn = state->consume;\n-\tvoid *consume_callback_data = state->consume_callback_data;\n-\n-\tfor (xch = xscr; xch; xch = xche->next) {\n-\t\txche = xdl_get_hunk(xch, xecfg);\n-\n-\t\ts1 = XDL_MAX(xch->i1 - xecfg->ctxlen, 0);\n-\t\ts2 = XDL_MAX(xch->i2 - xecfg->ctxlen, 0);\n-\t\tsame = s2 + XDL_MAX(xch->i1 - s1, 0);\n-\t\tp_next = xche->i1 + xche->chg1;\n-\t\tt_next = xche->i2 + xche->chg2;\n-\n-\t\tfn(consume_callback_data, same, p_next, t_next);\n-\t}\n-\treturn 0;\n-}\n-\n-int xdi_diff_hunks(mmfile_t *mf1, mmfile_t *mf2,\n-\t\t   xdiff_emit_hunk_consume_fn fn, void *consume_callback_data,\n-\t\t   xpparam_t const *xpp, xdemitconf_t *xecfg)\n-{\n-\tstruct xdiff_emit_hunk_state state;\n-\txdemitcb_t ecb;\n-\n-\tmemset(&state, 0, sizeof(state));\n-\tmemset(&ecb, 0, sizeof(ecb));\n-\tstate.consume = fn;\n-\tstate.consume_callback_data = consume_callback_data;\n-\txecfg->emit_func = (void (*)())process_diff;\n-\tecb.priv = &state;\n-\treturn xdi_diff(mf1, mf2, xpp, xecfg, &ecb);\n-}\n-\n int read_mmfile(mmfile_t *ptr, const char *filename)\n {\n \tstruct stat st;\ndiff --git a/xdiff-interface.h b/xdiff-interface.h\nindex 49d1116..eff7762 100644\n--- a/xdiff-interface.h\n+++ b/xdiff-interface.h\n@@ -4,15 +4,11 @@\n #include \"xdiff/xdiff.h\"\n \n typedef void (*xdiff_emit_consume_fn)(void *, char *, unsigned long);\n-typedef void (*xdiff_emit_hunk_consume_fn)(void *, long, long, long);\n \n int xdi_diff(mmfile_t *mf1, mmfile_t *mf2, xpparam_t const *xpp, xdemitconf_t const *xecfg, xdemitcb_t *ecb);\n int xdi_diff_outf(mmfile_t *mf1, mmfile_t *mf2,\n \t\t  xdiff_emit_consume_fn fn, void *consume_callback_data,\n \t\t  xpparam_t const *xpp, xdemitconf_t const *xecfg);\n-int xdi_diff_hunks(mmfile_t *mf1, mmfile_t *mf2,\n-\t\t   xdiff_emit_hunk_consume_fn fn, void *consume_callback_data,\n-\t\t   xpparam_t const *xpp, xdemitconf_t *xecfg);\n int parse_hunk_header(char *line, int len,\n \t\t      int *ob, int *on,\n \t\t      int *nb, int *nn);\ndiff --git a/xdiff/xdiff.h b/xdiff/xdiff.h\nindex 33c010b..219a3bb 100644\n--- a/xdiff/xdiff.h\n+++ b/xdiff/xdiff.h\n@@ -96,7 +96,6 @@ typedef struct s_xdemitconf {\n \tunsigned long flags;\n \tfind_func_t find_func;\n \tvoid *find_func_priv;\n-\tvoid (*emit_func)();\n \txdl_emit_hunk_consume_func_t hunk_func;\n } xdemitconf_t;\n \ndiff --git a/xdiff/xdiffi.c b/xdiff/xdiffi.c\nindex 4d671f4..1b7012a 100644\n--- a/xdiff/xdiffi.c\n+++ b/xdiff/xdiffi.c\n@@ -557,11 +557,7 @@ int xdl_diff(mmfile_t *mf1, mmfile_t *mf2, xpparam_t const *xpp,\n \t     xdemitconf_t const *xecfg, xdemitcb_t *ecb) {\n \txdchange_t *xscr;\n \txdfenv_t xe;\n-\temit_func_t ef = xecfg->emit_func ?\n-\t\t(emit_func_t)xecfg->emit_func : xdl_emit_diff;\n-\n-\tif (xecfg->hunk_func)\n-\t\tef = xdl_call_hunk_func;\n+\temit_func_t ef = xecfg->hunk_func ? xdl_call_hunk_func : xdl_emit_diff;\n \n \tif (xdl_do_diff(mf1, mf2, xpp, &xe) < 0) {\n \n-- \n1.7.10.1\n"},{"id":"191648","messageId":"87aa15hp0e.fsf@thomas.inf.ethz.ch","threadId":"30485","inReplyTo":"4FAAD13E.8030806@lsrfire.ath.cx","subject":"Re: [PATCH 0/5] xdiff: replace emit_func() with type-safe","fromName":"Thomas Rast","fromEmail":"trast@student.ethz.ch","sentAt":"2012-05-18T08:28:17Z","receivedAt":"2012-05-18T08:28:17Z","isPatch":true,"sender":{"key":"tr@thomasrast.ch","avatar":"https://avatars.githubusercontent.com/u/153510?v=4"},"body":"René Scharfe <rene.scharfe@lsrfire.ath.cx> writes:\n\n> Commit ef2e62fe added the ability to bypass the creation of textual diffs\n> and to access diff data directly, through the added emit_func member of\n> xdemitconf_t.  This function pointer has a type of \"void (*)()\", because\n> \"int (*)(xdfenv_t *, xdchange_t *, xdemitcb_t *, xdemitconf_t const *)\"\n> (its real type) would be difficult to export due to the many internal\n> types in that signature.\n>\n> This feature is currently used twice in git blame, through the function\n> xdi_diff_hunks().  Both cases only need to know which lines are affected\n> by the different hunks of a diff, i.e. the numbers shown in hunk headers\n> of unified diffs.\n>\n> This patch series adds a simpler mechanism to accommodate these two\n> callers, in a type-safe way, without exporting too many internal types\n> of libxdiff.  The last patch removes the old functions.\n\nCool, thanks a lot, this will come in handy when I finally get around to\nfinishing log -L.\n\n-- \nThomas Rast\ntrast@{inf,student}.ethz.ch\n"}]}