git.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH 1/2] api-parse-options.txt: Introduce documentation for parse options API
@ 2008-06-22  0:00 Stephan Beyer
  2008-06-22  0:00 ` [PATCH 2/2] Extend parse-options test suite Stephan Beyer
  2008-06-22 12:49 ` [PATCH 1/2] api-parse-options.txt: Introduce documentation for parse options API Michele Ballabio
  0 siblings, 2 replies; 7+ messages in thread
From: Stephan Beyer @ 2008-06-22  0:00 UTC (permalink / raw)
  To: git; +Cc: Pierre Habouzit, Junio C Hamano, Johannes Schindelin,
	Stephan Beyer

Add some documentation of basics, macros and callback
implementation of the parse-options API.

Signed-off-by: Stephan Beyer <s-beyer@gmx.net>
---
 Documentation/technical/api-parse-options.txt |  206 ++++++++++++++++++++++++-
 1 files changed, 204 insertions(+), 2 deletions(-)

diff --git a/Documentation/technical/api-parse-options.txt b/Documentation/technical/api-parse-options.txt
index b7cda94..a916db4 100644
--- a/Documentation/technical/api-parse-options.txt
+++ b/Documentation/technical/api-parse-options.txt
@@ -1,6 +1,208 @@
 parse-options API
 =================
 
-Talk about <parse-options.h>
+The parse-options API is used to parse and massage options in git
+and to provide a usage help with consistent look.
 
-(Pierre)
+Basics
+------
+
+The argument vector `argv[]` may usually contain mandatory or optional
+'non-option arguments', e.g. a filename or a branch, and 'options'.
+Options are optional arguments that start with a dash and
+that allow to change the behavior of a command.
+
+* There are basically three types of options:
+  'boolean' options,
+  options with (mandatory) 'arguments' and
+  options with 'optional arguments'
+  (i.e. a boolean option that can be adjusted).
+
+* There are basically two forms of options: 
+  'Short options' consist of one dash (`-`) and one alphanumeric
+  character.
+  'Long options' begin with two dashes (`\--`) and some 
+  alphanumeric characters.
+
+* Options are case-sensitive.
+  Please define 'lower-case long options' only.
+
+The parse-options API allows:
+
+* 'sticked' and 'separate form' of options with arguments.
+  `-oArg` is sticked, `-o Arg` is separate form.
+  `\--option=Arg` is sticked, `\--option Arg` is separate form.
+
+* Long options may be 'abbreviated', as long as the abbreviation
+  is unambiguous.
+
+* Short options may be bundled, e.g. `-a -b` can be specified as `-ab`.
+
+* Boolean long options can be 'negated' (or 'unset') by prepending
+  `no-`, e.g. `\--no-abbrev` instead of `\--abbrev`.
+
+* Options and other arguments can clearly be separated using the `\--`
+  option, e.g. `-a -b \--option \-- \--this-is-a-file` indicates that
+  `\--this-is-a-file` must not be processed as an option.
+
+Steps to parse options
+----------------------
+
+. `#include "parse-options.h"`
+
+. define a NULL-terminated
+  `static const char * const builtin_foo_usage[]` array
+  containing alternative usage strings
+
+. define `builtin_foo_options` array as described below
+  in section 'Data Structure'.
+
+. in `cmd_foo(int argc, const char **argv, const char *prefix)`
+  call
+
+	argc = parse_options(argc, argv, builtin_foo_options, builtin_foo_usage, flags);
++
+`parse_options()` will filter out the processed options of `argv[]` and leave the
+non-option arguments in `argv[]`.
+`argc` is updated appropriately because of the assignment.
++
+Flags are the bitwise-or of:
+
+`PARSE_OPT_KEEP_DASHDASH`::
+	Usually long options (`\--long-opt`) are boiled down to their
+	short option equivalent, if available.
+	Using this flag, long options are kept.
+
+`PARSE_OPT_STOP_AT_NON_OPTION`::
+	Usually all options the whole argument vector is massaged
+	and reordered.
+	Using this flag, processing is stopped at the first non-option
+	argument.
+
+Data Structure
+--------------
+
+The main data structure is an array of the `option` struct,
+say `static struct option builtin_add_options[]`.
+There are some macros to easily define options:
+
+`OPT__ABBREV(&int_var)`::
+	Add `\--abbrev [<n>]`.
+
+`OPT__DRY_RUN(&int_var)`::
+	Add `-n, \--dry-run`.
+
+`OPT__QUIET(&int_var)`::
+	Add `-q, \--quiet`.
+
+`OPT__VERBOSE(&int_var)`::
+	Add `-v, \--verbose`.
+
+`OPT_GROUP(description)`::
+	Start an option group. `description` is a short string that
+	describes the group or an empty string.
+	Start the description with an upper-case letter.
+
+`OPT_BOOLEAN(short, long, &int_var, description)`::
+	Introduce a boolean option.
+	`int_var` is incremented on each use.
+
+`OPT_BIT(short, long, &int_var, description, mask)`::
+	Introduce a boolean option.
+	If used, `int_var` is bitwise-ored with `mask`.
+
+`OPT_SET_INT(short, long, &int_var, description, integer)`::
+	Introduce a boolean option.
+	If used, set `int_var` to `integer`.
+
+`OPT_SET_PTR(short, long, &ptr_var, description, ptr)`::
+	Introduce a boolean option.
+	If used, set `ptr_var` to `ptr`.
+
+`OPT_STRING(short, long, &str_var, arg_str, description)`::
+	Introduce an option with string argument.
+	The string argument is put into `str_var`.
+
+`OPT_INTEGER(short, long, &int_var, description)`::
+	Introduce an option with integer argument.
+	The integer is put into `int_var`.
+
+`OPT_DATE(short, long, &int_var, description)`::
+	Introduce an option with date argument, see `approxidate()`.
+	The timestamp is put into `int_var`.
+
+`OPT_CALLBACK(short, long, &var, arg_str, description, func_ptr)`::
+	Introduce an option with argument.
+	The argument will be fed into the function given by `func_ptr`
+	and the result will be put into `var`.
+	See 'Option Callbacks' below for a more elaborate description.
+
+`OPT_ARGUMENT(long, description)`::
+	Introduce a long-option argument that will be kept in `argv[]`.
+
+
+The last element of the array must be `OPT_END()`.
+
+If not stated otherwise, interpret the arguments as follows:
+
+* `short` is a character for the short option
+  (e.g. `\'e\'` for `-e`, use `0` to omit),
+
+* `long` is a string for the long option
+  (e.g. `"example"` for `\--example`, use `NULL` to omit),
+
+* `int_var` is an integer variable,
+
+* `str_var` is a string variable (`char *`),
+
+* `arg_str` is the string that is shown as argument
+  (e.g. `"branch"` will result in `<branch>`).
+  If set to `NULL`, three dots (`...`) will be displayed.
+
+* `description` is a short string to describe the effect of the option.
+  It shall begin with a lower-case letter and a full stop (`.`) shall be
+  omitted at the end.
+
+Option Callbacks
+----------------
+
+The function must be defined in this form:
+
+	int func(const struct option *opt, const char *arg, int unset)
+
+The callback mechanism is as follows:
+
+* Inside `funct`, the only interesting member of the structure
+  given by `opt` is the void pointer `opt->value`.
+  `\*opt->value` will be the value that is saved into `var`, if you
+  use `OPT_CALLBACK()`.
+  For example, do `*(unsigned long *)opt->value = 42;` to get 42
+  into an `unsigned long` variable.
+
+* Return value `0` indicates success and non-zero return
+  value will invoke `usage_with_options()` and, thus, die.
+
+* If the user negates the option, `arg` is `NULL` and `unset` is 1.
+
+Sophisticated option parsing
+----------------------------
+
+If you need, for example, option callbacks with optional arguments
+or without arguments at all, or if you need other special cases,
+that are not handled by the macros above, you need to specify the
+members of the `option` structure manually.
+
+This is not covered in this document, but well documented
+in `parse-options.h` itself.
+
+Examples
+--------
+
+See `test-parse-options.c` and
+`builtin-add.c`,
+`builtin-clone.c`,
+`builtin-commit.c`,
+`builtin-fetch.c`,
+`builtin-fsck.c`,
+`builtin-rm.c`
+for real-world examples.
-- 
1.5.6.310.g344d

