source: code/trunk/vendor/modernc.org/opt/opt.go@ 823

Last change on this file since 823 was 822, checked in by yakumo.izuru, 22 months ago

Prefer immortal.run over runit and rc.d, use vendored modules
for convenience.

Signed-off-by: Izuru Yakumo <yakumo.izuru@…>

File size: 3.5 KB
Line 
1// Package opt implements command-line flag parsing.
2package opt // import "modernc.org/opt"
3
4import (
5 "fmt"
6 "strings"
7)
8
9type opt struct {
10 handler func(opt, arg string) error
11 name string
12
13 arg bool // Enable argument, e.g. `-I foo` or `-I=foo`
14}
15
16// A Set represents a set of defined options.
17type Set struct {
18 cfg map[string]*opt
19 imm []*opt
20}
21
22// NewSet returns a new, empty option set.
23func NewSet() *Set { return &Set{cfg: map[string]*opt{}} }
24
25// Opt defines a simple option, e.g. `-f`. When the option is found during
26// Parse, the handler is called with the value of the option, e.g. "-f".
27func (p *Set) Opt(name string, handler func(opt string) error) {
28 p.cfg[name] = &opt{
29 handler: func(opt, arg string) error { return handler(opt) },
30 }
31}
32
33// Arg defines a simple option with an argument, e.g. `-I foo` or `-I=foo`.
34// Setting imm argument enables additionally `-Ifoo`. When the option is found
35// during Parse, the handler is called with the values of the option and the
36// argument, e.g. "-I" and "foo" for all of the variants.
37func (p *Set) Arg(name string, imm bool, handler func(opt, arg string) error) {
38 switch {
39 case imm:
40 p.imm = append(p.imm, &opt{
41 handler: handler,
42 name: name,
43 })
44 default:
45 p.cfg[name] = &opt{
46 arg: true,
47 handler: handler,
48 name: name,
49 }
50 }
51}
52
53// Parse parses opts. Must be called after all options are defined. The handler
54// is called for all items in opts that were not defined before using Opt or
55// Arg.
56//
57// If any handler returns a non-nil error, Parse will stop. If the error is of
58// type Skip, the error returned by Parse will contain all the unprocessed
59// items of opts.
60//
61// The opts slice must not be modified by any handler while Parser is
62// executing.
63func (p *Set) Parse(opts []string, handler func(string) error) (err error) {
64 defer func() {
65 switch err.(type) {
66 case Skip:
67 err = Skip(opts)
68 }
69 }()
70
71 for len(opts) != 0 {
72 opt := opts[0]
73 opt0 := opt
74 opts = opts[1:]
75 var arg string
76 out:
77 switch {
78 case strings.HasPrefix(opt, "-"):
79 name := opt[1:]
80 for _, cfg := range p.imm {
81 if strings.HasPrefix(name, cfg.name) {
82 switch {
83 case name == cfg.name:
84 if len(opts) == 0 {
85 return fmt.Errorf("missing argument of %s", opt)
86 }
87
88 if err = cfg.handler(opt, opts[0]); err != nil {
89 return err
90 }
91
92 opts = opts[1:]
93 default:
94 opt = opt[:len(cfg.name)+1]
95 val := strings.TrimPrefix(name[len(cfg.name):], "=")
96 if err = cfg.handler(opt, val); err != nil {
97 return err
98 }
99 }
100 break out
101 }
102 }
103
104 if n := strings.IndexByte(opt, '='); n > 0 {
105 arg = opt[n+1:]
106 name = opt[1:n]
107 opt = opt[:n]
108 }
109 switch cfg := p.cfg[name]; {
110 case cfg == nil:
111 if err = handler(opt0); err != nil {
112 return err
113 }
114 default:
115 switch {
116 case cfg.arg:
117 switch {
118 case arg != "":
119 if err = cfg.handler(opt, arg); err != nil {
120 return err
121 }
122 default:
123 if len(opts) == 0 {
124 return fmt.Errorf("missing argument of %s", opt)
125 }
126
127 if err = cfg.handler(opt, opts[0]); err != nil {
128 return err
129 }
130
131 opts = opts[1:]
132 }
133 default:
134 if err = cfg.handler(opt, ""); err != nil {
135 return err
136 }
137 }
138 }
139 default:
140 if opt == "" {
141 break
142 }
143
144 if err = handler(opt); err != nil {
145 return err
146 }
147 }
148 }
149 return nil
150}
151
152// Skip is an error that contains all unprocessed items passed to Parse.
153type Skip []string
154
155func (s Skip) Error() string { return fmt.Sprint([]string(s)) }
Note: See TracBrowser for help on using the repository browser.