--- /dev/null
+Return-Path: <markwalters1009@gmail.com>\r
+X-Original-To: notmuch@notmuchmail.org\r
+Delivered-To: notmuch@notmuchmail.org\r
+Received: from localhost (localhost [127.0.0.1])\r
+ by olra.theworths.org (Postfix) with ESMTP id B1028431FB6\r
+ for <notmuch@notmuchmail.org>; Tue, 5 Jun 2012 07:36:44 -0700 (PDT)\r
+X-Virus-Scanned: Debian amavisd-new at olra.theworths.org\r
+X-Spam-Flag: NO\r
+X-Spam-Score: 0.201\r
+X-Spam-Level: \r
+X-Spam-Status: No, score=0.201 tagged_above=-999 required=5\r
+ tests=[DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1,\r
+ FREEMAIL_ENVFROM_END_DIGIT=1, FREEMAIL_FROM=0.001,\r
+ RCVD_IN_DNSWL_LOW=-0.7] autolearn=disabled\r
+Received: from olra.theworths.org ([127.0.0.1])\r
+ by localhost (olra.theworths.org [127.0.0.1]) (amavisd-new, port 10024)\r
+ with ESMTP id uV8m17Ibeigq for <notmuch@notmuchmail.org>;\r
+ Tue, 5 Jun 2012 07:36:42 -0700 (PDT)\r
+Received: from mail-wg0-f45.google.com (mail-wg0-f45.google.com\r
+ [74.125.82.45]) (using TLSv1 with cipher RC4-SHA (128/128 bits)) (No client\r
+ certificate requested) by olra.theworths.org (Postfix) with ESMTPS id\r
+ 8C2CD431FAE for <notmuch@notmuchmail.org>; Tue, 5 Jun 2012 07:36:42 -0700\r
+ (PDT)\r
+Received: by wgbdt14 with SMTP id dt14so4367607wgb.2\r
+ for <notmuch@notmuchmail.org>; Tue, 05 Jun 2012 07:36:39 -0700 (PDT)\r
+DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20120113;\r
+ h=from:to:cc:subject:date:message-id:x-mailer:in-reply-to:references;\r
+ bh=HWxzz8H+vobZV9ooepheMwydwZagFl56U1Ylacl7IMo=;\r
+ b=NZw9goUOlmoSQD9T4S57D54wU5K5A4c2dtBiNfX9ZgB8iZ6IB0eof/CFXbSg/N6Bcd\r
+ x93LF3eIfq3XkBkrwyOx/NrogiQDOfZymXhqYrrsSNustB93r4INq1J+Ln8Hz/g0zRN5\r
+ 655mMI/MT8WRbcNuXIcwC3acDbpaw6pnU7dcUcBn+P9BAVBAuyP9n3pHyZD9sJxG0x2E\r
+ +HihLvZ0WWBbzGhcmUxceA4//YEI/p4YF3CuTgZQVeUKHLdEpkUj3hoEnkt4W+7L20j8\r
+ YJzj4V8vJQkhKBdjxpdbeoP5268QAeRS7tk/YK7hglNi/pzBa0Cavaxd91T6IalzzDqg\r
+ 8mSQ==\r
+Received: by 10.216.206.164 with SMTP id l36mr14126494weo.154.1338906999766;\r
+ Tue, 05 Jun 2012 07:36:39 -0700 (PDT)\r
+Received: from localhost (94-192-233-223.zone6.bethere.co.uk.\r
+ [94.192.233.223]) by mx.google.com with ESMTPS id\r
+ m20sm27402051wie.6.2012.06.05.07.36.37 (version=TLSv1/SSLv3 cipher=OTHER);\r
+ Tue, 05 Jun 2012 07:36:38 -0700 (PDT)\r
+From: Mark Walters <markwalters1009@gmail.com>\r
+To: notmuch@notmuchmail.org\r
+Subject: [PATCH v2] cli: make the command line parser's errors more\r
+ informative.\r
+Date: Tue, 5 Jun 2012 15:36:36 +0100\r
+Message-Id: <1338906996-18720-1-git-send-email-markwalters1009@gmail.com>\r
+X-Mailer: git-send-email 1.7.9.1\r
+In-Reply-To: <87oboxakus.fsf@qmul.ac.uk>\r
+References: <87oboxakus.fsf@qmul.ac.uk>\r
+X-BeenThere: notmuch@notmuchmail.org\r
+X-Mailman-Version: 2.1.13\r
+Precedence: list\r
+List-Id: "Use and development of the notmuch mail system."\r
+ <notmuch.notmuchmail.org>\r
+List-Unsubscribe: <http://notmuchmail.org/mailman/options/notmuch>,\r
+ <mailto:notmuch-request@notmuchmail.org?subject=unsubscribe>\r
+List-Archive: <http://notmuchmail.org/pipermail/notmuch>\r
+List-Post: <mailto:notmuch@notmuchmail.org>\r
+List-Help: <mailto:notmuch-request@notmuchmail.org?subject=help>\r
+List-Subscribe: <http://notmuchmail.org/mailman/listinfo/notmuch>,\r
+ <mailto:notmuch-request@notmuchmail.org?subject=subscribe>\r
+X-List-Received-Date: Tue, 05 Jun 2012 14:36:44 -0000\r
+\r
+Previously, the cli parser was a little erratic in what errors it\r
+reported and would fail silently in many cases (for example, when no\r
+argument was passed to an integer option). This was particularly\r
+annoying as the user could not (easily) tell whether the command\r
+failed or just there were no search results.\r
+\r
+This patch tries to make the handling consistent and return a helpful\r
+error message in all cases.\r
+---\r
+ command-line-arguments.c | 76 ++++++++++++++++++++++++++++++----------------\r
+ 1 files changed, 50 insertions(+), 26 deletions(-)\r
+\r
+diff --git a/command-line-arguments.c b/command-line-arguments.c\r
+index b0a0dab..bf9aeca 100644\r
+--- a/command-line-arguments.c\r
++++ b/command-line-arguments.c\r
+@@ -15,7 +15,7 @@ _process_keyword_arg (const notmuch_opt_desc_t *arg_desc, char next, const char\r
+ \r
+ const notmuch_keyword_t *keywords = arg_desc->keywords;\r
+ \r
+- if (next == 0) {\r
++ if (next == '\0') {\r
+ /* No keyword given */\r
+ arg_str = "";\r
+ }\r
+@@ -29,17 +29,17 @@ _process_keyword_arg (const notmuch_opt_desc_t *arg_desc, char next, const char\r
+ }\r
+ keywords++;\r
+ }\r
+- if (next != 0)\r
+- fprintf (stderr, "unknown keyword: %s\n", arg_str);\r
++ if (next != '\0')\r
++ fprintf (stderr, "Unknown keyword argument \"%s\" for option \"%s\".\n", arg_str, arg_desc->name);\r
+ else\r
+- fprintf (stderr, "option %s needs a keyword\n", arg_desc->name);\r
++ fprintf (stderr, "Option \"%s\" needs a keyword argument.\n", arg_desc->name);\r
+ return FALSE;\r
+ }\r
+ \r
+ static notmuch_bool_t\r
+ _process_boolean_arg (const notmuch_opt_desc_t *arg_desc, char next, const char *arg_str) {\r
+ \r
+- if (next == 0) {\r
++ if (next == '\0') {\r
+ *((notmuch_bool_t *)arg_desc->output_var) = TRUE;\r
+ return TRUE;\r
+ }\r
+@@ -51,9 +51,43 @@ _process_boolean_arg (const notmuch_opt_desc_t *arg_desc, char next, const char\r
+ *((notmuch_bool_t *)arg_desc->output_var) = TRUE;\r
+ return TRUE;\r
+ }\r
++ fprintf (stderr, "Unknown argument \"%s\" for (boolean) option \"%s\".\n", arg_str, arg_desc->name);\r
+ return FALSE;\r
+ }\r
+ \r
++static notmuch_bool_t\r
++_process_int_arg (const notmuch_opt_desc_t *arg_desc, char next, const char *arg_str) {\r
++\r
++ char *endptr;\r
++ if (next == '\0' || arg_str[0] == '\0') {\r
++ fprintf (stderr, "Option \"%s\" needs an integer argument.\n", arg_desc->name);\r
++ return FALSE;\r
++ }\r
++\r
++ *((int *)arg_desc->output_var) = strtol (arg_str, &endptr, 10);\r
++ if (*endptr == '\0')\r
++ return TRUE;\r
++\r
++ fprintf (stderr, "Unable to parse argument \"%s\" for option \"%s\" as an integer.\n",\r
++ arg_str, arg_desc->name);\r
++ return FALSE;\r
++}\r
++\r
++static notmuch_bool_t\r
++_process_string_arg (const notmuch_opt_desc_t *arg_desc, char next, const char *arg_str) {\r
++\r
++ if (next == '\0') {\r
++ fprintf (stderr, "Option \"%s\" needs a string argument.\n", arg_desc->name);\r
++ return FALSE;\r
++ }\r
++ if (arg_str[0] == '\0') {\r
++ fprintf (stderr, "String argument for option \"%s\" must be non-empty.\n", arg_desc->name);\r
++ return FALSE;\r
++ }\r
++ *((const char **)arg_desc->output_var) = arg_str;\r
++ return TRUE;\r
++}\r
++\r
+ /*\r
+ Search for the {pos_arg_index}th position argument, return FALSE if\r
+ that does not exist.\r
+@@ -93,26 +127,19 @@ parse_option (const char *arg,\r
+ \r
+ arg += 2;\r
+ \r
+- const notmuch_opt_desc_t *try = options;\r
+- while (try->opt_type != NOTMUCH_OPT_END) {\r
++ const notmuch_opt_desc_t *try;\r
++ for (try = options; try->opt_type != NOTMUCH_OPT_END; try++) {\r
+ if (try->name && strncmp (arg, try->name, strlen (try->name)) == 0) {\r
+ char next = arg[strlen (try->name)];\r
+ const char *value= arg+strlen(try->name)+1;\r
+ \r
+- char *endptr;\r
+-\r
+- /* Everything but boolean arguments (switches) needs a\r
+- * delimiter, and a non-zero length value. Boolean\r
+- * arguments may take an optional =true or =false value.\r
+- */\r
+- if (next != '=' && next != ':' && next != 0) return FALSE;\r
+- if (next == 0) {\r
+- if (try->opt_type != NOTMUCH_OPT_BOOLEAN &&\r
+- try->opt_type != NOTMUCH_OPT_KEYWORD)\r
+- return FALSE;\r
+- } else {\r
+- if (value[0] == 0) return FALSE;\r
+- }\r
++ /* If we have not reached the end of the argument\r
++ (i.e. the next character is not a space or delimiter)\r
++ then the argument could still match a longer option\r
++ name later in the option table.\r
++ */\r
++ if (next != '=' && next != ':' && next != '\0')\r
++ continue;\r
+ \r
+ if (try->output_var == NULL)\r
+ INTERNAL_ERROR ("output pointer NULL for option %s", try->name);\r
+@@ -125,12 +152,10 @@ parse_option (const char *arg,\r
+ return _process_boolean_arg (try, next, value);\r
+ break;\r
+ case NOTMUCH_OPT_INT:\r
+- *((int *)try->output_var) = strtol (value, &endptr, 10);\r
+- return (*endptr == 0);\r
++ return _process_int_arg (try, next, value);\r
+ break;\r
+ case NOTMUCH_OPT_STRING:\r
+- *((const char **)try->output_var) = value;\r
+- return TRUE;\r
++ return _process_string_arg (try, next, value);\r
+ break;\r
+ case NOTMUCH_OPT_POSITION:\r
+ case NOTMUCH_OPT_END:\r
+@@ -139,7 +164,6 @@ parse_option (const char *arg,\r
+ /*UNREACHED*/\r
+ }\r
+ }\r
+- try++;\r
+ }\r
+ fprintf (stderr, "Unrecognized option: --%s\n", arg);\r
+ return FALSE;\r
+-- \r
+1.7.9.1\r
+\r