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 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224
|
// Copyright 2017 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
// ShortName always returns the short name of the option, or "" if there
// is no short name. The name does not include the "-".
ShortName() string
// LongName always returns the long name of the option, or "" if there
// is no long name. The name does not include the "--".
LongName() 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
// insensitivinsensitive, 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()
// Mandataory sets the mandatory flag of the option. Parse will
// fail if a mandatory option is missing.
Mandatory() Option
// SetGroup sets the option as part of a radio group. Parse will
// fail if two options in the same group are seen.
SetGroup(string) Option
}
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)
mandatory bool // this option must be specified
group string // mutual exclusion group
}
// 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) Mandatory() Option { o.mandatory = true; return o }
func (o *option) SetGroup(g string) Option { o.group = g; 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
}
func (o *option) ShortName() string {
if o.short != 0 {
return string(o.short)
}
return ""
}
func (o *option) LongName() string {
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)
}
|