^ permalink raw reply related	[flat|nested] 7+ messages in thread

* [PATCH 2/2] Extend parse-options test suite
  2008-06-22  0:00 [PATCH 1/2] api-parse-options.txt: Introduce documentation for parse options API Stephan Beyer
@ 2008-06-22  0:00 ` Stephan Beyer
  2008-06-22 12:49 ` [PATCH 1/2] api-parse-options.txt: Introduce documentation for parse options API Michele Ballabio
  1 sibling, 0 replies; 7+ messages in thread
From: Stephan Beyer @ 2008-06-22  0:00 UTC (permalink / raw)
  To: git; +Cc: Pierre Habouzit, Junio C Hamano, Johannes Schindelin,
	Stephan Beyer

This patch serves two purposes:
 1. test-parse-option.c should be a more complete
    example for the parse-options API, and
 2. there have been no tests for OPT_CALLBACK,
    OPT_DATE, OPT_BIT, OPT_SET_INT and OPT_SET_PTR
    before.

Signed-off-by: Stephan Beyer <s-beyer@gmx.net>
---
On reviewing you should perhaps first have a look at the .c file,
then the changes of t0040 make more sense.

 t/t0040-parse-options.sh |  116 +++++++++++++++++++++++++++++++++++++++++++---
 test-parse-options.c     |   39 ++++++++++++++--
 2 files changed, 144 insertions(+), 11 deletions(-)

diff --git a/t/t0040-parse-options.sh b/t/t0040-parse-options.sh
index 9965cfa..87c6164 100755
--- a/t/t0040-parse-options.sh
+++ b/t/t0040-parse-options.sh
@@ -11,23 +11,35 @@ cat > expect.err << EOF
 usage: test-parse-options <options>
 
     -b, --boolean         get a boolean
+    -4, --or4             bitwise-or boolean with ...0100
+
     -i, --integer <n>     get a integer
     -j <n>                get a integer, too
+    --set23               set integer to 23
+    -t <time>             get timestamp of <time>
+    -L, --length <str>    get length of <str>
 
-string options
+String options
     -s, --string <string>
                           get a string
     --string2 <str>       get another string
     --st <st>             get another string (pervert ordering)
     -o <str>              get another string
+    --default-string      set string to default
 
-magic arguments
+Magic arguments
     --quux                means --quux
 
+Standard options
+    --abbrev [<n>]        use <n> digits to display SHA-1s
+    -v, --verbose         be verbose
+    -n, --dry-run         dry run
+    -q, --quiet           be quiet
+
 EOF
 
 test_expect_success 'test help' '
-	! test-parse-options -h > output 2> output.err &&
+	test_must_fail test-parse-options -h > output 2> output.err &&
 	test ! -s output &&
 	test_cmp expect.err output.err
 '
@@ -36,21 +48,31 @@ cat > expect << EOF
 boolean: 2
 integer: 1729
 string: 123
