1// Copyright (c) 2013-2017 The btcsuite developers 2// Use of this source code is governed by an ISC 3// license that can be found in the LICENSE file. 4 5package btcutil 6 7import ( 8 "os" 9 "os/user" 10 "path/filepath" 11 "runtime" 12 "strings" 13 "unicode" 14) 15 16// appDataDir returns an operating system specific directory to be used for 17// storing application data for an application. See AppDataDir for more 18// details. This unexported version takes an operating system argument 19// primarily to enable the testing package to properly test the function by 20// forcing an operating system that is not the currently one. 21func appDataDir(goos, appName string, roaming bool) string { 22 if appName == "" || appName == "." { 23 return "." 24 } 25 26 // The caller really shouldn't prepend the appName with a period, but 27 // if they do, handle it gracefully by trimming it. 28 appName = strings.TrimPrefix(appName, ".") 29 appNameUpper := string(unicode.ToUpper(rune(appName[0]))) + appName[1:] 30 appNameLower := string(unicode.ToLower(rune(appName[0]))) + appName[1:] 31 32 // Get the OS specific home directory via the Go standard lib. 33 var homeDir string 34 usr, err := user.Current() 35 if err == nil { 36 homeDir = usr.HomeDir 37 } 38 39 // Fall back to standard HOME environment variable that works 40 // for most POSIX OSes if the directory from the Go standard 41 // lib failed. 42 if err != nil || homeDir == "" { 43 homeDir = os.Getenv("HOME") 44 } 45 46 switch goos { 47 // Attempt to use the LOCALAPPDATA or APPDATA environment variable on 48 // Windows. 49 case "windows": 50 // Windows XP and before didn't have a LOCALAPPDATA, so fallback 51 // to regular APPDATA when LOCALAPPDATA is not set. 52 appData := os.Getenv("LOCALAPPDATA") 53 if roaming || appData == "" { 54 appData = os.Getenv("APPDATA") 55 } 56 57 if appData != "" { 58 return filepath.Join(appData, appNameUpper) 59 } 60 61 case "darwin": 62 if homeDir != "" { 63 return filepath.Join(homeDir, "Library", 64 "Application Support", appNameUpper) 65 } 66 67 case "plan9": 68 if homeDir != "" { 69 return filepath.Join(homeDir, appNameLower) 70 } 71 72 default: 73 if homeDir != "" { 74 return filepath.Join(homeDir, "."+appNameLower) 75 } 76 } 77 78 // Fall back to the current directory if all else fails. 79 return "." 80} 81 82// AppDataDir returns an operating system specific directory to be used for 83// storing application data for an application. 84// 85// The appName parameter is the name of the application the data directory is 86// being requested for. This function will prepend a period to the appName for 87// POSIX style operating systems since that is standard practice. An empty 88// appName or one with a single dot is treated as requesting the current 89// directory so only "." will be returned. Further, the first character 90// of appName will be made lowercase for POSIX style operating systems and 91// uppercase for Mac and Windows since that is standard practice. 92// 93// The roaming parameter only applies to Windows where it specifies the roaming 94// application data profile (%APPDATA%) should be used instead of the local one 95// (%LOCALAPPDATA%) that is used by default. 96// 97// Example results: 98// dir := AppDataDir("myapp", false) 99// POSIX (Linux/BSD): ~/.myapp 100// Mac OS: $HOME/Library/Application Support/Myapp 101// Windows: %LOCALAPPDATA%\Myapp 102// Plan 9: $home/myapp 103func AppDataDir(appName string, roaming bool) string { 104 return appDataDir(runtime.GOOS, appName, roaming) 105} 106