1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193
|
// Copyright 2013 Google Inc. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package getopt
import (
"fmt"
"strings"
)
// An Option can be either a Flag or a Value
type Option interface {
// Name returns the name of the option. If the option has been seen
// then the last way it was referenced (short or long) is returned
// otherwise if there is a short name then this will be the short name
// as a string, else it will be the long name.
Name() string
// IsFlag returns true if Option is a flag.
IsFlag() bool
// Seen returns true if the flag was seen.
Seen() bool
// Count returns the number of times the flag was seen.
Count() int
// String returns the last value the option was set to.
String() string
// Value returns the Value of the option.
Value() Value
// SetOptional makes the value optional. The option and value are
// always a single argument. Either --option or --option=value. In
// the former case the value of the option does not change but the Set()
// will return true and the value returned by Count() is incremented.
// The short form is either -o or -ovalue. SetOptional returns
// the Option
SetOptional() Option
// SetFlag makes the value a flag. Flags are boolean values and
// normally do not taken a value. They are set to true when seen.
// If a value is passed in the long form then it must be on, case
// insenstive, one of "true", "false", "t", "f", "on", "off", "1", "0".
// SetFlag returns the Option
SetFlag() Option
// Reset resets the state of the option so it appears it has not
// yet been seen, including resetting the value of the option
// to its original default state.
Reset()
}
type option struct {
short rune // 0 means no short name
long string // "" means no long name
isLong bool // True if they used the long name
flag bool // true if a boolean flag
defval string // default value
optional bool // true if we take an optional value
help string // help message
where string // file where the option was defined
value Value // current value of option
count int // number of times we have seen this option
name string // name of the value (for usage)
uname string // name of the option (for usage)
}
// usageName returns the name of the option for printing usage lines in one
// of the following forms:
//
// -f
// --flag
// -f, --flag
// -s value
// --set=value
// -s, --set=value
func (o *option) usageName() string {
// Don't print help messages if we have none and there is only one
// way to specify the option.
if o.help == "" && (o.short == 0 || o.long == "") {
return ""
}
n := ""
switch {
case o.short != 0 && o.long == "":
n = "-" + string(o.short)
case o.short == 0 && o.long != "":
n = " --" + o.long
case o.short != 0 && o.long != "":
n = "-" + string(o.short) + ", --" + o.long
}
switch {
case o.flag:
return n
case o.optional:
return n + "[=" + o.name + "]"
case o.long != "":
return n + "=" + o.name
}
return n + " " + o.name
}
// sortName returns the name to sort the option on.
func (o *option) sortName() string {
if o.short != 0 {
return string(o.short) + o.long
}
return o.long[:1] + o.long
}
func (o *option) Seen() bool { return o.count > 0 }
func (o *option) Count() int { return o.count }
func (o *option) IsFlag() bool { return o.flag }
func (o *option) String() string { return o.value.String() }
func (o *option) SetOptional() Option { o.optional = true; return o }
func (o *option) SetFlag() Option { o.flag = true; return o }
func (o *option) Value() Value {
if o == nil {
return nil
}
return o.value
}
func (o *option) Name() string {
if !o.isLong && o.short != 0 {
return "-" + string(o.short)
}
return "--" + o.long
}
// Reset rests an option so that it appears it has not yet been seen.
func (o *option) Reset() {
o.isLong = false
o.count = 0
o.value.Set(o.defval, o)
}
type optionList []*option
func (ol optionList) Len() int { return len(ol) }
func (ol optionList) Swap(i, j int) { ol[i], ol[j] = ol[j], ol[i] }
func (ol optionList) Less(i, j int) bool {
// first check the short names (or the first letter of the long name)
// If they are not equal (case insensitive) then we have our answer
n1 := ol[i].sortName()
n2 := ol[j].sortName()
l1 := strings.ToLower(n1)
l2 := strings.ToLower(n2)
if l1 < l2 {
return true
}
if l2 < l1 {
return false
}
return n1 < n2
}
// AddOption add the option o to set CommandLine if o is not already in set
// CommandLine.
func AddOption(o Option) {
CommandLine.AddOption(o)
}
// AddOption add the option o to set s if o is not already in set s.
func (s *Set) AddOption(o Option) {
opt := o.(*option)
for _, eopt := range s.options {
if opt == eopt {
return
}
}
if opt.short != 0 {
if oo, ok := s.shortOptions[opt.short]; ok {
fmt.Fprintf(stderr, "%s: -%c already declared at %s\n", opt.where, opt.short, oo.where)
exit(1)
}
s.shortOptions[opt.short] = opt
}
if opt.long != "" {
if oo, ok := s.longOptions[opt.long]; ok {
fmt.Fprintf(stderr, "%s: --%s already declared at %s\n", opt.where, opt.long, oo.where)
exit(1)
}
s.longOptions[opt.long] = opt
}
s.options = append(s.options, opt)
}
|