1// Copyright 2017 Google Inc.  All rights reserved.
2// Use of this source code is governed by a BSD-style
3// license that can be found in the LICENSE file.
4
5package getopt
6
7import (
8	"io"
9	"os"
10	"sort"
11	"sync"
12)
13
14// A State is why the Getopt returned.
15type State int
16
17const (
18	InProgress     = State(iota) // Getopt is still running
19	Dash                         // Returned on "-"
20	DashDash                     // Returned on "--"
21	EndOfOptions                 // End of options reached
22	EndOfArguments               // No more arguments
23	Terminated                   // Terminated by callback function
24	Failure                      // Terminated due to error
25	Unknown                      // Indicates internal error
26)
27
28type Set struct {
29	stateMu sync.Mutex
30	state   State
31
32	// args are the parameters remaining after parsing the optoins.
33	args []string
34
35	// program is the name of the program for usage and error messages.
36	// If not set it will automatically be set to the base name of the
37	// first argument passed to parse.
38	program string
39
40	// parameters is what is displayed on the usage line after displaying
41	// the various options.
42	parameters string
43
44	usage func() // usage should print the programs usage and exit.
45
46	shortOptions map[rune]*option
47	longOptions  map[string]*option
48	options      optionList
49}
50
51// New returns a newly created option set.
52func New() *Set {
53	s := &Set{
54		shortOptions: make(map[rune]*option),
55		longOptions:  make(map[string]*option),
56		parameters:   "[parameters ...]",
57	}
58
59	s.usage = func() {
60		s.PrintUsage(stderr)
61	}
62	return s
63}
64
65func (s *Set) setState(state State) {
66	s.stateMu.Lock()
67	s.state = state
68	s.stateMu.Unlock()
69}
70
71// State returns the current state of the Set s.  The state is normally the
72// reason the most recent call to Getopt returned.
73func (s *Set) State() State {
74	s.stateMu.Lock()
75	defer s.stateMu.Unlock()
76	return s.state
77}
78
79// The default set of command-line options.
80var CommandLine = New()
81
82// PrintUsage calls PrintUsage in the default option set.
83func PrintUsage(w io.Writer) { CommandLine.PrintUsage(w) }
84
85// Usage calls the usage function in the default option set.
86func Usage() { CommandLine.usage() }
87
88// Parse calls Parse in the default option set with the command line arguments
89// found in os.Args.
90func Parse() { CommandLine.Parse(os.Args) }
91
92// Getops returns the result of calling Getop in the default option set with the
93// command line arguments found in os.Args.  The fn function, which may be nil,
94// is passed to Getopt.
95func Getopt(fn func(Option) bool) error { return CommandLine.Getopt(os.Args, fn) }
96
97// Arg returns the n'th command-line argument. Arg(0) is the first remaining
98// argument after options have been processed.
99func Arg(n int) string {
100	if n >= 0 && n < len(CommandLine.args) {
101		return CommandLine.args[n]
102	}
103	return ""
104}
105
106// Arg returns the n'th argument. Arg(0) is the first remaining
107// argument after options have been processed.
108func (s *Set) Arg(n int) string {
109	if n >= 0 && n < len(s.args) {
110		return s.args[n]
111	}
112	return ""
113}
114
115// Args returns the non-option command line arguments.
116func Args() []string {
117	return CommandLine.args
118}
119
120// Args returns the non-option arguments.
121func (s *Set) Args() []string {
122	return s.args
123}
124
125// NArgs returns the number of non-option command line arguments.
126func NArgs() int {
127	return len(CommandLine.args)
128}
129
130// NArgs returns the number of non-option arguments.
131func (s *Set) NArgs() int {
132	return len(s.args)
133}
134
135// SetParameters sets the parameters string for printing the command line
136// usage.  It defaults to "[parameters ...]"
137func SetParameters(parameters string) {
138	CommandLine.parameters = parameters
139}
140
141// SetParameters sets the parameters string for printing the s's usage.
142// It defaults to "[parameters ...]"
143func (s *Set) SetParameters(parameters string) {
144	s.parameters = parameters
145}
146
147// SetProgram sets the program name to program.  Normally it is determined
148// from the zeroth command line argument (see os.Args).
149func SetProgram(program string) {
150	CommandLine.program = program
151}
152
153// SetProgram sets s's program name to program.  Normally it is determined
154// from the zeroth argument passed to Getopt or Parse.
155func (s *Set) SetProgram(program string) {
156	s.program = program
157}
158
159// SetUsage sets the function used by Parse to display the commands usage
160// on error.  It defaults to calling PrintUsage(os.Stderr).
161func SetUsage(usage func()) {
162	CommandLine.usage = usage
163}
164
165// SetUsage sets the function used by Parse to display usage on error.  It
166// defaults to calling f.PrintUsage(os.Stderr).
167func (s *Set) SetUsage(usage func()) {
168	s.usage = usage
169}
170
171// Lookup returns the Option associated with name.  Name should either be
172// a rune (the short name) or a string (the long name).
173func Lookup(name interface{}) Option {
174	return CommandLine.Lookup(name)
175}
176
177// Lookup returns the Option associated with name in s.  Name should either be
178// a rune (the short name) or a string (the long name).
179func (s *Set) Lookup(name interface{}) Option {
180	switch v := name.(type) {
181	case rune:
182		return s.shortOptions[v]
183	case int:
184		return s.shortOptions[rune(v)]
185	case string:
186		return s.longOptions[v]
187	}
188	return nil
189}
190
191// IsSet returns true if the Option associated with name was seen while
192// parsing the command line arguments.  Name should either be a rune (the
193// short name) or a string (the long name).
194func IsSet(name interface{}) bool {
195	return CommandLine.IsSet(name)
196}
197
198// IsSet returns true if the Option associated with name was seen while
199// parsing s.  Name should either be a rune (the short name) or a string (the
200// long name).
201func (s *Set) IsSet(name interface{}) bool {
202	if opt := s.Lookup(name); opt != nil {
203		return opt.Seen()
204	}
205	return false
206}
207
208// GetCount returns the number of times the Option associated with name has been
209// seen while parsing the command line arguments.  Name should either be a rune
210// (the short name) or a string (the long name).
211func GetCount(name interface{}) int {
212	return CommandLine.GetCount(name)
213}
214
215// GetCount returns the number of times the Option associated with name has been
216// seen while parsing s's arguments.  Name should either be a rune (the short
217// name) or a string (the long name).
218func (s *Set) GetCount(name interface{}) int {
219	if opt := s.Lookup(name); opt != nil {
220		return opt.Count()
221	}
222	return 0
223}
224
225// GetValue returns the final value set to the command-line Option with name.
226// If the option has not been seen while parsing s then the default value is
227// returned.  Name should either be a rune (the short name) or a string (the
228// long name).
229func GetValue(name interface{}) string {
230	return CommandLine.GetValue(name)
231}
232
233// GetValue returns the final value set to the Option in s associated with name.
234// If the option has not been seen while parsing s then the default value is
235// returned.  Name should either be a rune (the short name) or a string (the
236// long name).
237func (s *Set) GetValue(name interface{}) string {
238	if opt := s.Lookup(name); opt != nil {
239		return opt.String()
240	}
241	return ""
242}
243
244// Visit visits the command-line options in lexicographical order, calling fn
245// for each. It visits only those options that have been set.
246func Visit(fn func(Option)) { CommandLine.Visit(fn) }
247
248// Visit visits the options in s in lexicographical order, calling fn
249// for each. It visits only those options that have been set.
250func (s *Set) Visit(fn func(Option)) {
251	sort.Sort(s.options)
252	for _, opt := range s.options {
253		if opt.count > 0 {
254			fn(opt)
255		}
256	}
257}
258
259// VisitAll visits the options in s in lexicographical order, calling fn
260// for each. It visits all options, even those not set.
261func VisitAll(fn func(Option)) { CommandLine.VisitAll(fn) }
262
263// VisitAll visits the command-line flags in lexicographical order, calling fn
264// for each. It visits all flags, even those not set.
265func (s *Set) VisitAll(fn func(Option)) {
266	sort.Sort(s.options)
267	for _, opt := range s.options {
268		fn(opt)
269	}
270}
271
272// Reset resets all the command line options to the initial state so it
273// appears none of them have been seen.
274func Reset() {
275	CommandLine.Reset()
276}
277
278// Reset resets all the options in s to the initial state so it
279// appears none of them have been seen.
280func (s *Set) Reset() {
281	for _, opt := range s.options {
282		opt.Reset()
283	}
284}
285