Merge pull request #39 from davecgh/support_windows_style_options

Support Windows-style options.
diff --git a/flags.go b/flags.go
index d17bc36..7c3d19b 100644
--- a/flags.go
+++ b/flags.go
@@ -23,6 +23,12 @@
 //     Supports maps
 //     Supports function callbacks
 //
+// Additional features specific to Windows:
+//     Options with short names (/v)
+//     Options with long names (/verbose)
+//     Windows-style options with arguments use a colon as the delimiter
+//     Modify generated help message with Windows-style / options
+//
 // The flags package uses structs, reflection and struct field tags
 // to allow users to specify command line options. This results in very simple
 // and consise specification of your application options. For example:
diff --git a/help.go b/help.go
index a39463e..929df70 100644
--- a/help.go
+++ b/help.go
@@ -73,7 +73,7 @@
 	line.WriteString(strings.Repeat(" ", paddingBeforeOption))
 
 	if option.ShortName != 0 {
-		line.WriteString("-")
+		line.WriteRune(defaultShortOptDelimiter)
 		line.WriteRune(option.ShortName)
 	} else if info.hasShort {
 		line.WriteString("  ")
@@ -100,12 +100,12 @@
 			line.WriteString("  ")
 		}
 
-		line.WriteString("--")
+		line.WriteString(defaultLongOptDelimiter)
 		line.WriteString(option.LongName)
 	}
 
 	if !option.isBool() {
-		line.WriteString("=")
+		line.WriteRune(defaultNameArgDelimiter)
 
 		if len(option.ValueName) > 0 {
 			line.WriteString(option.ValueName)
diff --git a/optstyle_other.go b/optstyle_other.go
new file mode 100644
index 0000000..00ce107
--- /dev/null
+++ b/optstyle_other.go
@@ -0,0 +1,50 @@
+// +build !windows
+
+package flags
+
+import (
+	"strings"
+)
+
+const (
+	defaultShortOptDelimiter = '-'
+	defaultLongOptDelimiter  = "--"
+	defaultNameArgDelimiter  = '='
+)
+
+func argumentIsOption(arg string) bool {
+	return len(arg) > 0 && arg[0] == '-'
+}
+
+// stripOptionPrefix returns the option without the prefix and whether or
+// not the option is a long option or not.
+func stripOptionPrefix(optname string) (string, bool) {
+	if strings.HasPrefix(optname, "--") {
+		return optname[2:], true
+	} else if strings.HasPrefix(optname, "-") {
+		return optname[1:], false
+	}
+
+	return optname, false
+}
+
+// splitOption attempts to split the passed option into a name and an argument.
+// When there is no argument specified, nil will be returned for it.
+func splitOption(option string) (string, *string) {
+	pos := strings.Index(option, "=")
+	if pos >= 0 {
+		rest := option[pos+1:]
+		return option[:pos], &rest
+	}
+
+	return option, nil
+}
+
+// newHelpGroup returns a new group that contains default help parameters.
+func newHelpGroup(showHelp func() error) *Group {
+	var help struct {
+		ShowHelp func() error `short:"h" long:"help" description:"Show this help message"`
+	}
+	help.ShowHelp = showHelp
+	return NewGroup("Help Options", &help)
+}
diff --git a/optstyle_windows.go b/optstyle_windows.go
new file mode 100644
index 0000000..ffc97de
--- /dev/null
+++ b/optstyle_windows.go
@@ -0,0 +1,80 @@
+package flags
+
+import (
+	"strings"
+)
+
+// Windows uses a front slash for both short and long options.  Also it uses
+// a colon for name/argument delimter.
+const (
+	defaultShortOptDelimiter = '/'
+	defaultLongOptDelimiter  = "/"
+	defaultNameArgDelimiter  = ':'
+)
+
+func argumentIsOption(arg string) bool {
+	// Windows-style options allow front slash for the option
+	// delimiter.
+	return len(arg) > 0 && (arg[0] == '-' || arg[0] == '/')
+}
+
+// stripOptionPrefix returns the option without the prefix and whether or
+// not the option is a long option or not.
+func stripOptionPrefix(optname string) (string, bool) {
+	// Determine if the argument is a long option or not.  Windows
+	// typically supports both long and short options with a single
+	// front slash as the option delimiter, so handle this situation
+	// nicely.
+	if strings.HasPrefix(optname, "--") {
+		return optname[2:], true
+	} else if strings.HasPrefix(optname, "-") {
+		return optname[1:], false
+	} else if strings.HasPrefix(optname, "/") {
+		optname = optname[1:]
+		if len(optname) > 1 {
+			return optname, true
+		}
+		return optname, false
+	}
+
+	return optname, false
+}
+
+// splitOption attempts to split the passed option into a name and an argument.
+// When there is no argument specified, nil will be returned for it.
+func splitOption(option string) (string, *string) {
+	if len(option) == 0 {
+		return option, nil
+	}
+
+	// Windows typically uses a colon for the option name and argument
+	// delimiter while POSIX typically uses an equals.  Support both styles,
+	// but don't allow the two to be mixed.  That is to say /foo:bar and
+	// --foo=bar are acceptable, but /foo=bar and --foo:bar are not.
+	var pos int
+	if option[0] == '/' {
+		pos = strings.Index(option, ":")
+	} else if option[0] == '-' {
+		pos = strings.Index(option, "=")
+	}
+
+	if pos >= 0 {
+		rest := option[pos+1:]
+		return option[:pos], &rest
+	}
+
+	return option, nil
+}
+
+// newHelpGroup returns a new group that contains default help parameters.
+func newHelpGroup(showHelp func() error) *Group {
+	// Windows CLI applications typically use /? for help, so make both
+	// that available as well as the POSIX style h and help.
+	var help struct {
+		ShowHelp  func() error `short:"?" description:"Show this help message"`
+		ShowHelp2 func() error `short:"h" long:"help" description:"Show this help message"`
+	}
+	help.ShowHelp = showHelp
+	help.ShowHelp2 = showHelp
+	return NewGroup("Help Options", &help)
+}
diff --git a/parser.go b/parser.go
index 8b57fcf..8a831e9 100644
--- a/parser.go
+++ b/parser.go
@@ -312,10 +312,6 @@
 	return commands[mincmd], mindist
 }
 
-func argumentIsOption(arg string) bool {
-	return len(arg) > 0 && arg[0] == '-'
-}
-
 // ParseArgs parses the command line arguments according to the option groups that
 // were added to the parser. On successful parsing of the arguments, the
 // remaining, non-option, arguments (if any) are returned. The returned error
@@ -333,17 +329,16 @@
 	p.storeDefaults()
 
 	if (p.Options & HelpFlag) != None {
-		var help struct {
-			ShowHelp func() error `short:"h" long:"help" description:"Show this help message"`
-		}
-
-		help.ShowHelp = func() error {
+		var showHelp = func() error {
 			var b bytes.Buffer
 			p.WriteHelp(&b)
 			return newError(ErrHelp, b.String())
 		}
 
-		helpgrp := NewGroup("Help Options", &help)
+		// Windows CLI applications typically use /? for help while
+		// POSIX typically uses -h and --help.  Get a help group
+		// appropriate to the OS.
+		helpgrp := newHelpGroup(showHelp)
 
 		// Append the help group to toplevel
 		p.Groups = append([]*Group{helpgrp}, p.Groups...)
@@ -412,32 +407,20 @@
 			continue
 		}
 
-		pos := strings.Index(arg, "=")
-		var argument *string
-		var optname string
-
-		if pos >= 0 {
-			rest := arg[pos+1:]
-			argument = &rest
-			optname = arg[:pos]
-		} else {
-			optname = arg
-		}
-
 		var err error
 		var option *Option
 
-		if strings.HasPrefix(optname, "--") {
-			err, i, option = p.parseLong(args, optname[2:], argument, i)
+		optname, argument := splitOption(arg)
+		optname, islong := stripOptionPrefix(optname)
+		if islong {
+			err, i, option = p.parseLong(args, optname, argument, i)
 		} else {
-			short := optname[1:]
-
-			for j, c := range short {
+			for j, c := range optname {
 				clen := utf8.RuneLen(c)
-				islast := (j+clen == len(short))
+				islast := (j+clen == len(optname))
 
 				if !islast && argument == nil {
-					rr := short[j+clen:]
+					rr := optname[j+clen:]
 					next, _ := utf8.DecodeRuneInString(rr)
 					info, _ := p.getShort(c)