github.com/zxy12/go_duplicate_1_12@v0.0.0-20200217043740-b1636fc0368b/src/cmd/internal/objabi/flag.go (about) 1 // Copyright 2015 The Go Authors. 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 5 package objabi 6 7 import ( 8 "flag" 9 "fmt" 10 "io" 11 "io/ioutil" 12 "log" 13 "os" 14 "strconv" 15 "strings" 16 ) 17 18 func Flagcount(name, usage string, val *int) { 19 flag.Var((*count)(val), name, usage) 20 } 21 22 func Flagfn1(name, usage string, f func(string)) { 23 flag.Var(fn1(f), name, usage) 24 } 25 26 func Flagprint(w io.Writer) { 27 flag.CommandLine.SetOutput(w) 28 flag.PrintDefaults() 29 } 30 31 func Flagparse(usage func()) { 32 flag.Usage = usage 33 os.Args = expandArgs(os.Args) 34 flag.Parse() 35 } 36 37 // expandArgs expands "response files" arguments in the provided slice. 38 // 39 // A "response file" argument starts with '@' and the rest of that 40 // argument is a filename with CR-or-CRLF-separated arguments. Each 41 // argument in the named files can also contain response file 42 // arguments. See Issue 18468. 43 // 44 // The returned slice 'out' aliases 'in' iff the input did not contain 45 // any response file arguments. 46 // 47 // TODO: handle relative paths of recursive expansions in different directories? 48 // Is there a spec for this? Are relative paths allowed? 49 func expandArgs(in []string) (out []string) { 50 // out is nil until we see a "@" argument. 51 for i, s := range in { 52 if strings.HasPrefix(s, "@") { 53 if out == nil { 54 out = make([]string, 0, len(in)*2) 55 out = append(out, in[:i]...) 56 } 57 slurp, err := ioutil.ReadFile(s[1:]) 58 if err != nil { 59 log.Fatal(err) 60 } 61 args := strings.Split(strings.TrimSpace(strings.Replace(string(slurp), "\r", "", -1)), "\n") 62 out = append(out, expandArgs(args)...) 63 } else if out != nil { 64 out = append(out, s) 65 } 66 } 67 if out == nil { 68 return in 69 } 70 return 71 } 72 73 func AddVersionFlag() { 74 flag.Var(versionFlag{}, "V", "print version and exit") 75 } 76 77 var buildID string // filled in by linker 78 79 type versionFlag struct{} 80 81 func (versionFlag) IsBoolFlag() bool { return true } 82 func (versionFlag) Get() interface{} { return nil } 83 func (versionFlag) String() string { return "" } 84 func (versionFlag) Set(s string) error { 85 name := os.Args[0] 86 name = name[strings.LastIndex(name, `/`)+1:] 87 name = name[strings.LastIndex(name, `\`)+1:] 88 name = strings.TrimSuffix(name, ".exe") 89 p := Expstring() 90 if p == DefaultExpstring() { 91 p = "" 92 } 93 sep := "" 94 if p != "" { 95 sep = " " 96 } 97 98 // The go command invokes -V=full to get a unique identifier 99 // for this tool. It is assumed that the release version is sufficient 100 // for releases, but during development we include the full 101 // build ID of the binary, so that if the compiler is changed and 102 // rebuilt, we notice and rebuild all packages. 103 if s == "full" { 104 // If there's an active experiment, include that, 105 // to distinguish go1.10.2 with an experiment 106 // from go1.10.2 without an experiment. 107 if x := Expstring(); x != "" { 108 p += " " + x 109 } 110 if strings.HasPrefix(Version, "devel") { 111 p += " buildID=" + buildID 112 } 113 } 114 115 fmt.Printf("%s version %s%s%s\n", name, Version, sep, p) 116 os.Exit(0) 117 return nil 118 } 119 120 // count is a flag.Value that is like a flag.Bool and a flag.Int. 121 // If used as -name, it increments the count, but -name=x sets the count. 122 // Used for verbose flag -v. 123 type count int 124 125 func (c *count) String() string { 126 return fmt.Sprint(int(*c)) 127 } 128 129 func (c *count) Set(s string) error { 130 switch s { 131 case "true": 132 *c++ 133 case "false": 134 *c = 0 135 default: 136 n, err := strconv.Atoi(s) 137 if err != nil { 138 return fmt.Errorf("invalid count %q", s) 139 } 140 *c = count(n) 141 } 142 return nil 143 } 144 145 func (c *count) Get() interface{} { 146 return int(*c) 147 } 148 149 func (c *count) IsBoolFlag() bool { 150 return true 151 } 152 153 func (c *count) IsCountFlag() bool { 154 return true 155 } 156 157 type fn1 func(string) 158 159 func (f fn1) Set(s string) error { 160 f(s) 161 return nil 162 } 163 164 func (f fn1) String() string { return "" }