github.com/rogpeppe/go-internal@v1.12.1-0.20240509064211-c8567cf8e95f/internal/os/execpath/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 execpath 6 7 import ( 8 "os" 9 "path/filepath" 10 "strings" 11 ) 12 13 func chkStat(file string) error { 14 d, err := os.Stat(file) 15 if err != nil { 16 return err 17 } 18 if d.IsDir() { 19 return os.ErrPermission 20 } 21 return nil 22 } 23 24 func hasExt(file string) bool { 25 i := strings.LastIndex(file, ".") 26 if i < 0 { 27 return false 28 } 29 return strings.LastIndexAny(file, `:\/`) < i 30 } 31 32 func findExecutable(file string, exts []string) (string, error) { 33 if len(exts) == 0 { 34 return file, chkStat(file) 35 } 36 if hasExt(file) { 37 if chkStat(file) == nil { 38 return file, nil 39 } 40 } 41 for _, e := range exts { 42 if f := file + e; chkStat(f) == nil { 43 return f, nil 44 } 45 } 46 return "", os.ErrNotExist 47 } 48 49 // Look searches for an executable named file, using getenv to look up 50 // environment variables. If getenv is nil, os.Getenv will be used. If file 51 // contains a slash, it is tried directly and getenv will not be called. The 52 // result may be an absolute path or a path relative to the current directory. 53 // Look also uses PATHEXT environment variable to match 54 // a suitable candidate. 55 func Look(file string, getenv func(string) string) (string, error) { 56 if getenv == nil { 57 getenv = os.Getenv 58 } 59 var exts []string 60 x := getenv(`PATHEXT`) 61 if x != "" { 62 for _, e := range strings.Split(strings.ToLower(x), `;`) { 63 if e == "" { 64 continue 65 } 66 if e[0] != '.' { 67 e = "." + e 68 } 69 exts = append(exts, e) 70 } 71 } else { 72 exts = []string{".com", ".exe", ".bat", ".cmd"} 73 } 74 75 if strings.ContainsAny(file, `:\/`) { 76 if f, err := findExecutable(file, exts); err == nil { 77 return f, nil 78 } else { 79 return "", &Error{file, err} 80 } 81 } 82 if f, err := findExecutable(filepath.Join(".", file), exts); err == nil { 83 return f, nil 84 } 85 path := getenv("path") 86 for _, dir := range filepath.SplitList(path) { 87 if f, err := findExecutable(filepath.Join(dir, file), exts); err == nil { 88 return f, nil 89 } 90 } 91 return "", &Error{file, ErrNotFound} 92 }