+abbrev: 7
+verbose: 2
+quiet: no
+dry run: yes
 EOF
 
 test_expect_success 'short options' '
-	test-parse-options -s123 -b -i 1729 -b > output 2> output.err &&
+	test-parse-options -s123 -b -i 1729 -b -vv -n > output 2> output.err &&
 	test_cmp expect output &&
 	test ! -s output.err
 '
+
 cat > expect << EOF
 boolean: 2
 integer: 1729
 string: 321
+abbrev: 10
+verbose: 2
+quiet: no
+dry run: no
 EOF
 
 test_expect_success 'long options' '
 	test-parse-options --boolean --integer 1729 --boolean --string2=321 \
+		--verbose --verbose --no-dry-run --abbrev=10 \
 		> output 2> output.err &&
 	test ! -s output.err &&
 	test_cmp expect output
@@ -60,6 +82,10 @@ cat > expect << EOF
 boolean: 1
 integer: 13
 string: 123
+abbrev: 7
+verbose: 0
+quiet: no
+dry run: no
 arg 00: a1
 arg 01: b1
 arg 02: --boolean
@@ -76,6 +102,10 @@ cat > expect << EOF
 boolean: 0
 integer: 2
 string: (not set)
+abbrev: 7
+verbose: 0
+quiet: no
+dry run: no
 EOF
 
 test_expect_success 'unambiguously abbreviated option' '
@@ -99,6 +129,10 @@ cat > expect << EOF
 boolean: 0
 integer: 0
 string: 123
+abbrev: 7
+verbose: 0
+quiet: no
+dry run: no
 EOF
 
 test_expect_success 'non ambiguous option (after two options it abbreviates)' '
@@ -107,20 +141,24 @@ test_expect_success 'non ambiguous option (after two options it abbreviates)' '
 	test_cmp expect output
 '
 
-cat > expect.err << EOF
+cat > typo.err << EOF
 error: did you mean \`--boolean\` (with two dashes ?)
 EOF
 
 test_expect_success 'detect possible typos' '
-	! test-parse-options -boolean > output 2> output.err &&
+	test_must_fail test-parse-options -boolean > output 2> output.err &&
 	test ! -s output &&
-	test_cmp expect.err output.err
+	test_cmp typo.err output.err
 '
 
 cat > expect <<EOF
 boolean: 0
 integer: 0
 string: (not set)
+abbrev: 7
+verbose: 0
+quiet: no
+dry run: no
 arg 00: --quux
 EOF
 
@@ -130,4 +168,68 @@ test_expect_success 'keep some options as arguments' '
         test_cmp expect output
 '
 
+cat > expect <<EOF
+boolean: 0
+integer: 1
+string: default
+abbrev: 7
+verbose: 0
+quiet: yes
+dry run: no
+arg 00: foo
+EOF
+
+test_expect_success 'OPT_DATE() and OPT_SET_PTR() work' '
+	test-parse-options -t "1970-01-01 00:00:01 +0000" --default-string \
+		foo -q > output 2> output.err &&
+	test ! -s output.err &&
+	test_cmp expect output
+'
+
+cat > expect <<EOF
+Callback: "four", 0
+boolean: 5
+integer: 4
+string: (not set)
+abbrev: 7
+verbose: 0
+quiet: no
+dry run: no
+EOF
+
+test_expect_success 'OPT_CALLBACK() and OPT_BIT() work' '
+	test-parse-options --length=four -b -4 > output 2> output.err &&
+	test ! -s output.err &&
+	test_cmp expect output
+'
+
+cat > expect <<EOF
+Callback: "not set", 1
+EOF
+
+test_expect_success 'OPT_CALLBACK() and callback errors work' '
+	test_must_fail test-parse-options --no-length > output 2> output.err &&
+	test_cmp expect output &&
+	test_cmp expect.err output.err
+'
+
+cat > expect <<EOF
+boolean: 1
+integer: 23
+string: (not set)
+abbrev: 7
+verbose: 0
+quiet: no
+dry run: no
+EOF
+
+test_expect_success 'OPT_BIT() and OPT_SET_INT() work' '
+	test-parse-options --set23 -bbbbb --no-or4 > output 2> output.err &&
+	test ! -s output.err &&
+	test_cmp expect output
+'
+
+# --or4
+# --no-or4
+
 test_done
diff --git a/test-parse-options.c b/test-parse-options.c
index 73360d7..2a79e72 100644
--- a/test-parse-options.c
+++ b/test-parse-options.c
@@ -2,9 +2,22 @@
 #include "parse-options.h"
 
 static int boolean = 0;
-static int integer = 0;
+static unsigned long integer = 0;
+static int abbrev = 7;
+static int verbose = 0, dry_run = 0, quiet = 0;
 static char *string = NULL;
 
+int length_callback(const struct option *opt, const char *arg, int unset)
+{
+	printf("Callback: \"%s\", %d\n",
+		(arg ? arg : "not set"), unset);
+	if (unset)
+		return 1; /* do not support unset */
+
+	*(unsigned long *)opt->value = strlen(arg);
+	return 0;
+}
+
 int main(int argc, const char **argv)
 {
 	const char *usage[] = {
@@ -13,15 +26,29 @@ int main(int argc, const char **argv)
 	};
 	struct option options[] = {
 		OPT_BOOLEAN('b', "boolean", &boolean, "get a boolean"),
+		OPT_BIT('4', "or4", &boolean,
+			"bitwise-or boolean with ...0100", 4),
+		OPT_GROUP(""),
 		OPT_INTEGER('i', "integer", &integer, "get a integer"),
 		OPT_INTEGER('j', NULL, &integer, "get a integer, too"),
-		OPT_GROUP("string options"),
+		OPT_SET_INT(0, "set23", &integer, "set integer to 23", 23),
+		OPT_DATE('t', NULL, &integer, "get timestamp of <time>"),
+		OPT_CALLBACK('L', "length", &integer, "str",
+			"get length of <str>", length_callback),
+		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_STRING('o', NULL, &string, "str", "get another string"),
-		OPT_GROUP("magic arguments"),
+		OPT_SET_PTR(0, "default-string", &string,
+			"set string to default", (unsigned long)"default"),
+		OPT_GROUP("Magic arguments"),
 		OPT_ARGUMENT("quux", "means --quux"),
+		OPT_GROUP("Standard options"),
+		OPT__ABBREV(&abbrev),
+		OPT__VERBOSE(&verbose),
+		OPT__DRY_RUN(&dry_run),
+		OPT__QUIET(&quiet),
 		OPT_END(),
 	};
 	int i;
@@ -29,8 +56,12 @@ int main(int argc, const char **argv)
 	argc = parse_options(argc, argv, options, usage, 0);
 
 	printf("boolean: %d\n", boolean);
-	printf("integer: %d\n", integer);
+	printf("integer: %lu\n", integer);
 	printf("string: %s\n", string ? string : "(not set)");
+	printf("abbrev: %d\n", abbrev);
+	printf("verbose: %d\n", verbose);
+	printf("quiet: %s\n", quiet ? "yes" : "no");
+	printf("dry run: %s\n", dry_run ? "yes" : "no");
 
 	for (i = 0; i < argc; i++)
 		printf("arg %02d: %s\n", i, argv[i]);
-- 
1.5.6.310.g344d

^ permalink raw reply related	[flat|nested] 7+ messages in thread

* Re: [PATCH 1/2] api-parse-options.txt: Introduce documentation for parse options API
  2008-06-22  0:00 [PATCH 1/2] api-parse-options.txt: Introduce documentation for parse options API Stephan Beyer
  2008-06-22  0:00 ` [PATCH 2/2] Extend parse-options test suite Stephan Beyer
