unofficial mirror of notmuch@notmuchmail.org
 help / color / mirror / code / Atom feed
From: Mark Walters <markwalters1009@gmail.com>
To: notmuch@notmuchmail.org
Subject: [PATCH v2] cli: make the command line parser's errors more informative.
Date: Tue,  5 Jun 2012 15:36:36 +0100	[thread overview]
Message-ID: <1338906996-18720-1-git-send-email-markwalters1009@gmail.com> (raw)
In-Reply-To: <87oboxakus.fsf@qmul.ac.uk>

Previously, the cli parser was a little erratic in what errors it
reported and would fail silently in many cases (for example, when no
argument was passed to an integer option). This was particularly
annoying as the user could not (easily) tell whether the command
failed or just there were no search results.

This patch tries to make the handling consistent and return a helpful
error message in all cases.
---
 command-line-arguments.c |   76 ++++++++++++++++++++++++++++++----------------
 1 files changed, 50 insertions(+), 26 deletions(-)

diff --git a/command-line-arguments.c b/command-line-arguments.c
index b0a0dab..bf9aeca 100644
--- a/command-line-arguments.c
+++ b/command-line-arguments.c
@@ -15,7 +15,7 @@ _process_keyword_arg (const notmuch_opt_desc_t *arg_desc, char next, const char
 
     const notmuch_keyword_t *keywords = arg_desc->keywords;
 
-    if (next == 0) {
+    if (next == '\0') {
 	/* No keyword given */
 	arg_str = "";
     }
@@ -29,17 +29,17 @@ _process_keyword_arg (const notmuch_opt_desc_t *arg_desc, char next, const char
 	}
 	keywords++;
     }
-    if (next != 0)
-	fprintf (stderr, "unknown keyword: %s\n", arg_str);
+    if (next != '\0')
+	fprintf (stderr, "Unknown keyword argument \"%s\" for option \"%s\".\n", arg_str, arg_desc->name);
     else
-	fprintf (stderr, "option %s needs a keyword\n", arg_desc->name);
+	fprintf (stderr, "Option \"%s\" needs a keyword argument.\n", arg_desc->name);
     return FALSE;
 }
 
 static notmuch_bool_t
 _process_boolean_arg (const notmuch_opt_desc_t *arg_desc, char next, const char *arg_str) {
 
-    if (next == 0) {
+    if (next == '\0') {
 	*((notmuch_bool_t *)arg_desc->output_var) = TRUE;
 	return TRUE;
     }
@@ -51,9 +51,43 @@ _process_boolean_arg (const notmuch_opt_desc_t *arg_desc, char next, const char
 	*((notmuch_bool_t *)arg_desc->output_var) = TRUE;
 	return TRUE;
     }
+    fprintf (stderr, "Unknown argument \"%s\" for (boolean) option \"%s\".\n", arg_str, arg_desc->name);
     return FALSE;
 }
 
+static notmuch_bool_t
+_process_int_arg (const notmuch_opt_desc_t *arg_desc, char next, const char *arg_str) {
+
+    char *endptr;
+    if (next == '\0' || arg_str[0] == '\0') {
+	fprintf (stderr, "Option \"%s\" needs an integer argument.\n", arg_desc->name);
+	return FALSE;
+    }
+
+    *((int *)arg_desc->output_var) = strtol (arg_str, &endptr, 10);
+    if (*endptr == '\0')
+	return TRUE;
+
+    fprintf (stderr, "Unable to parse argument \"%s\" for option \"%s\" as an integer.\n",
+	     arg_str, arg_desc->name);
+    return FALSE;
+}
+
+static notmuch_bool_t
+_process_string_arg (const notmuch_opt_desc_t *arg_desc, char next, const char *arg_str) {
+
+    if (next == '\0') {
+	fprintf (stderr, "Option \"%s\" needs a string argument.\n", arg_desc->name);
+	return FALSE;
+    }
+    if (arg_str[0] == '\0') {
+	fprintf (stderr, "String argument for option \"%s\" must be non-empty.\n", arg_desc->name);
+	return FALSE;
+    }
+    *((const char **)arg_desc->output_var) = arg_str;
+    return TRUE;
+}
+
 /*
    Search for the {pos_arg_index}th position argument, return FALSE if
    that does not exist.
@@ -93,26 +127,19 @@ parse_option (const char *arg,
 
     arg += 2;
 
-    const notmuch_opt_desc_t *try = options;
-    while (try->opt_type != NOTMUCH_OPT_END) {
+    const notmuch_opt_desc_t *try;
+    for (try = options; try->opt_type != NOTMUCH_OPT_END; try++) {
 	if (try->name && strncmp (arg, try->name, strlen (try->name)) == 0) {
 	    char next = arg[strlen (try->name)];
 	    const char *value= arg+strlen(try->name)+1;
 
-	    char *endptr;
-
-	    /* Everything but boolean arguments (switches) needs a
-	     * delimiter, and a non-zero length value. Boolean
-	     * arguments may take an optional =true or =false value.
-	     */
-	    if (next != '=' && next != ':' && next != 0) return FALSE;
-	    if (next == 0) {
-		if (try->opt_type != NOTMUCH_OPT_BOOLEAN &&
-		    try->opt_type != NOTMUCH_OPT_KEYWORD)
-		    return FALSE;
-	    } else {
-		if (value[0] == 0) return FALSE;
-	    }
+	    /* If we have not reached the end of the argument
+	       (i.e. the next character is not a space or delimiter)
+	       then the argument could still match a longer option
+	       name later in the option table.
+	    */
+	    if (next != '=' && next != ':' && next != '\0')
+		continue;
 
 	    if (try->output_var == NULL)
 		INTERNAL_ERROR ("output pointer NULL for option %s", try->name);
@@ -125,12 +152,10 @@ parse_option (const char *arg,
 		return _process_boolean_arg (try, next, value);
 		break;
 	    case NOTMUCH_OPT_INT:
-		*((int *)try->output_var) = strtol (value, &endptr, 10);
-		return (*endptr == 0);
+		return _process_int_arg (try, next, value);
 		break;
 	    case NOTMUCH_OPT_STRING:
-		*((const char **)try->output_var) = value;
-		return TRUE;
+		return _process_string_arg (try, next, value);
 		break;
 	    case NOTMUCH_OPT_POSITION:
 	    case NOTMUCH_OPT_END:
@@ -139,7 +164,6 @@ parse_option (const char *arg,
 		/*UNREACHED*/
 	    }
 	}
-	try++;
     }
     fprintf (stderr, "Unrecognized option: --%s\n", arg);
     return FALSE;
