Merge remote-tracking branch 'ogier/master' into merge

Conflicts:
	bool_test.go
	flag.go
	flag_test.go
diff --git a/bool.go b/bool.go
index 617971a..70e2e0a 100644
--- a/bool.go
+++ b/bool.go
@@ -26,6 +26,10 @@
 	return err
 }
 
+func (b *boolValue) Type() string {
+	return "bool"
+}
+
 func (b *boolValue) String() string { return fmt.Sprintf("%v", *b) }
 
 func (b *boolValue) IsBoolFlag() bool { return true }
diff --git a/duration.go b/duration.go
index db59463..66ed7ac 100644
--- a/duration.go
+++ b/duration.go
@@ -16,15 +16,12 @@
 	return err
 }
 
-func (d *durationValue) String() string { return (*time.Duration)(d).String() }
-
-// Value is the interface to the dynamic value stored in a flag.
-// (The default value is represented as a string.)
-type Value interface {
-	String() string
-	Set(string) error
+func (d *durationValue) Type() string {
+	return "duration"
 }
 
+func (d *durationValue) String() string { return (*time.Duration)(d).String() }
+
 // DurationVar defines a time.Duration flag with specified name, default value, and usage string.
 // The argument p points to a time.Duration variable in which to store the value of the flag.
 func (f *FlagSet) DurationVar(p *time.Duration, name string, value time.Duration, usage string) {
diff --git a/example_test.go b/example_test.go
index 03ebeaa..9be7a49 100644
--- a/example_test.go
+++ b/example_test.go
@@ -11,7 +11,7 @@
 	"strings"
 	"time"
 
-	flag "github.com/ogier/pflag"
+	flag "github.com/spf13/pflag"
 )
 
 // Example 1: A single string flag called "species" with default value "gopher".
@@ -29,6 +29,10 @@
 	return fmt.Sprint(*i)
 }
 
+func (i *interval) Type() string {
+	return "interval"
+}
+
 // Set is the method to set the flag value, part of the flag.Value interface.
 // Set's argument is a string to be parsed to set the flag.
 // It's a comma-separated list, so we split it.
diff --git a/flag.go b/flag.go
index f383058..55594df 100644
--- a/flag.go
+++ b/flag.go
@@ -99,6 +99,7 @@
 package pflag
 
 import (
+	"bytes"
 	"errors"
 	"fmt"
 	"io"
@@ -119,6 +120,10 @@
 	PanicOnError
 )
 
+// NormalizedName is a flag name that has been normalized according to rules
+// for the FlagSet (e.g. making '-' and '_' equivalent).
+type NormalizedName string
+
 // A FlagSet represents a set of defined flags.
 type FlagSet struct {
 	// Usage is the function called when an error occurs while parsing flags.
@@ -126,43 +131,75 @@
 	// a custom error handler.
 	Usage func()
 
-	name          string
-	parsed        bool
-	actual        map[string]*Flag
-	formal        map[string]*Flag
-	shorthands    map[byte]*Flag
-	args          []string // arguments after flags
-	exitOnError   bool     // does the program exit if there's an error?
-	errorHandling ErrorHandling
-	output        io.Writer // nil means stderr; use out() accessor
-	interspersed  bool      // allow interspersed option/non-option args
+	name              string
+	parsed            bool
+	actual            map[NormalizedName]*Flag
+	formal            map[NormalizedName]*Flag
+	shorthands        map[byte]*Flag
+	args              []string // arguments after flags
+	exitOnError       bool     // does the program exit if there's an error?
+	errorHandling     ErrorHandling
+	output            io.Writer // nil means stderr; use out() accessor
+	interspersed      bool      // allow interspersed option/non-option args
+	normalizeNameFunc func(f *FlagSet, name string) NormalizedName
 }
 
 // A Flag represents the state of a flag.
 type Flag struct {
-	Name      string // name as it appears on command line
-	Shorthand string // one-letter abbreviated flag
-	Usage     string // help message
-	Value     Value  // value as set
-	DefValue  string // default value (as text); for usage message
+	Name        string              // name as it appears on command line
+	Shorthand   string              // one-letter abbreviated flag
+	Usage       string              // help message
+	Value       Value               // value as set
+	DefValue    string              // default value (as text); for usage message
+	Changed     bool                // If the user set the value (or if left to default)
+	Deprecated  string              // If this flag is deprecated, this string is the new or now thing to use
+	Annotations map[string][]string // used by cobra.Command  bash autocomple code
+}
+
+// Value is the interface to the dynamic value stored in a flag.
+// (The default value is represented as a string.)
+type Value interface {
+	String() string
+	Set(string) error
+	Type() string
 }
 
 // sortFlags returns the flags as a slice in lexicographical sorted order.
