github.com/ccccaoqing/test@v0.0.0-20220510085219-3985d23445c0/src/os/exec/lp_windows.go (about) 1 // Copyright 2010 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 exec 6 7 import ( 8 "errors" 9 "os" 10 "strings" 11 ) 12 13 // ErrNotFound is the error resulting if a path search failed to find an executable file. 14 var ErrNotFound = errors.New("executable file not found in %PATH%") 15 16 func chkStat(file string) error { 17 d, err := os.Stat(file) 18 if err != nil { 19 return err 20 } 21 if d.IsDir() { 22 return os.ErrPermission 23 } 24 return nil 25 } 26 27 func hasExt(file string) bool { 28 i := strings.LastIndex(file, ".") 29 if i < 0 { 30 return false 31 } 32 return strings.LastIndexAny(file, `:\/`) < i 33 } 34 35 func findExecutable(file string, exts []string) (string, error) { 36 if len(exts) == 0 { 37 return file, chkStat(file) 38 } 39 if hasExt(file) { 40 if chkStat(file) == nil { 41 return file, nil 42 } 43 } 44 for _, e := range exts { 45 if f := file + e; chkStat(f) == nil { 46 return f, nil 47 } 48 } 49 return ``, os.ErrNotExist 50 } 51 52 // LookPath searches for an executable binary named file 53 // in the directories named by the PATH environment variable. 54 // If file contains a slash, it is tried directly and the PATH is not consulted. 55 // LookPath also uses PATHEXT environment variable to match 56 // a suitable candidate. 57 // The result may be an absolute path or a path relative to the current directory. 58 func LookPath(file string) (f string, err error) { 59 x := os.Getenv(`PATHEXT`) 60 if x == `` { 61 x = `.COM;.EXE;.BAT;.CMD` 62 } 63 exts := []string{} 64 for _, e := range strings.Split(strings.ToLower(x), `;`) { 65 if e == "" { 66 continue 67 } 68 if e[0] != '.' { 69 e = "." + e 70 } 71 exts = append(exts, e) 72 } 73 if strings.IndexAny(file, `:\/`) != -1 { 74 if f, err = findExecutable(file, exts); err == nil { 75 return 76 } 77 return ``, &Error{file, err} 78 } 79 if f, err = findExecutable(`.\`+file, exts); err == nil { 80 return 81 } 82 if pathenv := os.Getenv(`PATH`); pathenv != `` { 83 for _, dir := range splitList(pathenv) { 84 if f, err = findExecutable(dir+`\`+file, exts); err == nil { 85 return 86 } 87 } 88 } 89 return ``, &Error{file, ErrNotFound} 90 } 91 92 func splitList(path string) []string { 93 // The same implementation is used in SplitList in path/filepath; 94 // consider changing path/filepath when changing this. 95 96 if path == "" { 97 return []string{} 98 } 99 100 // Split path, respecting but preserving quotes. 101 list := []string{} 102 start := 0 103 quo := false 104 for i := 0; i < len(path); i++ { 105 switch c := path[i]; { 106 case c == '"': 107 quo = !quo 108 case c == os.PathListSeparator && !quo: 109 list = append(list, path[start:i]) 110 start = i + 1 111 } 112 } 113 list = append(list, path[start:]) 114 115 // Remove quotes. 116 for i, s := range list { 117 if strings.Contains(s, `"`) { 118 list[i] = strings.Replace(s, `"`, ``, -1) 119 } 120 } 121 122 return list 123 }