From mboxrd@z Thu Jan 1 00:00:00 1970 From: Johannes Schindelin Subject: [PATCH] parse-options: abbreviation engine fix. Date: Mon, 5 Nov 2007 12:34:00 +0000 (GMT) Message-ID: References: <1194264204-3475-1-git-send-email-madcoder@debian.org> <1194264204-3475-2-git-send-email-madcoder@debian.org> Mime-Version: 1.0 Content-Type: TEXT/PLAIN; charset=US-ASCII Cc: Junio C Hamano , git@vger.kernel.org To: Pierre Habouzit X-From: git-owner@vger.kernel.org Mon Nov 05 13:35:09 2007 Return-path: Envelope-to: gcvg-git-2@gmane.org Received: from vger.kernel.org ([209.132.176.167]) by lo.gmane.org with esmtp (Exim 4.50) id 1Ip1Ab-0002M3-0K for gcvg-git-2@gmane.org; Mon, 05 Nov 2007 13:35:09 +0100 Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1754791AbXKEMew (ORCPT ); Mon, 5 Nov 2007 07:34:52 -0500 Received: (majordomo@vger.kernel.org) by vger.kernel.org id S1754787AbXKEMew (ORCPT ); Mon, 5 Nov 2007 07:34:52 -0500 Received: from mail.gmx.net ([213.165.64.20]:48093 "HELO mail.gmx.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with SMTP id S1753522AbXKEMev (ORCPT ); Mon, 5 Nov 2007 07:34:51 -0500 Received: (qmail invoked by alias); 05 Nov 2007 12:34:49 -0000 Received: from unknown (EHLO [138.251.11.74]) [138.251.11.74] by mail.gmx.net (mp040) with SMTP; 05 Nov 2007 13:34:49 +0100 X-Authenticated: #1490710 X-Provags-ID: V01U2FsdGVkX19F4M8HnBlF1B5wM3xQtQabT0crD7cwozLcU9Ezfj EqhVeMD3tqLVEl X-X-Sender: gene099@racer.site In-Reply-To: <1194264204-3475-2-git-send-email-madcoder@debian.org> X-Y-GMX-Trusted: 0 Sender: git-owner@vger.kernel.org Precedence: bulk X-Mailing-List: git@vger.kernel.org Archived-At: When an option could be an ambiguous abbreviation of two options, the code used to error out. Even if an exact match would have occured later. Test and original patch by Pierre Habouzit. Signed-off-by: Johannes Schindelin --- On Mon, 5 Nov 2007, Pierre Habouzit wrote: > When we had at least two long option then followed by another > one that was a prefix of both of them, then the abbreviation > detector failed. Yeah, I assumed that you would never do such a thing, but I agree that with recursing option parsing it is much more likely. It took me some time to understand your patch, and that the moving of the UNSET handling was unnecessary. IMHO this patch is easier to read. parse-options.c | 33 +++++++++++++++++++++------------ t/t0040-parse-options.sh | 13 +++++++++++++ test-parse-options.c | 1 + 3 files changed, 35 insertions(+), 12 deletions(-) diff --git a/parse-options.c b/parse-options.c index cc09c98..15b32f7 100644 --- a/parse-options.c +++ b/parse-options.c @@ -119,8 +119,8 @@ static int parse_long_opt(struct optparse_t *p, const char *arg, const struct option *options) { const char *arg_end = strchr(arg, '='); - const struct option *abbrev_option = NULL; - int abbrev_flags = 0; + const struct option *abbrev_option = NULL, *ambiguous_option = NULL; + int abbrev_flags = 0, ambiguous_flags = 0; if (!arg_end) arg_end = arg + strlen(arg); @@ -137,16 +137,16 @@ static int parse_long_opt(struct optparse_t *p, const char *arg, /* abbreviated? */ if (!strncmp(options->long_name, arg, arg_end - arg)) { is_abbreviated: - if (abbrev_option) - return error("Ambiguous option: %s " - "(could be --%s%s or --%s%s)", - arg, - (flags & OPT_UNSET) ? - "no-" : "", - options->long_name, - (abbrev_flags & OPT_UNSET) ? - "no-" : "", - abbrev_option->long_name); + if (abbrev_option) { + /* + * If this is abbreviated, it is + * ambiguous. So when there is no + * exact match later, we need to + * error out. + */ + ambiguous_option = abbrev_option; + ambiguous_flags = abbrev_flags; + } if (!(flags & OPT_UNSET) && *arg_end) p->opt = arg_end + 1; abbrev_option = options; @@ -176,6 +176,15 @@ is_abbreviated: } return get_value(p, options, flags); } + + if (ambiguous_option) + return error("Ambiguous option: %s " + "(could be --%s%s or --%s%s)", + arg, + (ambiguous_flags & OPT_UNSET) ? "no-" : "", + ambiguous_option->long_name, + (abbrev_flags & OPT_UNSET) ? "no-" : "", + abbrev_option->long_name); if (abbrev_option) return get_value(p, abbrev_option, abbrev_flags); return error("unknown option `%s'", arg); diff --git a/t/t0040-parse-options.sh b/t/t0040-parse-options.sh index ae49424..ee758e5 100755 --- a/t/t0040-parse-options.sh +++ b/t/t0040-parse-options.sh @@ -18,6 +18,7 @@ string options -s, --string get a string --string2 get another string + --st get another string (pervert ordering) EOF @@ -90,4 +91,16 @@ test_expect_failure 'ambiguously abbreviated option' ' test $? != 129 ' +cat > expect << EOF +boolean: 0 +integer: 2 +string: 123 +EOF + +test_expect_failure 'non ambiguous option (after two options it abbreviates)' ' + test-parse-options --st 123 && + test ! -s output.err && + git diff expect output +' + test_done diff --git a/test-parse-options.c b/test-parse-options.c index 277cfe4..4d3e2ec 100644 --- a/test-parse-options.c +++ b/test-parse-options.c @@ -18,6 +18,7 @@ int main(int argc, const char **argv) OPT_GROUP("string options"), OPT_STRING('s', "string", &string, "string", "get a string"), OPT_STRING(0, "string2", &string, "str", "get another string"), + OPT_STRING(0, "st", &string, "st", "get another string (pervert ordering)"), OPT_END(), }; int i; -- 1.5.3.5.1549.g91a3