1 /**
2  * OS-specific paths.
3  *
4  * License:
5  *   This Source Code Form is subject to the terms of
6  *   the Mozilla Public License, v. 2.0. If a copy of
7  *   the MPL was not distributed with this file, You
8  *   can obtain one at http://mozilla.org/MPL/2.0/.
9  *
10  * Authors:
11  *   Vladimir Panteleev <vladimir@thecybershadow.net>
12  */
13 
14 module ae.sys.paths;
15 
16 import std.path;
17 
18 version (Windows)
19 {
20 	import core.stdc.wctype;
21 
22 	import std.exception;
23 	import std.file;
24 	import std.utf;
25 
26 	import win32.shlobj;
27 	import win32.objidl;
28 	import win32.windef;
29 	import win32.winbase;
30 
31 	string getExecutableName()
32 	{
33 		auto path = new char[MAX_PATH];
34 		path.length = enforce(GetModuleFileNameA(null, path.ptr, cast(uint)path.length));
35 		return baseName(assumeUnique(path));
36 	}
37 
38 	private string getShellPath(int csidl)
39 	{
40 		LPITEMIDLIST pidl;
41 		SHGetSpecialFolderLocation(null, csidl, &pidl);
42 		scope(exit)
43 		{
44 			IMalloc aMalloc;
45 			SHGetMalloc(&aMalloc);
46 			aMalloc.Free(pidl);
47 		}
48 
49 		auto path = new wchar[MAX_PATH];
50 		if (!SHGetPathFromIDListW(pidl, path.ptr))
51 			return null;
52 		path.length = wcslen(path.ptr);
53 
54 		return toUTF8(path);
55 	}
56 
57 	private string getAppDir(string appName, int csidl)
58 	{
59 		string dir = getShellPath(csidl) ~ `\` ~ (appName ? appName : getExecutableName());
60 		if (!exists(dir))
61 			mkdir(dir);
62 		return dir;
63 	}
64 
65 	string getLocalAppProfile  (string appName = null) { return getAppDir(appName, CSIDL_LOCAL_APPDATA); }
66 	string getRoamingAppProfile(string appName = null) { return getAppDir(appName, CSIDL_APPDATA); }
67 }
68 else // POSIX
69 {
70 	import std.string;
71 	import std.ascii;
72 	import std.file;
73 
74 	alias toLower = std.ascii.toLower;
75 
76 	string getExecutableName()
77 	{
78 		// TODO: is this valid with OS X app bundles?
79 		return baseName(readLink("/proc/self/exe"));
80 	}
81 
82 	private string getPosixAppName(string appName)
83 	{
84 		string s = appName ? appName : getExecutableName();
85 		string s2;
86 		foreach (c; s)
87 			if (isAlphaNum(c))
88 				s2 ~= toLower(c);
89 			else
90 				if (!s2.endsWith('-'))
91 					s2 ~= '-';
92 		return s2;
93 	}
94 
95 	string getAppProfile(string appName = null)
96 	{
97 		string path = expandTilde("~/." ~ getPosixAppName(appName));
98 		if (!exists(path))
99 			mkdir(path);
100 		return path;
101 	}
102 
103 	alias getAppProfile getLocalAppProfile;
104 	alias getAppProfile getRoamingAppProfile;
105 }