1
2
3
4
5 package objabi
6
7 import (
8 "bytes"
9 "flag"
10 "fmt"
11 "internal/buildcfg"
12 "io"
13 "io/ioutil"
14 "log"
15 "os"
16 "strconv"
17 "strings"
18 )
19
20 func Flagcount(name, usage string, val *int) {
21 flag.Var((*count)(val), name, usage)
22 }
23
24 func Flagfn1(name, usage string, f func(string)) {
25 flag.Var(fn1(f), name, usage)
26 }
27
28 func Flagprint(w io.Writer) {
29 flag.CommandLine.SetOutput(w)
30 flag.PrintDefaults()
31 }
32
33 func Flagparse(usage func()) {
34 flag.Usage = usage
35 os.Args = expandArgs(os.Args)
36 flag.Parse()
37 }
38
39
40
41
42
43
44
45
46
47
48
49
50
51 func expandArgs(in []string) (out []string) {
52
53 for i, s := range in {
54 if strings.HasPrefix(s, "@") {
55 if out == nil {
56 out = make([]string, 0, len(in)*2)
57 out = append(out, in[:i]...)
58 }
59 slurp, err := ioutil.ReadFile(s[1:])
60 if err != nil {
61 log.Fatal(err)
62 }
63 args := strings.Split(strings.TrimSpace(strings.Replace(string(slurp), "\r", "", -1)), "\n")
64 for i, arg := range args {
65 args[i] = DecodeArg(arg)
66 }
67 out = append(out, expandArgs(args)...)
68 } else if out != nil {
69 out = append(out, s)
70 }
71 }
72 if out == nil {
73 return in
74 }
75 return
76 }
77
78 func AddVersionFlag() {
79 flag.Var(versionFlag{}, "V", "print version and exit")
80 }
81
82 var buildID string
83
84 type versionFlag struct{}
85
86 func (versionFlag) IsBoolFlag() bool { return true }
87 func (versionFlag) Get() interface{} { return nil }
88 func (versionFlag) String() string { return "" }
89 func (versionFlag) Set(s string) error {
90 name := os.Args[0]
91 name = name[strings.LastIndex(name, `/`)+1:]
92 name = name[strings.LastIndex(name, `\`)+1:]
93 name = strings.TrimSuffix(name, ".exe")
94
95 p := ""
96
97 if s == "goexperiment" {
98
99
100 p = " X:" + strings.Join(buildcfg.AllExperiments(), ",")
101 } else {
102
103
104 if goexperiment := buildcfg.GOEXPERIMENT(); goexperiment != "" {
105 p = " X:" + goexperiment
106 }
107 }
108
109
110
111
112
113
114 if s == "full" {
115 if strings.HasPrefix(buildcfg.Version, "devel") {
116 p += " buildID=" + buildID
117 }
118 }
119
120 fmt.Printf("%s version %s%s\n", name, buildcfg.Version, p)
121 os.Exit(0)
122 return nil
123 }
124
125
126
127
128 type count int
129
130 func (c *count) String() string {
131 return fmt.Sprint(int(*c))
132 }
133
134 func (c *count) Set(s string) error {
135 switch s {
136 case "true":
137 *c++
138 case "false":
139 *c = 0
140 default:
141 n, err := strconv.Atoi(s)
142 if err != nil {
143 return fmt.Errorf("invalid count %q", s)
144 }
145 *c = count(n)
146 }
147 return nil
148 }
149
150 func (c *count) Get() interface{} {
151 return int(*c)
152 }
153
154 func (c *count) IsBoolFlag() bool {
155 return true
156 }
157
158 func (c *count) IsCountFlag() bool {
159 return true
160 }
161
162 type fn1 func(string)
163
164 func (f fn1) Set(s string) error {
165 f(s)
166 return nil
167 }
168
169 func (f fn1) String() string { return "" }
170
171
172
173
174 func DecodeArg(arg string) string {
175
176 if !strings.ContainsAny(arg, "\\\n") {
177 return arg
178 }
179
180
181 var b bytes.Buffer
182 var wasBS bool
183 for _, r := range arg {
184 if wasBS {
185 switch r {
186 case '\\':
187 b.WriteByte('\\')
188 case 'n':
189 b.WriteByte('\n')
190 default:
191
192
193 panic("badly formatted input")
194 }
195 } else if r == '\\' {
196 wasBS = true
197 continue
198 } else {
199 b.WriteRune(r)
200 }
201 wasBS = false
202 }
203 return b.String()
204 }
205
View as plain text