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 ae.sys.windows.imports;
27 	mixin(importWin32!q{shlobj});
28 	mixin(importWin32!q{objidl});
29 	mixin(importWin32!q{windef});
30 	mixin(importWin32!q{winbase});
31 
32 	string getExecutableName()
33 	{
34 		auto path = new char[MAX_PATH];
35 		path.length = enforce(GetModuleFileNameA(null, path.ptr, cast(uint)path.length));
36 		return baseName(assumeUnique(path));
37 	}
38 
39 	private string getShellPath(int csidl)
40 	{
41 		LPITEMIDLIST pidl;
42 		SHGetSpecialFolderLocation(null, csidl, &pidl);
43 		scope(exit)
44 		{
45 			IMalloc aMalloc;
46 			SHGetMalloc(&aMalloc);
47 			aMalloc.Free(pidl);
48 		}
49 
50 		auto path = new wchar[MAX_PATH];
51 		if (!SHGetPathFromIDListW(pidl, path.ptr))
52 			return null;
53 		path.length = wcslen(path.ptr);
54 
55 		return toUTF8(path);
56 	}
57 
58 	private string getAppDir(string appName, int csidl)
59 	{
60 		string dir = getShellPath(csidl) ~ `\` ~ (appName ? appName : getExecutableName());
61 		if (!exists(dir))
62 			mkdir(dir);
63 		return dir;
64 	}
65 
66 	string getLocalAppProfile  (string appName = null) { return getAppDir(appName, CSIDL_LOCAL_APPDATA); }
67 	string getRoamingAppProfile(string appName = null) { return getAppDir(appName, CSIDL_APPDATA); }
68 }
69 else // POSIX
70 {
71 	import std.string;
72 	import std.ascii;
73 	import std.file;
74 
75 	alias toLower = std.ascii.toLower;
76 
77 	string getExecutableName()
78 	{
79 		// TODO: is this valid with OS X app bundles?
80 		return baseName(readLink("/proc/self/exe"));
81 	}
82 
83 	private string getPosixAppName(string appName)
84 	{
85 		string s = appName ? appName : getExecutableName();
86 		string s2;
87 		foreach (c; s)
88 			if (isAlphaNum(c))
89 				s2 ~= toLower(c);
90 			else
91 				if (!s2.endsWith('-'))
92 					s2 ~= '-';
93 		return s2;
94 	}
95 
96 	string getAppProfile(string appName = null)
97 	{
98 		string path = expandTilde("~/." ~ getPosixAppName(appName));
99 		if (!exists(path))
100 			mkdir(path);
101 		return path;
102 	}
103 
104 	alias getAppProfile getLocalAppProfile;
105 	alias getAppProfile getRoamingAppProfile;
106 }