-func sortFlags(flags map[string]*Flag) []*Flag {
+func sortFlags(flags map[NormalizedName]*Flag) []*Flag {
 	list := make(sort.StringSlice, len(flags))
 	i := 0
-	for _, f := range flags {
-		list[i] = f.Name
+	for k := range flags {
+		list[i] = string(k)
 		i++
 	}
 	list.Sort()
 	result := make([]*Flag, len(list))
 	for i, name := range list {
-		result[i] = flags[name]
+		result[i] = flags[NormalizedName(name)]
 	}
 	return result
 }
 
+func (f *FlagSet) SetNormalizeFunc(n func(f *FlagSet, name string) NormalizedName) {
+	f.normalizeNameFunc = n
+	for k, v := range f.formal {
+		delete(f.formal, k)
+		f.formal[f.normalizeFlagName(string(k))] = v
+	}
+}
+
+func (f *FlagSet) GetNormalizeFunc() func(f *FlagSet, name string) NormalizedName {
+	if f.normalizeNameFunc != nil {
+		return f.normalizeNameFunc
+	}
+	return func(f *FlagSet, name string) NormalizedName { return NormalizedName(name) }
+}
+
+func (f *FlagSet) normalizeFlagName(name string) NormalizedName {
+	n := f.GetNormalizeFunc()
+	return n(f, name)
+}
+
 func (f *FlagSet) out() io.Writer {
 	if f.output == nil {
 		return os.Stderr
@@ -184,6 +221,10 @@
 	}
 }
 
+func (f *FlagSet) HasFlags() bool {
+	return len(f.formal) > 0
+}
+
 // VisitAll visits the command-line flags in lexicographical order, calling
 // fn for each.  It visits all flags, even those not set.
 func VisitAll(fn func(*Flag)) {
@@ -206,18 +247,34 @@
 
 // Lookup returns the Flag structure of the named flag, returning nil if none exists.
 func (f *FlagSet) Lookup(name string) *Flag {
+	return f.lookup(f.normalizeFlagName(name))
+}
+
+// lookup returns the Flag structure of the named flag, returning nil if none exists.
+func (f *FlagSet) lookup(name NormalizedName) *Flag {
 	return f.formal[name]
 }
 
+// Mark a flag deprecated in your program
+func (f *FlagSet) MarkDeprecated(name string, usageMessage string) error {
+	flag := f.Lookup(name)
+	if flag == nil {
+		return fmt.Errorf("flag %q does not exist", name)
+	}
+	flag.Deprecated = usageMessage
+	return nil
+}
+
 // Lookup returns the Flag structure of the named command-line flag,
 // returning nil if none exists.
 func Lookup(name string) *Flag {
-	return CommandLine.formal[name]
+	return CommandLine.Lookup(name)
 }
 
 // Set sets the value of the named flag.
 func (f *FlagSet) Set(name, value string) error {
-	flag, ok := f.formal[name]
+	normalName := f.normalizeFlagName(name)
+	flag, ok := f.formal[normalName]
 	if !ok {
 		return fmt.Errorf("no such flag -%v", name)
 	}
@@ -226,9 +283,13 @@
 		return err
 	}
 	if f.actual == nil {
-		f.actual = make(map[string]*Flag)
+		f.actual = make(map[NormalizedName]*Flag)
 	}
-	f.actual[name] = flag
+	f.actual[normalName] = flag
+	flag.Changed = true
+	if len(flag.Deprecated) > 0 {
+		fmt.Fprintf(os.Stderr, "Flag --%s has been deprecated, %s\n", flag.Name, flag.Deprecated)
+	}
 	return nil
 }
 
@@ -241,6 +302,9 @@
 // otherwise, the default values of all defined flags in the set.
 func (f *FlagSet) PrintDefaults() {
 	f.VisitAll(func(flag *Flag) {
+		if len(flag.Deprecated) > 0 {
+			return
+		}
 		format := "--%s=%s: %s\n"
 		if _, ok := flag.Value.(*stringValue); ok {
 			// put quotes on the value
@@ -255,6 +319,29 @@
 	})
 }
 
+func (f *FlagSet) FlagUsages() string {
+	x := new(bytes.Buffer)
+
+	f.VisitAll(func(flag *Flag) {
+		if len(flag.Deprecated) > 0 {
+			return
+		}
+		format := "--%s=%s: %s\n"
+		if _, ok := flag.Value.(*stringValue); ok {
+			// put quotes on the value
+			format = "--%s=%q: %s\n"
+		}
+		if len(flag.Shorthand) > 0 {
+			format = "  -%s, " + format
+		} else {
+			format = "   %s   " + format
+		}
+		fmt.Fprintf(x, format, flag.Shorthand, flag.Name, flag.DefValue, flag.Usage)
+	})
+
+	return x.String()
+}
+
 // PrintDefaults prints to standard error the default values of all defined command-line flags.
 func PrintDefaults() {
 	CommandLine.PrintDefaults()
@@ -323,32 +410,42 @@
 // Like Var, but accepts a shorthand letter that can be used after a single dash.
 func (f *FlagSet) VarP(value Value, name, shorthand, usage string) {
 	// Remember the default value as a string; it won't change.
-	flag := &Flag{name, shorthand, usage, value, value.String()}
-	_, alreadythere := f.formal[name]
+	flag := &Flag{
+		Name:      name,
+		Shorthand: shorthand,
+		Usage:     usage,
+		Value:     value,
+		DefValue:  value.String(),
+	}
+	f.AddFlag(flag)
+}
+
+func (f *FlagSet) AddFlag(flag *Flag) {
+	_, alreadythere := f.formal[f.normalizeFlagName(flag.Name)]
 	if alreadythere {
-		msg := fmt.Sprintf("%s flag redefined: %s", f.name, name)
+		msg := fmt.Sprintf("%s flag redefined: %s", f.name, flag.Name)
 		fmt.Fprintln(f.out(), msg)
 		panic(msg) // Happens only if flags are declared with identical names
 	}
 	if f.formal == nil {
-		f.formal = make(map[string]*Flag)
+		f.formal = make(map[NormalizedName]*Flag)
 	}
-	f.formal[name] = flag
+	f.formal[f.normalizeFlagName(flag.Name)] = flag
 
-	if len(shorthand) == 0 {
+	if len(flag.Shorthand) == 0 {
 		return
 	}
-	if len(shorthand) > 1 {
-		fmt.Fprintf(f.out(), "%s shorthand more than ASCII character: %s\n", f.name, shorthand)
+	if len(flag.Shorthand) > 1 {
+		fmt.Fprintf(f.out(), "%s shorthand more than ASCII character: %s\n", f.name, flag.Shorthand)
 		panic("shorthand is more than one character")
 	}
 	if f.shorthands == nil {
 		f.shorthands = make(map[byte]*Flag)
 	}
-	c := shorthand[0]
+	c := flag.Shorthand[0]
 	old, alreadythere := f.shorthands[c]
 	if alreadythere {
-		fmt.Fprintf(f.out(), "%s shorthand reused: %q for %s already used for %s\n", f.name, c, name, old.Name)
+		fmt.Fprintf(f.out(), "%s shorthand reused: %q for %s already used for %s\n", f.name, c, flag.Name, old.Name)
 		panic("shorthand redefinition")
 	}
 	f.shorthands[c] = flag
@@ -396,14 +493,104 @@
 	}
 	// mark as visited for Visit()
 	if f.actual == nil {
-		f.actual = make(map[string]*Flag)
+		f.actual = make(map[NormalizedName]*Flag)
 	}
-	f.actual[flag.Name] = flag
-
+	f.actual[f.normalizeFlagName(flag.Name)] = flag
+	flag.Changed = true
+	if len(flag.Deprecated) > 0 {
+		fmt.Fprintf(os.Stderr, "Flag --%s has been deprecated, %s\n", flag.Name, flag.Deprecated)
+	}
 	return nil
 }
 
-func (f *FlagSet) parseArgs(args []string) error {
+func (f *FlagSet) parseLongArg(s string, args []string) (a []string, err error) {
+	a = args
+	if len(s) == 2 { // "--" terminates the flags
+		f.args = append(f.args, args...)
+		return
+	}
+	name := s[2:]
+	if len(name) == 0 || name[0] == '-' || name[0] == '=' {
+		err = f.failf("bad flag syntax: %s", s)
+		return
+	}
+	split := strings.SplitN(name, "=", 2)
+	name = split[0]
+	m := f.formal
+	flag, alreadythere := m[f.normalizeFlagName(name)] // BUG
+	if !alreadythere {
+		if name == "help" { // special case for nice help message.
+			f.usage()
+			return args, ErrHelp
+		}
+		err = f.failf("unknown flag: --%s", name)
+		return
+	}
+	if len(split) == 1 {
+		if bv, ok := flag.Value.(boolFlag); !ok || !bv.IsBoolFlag() {
+			err = f.failf("flag needs an argument: %s", s)
+			return
+		}
+		f.setFlag(flag, "true", s)
+	} else {
+		if e := f.setFlag(flag, split[1], s); e != nil {
+			err = e
+			return
+		}
+	}
+	return args, nil
+}
+
+func (f *FlagSet) parseShortArg(s string, args []string) (a []string, err error) {
+	a = args
+	shorthands := s[1:]
+
+	for i := 0; i < len(shorthands); i++ {
+		c := shorthands[i]
+		flag, alreadythere := f.shorthands[c]
+		if !alreadythere {
+			if c == 'h' { // special case for nice help message.
+				f.usage()
+				err = ErrHelp
+				return
+			}
+			//TODO continue on error
+			err = f.failf("unknown shorthand flag: %q in -%s", c, shorthands)
+			if len(args) == 0 {
+				return
+			}
+			return
+		}
+		if alreadythere {
+			if bv, ok := flag.Value.(boolFlag); ok && bv.IsBoolFlag() {
+				f.setFlag(flag, "true", s)
+				continue
+			}
+			if i < len(shorthands)-1 {
+				v := strings.TrimPrefix(shorthands[i+1:], "=")
+				if e := f.setFlag(flag, v, s); e != nil {
+					err = e
+					return
+				}
+				break
+			}
+			if len(args) == 0 {
+				err = f.failf("flag needs an argument: %q in -%s", c, shorthands)
+				return
+			}
+			if e := f.setFlag(flag, args[0], s); e != nil {
+				err = e
+				return
+			}
+		}
+		a = args[1:]
+		break // should be unnecessary
+	}
+
+	return
+}
+
+func (f *FlagSet) parseArgs(args []string) (err error) {
 	for len(args) > 0 {
 		s := args[0]
 		args = args[1:]
@@ -418,69 +605,20 @@
 		}
 
 		if s[1] == '-' {
-			if len(s) == 2 { // "--" terminates the flags
-				f.args = append(f.args, args...)
-				return nil
-			}
-			name := s[2:]
-			if len(name) == 0 || name[0] == '-' || name[0] == '=' {
-				return f.failf("bad flag syntax: %s", s)
-			}
-			split := strings.SplitN(name, "=", 2)
-			name = split[0]
-			m := f.formal
-			flag, alreadythere := m[name] // BUG
-			if !alreadythere {
-				if name == "help" { // special case for nice help message.
-					f.usage()
-					return ErrHelp
-				}
-				return f.failf("unknown flag: --%s", name)
-			}
-			if len(split) == 1 {
-				if bv, ok := flag.Value.(boolFlag); !ok || !bv.IsBoolFlag() {
-					return f.failf("flag needs an argument: %s", s)
-				}
-				f.setFlag(flag, "true", s)
-			} else {
-				if err := f.setFlag(flag, split[1], s); err != nil {
-					return err
-				}
+			args, err = f.parseLongArg(s, args)
+
+			if len(s) == 2 {
+				// stop parsing after --
+				break
 			}
 		} else {
-			shorthands := s[1:]
-			for i := 0; i < len(shorthands); i++ {
-				c := shorthands[i]
-				flag, alreadythere := f.shorthands[c]
-				if !alreadythere {
-					if c == 'h' { // special case for nice help message.
-						f.usage()
-						return ErrHelp
-					}
-					return f.failf("unknown shorthand flag: %q in -%s", c, shorthands)
-				}
-				if bv, ok := flag.Value.(boolFlag); ok && bv.IsBoolFlag() {
-					f.setFlag(flag, "true", s)
-					continue
-				}
-				if i < len(shorthands)-1 {
-					if err := f.setFlag(flag, shorthands[i+1:], s); err != nil {
-						return err
-					}
-					break
-				}
-				if len(args) == 0 {
-					return f.failf("flag needs an argument: %q in -%s", c, shorthands)
-				}
-				if err := f.setFlag(flag, args[0], s); err != nil {
-					return err
-				}
-				args = args[1:]
-				break // should be unnecessary
-			}
+			args, err = f.parseShortArg(s, args)
+		}
+		if err != nil {
+			return
 		}
 	}
-	return nil
+	return
 }
 
 // Parse parses flag definitions from the argument list, which should not
diff --git a/flag_test.go b/flag_test.go
index 82f7fae..7d114b2 100644
--- a/flag_test.go
+++ b/flag_test.go
@@ -7,6 +7,8 @@
 import (
 	"bytes"
 	"fmt"
+	"io"
+	"io/ioutil"
 	"os"
 	"sort"
 	"strings"
@@ -182,7 +184,8 @@
 	boolaFlag := f.BoolP("boola", "a", false, "bool value")
 	boolbFlag := f.BoolP("boolb", "b", false, "bool2 value")
 	boolcFlag := f.BoolP("boolc", "c", false, "bool3 value")
-	stringFlag := f.StringP("string", "s", "0", "string value")
+	stringaFlag := f.StringP("stringa", "s", "0", "string value")
+	stringzFlag := f.StringP("stringz", "z", "0", "string value")
 	extra := "interspersed-argument"
 	notaflag := "--i-look-like-a-flag"
 	args := []string{
@@ -190,11 +193,13 @@
 		extra,
 		"-cs",
 		"hello",
+		"-z=something",
 		"--",
 		notaflag,
 	}
+	f.SetOutput(ioutil.Discard)
 	if err := f.Parse(args); err != nil {
-		t.Fatal(err)
+		t.Error("expected no error, got ", err)
 	}
 	if !f.Parsed() {
 		t.Error("f.Parse() = false after Parse")
@@ -208,8 +213,11 @@
 	if *boolcFlag != true {
 		t.Error("boolc flag should be true, is ", *boolcFlag)
 	}
-	if *stringFlag != "hello" {
-		t.Error("string flag should be `hello`, is ", *stringFlag)
+	if *stringaFlag != "hello" {
+		t.Error("stringa flag should be `hello`, is ", *stringaFlag)
+	}
+	if *stringzFlag != "something" {
+		t.Error("stringz flag should be `something`, is ", *stringzFlag)
 	}
 	if len(f.Args()) != 2 {
 		t.Error("expected one argument, got", len(f.Args()))
@@ -229,6 +237,110 @@
 	testParse(NewFlagSet("test", ContinueOnError), t)
 }
 
+func replaceSeparators(name string, from []string, to string) string {
+	result := name
+	for _, sep := range from {
+		result = strings.Replace(result, sep, to, -1)
+	}
+	// Type convert to indicate normalization has been done.
+	return result
+}
+
+func wordSepNormalizeFunc(f *FlagSet, name string) NormalizedName {
+	seps := []string{"-", "_"}
+	name = replaceSeparators(name, seps, ".")
+	return NormalizedName(name)
+}
+
+func testWordSepNormalizedNames(args []string, t *testing.T) {
+	f := NewFlagSet("normalized", ContinueOnError)
+	if f.Parsed() {
+		t.Error("f.Parse() = true before Parse")
+	}
+	withDashFlag := f.Bool("with-dash-flag", false, "bool value")
+	// Set this after some flags have been added and before others.
+	f.SetNormalizeFunc(wordSepNormalizeFunc)
+	withUnderFlag := f.Bool("with_under_flag", false, "bool value")
+	withBothFlag := f.Bool("with-both_flag", false, "bool value")
+	if err := f.Parse(args); err != nil {
+		t.Fatal(err)
+	}
+	if !f.Parsed() {
+		t.Error("f.Parse() = false after Parse")
+	}
+	if *withDashFlag != true {
+		t.Error("withDashFlag flag should be true, is ", *withDashFlag)
+	}
+	if *withUnderFlag != true {
+		t.Error("withUnderFlag flag should be true, is ", *withUnderFlag)
+	}
+	if *withBothFlag != true {
+		t.Error("withBothFlag flag should be true, is ", *withBothFlag)
+	}
+}
+
+func TestWordSepNormalizedNames(t *testing.T) {
+	args := []string{
+		"--with-dash-flag",
+		"--with-under-flag",
+		"--with-both-flag",
+	}
+	testWordSepNormalizedNames(args, t)
+
+	args = []string{
+		"--with_dash_flag",
+		"--with_under_flag",
+		"--with_both_flag",
+	}
+	testWordSepNormalizedNames(args, t)
+
+	args = []string{
+		"--with-dash_flag",
+		"--with-under_flag",
+		"--with-both_flag",
+	}
+	testWordSepNormalizedNames(args, t)
+}
+
+func aliasAndWordSepFlagNames(f *FlagSet, name string) NormalizedName {
+	seps := []string{"-", "_"}
+
+	oldName := replaceSeparators("old-valid_flag", seps, ".")
+	newName := replaceSeparators("valid-flag", seps, ".")
+
+	name = replaceSeparators(name, seps, ".")
+	switch name {
+	case oldName:
+		name = newName
+		break
+	}
+
+	return NormalizedName(name)
+}
+
+func TestCustomNormalizedNames(t *testing.T) {
+	f := NewFlagSet("normalized", ContinueOnError)
+	if f.Parsed() {
+		t.Error("f.Parse() = true before Parse")
+	}
+
+	validFlag := f.Bool("valid-flag", false, "bool value")
+	f.SetNormalizeFunc(aliasAndWordSepFlagNames)
+	someOtherFlag := f.Bool("some-other-flag", false, "bool value")
+
+	args := []string{"--old_valid_flag", "--some-other_flag"}
+	if err := f.Parse(args); err != nil {
+		t.Fatal(err)
+	}
+
+	if *validFlag != true {
+		t.Errorf("validFlag is %v even though we set the alias --old_valid_falg", *validFlag)
+	}
+	if *someOtherFlag != true {
+		t.Error("someOtherFlag should be true, is ", *someOtherFlag)
+	}
+}
+
 // Declare a user-defined flag type.
 type flagVar []string
 
@@ -241,6 +353,10 @@
 	return nil
 }
 
+func (f *flagVar) Type() string {
+	return "flagVar"
+}
+
 func TestUserDefined(t *testing.T) {
 	var flags FlagSet
 	flags.Init("test", ContinueOnError)
@@ -348,3 +464,108 @@
 		t.Fatal("expected interspersed options/non-options to fail")
 	}
 }
+
+func TestTermination(t *testing.T) {
+	f := NewFlagSet("termination", ContinueOnError)
+	boolFlag := f.BoolP("bool", "l", false, "bool value")
+	if f.Parsed() {
+		t.Error("f.Parse() = true before Parse")
+	}
+	arg1 := "ls"
+	arg2 := "-l"
+	args := []string{
+		"--",
+		arg1,
+		arg2,
+	}
+	f.SetOutput(ioutil.Discard)
+	if err := f.Parse(args); err != nil {
+		t.Fatal("expected no error; got ", err)
+	}
+	if !f.Parsed() {
+		t.Error("f.Parse() = false after Parse")
+	}
+	if *boolFlag {
+		t.Error("expected boolFlag=false, got true")
+	}
+	if len(f.Args()) != 2 {
+		t.Errorf("expected 2 arguments, got %d: %v", len(f.Args()), f.Args())
+	}
+	if f.Args()[0] != arg1 {
+		t.Errorf("expected argument %q got %q", arg1, f.Args()[0])
+	}
+	if f.Args()[1] != arg2 {
+		t.Errorf("expected argument %q got %q", arg2, f.Args()[1])
+	}
+}
+
+func TestDeprecatedFlagInDocs(t *testing.T) {
+	f := NewFlagSet("bob", ContinueOnError)
+	f.Bool("badflag", true, "always true")
+	f.MarkDeprecated("badflag", "use --good-flag instead")
+
+	out := new(bytes.Buffer)
+	f.SetOutput(out)
+	f.PrintDefaults()
+
+	if strings.Contains(out.String(), "badflag") {
+		t.Errorf("found deprecated flag in usage!")
+	}
+}
+
+func parseReturnStderr(t *testing.T, f *FlagSet, args []string) (string, error) {
+	oldStderr := os.Stderr
+	r, w, _ := os.Pipe()
+	os.Stderr = w
+
+	err := f.Parse(args)
+
+	outC := make(chan string)
+	// copy the output in a separate goroutine so printing can't block indefinitely
+	go func() {
+		var buf bytes.Buffer
+		io.Copy(&buf, r)
+		outC <- buf.String()
+	}()
+
+	w.Close()
+	os.Stderr = oldStderr
+	out := <-outC
+
+	return out, err
+}
+
+func TestDeprecatedFlagUsage(t *testing.T) {
+	f := NewFlagSet("bob", ContinueOnError)
+	f.Bool("badflag", true, "always true")
+	usageMsg := "use --good-flag instead"
+	f.MarkDeprecated("badflag", usageMsg)
+
+	args := []string{"--badflag"}
+	out, err := parseReturnStderr(t, f, args)
+	if err != nil {
+		t.Fatal("expected no error; got ", err)
+	}
+
+	if !strings.Contains(out, usageMsg) {
+		t.Errorf("usageMsg not printed when using a deprecated flag!")
+	}
+}
+
+func TestDeprecatedFlagUsageNormalized(t *testing.T) {
+	f := NewFlagSet("bob", ContinueOnError)
+	f.Bool("bad-double_flag", true, "always true")
+	f.SetNormalizeFunc(wordSepNormalizeFunc)
+	usageMsg := "use --good-flag instead"
+	f.MarkDeprecated("bad_double-flag", usageMsg)
+
+	args := []string{"--bad_double_flag"}
+	out, err := parseReturnStderr(t, f, args)
+	if err != nil {
+		t.Fatal("expected no error; got ", err)
+	}
+
+	if !strings.Contains(out, usageMsg) {
+		t.Errorf("usageMsg not printed when using a deprecated flag!")
+	}
+}
diff --git a/float32.go b/float32.go
index a0041e2..b7ad67d 100644
--- a/float32.go
+++ b/float32.go
@@ -19,6 +19,10 @@
 	return err
 }
 
+func (f *float32Value) Type() string {
+	return "float32"
+}
+
 func (f *float32Value) String() string { return fmt.Sprintf("%v", *f) }
 
 // Float32Var defines a float32 flag with specified name, default value, and usage string.
diff --git a/float64.go b/float64.go
index 8d79be0..0315512 100644
--- a/float64.go
+++ b/float64.go
@@ -19,6 +19,10 @@
 	return err
 }
 
+func (f *float64Value) Type() string {
+	return "float64"
+}
+
 func (f *float64Value) String() string { return fmt.Sprintf("%v", *f) }
 
 // Float64Var defines a float64 flag with specified name, default value, and usage string.
diff --git a/int.go b/int.go
index cb85e14..dca9da6 100644
--- a/int.go
+++ b/int.go
@@ -19,6 +19,10 @@
 	return err
 }
 
+func (i *intValue) Type() string {
+	return "int"
+}
+
 func (i *intValue) String() string { return fmt.Sprintf("%v", *i) }
 
 // IntVar defines an int flag with specified name, default value, and usage string.
diff --git a/int32.go b/int32.go
index 2e1a317..18eaacd 100644
--- a/int32.go
+++ b/int32.go
@@ -19,6 +19,10 @@
 	return err
 }
 
+func (i *int32Value) Type() string {
+	return "int32"
+}
+
 func (i *int32Value) String() string { return fmt.Sprintf("%v", *i) }
 
 // Int32Var defines an int32 flag with specified name, default value, and usage string.
diff --git a/int64.go b/int64.go
index 43aeced..0114aaa 100644
--- a/int64.go
+++ b/int64.go
@@ -19,6 +19,10 @@
 	return err
 }
 
+func (i *int64Value) Type() string {
+	return "int64"
+}
+
 func (i *int64Value) String() string { return fmt.Sprintf("%v", *i) }
 
 // Int64Var defines an int64 flag with specified name, default value, and usage string.
diff --git a/int8.go b/int8.go
index 539c4eb..aab1022 100644
--- a/int8.go
+++ b/int8.go
@@ -19,6 +19,10 @@
 	return err
 }
 
+func (i *int8Value) Type() string {
+	return "int8"
+}
+
 func (i *int8Value) String() string { return fmt.Sprintf("%v", *i) }
 
 // Int8Var defines an int8 flag with specified name, default value, and usage string.
diff --git a/ip.go b/ip.go
index 3a411fc..9d53bd3 100644
--- a/ip.go
+++ b/ip.go
@@ -26,6 +26,10 @@
 	return net.IP(*i)
 }
 