@ 2008-06-22 12:49 ` Michele Ballabio
  2008-06-22 13:45   ` Stephan Beyer
  1 sibling, 1 reply; 7+ messages in thread
From: Michele Ballabio @ 2008-06-22 12:49 UTC (permalink / raw)
  To: git; +Cc: Stephan Beyer, Pierre Habouzit, Junio C Hamano,
	Johannes Schindelin

On Sunday 22 June 2008, Stephan Beyer wrote:
> +`PARSE_OPT_KEEP_DASHDASH`::
> +       Usually long options (`\--long-opt`) are boiled down to their
> +       short option equivalent, if available.
> +       Using this flag, long options are kept.

No: PARSE_OPT_KEEP_DASHDASH keeps the "--" that usually separates options
from files, as in

	git ls-files [options] -- [files]

i.e. after parsing, the new argv will still contain "--".

> +`OPT__ABBREV(&int_var)`::
> +       Add `\--abbrev [<n>]`.

better:
+       Add `\--abbrev[=<n>]`.

since the <n> is optional.

^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: [PATCH 1/2] api-parse-options.txt: Introduce documentation for parse options API
  2008-06-22 12:49 ` [PATCH 1/2] api-parse-options.txt: Introduce documentation for parse options API Michele Ballabio
@ 2008-06-22 13:45   ` Stephan Beyer
  2008-06-22 14:39     ` [PATCH] parse-options.c: fix documentation syntax of optional arguments Michele Ballabio
  0 siblings, 1 reply; 7+ messages in thread
From: Stephan Beyer @ 2008-06-22 13:45 UTC (permalink / raw)
  To: Michele Ballabio
  Cc: git, Pierre Habouzit, Junio C Hamano, Johannes Schindelin

> > +`PARSE_OPT_KEEP_DASHDASH`::
> > +       Usually long options (`\--long-opt`) are boiled down to their
> > +       short option equivalent, if available.
> > +       Using this flag, long options are kept.
> 
> No: PARSE_OPT_KEEP_DASHDASH keeps the "--" that usually separates options
> from files, as in

Eh, right, of course!  What I wrote doesn't make any sense. ;-)

> > +`OPT__ABBREV(&int_var)`::
> > +       Add `\--abbrev [<n>]`.
> 
> better:
> +       Add `\--abbrev[=<n>]`.
> 
> since the <n> is optional.

That's right and I also expected that print_usage_with_options() would
do so, since the other variant is ambiguous, BUT:

$ ./test-parse-options -h 2>&1 | grep abbrev
    --abbrev [<n>]        use <n> digits to display SHA-1s

And I didn't want to change parse-options.c ;-)


Any other comments?

Regards,
  Stephan

-- 
Stephan Beyer <s-beyer@gmx.net>, PGP 0x6EDDD207FCC5040F

^ permalink raw reply	[flat|nested] 7+ messages in thread

* [PATCH] parse-options.c: fix documentation syntax of optional arguments
  2008-06-22 13:45   ` Stephan Beyer
@ 2008-06-22 14:39     ` Michele Ballabio
  2008-06-22 15:04       ` [PATCH v2 1/2] api-parse-options.txt: Introduce documentation for parse options API Stephan Beyer
  0 siblings, 1 reply; 7+ messages in thread
From: Michele Ballabio @ 2008-06-22 14:39 UTC (permalink / raw)
  To: git; +Cc: Stephan Beyer, Pierre Habouzit, Junio C Hamano,
	Johannes Schindelin

When an argument for an option is optional, short options don't need a
space between the option and the argument, and long options need a "=".
Otherwise, arguments are misinterpreted.

