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