add all current code

based off of docopt 0.6.1 (master branch at 8/29/2013)

all tests are passing
diff --git a/docopt.go b/docopt.go
new file mode 100644
index 0000000..77c52ab
--- /dev/null
+++ b/docopt.go
@@ -0,0 +1,1213 @@
+/*
+Based of off docopt.py: https://github.com/docopt/docopt
+
+Licensed under terms of MIT license (see LICENSE-MIT)
+Copyright (c) 2013 Keith Batten, kbatten@gmail.com
+*/
+
+package docopt
+
+import (
+	"fmt"
+	"os"
+	"reflect"
+	"regexp"
+	"strings"
+	"unicode"
+)
+
+// parse and return a map of args, output and all errors
+func Parse(doc string, argv []string, help bool, version string, optionsFirst bool) (args map[string]interface{}, output string, err error) {
+	if argv == nil && len(os.Args) > 1 {
+		argv = os.Args[1:]
+	}
+
+	usageSections := parseSection("usage:", doc)
+
+	if len(usageSections) == 0 {
+		err = newLanguageError("\"usage:\" (case-insensitive) not found.")
+		return
+	}
+	if len(usageSections) > 1 {
+		err = newLanguageError("More than one \"usage:\" (case-insensitive).")
+		return
+	}
+	usage := usageSections[0]
+
+	options := parseDefaults(doc)
+	pat, err := parsePattern(formalUsage(usage), &options)
+	if err != nil {
+		output = handleError(err, usage)
+		return
+	}
+
+	patternArgv, err := parseArgv(newTokenList(argv, ERROR_USER), &options, optionsFirst)
+	if err != nil {
+		output = handleError(err, usage)
+		return
+	}
+	patFlat, err := pat.flat(PATTERN_OPTION)
+	if err != nil {
+		output = handleError(err, usage)
+		return
+	}
+	patternOptions := patFlat.unique()
+
+	patFlat, err = pat.flat(PATTERN_OPTIONSSHORTCUT)
+	if err != nil {
+		output = handleError(err, usage)
+		return
+	}
+	for _, optionsShortcut := range patFlat {
+		docOptions := parseDefaults(doc)
+		optionsShortcut.children = docOptions.unique().diff(patternOptions)
+	}
+
+	if output = extras(help, version, patternArgv, doc); len(output) > 0 {
+		return
+	}
+
+	err = pat.fix()
+	if err != nil {
+		output = handleError(err, usage)
+		return
+	}
+	matched, left, collected := pat.match(&patternArgv, nil)
+	if matched && len(*left) == 0 {
+		patFlat, err = pat.flat(PATTERN_DEFAULT)
+		if err != nil {
+			output = handleError(err, usage)
+			return
+		}
+		args = append(patFlat, *collected...).dictionary()
+		return
+	}
+
+	err = newUserError("")
+	output = handleError(err, usage)
+	return
+}
+
+// parse just doc and return a map of args
+// handle all printing and non-fatal errors
+// panic on fatal errors
+// exit on user error or help
+func ParseEasy(doc string) map[string]interface{} {
+	return ParseLoud(doc, nil, true, "", false)
+}
+
+// parse and return a map of args and fatal errors
+// handle printing of help
+// exit on user error or help
+func ParseQuiet(doc string, argv []string, help bool, version string, optionsFirst bool) (map[string]interface{}, error) {
+	args, output, err := Parse(doc, argv, help, version, optionsFirst)
+	if _, ok := err.(*UserError); ok {
+		fmt.Println(output)
+		os.Exit(1)
+	} else if len(output) > 0 && err == nil {
+		fmt.Println(output)
+		os.Exit(0)
+	}
+	return args, err
+}
+
+// parse and return a map of args
+// handle all printing and non-fatal errors
+// panic on fatal errors
+// exit on user error or help
+func ParseLoud(doc string, argv []string, help bool, version string, optionsFirst bool) map[string]interface{} {
+	args, err := ParseQuiet(doc, argv, help, version, optionsFirst)
+	if _, ok := err.(*LanguageError); ok {
+		panic(fmt.Sprintf("(language) %s", err))
+	} else if err != nil {
+		panic(fmt.Sprintf("(internal) %s", err))
+	}
+	return args
+}
+
+func handleError(err error, usage string) string {
+	if _, ok := err.(*UserError); ok {
+		return strings.TrimSpace(fmt.Sprintf("%s\n%s", err, usage))
+	}
+	return ""
+}
+
+func parseSection(name, source string) []string {
+	p := regexp.MustCompile(`(?im)^([^\n]*` + name + `[^\n]*\n?(?:[ \t].*?(?:\n|$))*)`)
+	s := p.FindAllString(source, -1)
+	if s == nil {
+		s = []string{}
+	}
+	for i, v := range s {
+		s[i] = strings.TrimSpace(v)
+	}
+	return s
+}
+
+func parseDefaults(doc string) patternList {
+	defaults := patternList{}
+	p := regexp.MustCompile(`\n[ \t]*(-\S+?)`)
+	for _, s := range parseSection("options:", doc) {
+		// FIXME corner case "bla: options: --foo"
+		_, _, s = stringPartition(s, ":") // get rid of "options:"
+		split := p.Split("\n"+s, -1)[1:]
+		match := p.FindAllStringSubmatch("\n"+s, -1)
+		for i := range split {
+			optionDescription := match[i][1] + split[i]
+			if strings.HasPrefix(optionDescription, "-") {
+				defaults = append(defaults, parseOption(optionDescription))
+			}
+		}
+	}
+	return defaults
+}
+
+func parsePattern(source string, options *patternList) (*pattern, error) {
+	tokens := tokenListFromPattern(source)
+	result, err := parseExpr(tokens, options)
+	if err != nil {
+		return nil, err
+	}
+	if tokens.current() != nil {
+		return nil, tokens.errorFunc("unexpected ending: %s" + strings.Join(tokens.tokens, " "))
+	}
+	return newRequired(result...), nil
+}
+
+func parseArgv(tokens *tokenList, options *patternList, optionsFirst bool) (patternList, error) {
+	/*
+		Parse command-line argument vector.
+
+		If options_first:
+			argv ::= [ long | shorts ]* [ argument ]* [ '--' [ argument ]* ] ;
+		else:
+			argv ::= [ long | shorts | argument ]* [ '--' [ argument ]* ] ;
+	*/
+	parsed := patternList{}
+	for tokens.current() != nil {
+		if tokens.current().eq("--") {
+			for _, v := range tokens.tokens {
+				parsed = append(parsed, newArgument("", v))
+			}
+			return parsed, nil
+		} else if tokens.current().hasPrefix("--") {
+			pl, err := parseLong(tokens, options)
+			if err != nil {
+				return nil, err
+			}
+			parsed = append(parsed, pl...)
+		} else if tokens.current().hasPrefix("-") && !tokens.current().eq("-") {
+			ps, err := parseShorts(tokens, options)
+			if err != nil {
+				return nil, err
+			}
+			parsed = append(parsed, ps...)
+		} else if optionsFirst {
+			for _, v := range tokens.tokens {
+				parsed = append(parsed, newArgument("", v))
+			}
+			return parsed, nil
+		} else {
+			parsed = append(parsed, newArgument("", tokens.move().String()))
+		}
+	}
+	return parsed, nil
+}
+
+func parseOption(optionDescription string) *pattern {
+	optionDescription = strings.TrimSpace(optionDescription)
+	options, _, description := stringPartition(optionDescription, "  ")
+	options = strings.Replace(options, ",", " ", -1)
+	options = strings.Replace(options, "=", " ", -1)
+
+	short := ""
+	long := ""
+	argcount := 0
+	var value interface{}
+	value = false
+
+	reDefault := regexp.MustCompile(`(?i)\[default: (.*)\]`)
+	for _, s := range strings.Fields(options) {
+		if strings.HasPrefix(s, "--") {
+			long = s
+		} else if strings.HasPrefix(s, "-") {
+			short = s
+		} else {
+			argcount = 1
+		}
+		if argcount > 0 {
+			matched := reDefault.FindAllStringSubmatch(description, -1)
+			if len(matched) > 0 {
+				value = matched[0][1]
+			} else {
+				value = nil
+			}
+		}
+	}
+	return newOption(short, long, argcount, value)
+}
+
+func parseExpr(tokens *tokenList, options *patternList) (patternList, error) {
+	// expr ::= seq ( '|' seq )* ;
+	seq, err := parseSeq(tokens, options)
+	if err != nil {
+		return nil, err
+	}
+	if !tokens.current().eq("|") {
+		return seq, nil
+	}
+	var result patternList
+	if len(seq) > 1 {
+		result = patternList{newRequired(seq...)}
+	} else {
+		result = seq
+	}
+	for tokens.current().eq("|") {
+		tokens.move()
+		seq, err = parseSeq(tokens, options)
+		if err != nil {
+			return nil, err
+		}
+		if len(seq) > 1 {
+			result = append(result, newRequired(seq...))
+		} else {
+			result = append(result, seq...)
+		}
+	}
+	if len(result) > 1 {
+		return patternList{newEither(result...)}, nil
+	}
+	return result, nil
+}
+
+func parseSeq(tokens *tokenList, options *patternList) (patternList, error) {
+	// seq ::= ( atom [ '...' ] )* ;
+	result := patternList{}
+	for !tokens.current().match(true, "]", ")", "|") {
+		atom, err := parseAtom(tokens, options)
+		if err != nil {
+			return nil, err
+		}
+		if tokens.current().eq("...") {
+			atom = patternList{newOneOrMore(atom...)}
+			tokens.move()
+		}
+		result = append(result, atom...)
+	}
+	return result, nil
+}
+
+func parseAtom(tokens *tokenList, options *patternList) (patternList, error) {
+	// atom ::= '(' expr ')' | '[' expr ']' | 'options' | long | shorts | argument | command ;
+	tok := tokens.current()
+	result := patternList{}
+	if tokens.current().match(false, "(", "[") {
+		tokens.move()
+		var matching string
+		pl, err := parseExpr(tokens, options)
+		if err != nil {
+			return nil, err
+		}
+		if tok.eq("(") {
+			matching = ")"
+			result = patternList{newRequired(pl...)}
+		} else if tok.eq("[") {
+			matching = "]"
+			result = patternList{newOptional(pl...)}
+		}
+		moved := tokens.move()
+		if !moved.eq(matching) {
+			return nil, tokens.errorFunc("unmatched '%s', expected: '%s' got: '%s'", tok, matching, moved)
+		}
+		return result, nil
+	} else if tok.eq("options") {
+		tokens.move()
+		return patternList{newOptionsShortcut()}, nil
+	} else if tok.hasPrefix("--") && !tok.eq("--") {
+		return parseLong(tokens, options)
+	} else if tok.hasPrefix("-") && !tok.eq("-") && !tok.eq("--") {
+		return parseShorts(tokens, options)
+	} else if tok.hasPrefix("<") && tok.hasSuffix(">") || tok.isUpper() {
+		return patternList{newArgument(tokens.move().String(), nil)}, nil
+	}
+	return patternList{newCommand(tokens.move().String(), false)}, nil
+}
+
+func parseLong(tokens *tokenList, options *patternList) (patternList, error) {
+	// long ::= '--' chars [ ( ' ' | '=' ) chars ] ;
+	long, eq, v := stringPartition(tokens.move().String(), "=")
+	var value interface{}
+	var opt *pattern
+	if eq == "" && v == "" {
+		value = nil
+	} else {
+		value = v
+	}
+
+	if !strings.HasPrefix(long, "--") {
+		return nil, newError("long option '%s' doesn't start with --", long)
+	}
+	similar := patternList{}
+	for _, o := range *options {
+		if o.long == long {
+			similar = append(similar, o)
+		}
+	}
+	if tokens.err == ERROR_USER && len(similar) == 0 { // if no exact match
+		similar = patternList{}
+		for _, o := range *options {
+			if strings.HasPrefix(o.long, long) {
+				similar = append(similar, o)
+			}
+		}
+	}
+	if len(similar) > 1 { // might be simply specified ambiguously 2+ times?
+		similarLong := make([]string, len(similar))
+		for i, s := range similar {
+			similarLong[i] = s.long
+		}
+		return nil, tokens.errorFunc("%s is not a unique prefix: %s?", long, strings.Join(similarLong, ", "))
+	} else if len(similar) < 1 {
+		argcount := 0
+		if eq == "=" {
+			argcount = 1
+		}
+		opt = newOption("", long, argcount, false)
+		*options = append(*options, opt)
+		if tokens.err == ERROR_USER {
+			var val interface{}
+			if argcount > 0 {
+				val = value
+			} else {
+				val = true
+			}
+			opt = newOption("", long, argcount, val)
+		}
+	} else {
+		opt = newOption(similar[0].short, similar[0].long, similar[0].argcount, similar[0].value)
+		if opt.argcount == 0 {
+			if value != nil {
+				return nil, tokens.errorFunc("%s must not have an argument", opt.long)
+			}
+		} else {
+			if value == nil {
+				if tokens.current().match(true, "--") {
+					return nil, tokens.errorFunc("%s requires argument", opt.long)
+				}
+				moved := tokens.move()
+				if moved != nil {
+					value = moved.String() // only set as string if not nil
+				}
+			}
+		}
+		if tokens.err == ERROR_USER {
+			if value != nil {
+				opt.value = value
+			} else {
+				opt.value = true
+			}
+		}
+	}
+
+	return patternList{opt}, nil
+}
+
+func parseShorts(tokens *tokenList, options *patternList) (patternList, error) {
+	// shorts ::= '-' ( chars )* [ [ ' ' ] chars ] ;
+	tok := tokens.move()
+	if !tok.hasPrefix("-") || tok.hasPrefix("--") {
+		return nil, newError("short option '%s' doesn't start with -", tok)
+	}
+	left := strings.TrimLeft(tok.String(), "-")
+	parsed := patternList{}
+	for left != "" {
+		var opt *pattern
+		short := "-" + left[0:1]
+		left = left[1:]
+		similar := patternList{}
+		for _, o := range *options {
+			if o.short == short {
+				similar = append(similar, o)
+			}
+		}
+		if len(similar) > 1 {
+			return nil, tokens.errorFunc("%s is specified ambiguously %d times", short, len(similar))
+		} else if len(similar) < 1 {
+			opt = newOption(short, "", 0, false)
+			*options = append(*options, opt)
+			if tokens.err == ERROR_USER {
+				opt = newOption(short, "", 0, true)
+			}
+		} else { // why copying is necessary here?
+			opt = newOption(short, similar[0].long, similar[0].argcount, similar[0].value)
+			var value interface{}
+			if opt.argcount > 0 {
+				if left == "" {
+					if tokens.current().match(true, "--") {
+						return nil, tokens.errorFunc("%s requires argument", short)
+					}
+					value = tokens.move().String()
+				} else {
+					value = left
+					left = ""
+				}
+			}
+			if tokens.err == ERROR_USER {
+				if value != nil {
+					opt.value = value
+				} else {
+					opt.value = true
+				}
+			}
+		}
+		parsed = append(parsed, opt)
+	}
+	return parsed, nil
+}
+
+func newTokenList(source []string, err errorType) *tokenList {
+	errorFunc := newError
+	if err == ERROR_USER {
+		errorFunc = newUserError
+	} else if err == ERROR_LANGUAGE {
+		errorFunc = newLanguageError
+	}
+	return &tokenList{source, errorFunc, err}
+}
+
+func tokenListFromString(source string) *tokenList {
+	return newTokenList(strings.Fields(source), ERROR_USER)
+}
+
+func tokenListFromPattern(source string) *tokenList {
+	p := regexp.MustCompile(`([\[\]\(\)\|]|\.\.\.)`)
+	source = p.ReplaceAllString(source, ` $1 `)
+	p = regexp.MustCompile(`\s+|(\S*<.*?>)`)
+	split := p.Split(source, -1)
+	match := p.FindAllStringSubmatch(source, -1)
+	var result []string
+	l := len(split)
+	for i := 0; i < l; i++ {
+		if len(split[i]) > 0 {
+			result = append(result, split[i])
+		}
+		if i < l-1 && len(match[i][1]) > 0 {
+			result = append(result, match[i][1])
+		}
+	}
+	return newTokenList(result, ERROR_LANGUAGE)
+}
+
+func formalUsage(section string) string {
+	_, _, section = stringPartition(section, ":") // drop "usage:"
+	pu := strings.Fields(section)
+
+	result := "( "
+	for _, s := range pu[1:] {
+		if s == pu[0] {
+			result += ") | ( "
+		} else {
+			result += s + " "
+		}
+	}
+	result += ")"
+
+	return result
+}
+
+func extras(help bool, version string, options patternList, doc string) string {
+	if help {
+		for _, o := range options {
+			if (o.name == "-h" || o.name == "--help") && o.value == true {
+				return strings.Trim(doc, "\n")
+			}
+		}
+	}
+	if version != "" {
+		for _, o := range options {
+			if (o.name == "--version") && o.value == true {
+				return version
+			}
+		}
+	}
+	return ""
+}
+
+type errorType int
+
+const (
+	ERROR_USER errorType = iota
+	ERROR_LANGUAGE
+)
+
+func (self errorType) String() string {
+	switch self {
+	case ERROR_USER:
+		return "userError"
+	case ERROR_LANGUAGE:
+		return "languageError"
+	}
+	return ""
+}
+
+type UserError struct {
+	msg   string
+	Usage string
+}
+
+func (e UserError) Error() string {
+	return e.msg
+}
+func newUserError(msg string, f ...interface{}) error {
+	return &UserError{fmt.Sprintf(msg, f...), ""}
+}
+
+type LanguageError struct {
+	msg string
+}
+
+func (e LanguageError) Error() string {
+	return e.msg
+}
+func newLanguageError(msg string, f ...interface{}) error {
+	return &LanguageError{fmt.Sprintf(msg, f...)}
+}
+
+var newError = fmt.Errorf
+
+type tokenList struct {
+	tokens    []string
+	errorFunc func(string, ...interface{}) error
+	err       errorType
+}
+type token string
+
+func (self *token) eq(s string) bool {
+	if self == nil {
+		return false
+	}
+	return string(*self) == s
+}
+func (self *token) match(matchNil bool, tokenStrings ...string) bool {
+	if self == nil && matchNil {
+		return true
+	} else if self == nil && !matchNil {
+		return false
+	}
+
+	for _, t := range tokenStrings {
+		if t == string(*self) {
+			return true
+		}
+	}
+	return false
+}
+func (self *token) hasPrefix(prefix string) bool {
+	if self == nil {
+		return false
+	}
+	return strings.HasPrefix(string(*self), prefix)
+}
+func (self *token) hasSuffix(suffix string) bool {
+	if self == nil {
+		return false
+	}
+	return strings.HasSuffix(string(*self), suffix)
+}
+func (self *token) isUpper() bool {
+	if self == nil {
+		return false
+	}
+	return isStringUppercase(string(*self))
+}
+func (self *token) String() string {
+	if self == nil {
+		return ""
+	}
+	return string(*self)
+}
+
+func (self *tokenList) current() *token {
+	if len(self.tokens) > 0 {
+		return (*token)(&(self.tokens[0]))
+	}
+	return nil
+}
+
+func (self *tokenList) length() int {
+	return len(self.tokens)
+}
+
+func (self *tokenList) move() *token {
+	if len(self.tokens) > 0 {
+		t := self.tokens[0]
+		self.tokens = self.tokens[1:]
+		return (*token)(&t)
+	}
+	return nil
+}
+
+type patternType uint
+
+const (
+	// leaf
+	PATTERN_ARGUMENT patternType = 1 << iota
+	PATTERN_COMMAND
+	PATTERN_OPTION
+
+	// branch
+	PATTERN_REQUIRED
+	PATTERN_OPTIONAL
+	PATTERN_OPTIONSSHORTCUT // Marker/placeholder for [options] shortcut.
+	PATTERN_ONEORMORE
+	PATTERN_EITHER
+
+	PATTERN_LEAF = PATTERN_ARGUMENT +
+		PATTERN_COMMAND +
+		PATTERN_OPTION
+	PATTERN_BRANCH = PATTERN_REQUIRED +
+		PATTERN_OPTIONAL +
+		PATTERN_OPTIONSSHORTCUT +
+		PATTERN_ONEORMORE +
+		PATTERN_EITHER
+	PATTERN_ALL     = PATTERN_LEAF + PATTERN_BRANCH
+	PATTERN_DEFAULT = 0
+)
+
+func (self patternType) String() string {
+	switch self {
+	case PATTERN_ARGUMENT:
+		return "argument"
+	case PATTERN_COMMAND:
+		return "command"
+	case PATTERN_OPTION:
+		return "option"
+	case PATTERN_REQUIRED:
+		return "required"
+	case PATTERN_OPTIONAL:
+		return "optional"
+	case PATTERN_OPTIONSSHORTCUT:
+		return "optionsshortcut"
+	case PATTERN_ONEORMORE:
+		return "oneormore"
+	case PATTERN_EITHER:
+		return "either"
+	case PATTERN_LEAF:
+		return "leaf"
+	case PATTERN_BRANCH:
+		return "branch"
+	case PATTERN_ALL:
+		return "all"
+	case PATTERN_DEFAULT:
+		return "default"
+	}
+	return ""
+}
+
+type pattern struct {
+	t patternType
+
+	children patternList
+
+	name  string
+	value interface{}
+
+	short    string
+	long     string
+	argcount int
+}
+
+type patternList []*pattern
+
+func newBranchPattern(t patternType, pl ...*pattern) *pattern {
+	var p pattern
+	p.t = t
+	p.children = make(patternList, len(pl))
+	copy(p.children, pl)
+	return &p
+}
+
+func newRequired(pl ...*pattern) *pattern {
+	return newBranchPattern(PATTERN_REQUIRED, pl...)
+}
+
+func newEither(pl ...*pattern) *pattern {
+	return newBranchPattern(PATTERN_EITHER, pl...)
+}
+
+func newOneOrMore(pl ...*pattern) *pattern {
+	return newBranchPattern(PATTERN_ONEORMORE, pl...)
+}
+
+func newOptional(pl ...*pattern) *pattern {
+	return newBranchPattern(PATTERN_OPTIONAL, pl...)
+}
+
+func newOptionsShortcut() *pattern {
+	var p pattern
+	p.t = PATTERN_OPTIONSSHORTCUT
+	return &p
+}
+
+func newLeafPattern(t patternType, name string, value interface{}) *pattern {
+	// default: value=nil
+	var p pattern
+	p.t = t
+	p.name = name
+	p.value = value
+	return &p
+}
+
+func newArgument(name string, value interface{}) *pattern {
+	// default: value=nil
+	return newLeafPattern(PATTERN_ARGUMENT, name, value)
+}
+
+func newCommand(name string, value interface{}) *pattern {
+	// default: value=false
+	var p pattern
+	p.t = PATTERN_COMMAND
+	p.name = name
+	p.value = value
+	return &p
+}
+
+func newOption(short, long string, argcount int, value interface{}) *pattern {
+	// default: "", "", 0, false
+	var p pattern
+	p.t = PATTERN_OPTION
+	p.short = short
+	p.long = long
+	if long != "" {
+		p.name = long
+	} else {
+		p.name = short
+	}
+	p.argcount = argcount
+	if value == false && argcount > 0 {
+		p.value = nil
+	} else {
+		p.value = value
+	}
+	return &p
+}
+
+func (self *pattern) flat(types patternType) (patternList, error) {
+	if self.t&PATTERN_LEAF != 0 {
+		if types == PATTERN_DEFAULT {
+			types = PATTERN_ALL
+		}
+		if self.t&types != 0 {
+			return patternList{self}, nil
+		}
+		return patternList{}, nil
+	}
+
+	if self.t&PATTERN_BRANCH != 0 {
+		if self.t&types != 0 {
+			return patternList{self}, nil
+		}
+		result := patternList{}
+		for _, child := range self.children {
+			childFlat, err := child.flat(types)
+			if err != nil {
+				return nil, err
+			}
+			result = append(result, childFlat...)
+		}
+		return result, nil
+	}
+	return nil, newError("unknown pattern type: %d, %d", self.t, types)
+}
+
+func (self *pattern) fix() error {
+	err := self.fixIdentities(nil)
+	if err != nil {
+		return err
+	}
+	self.fixRepeatingArguments()
+	return nil
+}
+
+func (self *pattern) fixIdentities(uniq patternList) error {
+	// Make pattern-tree tips point to same object if they are equal.
+	if self.t&PATTERN_BRANCH == 0 {
+		return nil
+	}
+	if uniq == nil {
+		selfFlat, err := self.flat(PATTERN_DEFAULT)
+		if err != nil {
+			return err
+		}
+		uniq = selfFlat.unique()
+	}
+	for i, child := range self.children {
+		if child.t&PATTERN_BRANCH == 0 {
+			ind, err := uniq.index(child)
+			if err != nil {
+				return err
+			}
+			self.children[i] = uniq[ind]
+		} else {
+			err := child.fixIdentities(uniq)
+			if err != nil {
+				return err
+			}
+		}
+	}
+	return nil
+}
+
+func (self *pattern) fixRepeatingArguments() {
+	// Fix elements that should accumulate/increment values.
+	var either []patternList
+
+	for _, child := range self.transform().children {
+		either = append(either, child.children)
+	}
+	for _, cas := range either {
+		casMultiple := patternList{}
+		for _, e := range cas {
+			if cas.count(e) > 1 {
+				casMultiple = append(casMultiple, e)
+			}
+		}
+		for _, e := range casMultiple {
+			if e.t == PATTERN_ARGUMENT || e.t == PATTERN_OPTION && e.argcount > 0 {
+				switch e.value.(type) {
+				case string:
+					e.value = strings.Fields(e.value.(string))
+				case []string:
+				default:
+					e.value = []string{}
+				}
+			}
+			if e.t == PATTERN_COMMAND || e.t == PATTERN_OPTION && e.argcount == 0 {
+				e.value = 0
+			}
+		}
+	}
+}
+
+func (self *pattern) match(left *patternList, collected *patternList) (bool, *patternList, *patternList) {
+	if collected == nil {
+		collected = &patternList{}
+	}
+	if self.t&PATTERN_REQUIRED != 0 {
+		l := left
+		c := collected
+		for _, p := range self.children {
+			var matched bool
+			matched, l, c = p.match(l, c)
+			if !matched {
+				return false, left, collected
+			}
+		}
+		return true, l, c
+	} else if self.t&PATTERN_OPTIONAL != 0 || self.t&PATTERN_OPTIONSSHORTCUT != 0 {
+		for _, p := range self.children {
+			_, left, collected = p.match(left, collected)
+		}
+		return true, left, collected
+	} else if self.t&PATTERN_ONEORMORE != 0 {
+		if len(self.children) != 1 {
+			panic("OneOrMore.match(): assert len(self.children) == 1")
+		}
+		l := left
+		c := collected
+		var l_ *patternList
+		matched := true
+		times := 0
+		for matched {
+			// could it be that something didn't match but changed l or c?
+			matched, l, c = self.children[0].match(l, c)
+			if matched {
+				times += 1
+			}
+			if l_ == l {
+				break
+			}
+			l_ = l
+		}
+		if times >= 1 {
+			return true, l, c
+		}
+		return false, left, collected
+	} else if self.t&PATTERN_EITHER != 0 {
+		type outcomeStruct struct {
+			matched   bool
+			left      *patternList
+			collected *patternList
+			length    int
+		}
+		outcomes := []outcomeStruct{}
+		for _, p := range self.children {
+			matched, l, c := p.match(left, collected)
+			outcome := outcomeStruct{matched, l, c, len(*l)}
+			if matched {
+				outcomes = append(outcomes, outcome)
+			}
+		}
+		if len(outcomes) > 0 {
+			minLen := outcomes[0].length
+			minIndex := 0
+			for i, v := range outcomes {
+				if v.length < minLen {
+					minIndex = i
+				}
+			}
+			return outcomes[minIndex].matched, outcomes[minIndex].left, outcomes[minIndex].collected
+		}
+		return false, left, collected
+	} else if self.t&PATTERN_LEAF != 0 {
+		pos, match := self.singleMatch(left)
+		var increment interface{}
+		if match == nil {
+			return false, left, collected
+		}
+		left_ := make(patternList, len((*left)[:pos]), len((*left)[:pos])+len((*left)[pos+1:]))
+		copy(left_, (*left)[:pos])
+		left_ = append(left_, (*left)[pos+1:]...)
+		sameName := patternList{}
+		for _, a := range *collected {
+			if a.name == self.name {
+				sameName = append(sameName, a)
+			}
+		}
+
+		switch self.value.(type) {
+		case int, []string:
+			switch self.value.(type) {
+			case int:
+				increment = 1
+			case []string:
+				switch match.value.(type) {
+				case string:
+					increment = []string{match.value.(string)}
+				default:
+					increment = match.value
+				}
+			}
+			if len(sameName) == 0 {
+				match.value = increment
+				collectedMatch := make(patternList, len(*collected), len(*collected)+1)
+				copy(collectedMatch, *collected)
+				collectedMatch = append(collectedMatch, match)
+				return true, &left_, &collectedMatch
+			}
+			switch sameName[0].value.(type) {
+			case int:
+				sameName[0].value = sameName[0].value.(int) + increment.(int)
+			case []string:
+				sameName[0].value = append(sameName[0].value.([]string), increment.([]string)...)
+			}
+			return true, &left_, collected
+		}
+		collectedMatch := make(patternList, len(*collected), len(*collected)+1)
+		copy(collectedMatch, *collected)
+		collectedMatch = append(collectedMatch, match)
+		return true, &left_, &collectedMatch
+	}
+	panic("unmatched type")
+	return false, &patternList{}, &patternList{}
+}
+
+func (self *pattern) singleMatch(left *patternList) (int, *pattern) {
+	if self.t&PATTERN_ARGUMENT != 0 {
+		for n, p := range *left {
+			if p.t&PATTERN_ARGUMENT != 0 {
+				return n, newArgument(self.name, p.value)
+			}
+		}
+		return -1, nil
+	} else if self.t&PATTERN_COMMAND != 0 {
+		for n, p := range *left {
+			if p.t&PATTERN_ARGUMENT != 0 {
+				if p.value == self.name {
+					return n, newCommand(self.name, true)
+				} else {
+					break
+				}
+			}
+		}
+		return -1, nil
+	} else if self.t&PATTERN_OPTION != 0 {
+		for n, p := range *left {
+			if self.name == p.name {
+				return n, p
+			}
+		}
+		return -1, nil
+	}
+	panic("unmatched type")
+	return -1, nil
+}
+
+func (self *pattern) String() string {
+	if self.t&PATTERN_OPTION != 0 {
+		return fmt.Sprintf("%s(%s, %s, %d, %+v)", self.t, self.short, self.long, self.argcount, self.value)
+	} else if self.t&PATTERN_LEAF != 0 {
+		return fmt.Sprintf("%s(%s, %+v)", self.t, self.name, self.value)
+	} else if self.t&PATTERN_BRANCH != 0 {
+		result := ""
+		for i, child := range self.children {
+			if i > 0 {
+				result += ", "
+			}
+			result += child.String()
+		}
+		return fmt.Sprintf("%s(%s)", self.t, result)
+	}
+	panic("unmatched type")
+	return ""
+}
+
+func (self *pattern) transform() *pattern {
+	/*
+		Expand pattern into an (almost) equivalent one, but with single Either.
+
+		Example: ((-a | -b) (-c | -d)) => (-a -c | -a -d | -b -c | -b -d)
+		Quirks: [-a] => (-a), (-a...) => (-a -a)
+	*/
+	result := []patternList{}
+	groups := []patternList{patternList{self}}
+	parents := PATTERN_REQUIRED +
+		PATTERN_OPTIONAL +
+		PATTERN_OPTIONSSHORTCUT +
+		PATTERN_EITHER +
+		PATTERN_ONEORMORE
+	for len(groups) > 0 {
+		children := groups[0]
+		groups = groups[1:]
+		var child *pattern
+		for _, c := range children {
+			if c.t&parents != 0 {
+				child = c
+				break
+			}
+		}
+		if child != nil {
+			children.remove(child)
+			if child.t&PATTERN_EITHER != 0 {
+				for _, c := range child.children {
+					r := patternList{}
+					r = append(r, c)
+					r = append(r, children...)
+					groups = append(groups, r)
+				}
+			} else if child.t&PATTERN_ONEORMORE != 0 {
+				r := patternList{}
+				r = append(r, child.children.double()...)
+				r = append(r, children...)
+				groups = append(groups, r)
+			} else {
+				r := patternList{}
+				r = append(r, child.children...)
+				r = append(r, children...)
+				groups = append(groups, r)
+			}
+		} else {
+			result = append(result, children)
+		}
+	}
+	either := patternList{}
+	for _, e := range result {
+		either = append(either, newRequired(e...))
+	}
+	return newEither(either...)
+}
+
+func (self *pattern) eq(other *pattern) bool {
+	return reflect.DeepEqual(self, other)
+}
+
+func (pl patternList) unique() patternList {
+	table := make(map[string]bool)
+	result := patternList{}
+	for _, v := range pl {
+		if !table[v.String()] {
+			table[v.String()] = true
+			result = append(result, v)
+		}
+	}
+	return result
+}
+
+func (pl patternList) index(p *pattern) (int, error) {
+	for i, c := range pl {
+		if c.eq(p) {
+			return i, nil
+		}
+	}
+	return -1, newError("%s not in list", p)
+}
+
+func (pl patternList) count(p *pattern) int {
+	count := 0
+	for _, c := range pl {
+		if c.eq(p) {
+			count++
+		}
+	}
+	return count
+}
+
+func (pl patternList) diff(l patternList) patternList {
+	l_ := make(patternList, len(l))
+	copy(l_, l)
+	result := make(patternList, 0, len(pl))
+	for _, v := range pl {
+		if v != nil {
+			match := false
+			for i, w := range l_ {
+				if w.eq(v) {
+					match = true
+					l_[i] = nil
+					break
+				}
+			}
+			if match == false {
+				result = append(result, v)
+			}
+		}
+	}
+	return result
+}
+
+func (pl patternList) double() patternList {
+	l := len(pl)
+	result := make(patternList, l*2)
+	copy(result, pl)
+	copy(result[l:2*l], pl)
+	return result
+}
+
+func (self *patternList) remove(p *pattern) {
+	(*self) = self.diff(patternList{p})
+}
+
+func (pl patternList) dictionary() map[string]interface{} {
+	dict := make(map[string]interface{})
+	for _, a := range pl {
+		dict[a.name] = a.value
+	}
+	return dict
+}
+
+func stringPartition(s, sep string) (string, string, string) {
+	sepPos := strings.Index(s, sep)
+	if sepPos == -1 { // no seperator found
+		return s, "", ""
+	}
+	split := strings.SplitN(s, sep, 2)
+	return split[0], sep, split[1]
+}
+
+func isStringUppercase(s string) bool {
+	for _, c := range s {
+		if !unicode.IsUpper(c) {
+			return false
+		}
+	}
+	return true
+}
diff --git a/docopt_test.go b/docopt_test.go
new file mode 100644
index 0000000..5f21d07
--- /dev/null
+++ b/docopt_test.go
@@ -0,0 +1,1541 @@
+/*
+Based of off docopt.py: https://github.com/docopt/docopt
+
+Licensed under terms of MIT license (see LICENSE-MIT)
+Copyright (c) 2013 Keith Batten, kbatten@gmail.com
+*/
+
+package docopt
+
+import (
+	"bufio"
+	"bytes"
+	"encoding/json"
+	"fmt"
+	"io"
+	"os"
+	"reflect"
+	"regexp"
+	"strings"
+	"testing"
+)
+
+func TestPatternFlat(t *testing.T) {
+	q := patternList{
+		newArgument("N", nil),
+		newOption("-a", "", 0, false),
+		newArgument("M", nil)}
+	p, err := newRequired(
+		newOneOrMore(newArgument("N", nil)),
+		newOption("-a", "", 0, false),
+		newArgument("M", nil)).flat(PATTERN_DEFAULT)
+	if reflect.DeepEqual(p, q) != true {
+		t.Error(err)
+	}
+
+	q = patternList{newOptionsShortcut()}
+	p, err = newRequired(
+		newOptional(newOptionsShortcut()),
+		newOptional(newOption("-a", "", 0, false))).flat(PATTERN_OPTIONSSHORTCUT)
+	if reflect.DeepEqual(p, q) != true {
+		t.Error(err)
+	}
+	return
+}
+
+func TestOption(t *testing.T) {
+	if !parseOption("-h").eq(newOption("-h", "", 0, false)) {
+		t.Error()
+	}
+	if !parseOption("--help").eq(newOption("", "--help", 0, false)) {
+		t.Error()
+	}
+	if !parseOption("-h --help").eq(newOption("-h", "--help", 0, false)) {
+		t.Error()
+	}
+	if !parseOption("-h, --help").eq(newOption("-h", "--help", 0, false)) {
+		t.Error()
+	}
+
+	if !parseOption("-h TOPIC").eq(newOption("-h", "", 1, false)) {
+		t.Error()
+	}
+	if !parseOption("--help TOPIC").eq(newOption("", "--help", 1, false)) {
+		t.Error()
+	}
+	if !parseOption("-h TOPIC --help TOPIC").eq(newOption("-h", "--help", 1, false)) {
+		t.Error()
+	}
+	if !parseOption("-h TOPIC, --help TOPIC").eq(newOption("-h", "--help", 1, false)) {
+		t.Error()
+	}
+	if !parseOption("-h TOPIC, --help=TOPIC").eq(newOption("-h", "--help", 1, false)) {
+		t.Error()
+	}
+
+	if !parseOption("-h  Description...").eq(newOption("-h", "", 0, false)) {
+		t.Error()
+	}
+	if !parseOption("-h --help  Description...").eq(newOption("-h", "--help", 0, false)) {
+		t.Error()
+	}
+	if !parseOption("-h TOPIC  Description...").eq(newOption("-h", "", 1, false)) {
+		t.Error()
+	}
+
+	if !parseOption("    -h").eq(newOption("-h", "", 0, false)) {
+		t.Error()
+	}
+
+	if !parseOption("-h TOPIC  Description... [default: 2]").eq(newOption("-h", "", 1, "2")) {
+		t.Error()
+	}
+	if !parseOption("-h TOPIC  Descripton... [default: topic-1]").eq(newOption("-h", "", 1, "topic-1")) {
+		t.Error()
+	}
+	if !parseOption("--help=TOPIC  ... [default: 3.14]").eq(newOption("", "--help", 1, "3.14")) {
+		t.Error()
+	}
+	if !parseOption("-h, --help=DIR  ... [default: ./]").eq(newOption("-h", "--help", 1, "./")) {
+		t.Error()
+	}
+	if !parseOption("-h TOPIC  Descripton... [dEfAuLt: 2]").eq(newOption("-h", "", 1, "2")) {
+		t.Error()
+	}
+	return
+}
+
+func TestOptionName(t *testing.T) {
+	if newOption("-h", "", 0, false).name != "-h" {
+		t.Error()
+	}
+	if newOption("-h", "--help", 0, false).name != "--help" {
+		t.Error()
+	}
+	if newOption("", "--help", 0, false).name != "--help" {
+		t.Error()
+	}
+	return
+}
+
+func TestCommands(t *testing.T) {
+	if v, _, err := Parse("Usage: prog add", []string{"add"}, true, "", false); reflect.DeepEqual(v, map[string]interface{}{"add": true}) != true {
+		t.Error(err)
+	}
+	if v, _, err := Parse("Usage: prog [add]", []string{}, true, "", false); reflect.DeepEqual(v, map[string]interface{}{"add": false}) != true {
+		t.Error(err)
+	}
+	if v, _, err := Parse("Usage: prog [add]", []string{"add"}, true, "", false); reflect.DeepEqual(v, map[string]interface{}{"add": true}) != true {
+		t.Error(err)
+	}
+	if v, _, err := Parse("Usage: prog (add|rm)", []string{"add"}, true, "", false); reflect.DeepEqual(v, map[string]interface{}{"add": true, "rm": false}) != true {
+		t.Error(err)
+	}
+	if v, _, err := Parse("Usage: prog (add|rm)", []string{"rm"}, true, "", false); reflect.DeepEqual(v, map[string]interface{}{"add": false, "rm": true}) != true {
+		t.Error(err)
+	}
+	if v, _, err := Parse("Usage: prog a b", []string{"a", "b"}, true, "", false); reflect.DeepEqual(v, map[string]interface{}{"a": true, "b": true}) != true {
+		t.Error(err)
+	}
+	_, _, err := Parse("Usage: prog a b", []string{"b", "a"}, true, "", false)
+	if _, ok := err.(*UserError); !ok {
+		t.Error(err)
+	}
+	return
+}
+
+func TestFormalUsage(t *testing.T) {
+	doc := `
+    Usage: prog [-hv] ARG
+           prog N M
+
+    prog is a program`
+	usage := parseSection("usage:", doc)[0]
+	if usage != "Usage: prog [-hv] ARG\n           prog N M" {
+		t.Error()
+	}
+	if formalUsage(usage) != "( [-hv] ARG ) | ( N M )" {
+		t.Error()
+	}
+	return
+}
+
+func TestParseArgv(t *testing.T) {
+	o := patternList{
+		newOption("-h", "", 0, false),
+		newOption("-v", "--verbose", 0, false),
+		newOption("-f", "--file", 1, false),
+	}
+
+	p, err := parseArgv(tokenListFromString(""), &o, false)
+	q := patternList{}
+	if reflect.DeepEqual(p, q) != true {
+		t.Error(err)
+	}
+
+	p, err = parseArgv(tokenListFromString("-h"), &o, false)
+	q = patternList{newOption("-h", "", 0, true)}
+	if reflect.DeepEqual(p, q) != true {
+		t.Error(err)
+	}
+
+	p, err = parseArgv(tokenListFromString("-h --verbose"), &o, false)
+	q = patternList{
+		newOption("-h", "", 0, true),
+		newOption("-v", "--verbose", 0, true),
+	}
+	if reflect.DeepEqual(p, q) != true {
+		t.Error(err)
+	}
+
+	p, err = parseArgv(tokenListFromString("-h --file f.txt"), &o, false)
+	q = patternList{
+		newOption("-h", "", 0, true),
+		newOption("-f", "--file", 1, "f.txt"),
+	}
+	if reflect.DeepEqual(p, q) != true {
+		t.Error(err)
+	}
+
+	p, err = parseArgv(tokenListFromString("-h --file f.txt arg"), &o, false)
+	q = patternList{
+		newOption("-h", "", 0, true),
+		newOption("-f", "--file", 1, "f.txt"),
+		newArgument("", "arg"),
+	}
+	if reflect.DeepEqual(p, q) != true {
+		t.Error(err)
+	}
+
+	p, err = parseArgv(tokenListFromString("-h --file f.txt arg arg2"), &o, false)
+	q = patternList{
+		newOption("-h", "", 0, true),
+		newOption("-f", "--file", 1, "f.txt"),
+		newArgument("", "arg"),
+		newArgument("", "arg2"),
+	}
+	if reflect.DeepEqual(p, q) != true {
+		t.Error(err)
+	}
+
+	p, err = parseArgv(tokenListFromString("-h arg -- -v"), &o, false)
+	q = patternList{
+		newOption("-h", "", 0, true),
+		newArgument("", "arg"),
+		newArgument("", "--"),
+		newArgument("", "-v"),
+	}
+	if reflect.DeepEqual(p, q) != true {
+		t.Error(err)
+	}
+}
+
+func TestParsePattern(t *testing.T) {
+	o := patternList{
+		newOption("-h", "", 0, false),
+		newOption("-v", "--verbose", 0, false),
+		newOption("-f", "--file", 1, false),
+	}
+
+	p, err := parsePattern("[ -h ]", &o)
+	q := newRequired(newOptional(newOption("-h", "", 0, false)))
+	if p.eq(q) != true {
+		t.Error(err)
+	}
+
+	p, err = parsePattern("[ ARG ... ]", &o)
+	q = newRequired(newOptional(
+		newOneOrMore(
+			newArgument("ARG", nil))))
+	if p.eq(q) != true {
+		t.Error(err)
+	}
+
+	p, err = parsePattern("[ -h | -v ]", &o)
+	q = newRequired(
+		newOptional(
+			newEither(
+				newOption("-h", "", 0, false),
+				newOption("-v", "--verbose", 0, false))))
+	if p.eq(q) != true {
+		t.Error(err)
+	}
+
+	p, err = parsePattern("( -h | -v [ --file <f> ] )", &o)
+	q = newRequired(
+		newRequired(
+			newEither(
+				newOption("-h", "", 0, false),
+				newRequired(
+					newOption("-v", "--verbose", 0, false),
+					newOptional(
+						newOption("-f", "--file", 1, nil))))))
+	if p.eq(q) != true {
+		t.Error(err)
+	}
+
+	p, err = parsePattern("(-h|-v[--file=<f>]N...)", &o)
+	q = newRequired(
+		newRequired(
+			newEither(
+				newOption("-h", "", 0, false),
+				newRequired(
+					newOption("-v", "--verbose", 0, false),
+					newOptional(
+						newOption("-f", "--file", 1, nil)),
+					newOneOrMore(
+						newArgument("N", nil))))))
+	if p.eq(q) != true {
+		t.Error(err)
+	}
+
+	p, err = parsePattern("(N [M | (K | L)] | O P)", &o)
+	q = newRequired(
+		newRequired(
+			newEither(
+				newRequired(
+					newArgument("N", nil),
+					newOptional(
+						newEither(
+							newArgument("M", nil),
+							newRequired(
+								newEither(
+									newArgument("K", nil),
+									newArgument("L", nil)))))),
+				newRequired(
+					newArgument("O", nil),
+					newArgument("P", nil)))))
+	if p.eq(q) != true {
+		t.Error(err)
+	}
+
+	p, err = parsePattern("[ -h ] [N]", &o)
+	q = newRequired(
+		newOptional(
+			newOption("-h", "", 0, false)),
+		newOptional(
+			newArgument("N", nil)))
+	if p.eq(q) != true {
+		t.Error(err)
+	}
+
+	p, err = parsePattern("[options]", &o)
+	q = newRequired(
+		newOptional(
+			newOptionsShortcut()))
+	if p.eq(q) != true {
+		t.Error(err)
+	}
+
+	p, err = parsePattern("[options] A", &o)
+	q = newRequired(
+		newOptional(
+			newOptionsShortcut()),
+		newArgument("A", nil))
+	if p.eq(q) != true {
+		t.Error(err)
+	}
+
+	p, err = parsePattern("-v [options]", &o)
+	q = newRequired(
+		newOption("-v", "--verbose", 0, false),
+		newOptional(
+			newOptionsShortcut()))
+	if p.eq(q) != true {
+		t.Error(err)
+	}
+
+	p, err = parsePattern("ADD", &o)
+	q = newRequired(newArgument("ADD", nil))
+	if p.eq(q) != true {
+		t.Error(err)
+	}
+
+	p, err = parsePattern("<add>", &o)
+	q = newRequired(newArgument("<add>", nil))
+	if p.eq(q) != true {
+		t.Error(err)
+	}
+
+	p, err = parsePattern("add", &o)
+	q = newRequired(newCommand("add", false))
+	if p.eq(q) != true {
+		t.Error(err)
+	}
+}
+
+func TestOptionMatch(t *testing.T) {
+	v, w, x := newOption("-a", "", 0, false).match(
+		&patternList{newOption("-a", "", 0, true)}, nil)
+	y := patternList{newOption("-a", "", 0, true)}
+	if v != true ||
+		reflect.DeepEqual(*w, patternList{}) != true ||
+		reflect.DeepEqual(*x, y) != true {
+		t.Error()
+	}
+
+	v, w, x = newOption("-a", "", 0, false).match(
+		&patternList{newOption("-x", "", 0, false)}, nil)
+	y = patternList{newOption("-x", "", 0, false)}
+	if v != false ||
+		reflect.DeepEqual(*w, y) != true ||
+		reflect.DeepEqual(*x, patternList{}) != true {
+		t.Error()
+	}
+
+	v, w, x = newOption("-a", "", 0, false).match(
+		&patternList{newOption("-x", "", 0, false)}, nil)
+	y = patternList{newOption("-x", "", 0, false)}
+	if v != false ||
+		reflect.DeepEqual(*w, y) != true ||
+		reflect.DeepEqual(*x, patternList{}) != true {
+		t.Error()
+	}
+	v, w, x = newOption("-a", "", 0, false).match(
+		&patternList{newArgument("N", nil)}, nil)
+	y = patternList{newArgument("N", nil)}
+	if v != false ||
+		reflect.DeepEqual(*w, y) != true ||
+		reflect.DeepEqual(*x, patternList{}) != true {
+		t.Error()
+	}
+
+	v, w, x = newOption("-a", "", 0, false).match(
+		&patternList{
+			newOption("-x", "", 0, false),
+			newOption("-a", "", 0, false),
+			newArgument("N", nil)}, nil)
+	y = patternList{
+		newOption("-x", "", 0, false),
+		newArgument("N", nil)}
+	z := patternList{newOption("-a", "", 0, false)}
+	if v != true ||
+		reflect.DeepEqual(*w, y) != true ||
+		reflect.DeepEqual(*x, z) != true {
+		t.Error()
+	}
+
+	v, w, x = newOption("-a", "", 0, false).match(
+		&patternList{
+			newOption("-a", "", 0, true),
+			newOption("-a", "", 0, false)}, nil)
+	y = patternList{newOption("-a", "", 0, false)}
+	z = patternList{newOption("-a", "", 0, true)}
+	if v != true ||
+		reflect.DeepEqual(*w, y) != true ||
+		reflect.DeepEqual(*x, z) != true {
+		t.Error()
+	}
+}
+
+func TestArgumentMatch(t *testing.T) {
+	v, w, x := newArgument("N", nil).match(
+		&patternList{newArgument("N", 9)}, nil)
+	y := patternList{newArgument("N", 9)}
+	if v != true ||
+		reflect.DeepEqual(*w, patternList{}) != true ||
+		reflect.DeepEqual(*x, y) != true {
+		t.Error()
+	}
+
+	v, w, x = newArgument("N", nil).match(
+		&patternList{newOption("-x", "", 0, false)}, nil)
+	y = patternList{newOption("-x", "", 0, false)}
+	if v != false ||
+		reflect.DeepEqual(*w, y) != true ||
+		reflect.DeepEqual(*x, patternList{}) != true {
+		t.Error()
+	}
+
+	v, w, x = newArgument("N", nil).match(
+		&patternList{newOption("-x", "", 0, false),
+			newOption("-a", "", 0, false),
+			newArgument("", 5)}, nil)
+	y = patternList{newOption("-x", "", 0, false),
+		newOption("-a", "", 0, false)}
+	z := patternList{newArgument("N", 5)}
+	if v != true ||
+		reflect.DeepEqual(*w, y) != true ||
+		reflect.DeepEqual(*x, z) != true {
+		t.Error()
+	}
+
+	v, w, x = newArgument("N", nil).match(
+		&patternList{newArgument("", 9),
+			newArgument("", 0)}, nil)
+	y = patternList{newArgument("", 0)}
+	z = patternList{newArgument("N", 9)}
+	if v != true ||
+		reflect.DeepEqual(*w, y) != true ||
+		reflect.DeepEqual(*x, z) != true {
+		t.Error()
+	}
+}
+
+func TestCommandMatch(t *testing.T) {
+	v, w, x := newCommand("c", false).match(
+		&patternList{newArgument("", "c")}, nil)
+	y := patternList{newCommand("c", true)}
+	if v != true ||
+		reflect.DeepEqual(*w, patternList{}) != true ||
+		reflect.DeepEqual(*x, y) != true {
+		t.Error()
+	}
+
+	v, w, x = newCommand("c", false).match(
+		&patternList{newOption("-x", "", 0, false)}, nil)
+	y = patternList{newOption("-x", "", 0, false)}
+	if v != false ||
+		reflect.DeepEqual(*w, y) != true ||
+		reflect.DeepEqual(*x, patternList{}) != true {
+		t.Error()
+	}
+
+	v, w, x = newCommand("c", false).match(
+		&patternList{
+			newOption("-x", "", 0, false),
+			newOption("-a", "", 0, false),
+			newArgument("", "c")}, nil)
+	y = patternList{newOption("-x", "", 0, false),
+		newOption("-a", "", 0, false)}
+	z := patternList{newCommand("c", true)}
+	if v != true ||
+		reflect.DeepEqual(*w, y) != true ||
+		reflect.DeepEqual(*x, z) != true {
+		t.Error()
+	}
+
+	v, w, x = newEither(
+		newCommand("add", false),
+		newCommand("rm", false)).match(
+		&patternList{newArgument("", "rm")}, nil)
+	y = patternList{newCommand("rm", true)}
+	if v != true ||
+		reflect.DeepEqual(*w, patternList{}) != true ||
+		reflect.DeepEqual(*x, y) != true {
+		t.Error()
+	}
+}
+
+func TestOptionalMatch(t *testing.T) {
+	v, w, x := newOptional(newOption("-a", "", 0, false)).match(
+		&patternList{newOption("-a", "", 0, false)}, nil)
+	y := patternList{newOption("-a", "", 0, false)}
+	if v != true ||
+		reflect.DeepEqual(*w, patternList{}) != true ||
+		reflect.DeepEqual(*x, y) != true {
+		t.Error()
+	}
+
+	v, w, x = newOptional(newOption("-a", "", 0, false)).match(
+		&patternList{}, nil)
+	if v != true ||
+		reflect.DeepEqual(*w, patternList{}) != true ||
+		reflect.DeepEqual(*x, patternList{}) != true {
+		t.Error()
+	}
+
+	v, w, x = newOptional(newOption("-a", "", 0, false)).match(
+		&patternList{newOption("-x", "", 0, false)}, nil)
+	y = patternList{newOption("-x", "", 0, false)}
+	if v != true ||
+		reflect.DeepEqual(*w, y) != true ||
+		reflect.DeepEqual(*x, patternList{}) != true {
+		t.Error()
+	}
+
+	v, w, x = newOptional(newOption("-a", "", 0, false),
+		newOption("-b", "", 0, false)).match(
+		&patternList{newOption("-a", "", 0, false)}, nil)
+	y = patternList{newOption("-a", "", 0, false)}
+	if v != true ||
+		reflect.DeepEqual(*w, patternList{}) != true ||
+		reflect.DeepEqual(*x, y) != true {
+		t.Error()
+	}
+
+	v, w, x = newOptional(newOption("-a", "", 0, false),
+		newOption("-b", "", 0, false)).match(
+		&patternList{newOption("-b", "", 0, false)}, nil)
+	y = patternList{newOption("-b", "", 0, false)}
+	if v != true ||
+		reflect.DeepEqual(*w, patternList{}) != true ||
+		reflect.DeepEqual(*x, y) != true {
+		t.Error()
+	}
+
+	v, w, x = newOptional(newOption("-a", "", 0, false),
+		newOption("-b", "", 0, false)).match(
+		&patternList{newOption("-x", "", 0, false)}, nil)
+	y = patternList{newOption("-x", "", 0, false)}
+	if v != true ||
+		reflect.DeepEqual(*w, y) != true ||
+		reflect.DeepEqual(*x, patternList{}) != true {
+		t.Error()
+	}
+
+	v, w, x = newOptional(newArgument("N", nil)).match(
+		&patternList{newArgument("", 9)}, nil)
+	y = patternList{newArgument("N", 9)}
+	if v != true ||
+		reflect.DeepEqual(*w, patternList{}) != true ||
+		reflect.DeepEqual(*x, y) != true {
+		t.Error()
+	}
+
+	v, w, x = newOptional(newOption("-a", "", 0, false),
+		newOption("-b", "", 0, false)).match(
+		&patternList{newOption("-b", "", 0, false),
+			newOption("-x", "", 0, false),
+			newOption("-a", "", 0, false)}, nil)
+	y = patternList{newOption("-x", "", 0, false)}
+	z := patternList{newOption("-a", "", 0, false),
+		newOption("-b", "", 0, false)}
+	if v != true ||
+		reflect.DeepEqual(*w, y) != true ||
+		reflect.DeepEqual(*x, z) != true {
+		t.Error()
+	}
+}
+
+func TestRequiredMatch(t *testing.T) {
+	v, w, x := newRequired(newOption("-a", "", 0, false)).match(
+		&patternList{newOption("-a", "", 0, false)}, nil)
+	y := patternList{newOption("-a", "", 0, false)}
+	if v != true ||
+		reflect.DeepEqual(*w, patternList{}) != true ||
+		reflect.DeepEqual(*x, y) != true {
+		t.Error()
+	}
+
+	v, w, x = newRequired(newOption("-a", "", 0, false)).match(&patternList{}, nil)
+	if v != false ||
+		reflect.DeepEqual(*w, patternList{}) != true ||
+		reflect.DeepEqual(*x, patternList{}) != true {
+		t.Error()
+	}
+
+	v, w, x = newRequired(newOption("-a", "", 0, false)).match(
+		&patternList{newOption("-x", "", 0, false)}, nil)
+	y = patternList{newOption("-x", "", 0, false)}
+	if v != false ||
+		reflect.DeepEqual(*w, y) != true ||
+		reflect.DeepEqual(*x, patternList{}) != true {
+		t.Error()
+	}
+	v, w, x = newRequired(newOption("-a", "", 0, false),
+		newOption("-b", "", 0, false)).match(
+		&patternList{newOption("-a", "", 0, false)}, nil)
+	y = patternList{newOption("-a", "", 0, false)}
+	if v != false ||
+		reflect.DeepEqual(*w, y) != true ||
+		reflect.DeepEqual(*x, patternList{}) != true {
+		t.Error()
+	}
+}
+
+func TestEitherMatch(t *testing.T) {
+	v, w, x := newEither(
+		newOption("-a", "", 0, false),
+		newOption("-b", "", 0, false)).match(
+		&patternList{newOption("-a", "", 0, false)}, nil)
+	y := patternList{newOption("-a", "", 0, false)}
+	if v != true ||
+		reflect.DeepEqual(*w, patternList{}) != true ||
+		reflect.DeepEqual(*x, y) != true {
+		t.Error()
+	}
+
+	v, w, x = newEither(
+		newOption("-a", "", 0, false),
+		newOption("-b", "", 0, false)).match(&patternList{
+		newOption("-a", "", 0, false),
+		newOption("-b", "", 0, false)}, nil)
+	y = patternList{newOption("-b", "", 0, false)}
+	z := patternList{newOption("-a", "", 0, false)}
+	if v != true ||
+		reflect.DeepEqual(*w, y) != true ||
+		reflect.DeepEqual(*x, z) != true {
+		t.Error()
+	}
+
+	v, w, x = newEither(
+		newOption("-a", "", 0, false),
+		newOption("-b", "", 0, false)).match(&patternList{
+		newOption("-x", "", 0, false)}, nil)
+	y = patternList{newOption("-x", "", 0, false)}
+	z = patternList{}
+	if v != false ||
+		reflect.DeepEqual(*w, y) != true ||
+		reflect.DeepEqual(*x, z) != true {
+		t.Error()
+	}
+
+	v, w, x = newEither(
+		newOption("-a", "", 0, false),
+		newOption("-b", "", 0, false),
+		newOption("-c", "", 0, false)).match(&patternList{
+		newOption("-x", "", 0, false),
+		newOption("-b", "", 0, false)}, nil)
+	y = patternList{newOption("-x", "", 0, false)}
+	z = patternList{newOption("-b", "", 0, false)}
+	if v != true ||
+		reflect.DeepEqual(*w, y) != true ||
+		reflect.DeepEqual(*x, z) != true {
+		t.Error()
+	}
+	v, w, x = newEither(
+		newArgument("M", nil),
+		newRequired(newArgument("N", nil),
+			newArgument("M", nil))).match(&patternList{
+		newArgument("", 1),
+		newArgument("", 2)}, nil)
+	y = patternList{}
+	z = patternList{newArgument("N", 1), newArgument("M", 2)}
+	if v != true ||
+		reflect.DeepEqual(*w, y) != true ||
+		reflect.DeepEqual(*x, z) != true {
+		t.Error()
+	}
+}
+
+func TestOneOrMoreMatch(t *testing.T) {
+	v, w, x := newOneOrMore(newArgument("N", nil)).match(
+		&patternList{newArgument("", 9)}, nil)
+	y := patternList{newArgument("N", 9)}
+	if v != true ||
+		reflect.DeepEqual(*w, patternList{}) != true ||
+		reflect.DeepEqual(*x, y) != true {
+		t.Error()
+	}
+
+	v, w, x = newOneOrMore(newArgument("N", nil)).match(
+		&patternList{}, nil)
+	y = patternList{}
+	z := patternList{}
+	if v != false ||
+		reflect.DeepEqual(*w, y) != true ||
+		reflect.DeepEqual(*x, z) != true {
+		t.Error()
+	}
+
+	v, w, x = newOneOrMore(newArgument("N", nil)).match(
+		&patternList{newOption("-x", "", 0, false)}, nil)
+	y = patternList{newOption("-x", "", 0, false)}
+	z = patternList{}
+	if v != false ||
+		reflect.DeepEqual(*w, y) != true ||
+		reflect.DeepEqual(*x, z) != true {
+		t.Error()
+	}
+
+	v, w, x = newOneOrMore(newArgument("N", nil)).match(
+		&patternList{newArgument("", 9), newArgument("", 8)}, nil)
+	y = patternList{}
+	z = patternList{newArgument("N", 9), newArgument("N", 8)}
+	if v != true ||
+		reflect.DeepEqual(*w, y) != true ||
+		reflect.DeepEqual(*x, z) != true {
+		t.Error()
+	}
+
+	v, w, x = newOneOrMore(newArgument("N", nil)).match(&patternList{
+		newArgument("", 9),
+		newOption("-x", "", 0, false),
+		newArgument("", 8)}, nil)
+	y = patternList{newOption("-x", "", 0, false)}
+	z = patternList{newArgument("N", 9), newArgument("N", 8)}
+	if v != true ||
+		reflect.DeepEqual(*w, y) != true ||
+		reflect.DeepEqual(*x, z) != true {
+		t.Error()
+	}
+
+	v, w, x = newOneOrMore(newOption("-a", "", 0, false)).match(&patternList{
+		newOption("-a", "", 0, false),
+		newArgument("", 8),
+		newOption("-a", "", 0, false)}, nil)
+	y = patternList{newArgument("", 8)}
+	z = patternList{newOption("-a", "", 0, false), newOption("-a", "", 0, false)}
+	if v != true ||
+		reflect.DeepEqual(*w, y) != true ||
+		reflect.DeepEqual(*x, z) != true {
+		t.Error()
+	}
+
+	v, w, x = newOneOrMore(newOption("-a", "", 0, false)).match(&patternList{
+		newArgument("", 8),
+		newOption("-x", "", 0, false)}, nil)
+	y = patternList{newArgument("", 8), newOption("-x", "", 0, false)}
+	z = patternList{}
+	if v != false ||
+		reflect.DeepEqual(*w, y) != true ||
+		reflect.DeepEqual(*x, z) != true {
+		t.Error()
+	}
+
+	v, w, x = newOneOrMore(newRequired(newOption("-a", "", 0, false),
+		newArgument("N", nil))).match(&patternList{
+		newOption("-a", "", 0, false),
+		newArgument("", 1),
+		newOption("-x", "", 0, false),
+		newOption("-a", "", 0, false),
+		newArgument("", 2)}, nil)
+	y = patternList{newOption("-x", "", 0, false)}
+	z = patternList{newOption("-a", "", 0, false),
+		newArgument("N", 1),
+		newOption("-a", "", 0, false),
+		newArgument("N", 2)}
+	if v != true ||
+		reflect.DeepEqual(*w, y) != true ||
+		reflect.DeepEqual(*x, z) != true {
+		t.Error()
+	}
+
+	v, w, x = newOneOrMore(newOptional(newArgument("N", nil))).match(
+		&patternList{newArgument("", 9)}, nil)
+	y = patternList{}
+	z = patternList{newArgument("N", 9)}
+	if v != true ||
+		reflect.DeepEqual(*w, y) != true ||
+		reflect.DeepEqual(*x, z) != true {
+		t.Error()
+	}
+}
+
+func TestListArgumentMatch(t *testing.T) {
+	p := newRequired(
+		newArgument("N", nil),
+		newArgument("N", nil))
+	p.fix()
+	v, w, x := p.match(&patternList{newArgument("", "1"),
+		newArgument("", "2")}, nil)
+	y := patternList{newArgument("N", []string{"1", "2"})}
+	if v != true ||
+		reflect.DeepEqual(*w, patternList{}) != true ||
+		reflect.DeepEqual(*x, y) != true {
+		t.Error()
+	}
+
+	p = newOneOrMore(newArgument("N", nil))
+	p.fix()
+	v, w, x = p.match(&patternList{newArgument("", "1"),
+		newArgument("", "2"), newArgument("", "3")}, nil)
+	y = patternList{newArgument("N", []string{"1", "2", "3"})}
+	if v != true ||
+		reflect.DeepEqual(*w, patternList{}) != true ||
+		reflect.DeepEqual(*x, y) != true {
+		t.Error()
+	}
+
+	p = newRequired(newArgument("N", nil),
+		newOneOrMore(newArgument("N", nil)))
+	p.fix()
+	v, w, x = p.match(&patternList{
+		newArgument("", "1"),
+		newArgument("", "2"),
+		newArgument("", "3")}, nil)
+	y = patternList{newArgument("N", []string{"1", "2", "3"})}
+	if v != true ||
+		reflect.DeepEqual(*w, patternList{}) != true ||
+		reflect.DeepEqual(*x, y) != true {
+		t.Error()
+	}
+
+	p = newRequired(newArgument("N", nil),
+		newRequired(newArgument("N", nil)))
+	p.fix()
+	v, w, x = p.match(&patternList{
+		newArgument("", "1"),
+		newArgument("", "2")}, nil)
+	y = patternList{newArgument("N", []string{"1", "2"})}
+	if v != true ||
+		reflect.DeepEqual(*w, patternList{}) != true ||
+		reflect.DeepEqual(*x, y) != true {
+		t.Error()
+	}
+}
+
+func TestBasicPatternMatching(t *testing.T) {
+	// ( -a N [ -x Z ] )
+	p := newRequired(
+		newOption("-a", "", 0, false),
+		newArgument("N", nil),
+		newOptional(
+			newOption("-x", "", 0, false),
+			newArgument("Z", nil)))
+
+	// -a N
+	q := patternList{newOption("-a", "", 0, false), newArgument("", 9)}
+	y := patternList{newOption("-a", "", 0, false), newArgument("N", 9)}
+	v, w, x := p.match(&q, nil)
+	if v != true ||
+		reflect.DeepEqual(*w, patternList{}) != true ||
+		reflect.DeepEqual(*x, y) != true {
+		t.Error()
+	}
+
+	// -a -x N Z
+	q = patternList{newOption("-a", "", 0, false),
+		newOption("-x", "", 0, false),
+		newArgument("", 9), newArgument("", 5)}
+	y = patternList{}
+	z := patternList{newOption("-a", "", 0, false), newArgument("N", 9),
+		newOption("-x", "", 0, false), newArgument("Z", 5)}
+	v, w, x = p.match(&q, nil)
+	if v != true ||
+		reflect.DeepEqual(*w, y) != true ||
+		reflect.DeepEqual(*x, z) != true {
+		t.Error()
+	}
+
+	// -x N Z  # BZZ!
+	q = patternList{newOption("-x", "", 0, false),
+		newArgument("", 9), newArgument("", 5)}
+	y = patternList{newOption("-x", "", 0, false),
+		newArgument("", 9), newArgument("", 5)}
+	z = patternList{}
+	v, w, x = p.match(&q, nil)
+	if v != false ||
+		reflect.DeepEqual(*w, y) != true ||
+		reflect.DeepEqual(*x, z) != true {
+		t.Error()
+	}
+}
+
+func TestPatternEither(t *testing.T) {
+	p := newOption("-a", "", 0, false).transform()
+	q := newEither(newRequired(
+		newOption("-a", "", 0, false)))
+	if p.eq(q) != true {
+		t.Error()
+	}
+
+	p = newArgument("A", nil).transform()
+	q = newEither(newRequired(
+		newArgument("A", nil)))
+	if p.eq(q) != true {
+		t.Error()
+	}
+
+	p = newRequired(
+		newEither(
+			newOption("-a", "", 0, false),
+			newOption("-b", "", 0, false)),
+		newOption("-c", "", 0, false)).transform()
+	q = newEither(
+		newRequired(
+			newOption("-a", "", 0, false),
+			newOption("-c", "", 0, false)),
+		newRequired(
+			newOption("-b", "", 0, false),
+			newOption("-c", "", 0, false)))
+	if p.eq(q) != true {
+		t.Error()
+	}
+
+	p = newOptional(newOption("-a", "", 0, false),
+		newEither(newOption("-b", "", 0, false),
+			newOption("-c", "", 0, false))).transform()
+	q = newEither(
+		newRequired(
+			newOption("-b", "", 0, false), newOption("-a", "", 0, false)),
+		newRequired(
+			newOption("-c", "", 0, false), newOption("-a", "", 0, false)))
+	if p.eq(q) != true {
+		t.Error()
+	}
+
+	p = newEither(newOption("-x", "", 0, false),
+		newEither(newOption("-y", "", 0, false),
+			newOption("-z", "", 0, false))).transform()
+	q = newEither(
+		newRequired(newOption("-x", "", 0, false)),
+		newRequired(newOption("-y", "", 0, false)),
+		newRequired(newOption("-z", "", 0, false)))
+	if p.eq(q) != true {
+		t.Error()
+	}
+
+	p = newOneOrMore(newArgument("N", nil),
+		newArgument("M", nil)).transform()
+	q = newEither(
+		newRequired(newArgument("N", nil), newArgument("M", nil),
+			newArgument("N", nil), newArgument("M", nil)))
+	if p.eq(q) != true {
+		t.Error()
+	}
+}
+
+func TestPatternFixRepeatingArguments(t *testing.T) {
+	p := newOption("-a", "", 0, false)
+	p.fixRepeatingArguments()
+	if p.eq(newOption("-a", "", 0, false)) != true {
+		t.Error()
+	}
+
+	p = newArgument("N", nil)
+	p.fixRepeatingArguments()
+	if p.eq(newArgument("N", nil)) != true {
+		t.Error()
+	}
+
+	p = newRequired(
+		newArgument("N", nil),
+		newArgument("N", nil))
+	q := newRequired(
+		newArgument("N", []string{}),
+		newArgument("N", []string{}))
+	p.fixRepeatingArguments()
+	if p.eq(q) != true {
+		t.Error()
+	}
+
+	p = newEither(
+		newArgument("N", nil),
+		newOneOrMore(newArgument("N", nil)))
+	q = newEither(
+		newArgument("N", []string{}),
+		newOneOrMore(newArgument("N", []string{})))
+	p.fix()
+	if p.eq(q) != true {
+		t.Error()
+	}
+}
+
+func TestSet(t *testing.T) {
+	p := newArgument("N", nil)
+	q := newArgument("N", nil)
+	if reflect.DeepEqual(p, q) != true {
+		t.Error()
+	}
+	pl := patternList{newArgument("N", nil), newArgument("N", nil)}
+	ql := patternList{newArgument("N", nil)}
+	if reflect.DeepEqual(pl.unique(), ql.unique()) != true {
+		t.Error()
+	}
+}
+
+func TestPatternFixIdentities1(t *testing.T) {
+	p := newRequired(
+		newArgument("N", nil),
+		newArgument("N", nil))
+	if len(p.children) < 2 {
+		t.Fatal()
+	}
+	if p.children[0].eq(p.children[1]) != true {
+		t.Error()
+	}
+	if p.children[0] == p.children[1] {
+		t.Error()
+	}
+	p.fixIdentities(nil)
+	if p.children[0] != p.children[1] {
+		t.Error()
+	}
+}
+
+func TestPatternFixIdentities2(t *testing.T) {
+	p := newRequired(
+		newOptional(
+			newArgument("X", nil),
+			newArgument("N", nil)),
+		newArgument("N", nil))
+	if len(p.children) < 2 {
+		t.Fatal()
+	}
+	if len(p.children[0].children) < 2 {
+		t.Fatal()
+	}
+	if p.children[0].children[1].eq(p.children[1]) != true {
+		t.Error()
+	}
+	if p.children[0].children[1] == p.children[1] {
+		t.Error()
+	}
+	p.fixIdentities(nil)
+	if p.children[0].children[1] != p.children[1] {
+		t.Error()
+	}
+}
+
+func TestLongOptionsErrorHandling(t *testing.T) {
+	_, _, err := Parse("Usage: prog", []string{"--non-existent"}, true, "", false)
+	if _, ok := err.(*UserError); !ok {
+		t.Error(fmt.Sprintf("(%s) %s", reflect.TypeOf(err), err))
+	}
+	_, _, err = Parse("Usage: prog [--version --verbose]\nOptions: --version\n --verbose",
+		[]string{"--ver"}, true, "", false)
+	if _, ok := err.(*UserError); !ok {
+		t.Error(err)
+	}
+	_, _, err = Parse("Usage: prog --long\nOptions: --long ARG", []string{}, true, "", false)
+	if _, ok := err.(*LanguageError); !ok {
+		t.Error(err)
+	}
+	_, _, err = Parse("Usage: prog --long ARG\nOptions: --long ARG",
+		[]string{"--long"}, true, "", false)
+	if _, ok := err.(*UserError); !ok {
+		t.Error(fmt.Sprintf("(%s) %s", reflect.TypeOf(err), err))
+	}
+	_, _, err = Parse("Usage: prog --long=ARG\nOptions: --long", []string{}, true, "", false)
+	if _, ok := err.(*LanguageError); !ok {
+		t.Error(err)
+	}
+	_, _, err = Parse("Usage: prog --long\nOptions: --long",
+		[]string{}, true, "--long=ARG", false)
+	if _, ok := err.(*UserError); !ok {
+		t.Error(err)
+	}
+}
+
+func TestShortOptionsErrorHandling(t *testing.T) {
+	_, _, err := Parse("Usage: prog -x\nOptions: -x  this\n -x  that", []string{}, true, "", false)
+	if _, ok := err.(*LanguageError); !ok {
+		t.Error(fmt.Sprintf("(%s) %s", reflect.TypeOf(err), err))
+	}
+	_, _, err = Parse("Usage: prog", []string{"-x"}, true, "", false)
+	if _, ok := err.(*UserError); !ok {
+		t.Error(err)
+	}
+	_, _, err = Parse("Usage: prog -o\nOptions: -o ARG", []string{}, true, "", false)
+	if _, ok := err.(*LanguageError); !ok {
+		t.Error(err)
+	}
+	_, _, err = Parse("Usage: prog -o ARG\nOptions: -o ARG", []string{"-o"}, true, "", false)
+	if _, ok := err.(*UserError); !ok {
+		t.Error(err)
+	}
+}
+
+func TestMatchingParen(t *testing.T) {
+	_, _, err := Parse("Usage: prog [a [b]", []string{}, true, "", false)
+	if _, ok := err.(*LanguageError); !ok {
+		t.Error(err)
+	}
+	_, _, err = Parse("Usage: prog [a [b] ] c )", []string{}, true, "", false)
+	if _, ok := err.(*LanguageError); !ok {
+		t.Error(err)
+	}
+}
+
+func TestAllowDoubleDash(t *testing.T) {
+	if v, _, err := Parse("usage: prog [-o] [--] <arg>\noptions: -o", []string{"--", "-o"}, true, "", false); reflect.DeepEqual(v, map[string]interface{}{"-o": false, "<arg>": "-o", "--": true}) != true {
+		t.Error(err)
+	}
+	if v, _, err := Parse("usage: prog [-o] [--] <arg>\noptions: -o", []string{"-o", "1"}, true, "", false); reflect.DeepEqual(v, map[string]interface{}{"-o": true, "<arg>": "1", "--": false}) != true {
+		t.Error(err)
+	}
+	_, _, err := Parse("usage: prog [-o] <arg>\noptions:-o", []string{"-o"}, true, "", false)
+	if _, ok := err.(*UserError); !ok { //"--" is not allowed; FIXME?
+		t.Error(err)
+	}
+}
+
+func TestDocopt(t *testing.T) {
+	doc := `Usage: prog [-v] A
+
+                Options: -v  Be verbose.`
+	if v, _, err := Parse(doc, []string{"arg"}, true, "", false); reflect.DeepEqual(v, map[string]interface{}{"-v": false, "A": "arg"}) != true {
+		t.Error(err)
+	}
+	if v, _, err := Parse(doc, []string{"-v", "arg"}, true, "", false); reflect.DeepEqual(v, map[string]interface{}{"-v": true, "A": "arg"}) != true {
+		t.Error(err)
+	}
+
+	doc = `Usage: prog [-vqr] [FILE]
+              prog INPUT OUTPUT
+              prog --help
+
+    Options:
+      -v  print status messages
+      -q  report only file names
+      -r  show all occurrences of the same error
+      --help
+
+    `
+	if v, _, err := Parse(doc, []string{"-v", "file.py"}, true, "", false); reflect.DeepEqual(v, map[string]interface{}{"-v": true, "-q": false, "-r": false, "--help": false, "FILE": "file.py", "INPUT": nil, "OUTPUT": nil}) != true {
+		t.Error(err)
+	}
+	if v, _, err := Parse(doc, []string{"-v"}, true, "", false); reflect.DeepEqual(v, map[string]interface{}{"-v": true, "-q": false, "-r": false, "--help": false, "FILE": nil, "INPUT": nil, "OUTPUT": nil}) != true {
+		t.Error(err)
+	}
+
+	_, _, err := Parse(doc, []string{"-v", "input.py", "output.py"}, true, "", false) // does not match
+	if _, ok := err.(*UserError); !ok {
+		t.Error(err)
+	}
+	_, _, err = Parse(doc, []string{"--fake"}, true, "", false)
+	if _, ok := err.(*UserError); !ok {
+		t.Error(err)
+	}
+	_, output, err := Parse(doc, []string{"--hel"}, true, "", false)
+	if err != nil || len(output) == 0 {
+		t.Error(err)
+	}
+}
+
+func TestLanguageErrors(t *testing.T) {
+	_, _, err := Parse("no usage with colon here", []string{}, true, "", false)
+	if _, ok := err.(*LanguageError); !ok {
+		t.Error(err)
+	}
+	_, _, err = Parse("usage: here \n\n and again usage: here", []string{}, true, "", false)
+	if _, ok := err.(*LanguageError); !ok {
+		t.Error(err)
+	}
+}
+
+func TestIssue40(t *testing.T) {
+	_, output, err := Parse("usage: prog --help-commands | --help", []string{"--help"}, true, "", false)
+	if err != nil || len(output) == 0 {
+		t.Error(err)
+	}
+	if v, _, err := Parse("usage: prog --aabb | --aa", []string{"--aa"}, true, "", false); reflect.DeepEqual(v, map[string]interface{}{"--aabb": false, "--aa": true}) != true {
+		t.Error(err)
+	}
+}
+
+func TestIssue34UnicodeStrings(t *testing.T) {
+	// TODO: see if applicable
+}
+
+func TestCountMultipleFlags(t *testing.T) {
+	if v, _, err := Parse("usage: prog [-v]", []string{"-v"}, true, "", false); reflect.DeepEqual(v, map[string]interface{}{"-v": true}) != true {
+		t.Error(err)
+	}
+	if v, _, err := Parse("usage: prog [-vv]", nil, true, "", false); reflect.DeepEqual(v, map[string]interface{}{"-v": 0}) != true {
+		t.Error(err)
+	}
+	if v, _, err := Parse("usage: prog [-vv]", []string{"-v"}, true, "", false); reflect.DeepEqual(v, map[string]interface{}{"-v": 1}) != true {
+		t.Error(err)
+	}
+	if v, _, err := Parse("usage: prog [-vv]", []string{"-vv"}, true, "", false); reflect.DeepEqual(v, map[string]interface{}{"-v": 2}) != true {
+		t.Error(err)
+	}
+	_, _, err := Parse("usage: prog [-vv]", []string{"-vvv"}, true, "", false)
+	if _, ok := err.(*UserError); !ok {
+		t.Error(err)
+	}
+	if v, _, err := Parse("usage: prog [-v | -vv | -vvv]", []string{"-vvv"}, true, "", false); reflect.DeepEqual(v, map[string]interface{}{"-v": 3}) != true {
+		t.Error(err)
+	}
+	if v, _, err := Parse("usage: prog [-v...]", []string{"-vvvvvv"}, true, "", false); reflect.DeepEqual(v, map[string]interface{}{"-v": 6}) != true {
+		t.Error(err)
+	}
+	if v, _, err := Parse("usage: prog [--ver --ver]", []string{"--ver", "--ver"}, true, "", false); reflect.DeepEqual(v, map[string]interface{}{"--ver": 2}) != true {
+		t.Error(err)
+	}
+}
+
+func TestAnyOptionsParameter(t *testing.T) {
+	_, _, err := Parse("usage: prog [options]",
+		[]string{"-foo", "--bar", "--spam=eggs"}, true, "", false)
+	if _, ok := err.(*UserError); !ok {
+		t.Error()
+	}
+
+	_, _, err = Parse("usage: prog [options]",
+		[]string{"--foo", "--bar", "--bar"}, true, "", false)
+	if _, ok := err.(*UserError); !ok {
+		t.Error()
+	}
+	_, _, err = Parse("usage: prog [options]",
+		[]string{"--bar", "--bar", "--bar", "-ffff"}, true, "", false)
+	if _, ok := err.(*UserError); !ok {
+		t.Error()
+	}
+	_, _, err = Parse("usage: prog [options]",
+		[]string{"--long=arg", "--long=another"}, true, "", false)
+	if _, ok := err.(*UserError); !ok {
+		t.Error()
+	}
+}
+
+func TestDefaultValueForPositionalArguments(t *testing.T) {
+	if v, _, err := Parse("usage: prog [<p>]\n\n<p>  [default: x]", []string{}, true, "", false); reflect.DeepEqual(v, map[string]interface{}{"<p>": nil}) != true {
+		t.Error(err)
+	}
+
+	if v, _, err := Parse("usage: prog [<p>]...\n\n<p>  [default: x y]", []string{}, true, "", false); reflect.DeepEqual(v, map[string]interface{}{"<p>": []string{}}) != true {
+		t.Error(err)
+	}
+
+	if v, _, err := Parse("usage: prog [<p>]...\n\n<p>  [default: x y]", []string{"this"}, true, "", false); reflect.DeepEqual(v, map[string]interface{}{"<p>": []string{"this"}}) != true {
+		t.Error(err)
+	}
+}
+
+func TestIssue59(t *testing.T) {
+	if v, _, err := Parse("usage: prog --long=<a>", []string{"--long="}, true, "", false); reflect.DeepEqual(v, map[string]interface{}{"--long": ""}) != true {
+		t.Error(err)
+	}
+
+	if v, _, err := Parse("usage: prog -l <a>\noptions: -l <a>", []string{"-l", ""}, true, "", false); reflect.DeepEqual(v, map[string]interface{}{"-l": ""}) != true {
+		t.Error(err)
+	}
+}
+
+func TestOptionsFirst(t *testing.T) {
+	if v, _, err := Parse("usage: prog [--opt] [<args>...]", []string{"--opt", "this", "that"}, true, "", false); reflect.DeepEqual(v, map[string]interface{}{"--opt": true, "<args>": []string{"this", "that"}}) != true {
+		t.Error(err)
+	}
+
+	if v, _, err := Parse("usage: prog [--opt] [<args>...]", []string{"this", "that", "--opt"}, true, "", false); reflect.DeepEqual(v, map[string]interface{}{"--opt": true, "<args>": []string{"this", "that"}}) != true {
+		t.Error(err)
+	}
+
+	if v, _, err := Parse("usage: prog [--opt] [<args>...]", []string{"this", "that", "--opt"}, true, "", true); reflect.DeepEqual(v, map[string]interface{}{"--opt": false, "<args>": []string{"this", "that", "--opt"}}) != true {
+		t.Error(err)
+	}
+}
+
+func TestIssue68OptionsShortcutDoesNotIncludeOptionsInUsagePattern(t *testing.T) {
+	args, _, err := Parse("usage: prog [-ab] [options]\noptions: -x\n -y", []string{"-ax"}, true, "", false)
+
+	if args["-a"] != true {
+		t.Error(err)
+	}
+	if args["-b"] != false {
+		t.Error(err)
+	}
+	if args["-x"] != true {
+		t.Error(err)
+	}
+	if args["-y"] != false {
+		t.Error(err)
+	}
+}
+
+func TestIssue65EvaluateArgvWhenCalledNotWhenImported(t *testing.T) {
+	os.Args = strings.Fields("prog -a")
+	v, _, err := Parse("usage: prog [-ab]", nil, true, "", false)
+	w := map[string]interface{}{"-a": true, "-b": false}
+	if reflect.DeepEqual(v, w) != true {
+		t.Error(err)
+	}
+
+	os.Args = strings.Fields("prog -b")
+	v, _, err = Parse("usage: prog [-ab]", nil, true, "", false)
+	w = map[string]interface{}{"-a": false, "-b": true}
+	if reflect.DeepEqual(v, w) != true {
+		t.Error(err)
+	}
+}
+
+func TestIssue71DoubleDashIsNotAValidOptionArgument(t *testing.T) {
+	_, _, err := Parse("usage: prog [--log=LEVEL] [--] <args>...",
+		[]string{"--log", "--", "1", "2"}, true, "", false)
+	if _, ok := err.(*UserError); !ok {
+		t.Error()
+	}
+
+	_, _, err = Parse(`usage: prog [-l LEVEL] [--] <args>...
+                  options: -l LEVEL`, []string{"-l", "--", "1", "2"}, true, "", false)
+	if _, ok := err.(*UserError); !ok {
+		t.Error()
+	}
+}
+
+func TestParseSection(t *testing.T) {
+	v := parseSection("usage:", "foo bar fizz buzz")
+	w := []string{}
+	if reflect.DeepEqual(v, w) != true {
+		t.Error()
+	}
+
+	v = parseSection("usage:", "usage: prog")
+	w = []string{"usage: prog"}
+	if reflect.DeepEqual(v, w) != true {
+		t.Error()
+	}
+
+	v = parseSection("usage:", "usage: -x\n -y")
+	w = []string{"usage: -x\n -y"}
+	if reflect.DeepEqual(v, w) != true {
+		t.Error()
+	}
+
+	usage := `usage: this
+
+usage:hai
+usage: this that
+
+usage: foo
+       bar
+
+PROGRAM USAGE:
+ foo
+ bar
+usage:
+` + "\t" + `too
+` + "\t" + `tar
+Usage: eggs spam
+BAZZ
+usage: pit stop`
+
+	v = parseSection("usage:", usage)
+	w = []string{"usage: this",
+		"usage:hai",
+		"usage: this that",
+		"usage: foo\n       bar",
+		"PROGRAM USAGE:\n foo\n bar",
+		"usage:\n\ttoo\n\ttar",
+		"Usage: eggs spam",
+		"usage: pit stop",
+	}
+	if reflect.DeepEqual(v, w) != true {
+		t.Error()
+	}
+}
+
+func TestIssue126DefaultsNotParsedCorrectlyWhenTabs(t *testing.T) {
+	section := "Options:\n\t--foo=<arg>  [default: bar]"
+	v := patternList{newOption("", "--foo", 1, "bar")}
+	if reflect.DeepEqual(parseDefaults(section), v) != true {
+		t.Error()
+	}
+}
+
+// conf file based test cases
+func TestFileTestcases(t *testing.T) {
+	filename := "testcases.docopt"
+	file, err := os.Open(filename)
+	if err != nil {
+		t.Fatal(err)
+	}
+	defer file.Close()
+
+	for c := range parseTest(file) {
+		if c.err != nil {
+			t.Fatal(err)
+			break
+		}
+		result, _, err := Parse(c.doc, c.argv, true, "", false)
+		if _, ok := err.(*UserError); c.userError && !ok {
+			// expected a user-error
+			t.Error("testcase:", c.id, "result:", result)
+		} else if _, ok := err.(*UserError); !c.userError && ok {
+			// unexpected user-error
+			t.Error("testcase:", c.id, "error:", err, "result:", result)
+		} else if reflect.DeepEqual(c.expect, result) != true {
+			t.Error("testcase:", c.id, "result:", result)
+		}
+	}
+}
+
+type testcase struct {
+	id        int
+	doc       string
+	prog      string
+	argv      []string
+	expect    map[string]interface{}
+	userError bool
+	err       error
+}
+
+func parseTest(raw io.Reader) <-chan testcase {
+	c := make(chan testcase)
+
+	go func() {
+		scanner := bufio.NewScanner(raw)
+		commentPattern := regexp.MustCompile("#.*($|\n)")
+		scanner.Split(func(data []byte, atEOF bool) (advance int, token []byte, err error) {
+			// look for matching `r"""` or `r"""`+EOF
+			sep := []byte(`r"""`)
+			count := bytes.Count(data, sep)
+			start := bytes.Index(data, sep)
+			end := len(data)
+
+			if atEOF && count == 0 {
+				// no more matches, so consume everything
+				return end, nil, nil
+			}
+			if atEOF && count == 1 {
+				// already matched up to end
+			} else if count >= 2 {
+				end = start + len(sep) + bytes.Index(data[start+len(sep):], sep)
+			} else {
+				// haven't found a match yet so ask for more data
+				return 0, nil, nil
+			}
+			token = data[start:end]
+			token = commentPattern.ReplaceAllLiteral(token, []byte(""))
+			return end, token, nil
+		})
+
+		for id := 0; scanner.Scan(); {
+			data := scanner.Bytes()
+
+			offset := 4
+			end := offset + bytes.Index(data[offset:], []byte(`"""`))
+			doc := string(data[offset:end])
+			offset = end + 3
+
+			for offset < len(data) {
+				offset = offset + bytes.Index(data[offset:], []byte(`$ `)) + 2
+				end = offset + bytes.Index(data[offset:], []byte("\n"))
+				prog, _, args := stringPartition(string(data[offset:end]), " ")
+				argv := strings.Fields(args)
+				offset = end + 1
+
+				if bytes.Contains(data[offset:], []byte("$ ")) {
+					end = offset + bytes.Index(data[offset:], []byte("$ "))
+				} else {
+					end = len(data)
+				}
+				var expectUntyped interface{}
+				err := json.Unmarshal(data[offset:end], &expectUntyped)
+				offset = end
+
+				if err != nil {
+					c <- testcase{id, doc, prog, argv, nil, false, err}
+					break
+				}
+
+				switch expect := expectUntyped.(type) {
+				case string: // user-error
+					c <- testcase{id, doc, prog, argv, nil, true, nil}
+				case map[string]interface{}:
+					// convert []interface{} values to []string
+					// convert float64 values to int
+					for k, vUntyped := range expect {
+						switch v := vUntyped.(type) {
+						case []interface{}:
+							itemList := make([]string, len(v))
+							for i, itemUntyped := range v {
+								if item, ok := itemUntyped.(string); ok {
+									itemList[i] = item
+								}
+							}
+							expect[k] = itemList
+						case float64:
+							expect[k] = int(v)
+						}
+					}
+					c <- testcase{id, doc, prog, argv, expect, false, nil}
+				}
+				id++
+			}
+		}
+		close(c)
+	}()
+	return c
+}
+
+var debugEnabled = false
+
+func debugOn(l ...interface{}) {
+	debugEnabled = true
+	debug(l...)
+}
+func debugOff(l ...interface{}) {
+	debug(l...)
+	debugEnabled = false
+}
+
+func debug(l ...interface{}) {
+	if debugEnabled {
+		fmt.Println(l...)
+	}
+}
diff --git a/testcases.docopt b/testcases.docopt
new file mode 100644
index 0000000..efe9a07
--- /dev/null
+++ b/testcases.docopt
@@ -0,0 +1,957 @@
+r"""Usage: prog
+
+"""
+$ prog
+{}
+
+$ prog --xxx
+"user-error"
+
+
+r"""Usage: prog [options]
+
+Options: -a  All.
+
+"""
+$ prog
+{"-a": false}
+
+$ prog -a
+{"-a": true}
+
+$ prog -x
+"user-error"
+
+
+r"""Usage: prog [options]
+
+Options: --all  All.
+
+"""
+$ prog
+{"--all": false}
+
+$ prog --all
+{"--all": true}
+
+$ prog --xxx
+"user-error"
+
+
+r"""Usage: prog [options]
+
+Options: -v, --verbose  Verbose.
+
+"""
+$ prog --verbose
+{"--verbose": true}
+
+$ prog --ver
+{"--verbose": true}
+
+$ prog -v
+{"--verbose": true}
+
+
+r"""Usage: prog [options]
+
+Options: -p PATH
+
+"""
+$ prog -p home/
+{"-p": "home/"}
+
+$ prog -phome/
+{"-p": "home/"}
+
+$ prog -p
+"user-error"
+
+
+r"""Usage: prog [options]
+
+Options: --path <path>
+
+"""
+$ prog --path home/
+{"--path": "home/"}
+
+$ prog --path=home/
+{"--path": "home/"}
+
+$ prog --pa home/
+{"--path": "home/"}
+
+$ prog --pa=home/
+{"--path": "home/"}
+
+$ prog --path
+"user-error"
+
+
+r"""Usage: prog [options]
+
+Options: -p PATH, --path=<path>  Path to files.
+
+"""
+$ prog -proot
+{"--path": "root"}
+
+
+r"""Usage: prog [options]
+
+Options:    -p --path PATH  Path to files.
+
+"""
+$ prog -p root
+{"--path": "root"}
+
+$ prog --path root
+{"--path": "root"}
+
+
+r"""Usage: prog [options]
+
+Options:
+ -p PATH  Path to files [default: ./]
+
+"""
+$ prog
+{"-p": "./"}
+
+$ prog -phome
+{"-p": "home"}
+
+
+r"""UsAgE: prog [options]
+
+OpTiOnS: --path=<files>  Path to files
+                [dEfAuLt: /root]
+
+"""
+$ prog
+{"--path": "/root"}
+
+$ prog --path=home
+{"--path": "home"}
+
+
+r"""usage: prog [options]
+
+options:
+    -a        Add
+    -r        Remote
+    -m <msg>  Message
+
+"""
+$ prog -a -r -m Hello
+{"-a": true,
+ "-r": true,
+ "-m": "Hello"}
+
+$ prog -armyourass
+{"-a": true,
+ "-r": true,
+ "-m": "yourass"}
+
+$ prog -a -r
+{"-a": true,
+ "-r": true,
+ "-m": null}
+
+
+r"""Usage: prog [options]
+
+Options: --version
+         --verbose
+
+"""
+$ prog --version
+{"--version": true,
+ "--verbose": false}
+
+$ prog --verbose
+{"--version": false,
+ "--verbose": true}
+
+$ prog --ver
+"user-error"
+
+$ prog --verb
+{"--version": false,
+ "--verbose": true}
+
+
+r"""usage: prog [-a -r -m <msg>]
+
+options:
+ -a        Add
+ -r        Remote
+ -m <msg>  Message
+
+"""
+$ prog -armyourass
+{"-a": true,
+ "-r": true,
+ "-m": "yourass"}
+
+
+r"""usage: prog [-armmsg]
+
+options: -a        Add
+         -r        Remote
+         -m <msg>  Message
+
+"""
+$ prog -a -r -m Hello
+{"-a": true,
+ "-r": true,
+ "-m": "Hello"}
+
+
+r"""usage: prog -a -b
+
+options:
+ -a
+ -b
+
+"""
+$ prog -a -b
+{"-a": true, "-b": true}
+
+$ prog -b -a
+{"-a": true, "-b": true}
+
+$ prog -a
+"user-error"
+
+$ prog
+"user-error"
+
+
+r"""usage: prog (-a -b)
+
+options: -a
+         -b
+
+"""
+$ prog -a -b
+{"-a": true, "-b": true}
+
+$ prog -b -a
+{"-a": true, "-b": true}
+
+$ prog -a
+"user-error"
+
+$ prog
+"user-error"
+
+
+r"""usage: prog [-a] -b
+
+options: -a
+ -b
+
+"""
+$ prog -a -b
+{"-a": true, "-b": true}
+
+$ prog -b -a
+{"-a": true, "-b": true}
+
+$ prog -a
+"user-error"
+
+$ prog -b
+{"-a": false, "-b": true}
+
+$ prog
+"user-error"
+
+
+r"""usage: prog [(-a -b)]
+
+options: -a
+         -b
+
+"""
+$ prog -a -b
+{"-a": true, "-b": true}
+
+$ prog -b -a
+{"-a": true, "-b": true}
+
+$ prog -a
+"user-error"
+
+$ prog -b
+"user-error"
+
+$ prog
+{"-a": false, "-b": false}
+
+
+r"""usage: prog (-a|-b)
+
+options: -a
+         -b
+
+"""
+$ prog -a -b
+"user-error"
+
+$ prog
+"user-error"
+
+$ prog -a
+{"-a": true, "-b": false}
+
+$ prog -b
+{"-a": false, "-b": true}
+
+
+r"""usage: prog [ -a | -b ]
+
+options: -a
+         -b
+
+"""
+$ prog -a -b
+"user-error"
+
+$ prog
+{"-a": false, "-b": false}
+
+$ prog -a
+{"-a": true, "-b": false}
+
+$ prog -b
+{"-a": false, "-b": true}
+
+
+r"""usage: prog <arg>"""
+$ prog 10
+{"<arg>": "10"}
+
+$ prog 10 20
+"user-error"
+
+$ prog
+"user-error"
+
+
+r"""usage: prog [<arg>]"""
+$ prog 10
+{"<arg>": "10"}
+
+$ prog 10 20
+"user-error"
+
+$ prog
+{"<arg>": null}
+
+
+r"""usage: prog <kind> <name> <type>"""
+$ prog 10 20 40
+{"<kind>": "10", "<name>": "20", "<type>": "40"}
+
+$ prog 10 20
+"user-error"
+
+$ prog
+"user-error"
+
+
+r"""usage: prog <kind> [<name> <type>]"""
+$ prog 10 20 40
+{"<kind>": "10", "<name>": "20", "<type>": "40"}
+
+$ prog 10 20
+{"<kind>": "10", "<name>": "20", "<type>": null}
+
+$ prog
+"user-error"
+
+
+r"""usage: prog [<kind> | <name> <type>]"""
+$ prog 10 20 40
+"user-error"
+
+$ prog 20 40
+{"<kind>": null, "<name>": "20", "<type>": "40"}
+
+$ prog
+{"<kind>": null, "<name>": null, "<type>": null}
+
+
+r"""usage: prog (<kind> --all | <name>)
+
+options:
+ --all
+
+"""
+$ prog 10 --all
+{"<kind>": "10", "--all": true, "<name>": null}
+
+$ prog 10
+{"<kind>": null, "--all": false, "<name>": "10"}
+
+$ prog
+"user-error"
+
+
+r"""usage: prog [<name> <name>]"""
+$ prog 10 20
+{"<name>": ["10", "20"]}
+
+$ prog 10
+{"<name>": ["10"]}
+
+$ prog
+{"<name>": []}
+
+
+r"""usage: prog [(<name> <name>)]"""
+$ prog 10 20
+{"<name>": ["10", "20"]}
+
+$ prog 10
+"user-error"
+
+$ prog
+{"<name>": []}
+
+
+r"""usage: prog NAME..."""
+$ prog 10 20
+{"NAME": ["10", "20"]}
+
+$ prog 10
+{"NAME": ["10"]}
+
+$ prog
+"user-error"
+
+
+r"""usage: prog [NAME]..."""
+$ prog 10 20
+{"NAME": ["10", "20"]}
+
+$ prog 10
+{"NAME": ["10"]}
+
+$ prog
+{"NAME": []}
+
+
+r"""usage: prog [NAME...]"""
+$ prog 10 20
+{"NAME": ["10", "20"]}
+
+$ prog 10
+{"NAME": ["10"]}
+
+$ prog
+{"NAME": []}
+
+
+r"""usage: prog [NAME [NAME ...]]"""
+$ prog 10 20
+{"NAME": ["10", "20"]}
+
+$ prog 10
+{"NAME": ["10"]}
+
+$ prog
+{"NAME": []}
+
+
+r"""usage: prog (NAME | --foo NAME)
+
+options: --foo
+
+"""
+$ prog 10
+{"NAME": "10", "--foo": false}
+
+$ prog --foo 10
+{"NAME": "10", "--foo": true}
+
+$ prog --foo=10
+"user-error"
+
+
+r"""usage: prog (NAME | --foo) [--bar | NAME]
+
+options: --foo
+options: --bar
+
+"""
+$ prog 10
+{"NAME": ["10"], "--foo": false, "--bar": false}
+
+$ prog 10 20
+{"NAME": ["10", "20"], "--foo": false, "--bar": false}
+
+$ prog --foo --bar
+{"NAME": [], "--foo": true, "--bar": true}
+
+
+r"""Naval Fate.
+
+Usage:
+  prog ship new <name>...
+  prog ship [<name>] move <x> <y> [--speed=<kn>]
+  prog ship shoot <x> <y>
+  prog mine (set|remove) <x> <y> [--moored|--drifting]
+  prog -h | --help
+  prog --version
+
+Options:
+  -h --help     Show this screen.
+  --version     Show version.
+  --speed=<kn>  Speed in knots [default: 10].
+  --moored      Mored (anchored) mine.
+  --drifting    Drifting mine.
+
+"""
+$ prog ship Guardian move 150 300 --speed=20
+{"--drifting": false,
+ "--help": false,
+ "--moored": false,
+ "--speed": "20",
+ "--version": false,
+ "<name>": ["Guardian"],
+ "<x>": "150",
+ "<y>": "300",
+ "mine": false,
+ "move": true,
+ "new": false,
+ "remove": false,
+ "set": false,
+ "ship": true,
+ "shoot": false}
+
+
+r"""usage: prog --hello"""
+$ prog --hello
+{"--hello": true}
+
+
+r"""usage: prog [--hello=<world>]"""
+$ prog
+{"--hello": null}
+
+$ prog --hello wrld
+{"--hello": "wrld"}
+
+
+r"""usage: prog [-o]"""
+$ prog
+{"-o": false}
+
+$ prog -o
+{"-o": true}
+
+
+r"""usage: prog [-opr]"""
+$ prog -op
+{"-o": true, "-p": true, "-r": false}
+
+
+r"""usage: prog --aabb | --aa"""
+$ prog --aa
+{"--aabb": false, "--aa": true}
+
+$ prog --a
+"user-error"  # not a unique prefix
+
+#
+# Counting number of flags
+#
+
+r"""Usage: prog -v"""
+$ prog -v
+{"-v": true}
+
+
+r"""Usage: prog [-v -v]"""
+$ prog
+{"-v": 0}
+
+$ prog -v
+{"-v": 1}
+
+$ prog -vv
+{"-v": 2}
+
+
+r"""Usage: prog -v ..."""
+$ prog
+"user-error"
+
+$ prog -v
+{"-v": 1}
+
+$ prog -vv
+{"-v": 2}
+
+$ prog -vvvvvv
+{"-v": 6}
+
+
+r"""Usage: prog [-v | -vv | -vvv]
+
+This one is probably most readable user-friednly variant.
+
+"""
+$ prog
+{"-v": 0}
+
+$ prog -v
+{"-v": 1}
+
+$ prog -vv
+{"-v": 2}
+
+$ prog -vvvv
+"user-error"
+
+
+r"""usage: prog [--ver --ver]"""
+$ prog --ver --ver
+{"--ver": 2}
+
+
+#
+# Counting commands
+#
+
+r"""usage: prog [go]"""
+$ prog go
+{"go": true}
+
+
+r"""usage: prog [go go]"""
+$ prog
+{"go": 0}
+
+$ prog go
+{"go": 1}
+
+$ prog go go
+{"go": 2}
+
+$ prog go go go
+"user-error"
+
+r"""usage: prog go..."""
+$ prog go go go go go
+{"go": 5}
+
+#
+# [options] does not include options from usage-pattern
+#
+r"""usage: prog [options] [-a]
+
+options: -a
+         -b
+"""
+$ prog -a
+{"-a": true, "-b": false}
+
+$ prog -aa
+"user-error"
+
+#
+# Test [options] shourtcut
+#
+
+r"""Usage: prog [options] A
+Options:
+    -q  Be quiet
+    -v  Be verbose.
+
+"""
+$ prog arg
+{"A": "arg", "-v": false, "-q": false}
+
+$ prog -v arg
+{"A": "arg", "-v": true, "-q": false}
+
+$ prog -q arg
+{"A": "arg", "-v": false, "-q": true}
+
+#
+# Test single dash
+#
+
+r"""usage: prog [-]"""
+
+$ prog -
+{"-": true}
+
+$ prog
+{"-": false}
+
+#
+# If argument is repeated, its value should always be a list
+#
+
+r"""usage: prog [NAME [NAME ...]]"""
+
+$ prog a b
+{"NAME": ["a", "b"]}
+
+$ prog
+{"NAME": []}
+
+#
+# Option's argument defaults to null/None
+#
+
+r"""usage: prog [options]
+options:
+ -a        Add
+ -m <msg>  Message
+
+"""
+$ prog -a
+{"-m": null, "-a": true}
+
+#
+# Test options without description
+#
+
+r"""usage: prog --hello"""
+$ prog --hello
+{"--hello": true}
+
+r"""usage: prog [--hello=<world>]"""
+$ prog
+{"--hello": null}
+
+$ prog --hello wrld
+{"--hello": "wrld"}
+
+r"""usage: prog [-o]"""
+$ prog
+{"-o": false}
+
+$ prog -o
+{"-o": true}
+
+r"""usage: prog [-opr]"""
+$ prog -op
+{"-o": true, "-p": true, "-r": false}
+
+r"""usage: git [-v | --verbose]"""
+$ prog -v
+{"-v": true, "--verbose": false}
+
+r"""usage: git remote [-v | --verbose]"""
+$ prog remote -v
+{"remote": true, "-v": true, "--verbose": false}
+
+#
+# Test empty usage pattern
+#
+
+r"""usage: prog"""
+$ prog
+{}
+
+r"""usage: prog
+           prog <a> <b>
+"""
+$ prog 1 2
+{"<a>": "1", "<b>": "2"}
+
+$ prog
+{"<a>": null, "<b>": null}
+
+r"""usage: prog <a> <b>
+           prog
+"""
+$ prog
+{"<a>": null, "<b>": null}
+
+#
+# Option's argument should not capture default value from usage pattern
+#
+
+r"""usage: prog [--file=<f>]"""
+$ prog
+{"--file": null}
+
+r"""usage: prog [--file=<f>]
+
+options: --file <a>
+
+"""
+$ prog
+{"--file": null}
+
+r"""Usage: prog [-a <host:port>]
+
+Options: -a, --address <host:port>  TCP address [default: localhost:6283].
+
+"""
+$ prog
+{"--address": "localhost:6283"}
+
+#
+# If option with argument could be repeated,
+# its arguments should be accumulated into a list
+#
+
+r"""usage: prog --long=<arg> ..."""
+
+$ prog --long one
+{"--long": ["one"]}
+
+$ prog --long one --long two
+{"--long": ["one", "two"]}
+
+#
+# Test multiple elements repeated at once
+#
+
+r"""usage: prog (go <direction> --speed=<km/h>)..."""
+$ prog  go left --speed=5  go right --speed=9
+{"go": 2, "<direction>": ["left", "right"], "--speed": ["5", "9"]}
+
+#
+# Required options should work with option shortcut
+#
+
+r"""usage: prog [options] -a
+
+options: -a
+
+"""
+$ prog -a
+{"-a": true}
+
+#
+# If option could be repeated its defaults should be split into a list
+#
+
+r"""usage: prog [-o <o>]...
+
+options: -o <o>  [default: x]
+
+"""
+$ prog -o this -o that
+{"-o": ["this", "that"]}
+
+$ prog
+{"-o": ["x"]}
+
+r"""usage: prog [-o <o>]...
+
+options: -o <o>  [default: x y]
+
+"""
+$ prog -o this
+{"-o": ["this"]}
+
+$ prog
+{"-o": ["x", "y"]}
+
+#
+# Test stacked option's argument
+#
+
+r"""usage: prog -pPATH
+
+options: -p PATH
+
+"""
+$ prog -pHOME
+{"-p": "HOME"}
+
+#
+# Issue 56: Repeated mutually exclusive args give nested lists sometimes
+#
+
+r"""Usage: foo (--xx=x|--yy=y)..."""
+$ prog --xx=1 --yy=2
+{"--xx": ["1"], "--yy": ["2"]}
+
+#
+# POSIXly correct tokenization
+#
+
+r"""usage: prog [<input file>]"""
+$ prog f.txt
+{"<input file>": "f.txt"}
+
+r"""usage: prog [--input=<file name>]..."""
+$ prog --input a.txt --input=b.txt
+{"--input": ["a.txt", "b.txt"]}
+
+#
+# Issue 85: `[options]` shourtcut with multiple subcommands
+#
+
+r"""usage: prog good [options]
+           prog fail [options]
+
+options: --loglevel=N
+
+"""
+$ prog fail --loglevel 5
+{"--loglevel": "5", "fail": true, "good": false}
+
+#
+# Usage-section syntax
+#
+
+r"""usage:prog --foo"""
+$ prog --foo
+{"--foo": true}
+
+r"""PROGRAM USAGE: prog --foo"""
+$ prog --foo
+{"--foo": true}
+
+r"""Usage: prog --foo
+           prog --bar
+NOT PART OF SECTION"""
+$ prog --foo
+{"--foo": true, "--bar": false}
+
+r"""Usage:
+ prog --foo
+ prog --bar
+
+NOT PART OF SECTION"""
+$ prog --foo
+{"--foo": true, "--bar": false}
+
+r"""Usage:
+ prog --foo
+ prog --bar
+NOT PART OF SECTION"""
+$ prog --foo
+{"--foo": true, "--bar": false}
+
+#
+# Options-section syntax
+#
+
+r"""Usage: prog [options]
+
+global options: --foo
+local options: --baz
+               --bar
+other options:
+ --egg
+ --spam
+-not-an-option-
+
+"""
+$ prog --baz --egg
+{"--foo": false, "--baz": true, "--bar": false, "--egg": true, "--spam": false}