Signed-off-by: Michele Ballabio <barra_cuda@katamail.com>
---

On Sunday 22 June 2008, Stephan Beyer wrote:
> > > +`OPT__ABBREV(&int_var)`::
> > > +       Add `\--abbrev [<n>]`.
> > 
> > better:
> > +       Add `\--abbrev[=<n>]`.
> > 
> > since the <n> is optional.
> 
> That's right and I also expected that print_usage_with_options() would
> do so, since the other variant is ambiguous, BUT:
> 
> $ ./test-parse-options -h 2>&1 | grep abbrev
>     --abbrev [<n>]        use <n> digits to display SHA-1s
> 
> And I didn't want to change parse-options.c ;-)

Here it is.

 parse-options.c               |   15 ++++++++++++---
 t/t1502-rev-parse-parseopt.sh |    2 +-
 2 files changed, 13 insertions(+), 4 deletions(-)

diff --git a/parse-options.c b/parse-options.c
index acf3fe3..f8d52e2 100644
--- a/parse-options.c
+++ b/parse-options.c
@@ -344,7 +344,10 @@ void usage_with_options_internal(const char * const *usagestr,
 			break;
 		case OPTION_INTEGER:
 			if (opts->flags & PARSE_OPT_OPTARG)
-				pos += fprintf(stderr, "[<n>]");
+				if (opts->long_name)
+					pos += fprintf(stderr, "[=<n>]");
+				else
+					pos += fprintf(stderr, "[<n>]");
 			else
 				pos += fprintf(stderr, " <n>");
 			break;
@@ -355,12 +358,18 @@ void usage_with_options_internal(const char * const *usagestr,
 		case OPTION_STRING:
 			if (opts->argh) {
 				if (opts->flags & PARSE_OPT_OPTARG)
-					pos += fprintf(stderr, " [<%s>]", opts->argh);
+					if (opts->long_name)
+						pos += fprintf(stderr, "[=<%s>]", opts->argh);
+					else
+						pos += fprintf(stderr, "[<%s>]", opts->argh);
 				else
 					pos += fprintf(stderr, " <%s>", opts->argh);
 			} else {
 				if (opts->flags & PARSE_OPT_OPTARG)
-					pos += fprintf(stderr, " [...]");
+					if (opts->long_name)
+						pos += fprintf(stderr, "[=...]");
+					else
+						pos += fprintf(stderr, "[...]");
 				else
 					pos += fprintf(stderr, " ...");
 			}
diff --git a/t/t1502-rev-parse-parseopt.sh b/t/t1502-rev-parse-parseopt.sh
index d24a47d..3508d0a 100755
--- a/t/t1502-rev-parse-parseopt.sh
+++ b/t/t1502-rev-parse-parseopt.sh
@@ -13,7 +13,7 @@ usage: some-command [options] <args>...
     --bar ...             some cool option --bar with an argument
 
 An option group Header
-    -C [...]              option C with an optional argument
+    -C[...]               option C with an optional argument
 
 Extras
     --extra1              line above used to cause a segfault but no longer does
-- 
1.5.6

^ permalink raw reply related	[flat|nested] 7+ messages in thread

* [PATCH v2 1/2] api-parse-options.txt: Introduce documentation for parse options API
  2008-06-22 14:39     ` [PATCH] parse-options.c: fix documentation syntax of optional arguments Michele Ballabio
@ 2008-06-22 15:04       ` Stephan Beyer
  2008-06-22 15:04         ` [PATCH v2 2/2] Extend parse-options test suite Stephan Beyer
  0 siblings, 1 reply; 7+ messages in thread
From: Stephan Beyer @ 2008-06-22 15:04 UTC (permalink / raw)
  To: Michele Ballabio
  Cc: git, Pierre Habouzit, Junio C Hamano, Johannes Schindelin,
	Stephan Beyer

Add some documentation of basics, macros and callback
implementation of the parse-options API.

Signed-off-by: Stephan Beyer <s-beyer@gmx.net>
---
Ha, great ;)

So here are my patches, now based on your one.

Regards,
  Stephan

 Documentation/technical/api-parse-options.txt |  204 ++++++++++++++++++++++++-
 1 files changed, 202 insertions(+), 2 deletions(-)

diff --git a/Documentation/technical/api-parse-options.txt b/Documentation/technical/api-parse-options.txt
index b7cda94..60a433b 100644
--- a/Documentation/technical/api-parse-options.txt
+++ b/Documentation/technical/api-parse-options.txt
@@ -1,6 +1,206 @@
 parse-options API
 =================
 
-Talk about <parse-options.h>
+The parse-options API is used to parse and massage options in git
+and to provide a usage help with consistent look.
 
-(Pierre)
+Basics
+------
+
+The argument vector `argv[]` may usually contain mandatory or optional
+'non-option arguments', e.g. a filename or a branch, and 'options'.
+Options are optional arguments that start with a dash and
+that allow to change the behavior of a command.
+
+* There are basically three types of options:
+  'boolean' options,
+  options with (mandatory) 'arguments' and
+  options with 'optional arguments'
+  (i.e. a boolean option that can be adjusted).
+
+* There are basically two forms of options: 
+  'Short options' consist of one dash (`-`) and one alphanumeric
+  character.
+  'Long options' begin with two dashes (`\--`) and some 
+  alphanumeric characters.
+
+* Options are case-sensitive.
+  Please define 'lower-case long options' only.
+
+The parse-options API allows:
+
+* 'sticked' and 'separate form' of options with arguments.
+  `-oArg` is sticked, `-o Arg` is separate form.
+  `\--option=Arg` is sticked, `\--option Arg` is separate form.
+
+* Long options may be 'abbreviated', as long as the abbreviation
+  is unambiguous.
+
+* Short options may be bundled, e.g. `-a -b` can be specified as `-ab`.
+
+* Boolean long options can be 'negated' (or 'unset') by prepending
+  `no-`, e.g. `\--no-abbrev` instead of `\--abbrev`.
+
+* Options and non-option arguments can clearly be separated using the `\--`
+  option, e.g. `-a -b \--option \-- \--this-is-a-file` indicates that
+  `\--this-is-a-file` must not be processed as an option.
+
+Steps to parse options
+----------------------
+
+. `#include "parse-options.h"`
+
+. define a NULL-terminated
+  `static const char * const builtin_foo_usage[]` array
+  containing alternative usage strings
+
+. define `builtin_foo_options` array as described below
+  in section 'Data Structure'.
+
+. in `cmd_foo(int argc, const char **argv, const char *prefix)`
+  call
+
+	argc = parse_options(argc, argv, builtin_foo_options, builtin_foo_usage, flags);
++
+`parse_options()` will filter out the processed options of `argv[]` and leave the
+non-option arguments in `argv[]`.
+`argc` is updated appropriately because of the assignment.
++
+Flags are the bitwise-or of:
+
+`PARSE_OPT_KEEP_DASHDASH`::
+	Keep the `\--` that usually separates options from
+	non-option arguments.
+
+`PARSE_OPT_STOP_AT_NON_OPTION`::
+	Usually the whole argument vector is massaged and reordered.
+	Using this flag, processing is stopped at the first non-option
+	argument.
+
+Data Structure
+--------------
+
+The main data structure is an array of the `option` struct,
+say `static struct option builtin_add_options[]`.
+There are some macros to easily define options:
+
+`OPT__ABBREV(&int_var)`::
+	Add `\--abbrev[=<n>]`.
+
+`OPT__DRY_RUN(&int_var)`::
+	Add `-n, \--dry-run`.
+
+`OPT__QUIET(&int_var)`::
+	Add `-q, \--quiet`.
+
+`OPT__VERBOSE(&int_var)`::
+	Add `-v, \--verbose`.
+
+`OPT_GROUP(description)`::
+	Start an option group. `description` is a short string that
+	describes the group or an empty string.
+	Start the description with an upper-case letter.
+
+`OPT_BOOLEAN(short, long, &int_var, description)`::
+	Introduce a boolean option.
+	`int_var` is incremented on each use.
+
+`OPT_BIT(short, long, &int_var, description, mask)`::
+	Introduce a boolean option.
+	If used, `int_var` is bitwise-ored with `mask`.
+
+`OPT_SET_INT(short, long, &int_var, description, integer)`::
+	Introduce a boolean option.
+	If used, set `int_var` to `integer`.
+
+`OPT_SET_PTR(short, long, &ptr_var, description, ptr)`::
+	Introduce a boolean option.
+	If used, set `ptr_var` to `ptr`.
+
+`OPT_STRING(short, long, &str_var, arg_str, description)`::
+	Introduce an option with string argument.
+	The string argument is put into `str_var`.
+
+`OPT_INTEGER(short, long, &int_var, description)`::
+	Introduce an option with integer argument.
+	The integer is put into `int_var`.
+
+`OPT_DATE(short, long, &int_var, description)`::
+	Introduce an option with date argument, see `approxidate()`.
+	The timestamp is put into `int_var`.
+
+`OPT_CALLBACK(short, long, &var, arg_str, description, func_ptr)`::
+	Introduce an option with argument.
+	The argument will be fed into the function given by `func_ptr`
+	and the result will be put into `var`.
+	See 'Option Callbacks' below for a more elaborate description.
+
+`OPT_ARGUMENT(long, description)`::
+	Introduce a long-option argument that will be kept in `argv[]`.
+
+
+The last element of the array must be `OPT_END()`.
+
+If not stated otherwise, interpret the arguments as follows:
+
+* `short` is a character for the short option
+  (e.g. `\'e\'` for `-e`, use `0` to omit),
+
+* `long` is a string for the long option
+  (e.g. `"example"` for `\--example`, use `NULL` to omit),
+
+* `int_var` is an integer variable,
+
+* `str_var` is a string variable (`char *`),
+
+* `arg_str` is the string that is shown as argument
+  (e.g. `"branch"` will result in `<branch>`).
+  If set to `NULL`, three dots (`...`) will be displayed.
+
+* `description` is a short string to describe the effect of the option.
+  It shall begin with a lower-case letter and a full stop (`.`) shall be
+  omitted at the end.
+
+Option Callbacks
+----------------
+
+The function must be defined in this form:
+
+	int func(const struct option *opt, const char *arg, int unset)
+
+The callback mechanism is as follows:
+
+* Inside `funct`, the only interesting member of the structure
+  given by `opt` is the void pointer `opt->value`.
+  `\*opt->value` will be the value that is saved into `var`, if you
+  use `OPT_CALLBACK()`.
+  For example, do `*(unsigned long *)opt->value = 42;` to get 42
+  into an `unsigned long` variable.
+
+* Return value `0` indicates success and non-zero return
+  value will invoke `usage_with_options()` and, thus, die.
+
+* If the user negates the option, `arg` is `NULL` and `unset` is 1.
+
+Sophisticated option parsing
+----------------------------
+
+If you need, for example, option callbacks with optional arguments
+or without arguments at all, or if you need other special cases,
+that are not handled by the macros above, you need to specify the
+members of the `option` structure manually.
+
+This is not covered in this document, but well documented
+in `parse-options.h` itself.
+
+Examples
+--------
+
+See `test-parse-options.c` and
+`builtin-add.c`,
+`builtin-clone.c`,
+`builtin-commit.c`,
+`builtin-fetch.c`,
+`builtin-fsck.c`,
+`builtin-rm.c`
+for real-world examples.
-- 
1.5.6.310.g344d

^ permalink raw reply related	[flat|nested] 7+ messages in thread

* [PATCH v2 2/2] Extend parse-options test suite
  2008-06-22 15:04       ` [PATCH v2 1/2] api-parse-options.txt: Introduce documentation for parse options API Stephan Beyer
@ 2008-06-22 15:04         ` Stephan Beyer
  0 siblings, 0 replies; 7+ messages in thread
From: Stephan Beyer @ 2008-06-22 15:04 UTC (permalink / raw)
  To: Michele Ballabio
  Cc: git, Pierre Habouzit, Junio C Hamano, Johannes Schindelin,
	Stephan Beyer

This patch serves two purposes:
 1. test-parse-option.c should be a more complete
    example for the parse-options API, and
 2. there have been no tests for OPT_CALLBACK,
    OPT_DATE, OPT_BIT, OPT_SET_INT and OPT_SET_PTR
    before.

Signed-off-by: Stephan Beyer <s-beyer@gmx.net>
---
 t/t0040-parse-options.sh |  116 +++++++++++++++++++++++++++++++++++++++++++---
 test-parse-options.c     |   39 ++++++++++++++--
 2 files changed, 144 insertions(+), 11 deletions(-)

diff --git a/t/t0040-parse-options.sh b/t/t0040-parse-options.sh
index 9965cfa..6309aed 100755
--- a/t/t0040-parse-options.sh
+++ b/t/t0040-parse-options.sh
@@ -11,23 +11,35 @@ cat > expect.err << EOF
 usage: test-parse-options <options>
 
     -b, --boolean         get a boolean
+    -4, --or4             bitwise-or boolean with ...0100
+
     -i, --integer <n>     get a integer
     -j <n>                get a integer, too
+    --set23               set integer to 23
+    -t <time>             get timestamp of <time>
+    -L, --length <str>    get length of <str>
 
-string options
+String options
     -s, --string <string>
                           get a string
     --string2 <str>       get another string
     --st <st>             get another string (pervert ordering)
     -o <str>              get another string
+    --default-string      set string to default
 
-magic arguments
+Magic arguments
     --quux                means --quux
 
+Standard options
+    --abbrev[=<n>]        use <n> digits to display SHA-1s
+    -v, --verbose         be verbose
+    -n, --dry-run         dry run
+    -q, --quiet           be quiet
+
 EOF
 
 test_expect_success 'test help' '
-	! test-parse-options -h > output 2> output.err &&
+	test_must_fail test-parse-options -h > output 2> output.err &&
 	test ! -s output &&
 	test_cmp expect.err output.err
 '
@@ -36,21 +48,31 @@ cat > expect << EOF
 boolean: 2
 integer: 1729
 string: 123
+abbrev: 7
+verbose: 2
+quiet: no
+dry run: yes
 EOF
 
 test_expect_success 'short options' '
-	test-parse-options -s123 -b -i 1729 -b > output 2> output.err &&
+	test-parse-options -s123 -b -i 1729 -b -vv -n > output 2> output.err &&
 	test_cmp expect output &&
 	test ! -s output.err
 '
+
 cat > expect << EOF
 boolean: 2
 integer: 1729
 string: 321
+abbrev: 10
+verbose: 2
+quiet: no
+dry run: no
 EOF
 
 test_expect_success 'long options' '
 	test-parse-options --boolean --integer 1729 --boolean --string2=321 \
+		--verbose --verbose --no-dry-run --abbrev=10 \
 		> output 2> output.err &&
 	test ! -s output.err &&
 	test_cmp expect output
@@ -60,6 +82,10 @@ cat > expect << EOF
 boolean: 1
 integer: 13
 string: 123
+abbrev: 7
+verbose: 0
+quiet: no
+dry run: no
 arg 00: a1
 arg 01: b1
 arg 02: --boolean
@@ -76,6 +102,10 @@ cat > expect << EOF
 boolean: 0
 integer: 2
 string: (not set)
+abbrev: 7
+verbose: 0
+quiet: no
+dry run: no
 EOF
 
 test_expect_success 'unambiguously abbreviated option' '
@@ -99,6 +129,10 @@ cat > expect << EOF
 boolean: 0
 integer: 0
 string: 123
+abbrev: 7
+verbose: 0
+quiet: no
+dry run: no
 EOF
 
 test_expect_success 'non ambiguous option (after two options it abbreviates)' '
@@ -107,20 +141,24 @@ test_expect_success 'non ambiguous option (after two options it abbreviates)' '
 	test_cmp expect output
 '
 
-cat > expect.err << EOF
+cat > typo.err << EOF
 error: did you mean \`--boolean\` (with two dashes ?)
 EOF
 
 test_expect_success 'detect possible typos' '
-	! test-parse-options -boolean > output 2> output.err &&
+	test_must_fail test-parse-options -boolean > output 2> output.err &&
 	test ! -s output &&
-	test_cmp expect.err output.err
+	test_cmp typo.err output.err
 '
 
 cat > expect <<EOF
 boolean: 0
 integer: 0
 string: (not set)
+abbrev: 7
+verbose: 0
+quiet: no
+dry run: no
 arg 00: --quux
 EOF
 
@@ -130,4 +168,68 @@ test_expect_success 'keep some options as arguments' '
         test_cmp expect output
 '
 
+cat > expect <<EOF
+boolean: 0
+integer: 1
+string: default
+abbrev: 7
+verbose: 0
+quiet: yes
+dry run: no
+arg 00: foo
+EOF
+
+test_expect_success 'OPT_DATE() and OPT_SET_PTR() work' '
+	test-parse-options -t "1970-01-01 00:00:01 +0000" --default-string \
+		foo -q > output 2> output.err &&
+	test ! -s output.err &&
+	test_cmp expect output
+'
+
+cat > expect <<EOF
+Callback: "four", 0
+boolean: 5
+integer: 4
+string: (not set)
+abbrev: 7
+verbose: 0
+quiet: no
+dry run: no
+EOF
+
+test_expect_success 'OPT_CALLBACK() and OPT_BIT() work' '
+	test-parse-options --length=four -b -4 > output 2> output.err &&
+	test ! -s output.err &&
+	test_cmp expect output
+'
+
+cat > expect <<EOF
+Callback: "not set", 1
+EOF
+
+test_expect_success 'OPT_CALLBACK() and callback errors work' '
+	test_must_fail test-parse-options --no-length > output 2> output.err &&
+	test_cmp expect output &&
+	test_cmp expect.err output.err
+'
+
+cat > expect <<EOF
+boolean: 1
+integer: 23
+string: (not set)
+abbrev: 7
+verbose: 0
+quiet: no
+dry run: no
+EOF
+
+test_expect_success 'OPT_BIT() and OPT_SET_INT() work' '
+	test-parse-options --set23 -bbbbb --no-or4 > output 2> output.err &&
+	test ! -s output.err &&
+	test_cmp expect output
+'
+
+# --or4
+# --no-or4
+
 test_done
diff --git a/test-parse-options.c b/test-parse-options.c
index 73360d7..2a79e72 100644
--- a/test-parse-options.c
+++ b/test-parse-options.c
@@ -2,9 +2,22 @@
 #include "parse-options.h"
 
 static int boolean = 0;
-static int integer = 0;
+static unsigned long integer = 0;
+static int abbrev = 7;
+static int verbose = 0, dry_run = 0, quiet = 0;
 static char *string = NULL;
 
+int length_callback(const struct option *opt, const char *arg, int unset)
+{
+	printf("Callback: \"%s\", %d\n",
+		(arg ? arg : "not set"), unset);
+	if (unset)
+		return 1; /* do not support unset */
+
+	*(unsigned long *)opt->value = strlen(arg);
+	return 0;
+}
+
 int main(int argc, const char **argv)
 {
 	const char *usage[] = {
@@ -13,15 +26,29 @@ int main(int argc, const char **argv)
 	};
 	struct option options[] = {
 		OPT_BOOLEAN('b', "boolean", &boolean, "get a boolean"),
+		OPT_BIT('4', "or4", &boolean,
+			"bitwise-or boolean with ...0100", 4),
+		OPT_GROUP(""),
 		OPT_INTEGER('i', "integer", &integer, "get a integer"),
 		OPT_INTEGER('j', NULL, &integer, "get a integer, too"),
-		OPT_GROUP("string options"),
+		OPT_SET_INT(0, "set23", &integer, "set integer to 23", 23),
+		OPT_DATE('t', NULL, &integer, "get timestamp of <time>"),
+		OPT_CALLBACK('L', "length", &integer, "str",
+			"get length of <str>", length_callback),
+		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_STRING('o', NULL, &string, "str", "get another string"),
-		OPT_GROUP("magic arguments"),
+		OPT_SET_PTR(0, "default-string", &string,
+			"set string to default", (unsigned long)"default"),
+		OPT_GROUP("Magic arguments"),
 		OPT_ARGUMENT("quux", "means --quux"),
+		OPT_GROUP("Standard options"),
+		OPT__ABBREV(&abbrev),
+		OPT__VERBOSE(&verbose),
+		OPT__DRY_RUN(&dry_run),
+		OPT__QUIET(&quiet),
 		OPT_END(),
 	};
 	int i;
@@ -29,8 +56,12 @@ int main(int argc, const char **argv)
 	argc = parse_options(argc, argv, options, usage, 0);
 
 	printf("boolean: %d\n", boolean);
-	printf("integer: %d\n", integer);
+	printf("integer: %lu\n", integer);
 	printf("string: %s\n", string ? string : "(not set)");
+	printf("abbrev: %d\n", abbrev);
+	printf("verbose: %d\n", verbose);
+	printf("quiet: %s\n", quiet ? "yes" : "no");
+	printf("dry run: %s\n", dry_run ? "yes" : "no");
 
 	for (i = 0; i < argc; i++)
 		printf("arg %02d: %s\n", i, argv[i]);
-- 
1.5.6.310.g344d

^ permalink raw reply related	[flat|nested] 7+ messages in thread

end of thread, other threads:[~2008-06-22 15:05 UTC | newest]

Thread overview: 7+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2008-06-22  0:00 [PATCH 1/2] api-parse-options.txt: Introduce documentation for parse options API Stephan Beyer
2008-06-22  0:00 ` [PATCH 2/2] Extend parse-options test suite Stephan Beyer
2008-06-22 12:49 ` [PATCH 1/2] api-parse-options.txt: Introduce documentation for parse options API Michele Ballabio
2008-06-22 13:45   ` Stephan Beyer
2008-06-22 14:39     ` [PATCH] parse-options.c: fix documentation syntax of optional arguments Michele Ballabio
2008-06-22 15:04       ` [PATCH v2 1/2] api-parse-options.txt: Introduce documentation for parse options API Stephan Beyer
2008-06-22 15:04         ` [PATCH v2 2/2] Extend parse-options test suite Stephan Beyer

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 NNTP newsgroup(s).