1package main 2 3import ( 4 "errors" 5 "os" 6 "path/filepath" 7 "time" 8) 9 10// Don't search for a corresponding header/source file for longer than ~0.5 seconds 11var fileSearchMaxTime = 500 * time.Millisecond 12 13// ExtFileSearch will search for a corresponding file, given a silce of extensions. 14// This is useful for ie. finding a corresponding .h file for a .c file. 15// The search starts in the current directory, then searches every parent directory in depth. 16// TODO: Search sibling and parent directories named "include" first, then search the rest. 17func ExtFileSearch(absCppFilename string, headerExtensions []string, maxTime time.Duration) (string, error) { 18 cppBasename := filepath.Base(absCppFilename) 19 searchPath := filepath.Dir(absCppFilename) 20 ext := filepath.Ext(cppBasename) 21 if ext == "" { 22 return "", errors.New("filename has no extension: " + cppBasename) 23 } 24 firstName := cppBasename[:len(cppBasename)-len(ext)] 25 var headerNames []string 26 for _, ext := range headerExtensions { 27 headerNames = append(headerNames, firstName+ext) 28 } 29 foundHeaderAbsPath := "" 30 startTime := time.Now() 31 for { 32 err := filepath.Walk(searchPath, func(path string, info os.FileInfo, err error) error { 33 basename := filepath.Base(info.Name()) 34 if err == nil { 35 //logf("Walking %s\n", path) 36 for _, headerName := range headerNames { 37 if time.Since(startTime) > maxTime { 38 return errors.New("file search timeout") 39 } 40 if basename == headerName { 41 // Found the corresponding header! 42 absFilename, err := filepath.Abs(path) 43 if err != nil { 44 continue 45 } 46 foundHeaderAbsPath = absFilename 47 //logf("Found %s!\n", absFilename) 48 return nil 49 } 50 } 51 } 52 // No result 53 return nil 54 }) 55 if err != nil { 56 return "", errors.New("error when searching for a corresponding header for " + cppBasename + ":" + err.Error()) 57 } 58 if len(foundHeaderAbsPath) == 0 { 59 // Try the parent directory 60 searchPath = filepath.Dir(searchPath) 61 if len(searchPath) > 2 { 62 continue 63 } 64 } 65 break 66 } 67 if len(foundHeaderAbsPath) == 0 { 68 return "", errors.New("found no corresponding header for " + cppBasename) 69 } 70 71 // Return the result 72 return foundHeaderAbsPath, nil 73} 74