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	requiredGroups []string
50}
51
52// New returns a newly created option set.
53func New() *Set {
54	s := &Set{
55		shortOptions: make(map[rune]*option),
56		longOptions:  make(map[string]*option),
57		parameters:   "[parameters ...]",
58	}
59
60	s.usage = func() {
61		s.PrintUsage(stderr)
62	}
63	return s
64}
65
66func (s *Set) setState(state State) {
67	s.stateMu.Lock()
68	s.state = state
69	s.stateMu.Unlock()
70}
71
72// State returns the current state of the Set s.  The state is normally the
73// reason the most recent call to Getopt returned.
74func (s *Set) State() State {
75	s.stateMu.Lock()
76	defer s.stateMu.Unlock()
77	return s.state
78}
79
80// The default set of command-line options.
81var CommandLine = New()
82
83// PrintUsage calls PrintUsage in the default option set.
84func PrintUsage(w io.Writer) { CommandLine.PrintUsage(w) }
85
86// Usage calls the usage function in the default option set.
87func Usage() { CommandLine.usage() }
88
89// Parse calls Parse in the default option set with the command line arguments
90// found in os.Args.
91func Parse() { CommandLine.Parse(os.Args) }
92
93// Same as parse but not found in version 1 of getopt.
94func ParseV2() { CommandLine.Parse(os.Args) }
95
96// Getops returns the result of calling Getop in the default option set with the
97// command line arguments found in os.Args.  The fn function, which may be nil,
98// is passed to Getopt.
99func Getopt(fn func(Option) bool) error { return CommandLine.Getopt(os.Args, fn) }
100
101// Arg returns the n'th command-line argument. Arg(0) is the first remaining
102// argument after options have been processed.
103func Arg(n int) string {
104	if n >= 0 && n < len(CommandLine.args) {
105		return CommandLine.args[n]
106	}
107	return ""
108}
109
110// Arg returns the n'th argument. Arg(0) is the first remaining
111// argument after options have been processed.
112func (s *Set) Arg(n int) string {
113	if n >= 0 && n < len(s.args) {
114		return s.args[n]
115	}
116	return ""
117}
118
119// Args returns the non-option command line arguments.
120func Args() []string {
121	return CommandLine.args
122}
123
124// Args returns the non-option arguments.
125func (s *Set) Args() []string {
126	return s.args
127}
128
129// NArgs returns the number of non-option command line arguments.
130func NArgs() int {
131	return len(CommandLine.args)
132}
133
134// NArgs returns the number of non-option arguments.
135func (s *Set) NArgs() int {
136	return len(s.args)
137}
138
139// SetParameters sets the parameters string for printing the command line
140// usage.  It defaults to "[parameters ...]"
141func SetParameters(parameters string) {
142	CommandLine.parameters = parameters
143}
144
145// SetParameters sets the parameters string for printing the s's usage.
146// It defaults to "[parameters ...]"
147func (s *Set) SetParameters(parameters string) {
148	s.parameters = parameters
149}
150
151// Parameters returns the parameters set by SetParameters on s.
152func (s *Set) Parameters() string { return s.parameters }
153
154// SetProgram sets the program name to program.  Normally it is determined
155// from the zeroth command line argument (see os.Args).
156func SetProgram(program string) {
157	CommandLine.program = program
158}
159
160// SetProgram sets s's program name to program.  Normally it is determined
161// from the zeroth argument passed to Getopt or Parse.
162func (s *Set) SetProgram(program string) {
163	s.program = program
164}
165
166// Program returns the program name associated with Set s.
167func (s *Set) Program() string { return s.program }
168
169// SetUsage sets the function used by Parse to display the commands usage
170// on error.  It defaults to calling PrintUsage(os.Stderr).
171func SetUsage(usage func()) {
172	CommandLine.usage = usage
173}
174
175// SetUsage sets the function used by Parse to display usage on error.  It
176// defaults to calling f.PrintUsage(os.Stderr).
177func (s *Set) SetUsage(usage func()) {
178	s.usage = usage
179}
180
181// Lookup returns the Option associated with name.  Name should either be
182// a rune (the short name) or a string (the long name).
183func Lookup(name interface{}) Option {
184	return CommandLine.Lookup(name)
185}
186
187// Lookup returns the Option associated with name in s.  Name should either be
188// a rune (the short name) or a string (the long name).
189func (s *Set) Lookup(name interface{}) Option {
190	switch v := name.(type) {
191	case rune:
192		return s.shortOptions[v]
193	case int:
194		return s.shortOptions[rune(v)]
195	case string:
196		return s.longOptions[v]
197	}
198	return nil
199}
200
201// IsSet returns true if the Option associated with name was seen while
202// parsing the command line arguments.  Name should either be a rune (the
203// short name) or a string (the long name).
204func IsSet(name interface{}) bool {
205	return CommandLine.IsSet(name)
206}
207
208// IsSet returns true if the Option associated with name was seen while
209// parsing s.  Name should either be a rune (the short name) or a string (the
210// long name).
211func (s *Set) IsSet(name interface{}) bool {
212	if opt := s.Lookup(name); opt != nil {
213		return opt.Seen()
214	}
215	return false
216}
217
218// GetCount returns the number of times the Option associated with name has been
219// seen while parsing the command line arguments.  Name should either be a rune
220// (the short name) or a string (the long name).
221func GetCount(name interface{}) int {
222	return CommandLine.GetCount(name)
223}
224
225// GetCount returns the number of times the Option associated with name has been
226// seen while parsing s's arguments.  Name should either be a rune (the short
227// name) or a string (the long name).
228func (s *Set) GetCount(name interface{}) int {
229	if opt := s.Lookup(name); opt != nil {
230		return opt.Count()
231	}
232	return 0
233}
234
235// GetValue returns the final value set to the command-line Option with name.
236// If the option has not been seen while parsing s then the default value is
237// returned.  Name should either be a rune (the short name) or a string (the
238// long name).
239func GetValue(name interface{}) string {
240	return CommandLine.GetValue(name)
241}
242
243// GetValue returns the final value set to the Option in s associated with name.
244// If the option has not been seen while parsing s then the default value is
245// returned.  Name should either be a rune (the short name) or a string (the
246// long name).
247func (s *Set) GetValue(name interface{}) string {
248	if opt := s.Lookup(name); opt != nil {
249		return opt.String()
250	}
251	return ""
252}
253
254// Visit visits the command-line options in lexicographical order, calling fn
255// for each. It visits only those options that have been set.
256func Visit(fn func(Option)) { CommandLine.Visit(fn) }
257
258// Visit visits the options in s in lexicographical order, calling fn
259// for each. It visits only those options that have been set.
260func (s *Set) Visit(fn func(Option)) {
261	sort.Sort(s.options)
262	for _, opt := range s.options {
263		if opt.count > 0 {
264			fn(opt)
265		}
266	}
267}
268
269// VisitAll visits the options in s in lexicographical order, calling fn
270// for each. It visits all options, even those not set.
271func VisitAll(fn func(Option)) { CommandLine.VisitAll(fn) }
272
273// VisitAll visits the command-line flags in lexicographical order, calling fn
274// for each. It visits all flags, even those not set.
275func (s *Set) VisitAll(fn func(Option)) {
276	sort.Sort(s.options)
277	for _, opt := range s.options {
278		fn(opt)
279	}
280}
281
282// Reset resets all the command line options to the initial state so it
283// appears none of them have been seen.
284func Reset() {
285	CommandLine.Reset()
286}
287
288// Reset resets all the options in s to the initial state so it
289// appears none of them have been seen.
290func (s *Set) Reset() {
291	for _, opt := range s.options {
292		opt.Reset()
293	}
294}
295
296// RequiredGroup marks the group set with Option.SetGroup as required.  At least
297// one option in the group must be seen by parse.  Calling RequiredGroup with a
298// group name that has no options will cause parsing to always fail.
299func (s *Set) RequiredGroup(group string) {
300	s.requiredGroups = append(s.requiredGroups, group)
301}
302
303// RequiredGroup marks the group set with Option.SetGroup as required on the
304// command line.  At least one option in the group must be seen by parse.
305// Calling RequiredGroup with a group name that has no options will cause
306// parsing to always fail.
307func RequiredGroup(group string) {
308	CommandLine.requiredGroups = append(CommandLine.requiredGroups, group)
309}
310