+func (i *ipValue) Type() string {
+	return "ip"
+}
+
 // IPVar defines an net.IP flag with specified name, default value, and usage string.
 // The argument p points to an net.IP variable in which to store the value of the flag.
 func (f *FlagSet) IPVar(p *net.IP, name string, value net.IP, usage string) {
diff --git a/ipmask.go b/ipmask.go
index b8a164a..6f85be9 100644
--- a/ipmask.go
+++ b/ipmask.go
@@ -26,6 +26,10 @@
 	return net.IPMask(*i)
 }
 
+func (i *ipMaskValue) Type() string {
+	return "ipMask"
+}
+
 // Parse IPv4 netmask written in IP form (e.g. 255.255.255.0).
 // This function should really belong to the net package.
 func ParseIPv4Mask(s string) net.IPMask {
diff --git a/string.go b/string.go
index 65c0cb7..362fbf8 100644
--- a/string.go
+++ b/string.go
@@ -14,6 +14,9 @@
 	*s = stringValue(val)
 	return nil
 }
+func (s *stringValue) Type() string {
+	return "string"
+}
 
 func (s *stringValue) String() string { return fmt.Sprintf("%s", *s) }
 
diff --git a/uint.go b/uint.go
index 40b9ebb..c063fe7 100644
--- a/uint.go
+++ b/uint.go
@@ -19,6 +19,10 @@
 	return err
 }
 
