github.com/miolini/go@v0.0.0-20160405192216-fca68c8cb408/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) (string, 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.ContainsAny(file, `:\/`) { 74 if f, err := findExecutable(file, exts); err == nil { 75 return f, nil 76 } else { 77 return "", &Error{file, err} 78 } 79 } 80 if f, err := findExecutable(`.\`+file, exts); err == nil { 81 return f, nil 82 } 83 if pathenv := os.Getenv(`PATH`); pathenv != "" { 84 for _, dir := range splitList(pathenv) { 85 if f, err := findExecutable(dir+`\`+file, exts); err == nil { 86 return f, nil 87 } 88 } 89 } 90 return "", &Error{file, ErrNotFound} 91 } 92 93 func splitList(path string) []string { 94 // The same implementation is used in SplitList in path/filepath; 95 // consider changing path/filepath when changing this. 96 97 if path == "" { 98 return []string{} 99 } 100 101 // Split path, respecting but preserving quotes. 102 list := []string{} 103 start := 0 104 quo := false 105 for i := 0; i < len(path); i++ { 106 switch c := path[i]; { 107 case c == '"': 108 quo = !quo 109 case c == os.PathListSeparator && !quo: 110 list = append(list, path[start:i]) 111 start = i + 1 112 } 113 } 114 list = append(list, path[start:]) 115 116 // Remove quotes. 117 for i, s := range list { 118 if strings.Contains(s, `"`) { 119 list[i] = strings.Replace(s, `"`, "", -1) 120 } 121 } 122 123 return list 124 }