-- 
1.7.9.1

  reply	other threads:[~2012-06-05 14:36 UTC|newest]

Thread overview: 12+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2012-06-03 11:46 [Patch v7 0/6] Allow JSON to use non-entire thread, and use for elide Mark Walters
2012-06-03 11:46 ` [Patch v7 1/6] cli: command line parsing: allow default for keyword options Mark Walters
2012-06-03 11:46 ` [Patch v7 2/6] cli: Let json output "null" messages for non --entire-thread Mark Walters
2012-06-03 11:46 ` [Patch v7 3/6] cli: make --entire-thread=false work for format=json Mark Walters
2012-06-03 11:46 ` [Patch v7 4/6] Update devel/schemata for --entire-thread=false Mark Walters
2012-06-03 11:46 ` [Patch v7 5/6] emacs: make elide messages use notmuch-show for omitting messages Mark Walters
2012-06-03 11:46 ` [Patch v7 6/6] cli: notmuch-show.c fix whitespace error Mark Walters
2012-06-03 11:48 ` [PATCH] cli: make the command line parser's errors more informative Mark Walters
2012-06-05  8:40   ` Peter Wang
2012-06-05 14:34     ` Mark Walters
2012-06-05 14:36       ` Mark Walters [this message]
2012-09-02  2:35         ` [PATCH v2] " David Bremner

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

  List information: https://notmuchmail.org/

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=1338906996-18720-1-git-send-email-markwalters1009@gmail.com \
    --to=markwalters1009@gmail.com \
    --cc=notmuch@notmuchmail.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
Code repositories for project(s) associated with this public inbox

	https://yhetil.org/notmuch.git/

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).