+func (i *uintValue) Type() string {
+	return "uint"
+}
+
 func (i *uintValue) String() string { return fmt.Sprintf("%v", *i) }
 
 // UintVar defines a uint flag with specified name, default value, and usage string.
diff --git a/uint16.go b/uint16.go
index 182dc40..ec14ab0 100644
--- a/uint16.go
+++ b/uint16.go
@@ -18,10 +18,15 @@
 	*i = uint16Value(v)
 	return err
 }
+
 func (i *uint16Value) Get() interface{} {
 	return uint16(*i)
 }
 
+func (i *uint16Value) Type() string {
+	return "uint16"
+}
+
 // Uint16Var defines a uint flag with specified name, default value, and usage string.
 // The argument p points to a uint variable in which to store the value of the flag.
 func (f *FlagSet) Uint16Var(p *uint16, name string, value uint16, usage string) {
diff --git a/uint32.go b/uint32.go
index 165c8b2..05bc3bd 100644
--- a/uint32.go
+++ b/uint32.go
@@ -22,6 +22,10 @@
 	return uint32(*i)
 }
 
+func (i *uint32Value) Type() string {
+	return "uint32"
+}
+
 // Uint32Var defines a uint32 flag with specified name, default value, and usage string.
 // The argument p points to a uint32 variable in which to store the value of the flag.
 func (f *FlagSet) Uint32Var(p *uint32, name string, value uint32, usage string) {
diff --git a/uint64.go b/uint64.go
index f41c5a2..99c7e80 100644
--- a/uint64.go
+++ b/uint64.go
@@ -19,6 +19,10 @@
 	return err
 }
 
+func (i *uint64Value) Type() string {
+	return "uint64"
+}
+
 func (i *uint64Value) String() string { return fmt.Sprintf("%v", *i) }
 
 // Uint64Var defines a uint64 flag with specified name, default value, and usage string.
diff --git a/uint8.go b/uint8.go
index 174f99c..6fef508 100644
--- a/uint8.go
+++ b/uint8.go
@@ -19,6 +19,10 @@
 	return err
 }
 
+func (i *uint8Value) Type() string {
+	return "uint8"
+}
+
 func (i *uint8Value) String() string { return fmt.Sprintf("%v", *i) }
 
 // Uint8Var defines a uint8 flag with specified name, default value, and usage string.