{"thread":{"id":"5316","subject":"[PATCH] cleans up builtin-mv","startedAt":"2006-08-18T05:59:22Z","lastAt":"2006-08-19T01:26:39Z","messageCount":8,"participants":["David Rientjes","Johannes Schindelin","Josef Weidendorfer","Junio C Hamano"],"isPatch":true,"patchVersion":1,"patchTotal":null},"messages":[{"id":"25525","messageId":"Pine.LNX.4.63.0608172230470.25827@chino.corp.google.com","threadId":"5316","inReplyTo":null,"subject":"[PATCH] cleans up builtin-mv","fromName":"David Rientjes","fromEmail":"rientjes@google.com","sentAt":"2006-08-18T05:59:22Z","receivedAt":"2006-08-18T05:59:22Z","isPatch":true,"sender":{"key":"rientjes@google.com","avatar":null},"body":"Cleans up builtin-mv by removing a needless check of source's length, \nredefinition of source's length, and misuse of strlen call that was \nalready assigned.\n\nSigned-off-by: David Rientjes <rientjes@google.com>\n---\n builtin-mv.c |   14 +++++++-------\n 1 files changed, 7 insertions(+), 7 deletions(-)\n\ndiff --git a/builtin-mv.c b/builtin-mv.c\nindex c0c8764..54c9262 100644\n--- a/builtin-mv.c\n+++ b/builtin-mv.c\n@@ -126,7 +126,7 @@ int cmd_mv(int argc, const char **argv, \n \n \t/* Checking */\n \tfor (i = 0; i < count; i++) {\n-\t\tint length;\n+\t\tint length = strlen(source[i]);\n \t\tconst char *bad = NULL;\n \n \t\tif (show_only)\n@@ -137,14 +137,13 @@ int cmd_mv(int argc, const char **argv, \n \t\t\tbad = \"bad source\";\n \n \t\tif (!bad &&\n-\t\t    (length = strlen(source[i])) >= 0 &&\n \t\t    !strncmp(destination[i], source[i], length) &&\n \t\t    (destination[i][length] == 0 || destination[i][length] == '/'))\n \t\t\tbad = \"can not move directory into itself\";\n \n \t\tif (S_ISDIR(st.st_mode)) {\n \t\t\tconst char *dir = source[i], *dest_dir = destination[i];\n-\t\t\tint first, last, len = strlen(dir);\n+\t\t\tint first, last;\n \n \t\t\tif (lstat(dest_dir, &st) == 0) {\n \t\t\t\tbad = \"cannot move directory over file\";\n@@ -153,14 +152,15 @@ int cmd_mv(int argc, const char **argv, \n \n \t\t\tmodes[i] = WORKING_DIRECTORY;\n \n-\t\t\tfirst = cache_name_pos(source[i], len);\n+\t\t\tfirst = cache_name_pos(source[i], length);\n \t\t\tif (first >= 0)\n \t\t\t\tdie (\"Huh? %s/ is in index?\", dir);\n \n \t\t\tfirst = -1 - first;\n \t\t\tfor (last = first; last < active_nr; last++) {\n \t\t\t\tconst char *path = active_cache[last]->name;\n-\t\t\t\tif (strncmp(path, dir, len) || path[len] != '/')\n+\t\t\t\tif (strncmp(path, dir, length) ||\n+\t\t\t\t    path[length] != '/')\n \t\t\t\t\tbreak;\n \t\t\t}\n \n@@ -189,7 +189,7 @@ int cmd_mv(int argc, const char **argv, \n \t\t\t\t\tsource[count + j] = path;\n \t\t\t\t\tdestination[count + j] =\n \t\t\t\t\t\tprefix_path(dest_dir, dst_len,\n-\t\t\t\t\t\t\tpath + len);\n+\t\t\t\t\t\t\tpath + length);\n \t\t\t\t\tmodes[count + j] = INDEX;\n \t\t\t\t}\n \t\t\t\tcount += last - first;\n@@ -217,7 +217,7 @@ int cmd_mv(int argc, const char **argv, \n \t\t\t}\n \t\t}\n \n-\t\tif (!bad && cache_name_pos(source[i], strlen(source[i])) < 0)\n+\t\tif (!bad && cache_name_pos(source[i], length) < 0)\n \t\t\tbad = \"not under version control\";\n \n \t\tif (!bad) {\n-- \n1.4.2.rc4.g55c3-dirty\n"},{"id":"25527","messageId":"Pine.LNX.4.63.0608172301520.25827@chino.corp.google.com","threadId":"5316","inReplyTo":"Pine.LNX.4.63.0608172230470.25827@chino.corp.google.com","subject":"Re: [PATCH] cleans up builtin-mv","fromName":"David Rientjes","fromEmail":"rientjes@google.com","sentAt":"2006-08-18T06:12:02Z","receivedAt":"2006-08-18T06:12:02Z","isPatch":true,"sender":{"key":"rientjes@google.com","avatar":null},"body":"On Thu, 17 Aug 2006, David Rientjes wrote:\n\n> Cleans up builtin-mv by removing a needless check of source's length, \n> redefinition of source's length, and misuse of strlen call that was \n> already assigned.\n> \n\nI'm not sure when this command had been added to the tree because it \ndefinitely was not included six months ago in a git tree I use everyday.  \nIt seems to me like this would more appropriately be handled by a simple \nshell script that would be much simpler to implement and could not \npossibly be slower than this implementation.\n\nThis patch is a small fraction of what could be changed in this \nimplementation and I don't doubt it will undergo a complete rewrite in the \nfuture.  I think the problems with it have compounded on top of itself \nover time which doesn't make a lot of sense since it appears to be a \nrelatively new addition.\n\nFor example:\n\t(length = strlen(source[i])) >= 0\n\nwas _completely_ unnecessary since the previous instruction was a call to \nlstat(source[i], ...) which would return ENOENT if source[i] was empty.  \nstrlen(source[i]) was assigned to a variable later in the function, this \ntime called \"len\" instead.  There was also an additional call to \nstrlen(source[i]) on its own even though the len variable was within \nscope.\n\nThis code is _utterly_ unsatisfactory.\n\n\t\tDavid\n"},{"id":"25534","messageId":"Pine.LNX.4.63.0608181137000.28360@wbgn013.biozentrum.uni-wuerzburg.de","threadId":"5316","inReplyTo":"Pine.LNX.4.63.0608172301520.25827@chino.corp.google.com","subject":"Re: [PATCH] cleans up builtin-mv","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2006-08-18T09:51:47Z","receivedAt":"2006-08-18T09:51:47Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Hi,\n\nOn Thu, 17 Aug 2006, David Rientjes wrote:\n\n> On Thu, 17 Aug 2006, David Rientjes wrote:\n> \n> > Cleans up builtin-mv by removing a needless check of source's length, \n> > redefinition of source's length, and misuse of strlen call that was \n> > already assigned.\n> > \n> \n> I'm not sure when this command had been added to the tree\n\nTip of the day: \"git log builtin-mv.c\"\n\n> because it definitely was not included six months ago in a git tree I \n> use everyday.  It seems to me like this would more appropriately be \n> handled by a simple shell script\n\nNooooooo!\n\nFirst, it _was_ a perl script, which you probably could find out by \nchecking your old git.\n\nSecond, it was rewritten to use Git.pm, and because _that_ did not work, \ngit-mv was rewritten as a builtin.\n\n> that would be much simpler to implement and could not possibly be slower \n> than this implementation.\n\nNot slower? I beg to differ, admitting it is only a few percent. But your \nstatement is obviously uncorrect.\n\nAs for the \"simpler to implement\": \"harder to port\" comes into mind. And \ndo not try to argue that everybody and his dog could switch to Linux.\n\n> This patch is a small fraction of what could be changed in this \n> implementation and I don't doubt it will undergo a complete rewrite in \n> the future.\n\nWell, the patch has an improvement factor of almost none. I actually read \nthe patch, and asked myself: why would anybody fix a non-problem?\n\n> I think the problems with it have compounded on top of itself over time \n> which doesn't make a lot of sense since it appears to be a relatively \n> new addition.\n> \n> For example:\n> \t(length = strlen(source[i])) >= 0\n\nYes. Taken out of context, this sure sounds silly.\n\nWhat you cleverly did not mention: It was inside a\n\n\tif (!bad &&\n\t\t(length = strlen(source[i])) >= 0 &&\n\t\t!strncmp(destination[i], source[i], length) &&\n\t\t(destination[i][length] == 0 || destination[i][length] == '/'))\n\nconstruct. So, we assign the \"length\" variable only if we have to. And the \n\">= 0\" trick is a common one. I could have done\n\n\t\t!strncmp(destination[i], source[i], (length = strlen(source[i])))\n\nbut even I find that ugly.\n\t\t\n> was _completely_ unnecessary since the previous instruction was a call to \n> lstat(source[i], ...) which would return ENOENT if source[i] was empty.  \n\nClarified enough?\n\n> strlen(source[i]) was assigned to a variable later in the function, this \n> time called \"len\" instead.\n\nOnly if source[i] is a directory. So again, we only do it when we need to.\n\n> This code is _utterly_ unsatisfactory.\n\nI disagree.\n\nWhat is unsatisfactory to me is that I expected some performance \nimprovements from one of your earlier mails, and I see patches which \nrearrange working code. This _can_ result in performance improvements, but \nin these cases, no, it doesn't.\n\nHaving said that, I do not have anything against the patch being applied, \nbut if I see more of these i-would-like-the-cupboard-here-not-there \npatches, I will just not review them any more.\n\nCiao,\nDscho\n"},{"id":"25574","messageId":"Pine.LNX.4.63.0608180956100.29405@chino.corp.google.com","threadId":"5316","inReplyTo":"Pine.LNX.4.63.0608181137000.28360@wbgn013.biozentrum.uni-wuerzburg.de","subject":"Re: [PATCH] cleans up builtin-mv","fromName":"David Rientjes","fromEmail":"rientjes@google.com","sentAt":"2006-08-18T17:07:25Z","receivedAt":"2006-08-18T17:07:25Z","isPatch":true,"sender":{"key":"rientjes@google.com","avatar":null},"body":"On Fri, 18 Aug 2006, Johannes Schindelin wrote:\n\n> First, it _was_ a perl script, which you probably could find out by \n> checking your old git.\n> \n> Second, it was rewritten to use Git.pm, and because _that_ did not work, \n> git-mv was rewritten as a builtin.\n> \n\nIt shouldn't have ever been a perl script, it should have been /bin/sh.  \nAny shell implementation of this would be significantly faster than the \ncurrent implementation.\n\n> Not slower? I beg to differ, admitting it is only a few percent. But your \n> statement is obviously uncorrect.\n> \n\nIt _is_ slower since it takes considerably more time to do its job than \nany corresponding shell script.\n\n> Well, the patch has an improvement factor of almost none. I actually read \n> the patch, and asked myself: why would anybody fix a non-problem?\n> \n\nBecause it's _wrong_.  Secondly, it's WRONG.\n\n> > For example:\n> > \t(length = strlen(source[i])) >= 0\n> \n> Yes. Taken out of context, this sure sounds silly.\n> \n> What you cleverly did not mention: It was inside a\n> \n> \tif (!bad &&\n> \t\t(length = strlen(source[i])) >= 0 &&\n> \t\t!strncmp(destination[i], source[i], length) &&\n> \t\t(destination[i][length] == 0 || destination[i][length] == '/'))\n> \n> construct. So, we assign the \"length\" variable only if we have to. And the \n> \">= 0\" trick is a common one. I could have done\n> \t\t\n\nThis is not a plausible justification _at all_.  The idea that \"length\" is \nassigned only on the condition that lstat(path, ...) failed does not \njustify its comparison to >= 0 since this comparison is always true, nor \ndoes it justify the assignment of\n\n\tchar *dir = source[i];\n\tint len = strlen(dir);\n\nlater.\n\n> > strlen(source[i]) was assigned to a variable later in the function, this \n> > time called \"len\" instead.\n> \n> Only if source[i] is a directory. So again, we only do it when we need to.\n> \n\nYou're completely ignoring the point, and more importantly, ignoring the \ncode path.  Your implementation would have _always_ assigned \nstrlen(source[i]) to \"length\" if lstat returned 0.  So at this point in \nthe code, \"length\" is always equal to strlen(source[i]).  But your code \nintroduces another call to strlen, another variable, and another \nassignment.\n\n> Having said that, I do not have anything against the patch being applied, \n> but if I see more of these i-would-like-the-cupboard-here-not-there \n> patches, I will just not review them any more.\n> \n\nMy patch is correct and improves your code.  Any criticism for such a \npatch has purely personal motives, and not technical motives, assigned to \nit.\n\n\t\tDavid\n"},{"id":"25581","messageId":"200608182035.47208.Josef.Weidendorfer@gmx.de","threadId":"5316","inReplyTo":"Pine.LNX.4.63.0608180956100.29405@chino.corp.google.com","subject":"Re: [PATCH] cleans up builtin-mv","fromName":"Josef Weidendorfer","fromEmail":"josef.weidendorfer@gmx.de","sentAt":"2006-08-18T18:35:46Z","receivedAt":"2006-08-18T18:35:46Z","isPatch":true,"sender":{"key":"josef.weidendorfer@gmx.de","avatar":null},"body":"On Friday 18 August 2006 19:07, David Rientjes wrote:\n> It shouldn't have ever been a perl script, it should have been /bin/sh.  \n> Any shell implementation of this would be significantly faster than the \n> current implementation.\n\nCan you explain your reasoning in more detail?\nC compiles to native code. Bash itself first has to\nparse the script. How on earth can this be faster than native code?\n\nI simply do not understand this discussion about implementation language,\nespecially in this case where most of the work is probably done changing\ngit's index (the add's and rm's of tree entries). Of course it could have\nbeen done in /bin/sh, but it wasn't (it started as git-rename.perl).\n\nThe portability argument speaks for C, thus I agree with Dscho.\n\n> > \tif (!bad &&\n> > \t\t(length = strlen(source[i])) >= 0 &&\n> > \t\t!strncmp(destination[i], source[i], length) &&\n> > \t\t(destination[i][length] == 0 || destination[i][length] == '/'))\n> > \n> > construct. So, we assign the \"length\" variable only if we have to. And the \n> > \">= 0\" trick is a common one. I could have done\n> > \t\t\n> \n> This is not a plausible justification _at all_.\n\nHmm... I suppose Dscho's argument was that this \"... >=0\" is a standard way\nto code an assignment inside of an expression.\n\nJosef\n"},{"id":"25582","messageId":"Pine.LNX.4.63.0608181143040.30274@chino.corp.google.com","threadId":"5316","inReplyTo":"200608182035.47208.Josef.Weidendorfer@gmx.de","subject":"Re: [PATCH] cleans up builtin-mv","fromName":"David Rientjes","fromEmail":"rientjes@google.com","sentAt":"2006-08-18T19:01:33Z","receivedAt":"2006-08-18T19:01:33Z","isPatch":true,"sender":{"key":"rientjes@google.com","avatar":null},"body":"On Fri, 18 Aug 2006, Josef Weidendorfer wrote:\n\n> Can you explain your reasoning in more detail?\n> C compiles to native code. Bash itself first has to\n> parse the script. How on earth can this be faster than native code?\n> \n> I simply do not understand this discussion about implementation language,\n> especially in this case where most of the work is probably done changing\n> git's index (the add's and rm's of tree entries). Of course it could have\n> been done in /bin/sh, but it wasn't (it started as git-rename.perl).\n> \n\nIt's not faster than native code, it's faster than the current \nimplementation of builtin-mv.  And when you're working with terabytes of \ndata like I am, I would prefer to use something fast.\n\n> Hmm... I suppose Dscho's argument was that this \"... >=0\" is a standard way\n> to code an assignment inside of an expression.\n> \n\nThat argument is unjustified since the only advantage of putting it in an \nexpression is to not evaluate it if the lstat failed (and not fail by \nmeans of ENOENT because copy_pathspec guarantees all results have strlen > \n0).  So \"length\" is set unnecessarily only if lstat fails which should \nnever happen if copy_pathspec does it's job with correct arguments.  I'm \nwilling to sacrifice that if the _working_ case is faster (and \nsignificantly faster) especially since this is an iteration and is \ndirectly tied to the command's speed.\n\nThe comparison to 0 simply creates a cmpl $0, x(%ebp) that will always be \ntrue and a jump to a label that never needed to exist.\n\nLikewise, the additional declaration and initilization of a completely \nredundant case call to strlen slows us down FOR EVERY ITERATION OF THE \nMOVE:\n\tmovl\t%eax, x(%ebp)\n\tmovl\t(x*2)(%ebp), %eax\n\tmovl\t$-1, %ecx\n\tmovl\t%eax, (x*4)(%ebp)\n\tmovb\t%0, %al\n\tcld\n\tmovl\t(x*4)(%ebp), %edi\n\trepnz\n\tscasb\n\tmovl\t%ecx, %eax\n\tnotl\t%eax\n\tdecl\t%eax\n\nAnd then repeat that same call again because of its miscall later on when \nit's already been assigned to a variable.\n\n\t\tDavid\n"},{"id":"25583","messageId":"7vbqqh96v2.fsf@assigned-by-dhcp.cox.net","threadId":"5316","inReplyTo":"Pine.LNX.4.63.0608181137000.28360@wbgn013.biozentrum.uni-wuerzburg.de","subject":"Re: [PATCH] cleans up builtin-mv","fromName":"Junio C Hamano","fromEmail":"junkio@cox.net","sentAt":"2006-08-18T19:33:21Z","receivedAt":"2006-08-18T19:33:21Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Johannes Schindelin <Johannes.Schindelin@gmx.de> writes:\n\n> What you cleverly did not mention: It was inside a\n>\n> \tif (!bad &&\n> \t\t(length = strlen(source[i])) >= 0 &&\n> \t\t!strncmp(destination[i], source[i], length) &&\n> \t\t(destination[i][length] == 0 || destination[i][length] == '/'))\n>\n> construct. So, we assign the \"length\" variable only if we have to. And the \n> \">= 0\" trick is a common one. I could have done\n>\n> \t\t!strncmp(destination[i], source[i], (length = strlen(source[i])))\n>\n> but even I find that ugly.\n\nI usually side with you but on this I can't.\n\nThere are 2 ways to generate branch instructions in C.\n\n - compound statements specifically designed for expressing\n   control structure: if () ... else ..., for (), while (),\n   switch (), etc.\n\n - expressions using conditional operators or logical operators\n   that short circuit: ... ? ... : ..., ... && ... || ...\n\nThe latter form may still be readable even with simple side\neffects inside its terms, but \"(l = strlen(s)) >= 0\" is done\nsolely for the side effect, and its computed value does not have\nanything to do with the logical operation &&.\n\nTHIS IS UGLY.  And do not want to live in a world where this\nugliness is a \"common one\", as you put it.\n\nAnd this avoiding one call to strlen(source[i]) is unnecessary\neven as an optimization -- you end up calling strlen() on it\nlater in the code anyway, as David points out.\n\nI think this part is far easier to read if you did it like this:\n \n\t\tlength = strlen(source[i]);\n\t\tif (lstat(source[i], &st) < 0)\n\t\t\tbad = \"bad source\";\n\t\telse if (!strncmp(destination[i], source[i], length) &&\n\t\t\t (destination[i][length] == 0 ||\n\t\t\t  destination[i][length] == '/'))\n\t\t\tbad = \"can not move directory into itself\";\n\n\t\tif (S_ISDIR(st.st_mode)) {\n\t\t\t...\n\nNote that the above is an absolute minimum rewrite.  Other\nthings I noticed are:\n\n - source[i] and destination[i] are referenced all the time; the\n   code would be easer to read if you had something like this\n   upfront:\n\n                /* Checking */\n                for (i = 0; i < count; i++) {\n                        const char *bad = NULL;\n\t\t\tconst char *src = source[i];\n                        const char *dst = destination[i];\n                        int srclen = strlen(src);\n                        int dstlen = strlen(dst);\n\n   You might end up not using dstlen in some cases, but I think\n   this would be far easier to read.  Micro-optimizing by saying\n   \"this is used only in this branch of this later if()\n   statement but in that case it is always set in that branch of\n   that earlier if() statement\" makes unmaintainably confusing\n   code.\n\n - I do not think you need \"const char *dir, *dest_dir\" inside\n   the \"source is directory\" branch; I would just use src and dst\n   consistently;\n\n - You muck with dest_dir by calling add_slash(dest_dir) but\n   call prefix_path() with dst_len you computed earlier;\n   prefix_path() may know what to do, but is this intended?\n"},{"id":"25596","messageId":"Pine.LNX.4.63.0608190323010.28360@wbgn013.biozentrum.uni-wuerzburg.de","threadId":"5316","inReplyTo":"7vbqqh96v2.fsf@assigned-by-dhcp.cox.net","subject":"Re: [PATCH] cleans up builtin-mv","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2006-08-19T01:26:39Z","receivedAt":"2006-08-19T01:26:39Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Hi,\n\nOn Fri, 18 Aug 2006, Junio C Hamano wrote:\n\n> Johannes Schindelin <Johannes.Schindelin@gmx.de> writes:\n> \n> > What you cleverly did not mention: It was inside a\n> >\n> > \tif (!bad &&\n> > \t\t(length = strlen(source[i])) >= 0 &&\n> > \t\t!strncmp(destination[i], source[i], length) &&\n> > \t\t(destination[i][length] == 0 || destination[i][length] == '/'))\n> >\n> > construct. So, we assign the \"length\" variable only if we have to. And the \n> > \">= 0\" trick is a common one. I could have done\n> >\n> > \t\t!strncmp(destination[i], source[i], (length = strlen(source[i])))\n> >\n> > but even I find that ugly.\n> \n> I usually side with you but on this I can't.\n> \n> There are 2 ways to generate branch instructions in C.\n> \n>  - compound statements specifically designed for expressing\n>    control structure: if () ... else ..., for (), while (),\n>    switch (), etc.\n> \n>  - expressions using conditional operators or logical operators\n>    that short circuit: ... ? ... : ..., ... && ... || ...\n> \n> The latter form may still be readable even with simple side\n> effects inside its terms, but \"(l = strlen(s)) >= 0\" is done\n> solely for the side effect, and its computed value does not have\n> anything to do with the logical operation &&.\n> \n> THIS IS UGLY.  And do not want to live in a world where this\n> ugliness is a \"common one\", as you put it.\n\nOkay. Probably the explanation is: I do not use git-mv myself, but only \ngot annoyed enough by a failing t7001 to rewrite it.\n\n> And this avoiding one call to strlen(source[i]) is unnecessary\n> even as an optimization -- you end up calling strlen() on it\n> later in the code anyway, as David points out.\n> \n> I think this part is far easier to read if you did it like this:\n>  \n> \t\tlength = strlen(source[i]);\n> \t\tif (lstat(source[i], &st) < 0)\n> \t\t\tbad = \"bad source\";\n> \t\telse if (!strncmp(destination[i], source[i], length) &&\n> \t\t\t (destination[i][length] == 0 ||\n> \t\t\t  destination[i][length] == '/'))\n> \t\t\tbad = \"can not move directory into itself\";\n> \n> \t\tif (S_ISDIR(st.st_mode)) {\n> \t\t\t...\n> \n> Note that the above is an absolute minimum rewrite.  Other\n> things I noticed are:\n> \n>  - source[i] and destination[i] are referenced all the time; the\n>    code would be easer to read if you had something like this\n>    upfront:\n> \n>                 /* Checking */\n>                 for (i = 0; i < count; i++) {\n>                         const char *bad = NULL;\n> \t\t\tconst char *src = source[i];\n>                         const char *dst = destination[i];\n>                         int srclen = strlen(src);\n>                         int dstlen = strlen(dst);\n> \n>    You might end up not using dstlen in some cases, but I think\n>    this would be far easier to read.  Micro-optimizing by saying\n>    \"this is used only in this branch of this later if()\n>    statement but in that case it is always set in that branch of\n>    that earlier if() statement\" makes unmaintainably confusing\n>    code.\n> \n>  - I do not think you need \"const char *dir, *dest_dir\" inside\n>    the \"source is directory\" branch; I would just use src and dst\n>    consistently;\n\nThese changes would make the source more readable, yes.\n\n>  - You muck with dest_dir by calling add_slash(dest_dir) but\n>    call prefix_path() with dst_len you computed earlier;\n>    prefix_path() may know what to do, but is this intended?\n\nThat is probably a late night oversight.\n\nIf noone else is faster, I will do the requested changes tomorrow.\n\nCiao,\nDscho\n"}]}