1 //this file is part of notepad++
2 //Copyright (C)2003 Don HO <donho@altern.org>
3 //
4 //This program is free software; you can redistribute it and/or
5 //modify it under the terms of the GNU General Public License
6 //as published by the Free Software Foundation; either
7 //version 2 of the License, or (at your option) any later version.
8 //
9 //This program is distributed in the hope that it will be useful,
10 //but WITHOUT ANY WARRANTY; without even the implied warranty of
11 //MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12 //GNU General Public License for more details.
13 //
14 //You should have received a copy of the GNU General Public License
15 //along with this program; if not, write to the Free Software
16 //Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
17 /**
18  * npp menu
19  *
20  * Author: dokutoku, https://twitter.com/dokutoku3
21  * License: GPL-2.0 or later
22  */
23 module npp_api.pluginfunc.path;
24 
25 
26 version (Windows):
27 version (Not_betterC):
28 
29 private static import core.sys.windows.winbase;
30 private static import core.sys.windows.windef;
31 private static import core.sys.windows.winnt;
32 private static import npp_api.PowerEditor.MISC.PluginsManager.PluginInterface;
33 private static import npp_api.pluginfunc.npp_msgs;
34 private static import npp_api.pluginfunc.string;
35 private static import std.algorithm;
36 private static import std.array;
37 private static import std.file;
38 private static import std.path;
39 private static import std.process;
40 private static import std.string;
41 
42 enum OS_MAX_PATH = 32768;
43 
44 /**
45  * get file path
46  */
47 nothrow @nogc
48 bool get_full_current_path(core.sys.windows.windef.HWND _nppHandle, ref core.sys.windows.winnt.WCHAR[.OS_MAX_PATH] path_temp)
49 
50 	do
51 	{
52 		path_temp[] = '\0';
53 
54 		if (npp_api.pluginfunc.npp_msgs.send_NPPM_GETFULLCURRENTPATH(_nppHandle, .OS_MAX_PATH, &(path_temp[0])) == core.sys.windows.windef.TRUE) {
55 			return true;
56 		} else {
57 			return false;
58 		}
59 	}
60 
61 nothrow
62 wstring get_file_path(core.sys.windows.windef.HWND _nppHandle)
63 
64 	do
65 	{
66 		core.sys.windows.winnt.WCHAR[.OS_MAX_PATH] path_temp;
67 
68 		if (.get_full_current_path(_nppHandle, path_temp)) {
69 			return npp_api.pluginfunc..string.from_stringz(path_temp);
70 		} else {
71 			return null;
72 		}
73 	}
74 
75 nothrow
76 wstring get_directory_path(core.sys.windows.windef.HWND _nppHandle)
77 
78 	do
79 	{
80 		core.sys.windows.winnt.WCHAR[.OS_MAX_PATH] path_temp;
81 
82 		if (npp_api.pluginfunc.npp_msgs.send_NPPM_GETCURRENTDIRECTORY(_nppHandle, .OS_MAX_PATH, &(path_temp[0])) == core.sys.windows.windef.TRUE) {
83 			return npp_api.pluginfunc..string.from_stringz(path_temp);
84 		} else {
85 			return null;
86 		}
87 	}
88 
89 pure nothrow @safe
90 private immutable (C)[][] c_names(C)(const C[][] input)
91 
92 	do
93 	{
94 		immutable (C)[][] output = new immutable (C)[][input.length];
95 
96 		for (size_t i = 0; i < input.length; i++) {
97 			output[i] = (input[i] ~ '\0').idup;
98 		}
99 
100 		return output;
101 	}
102 
103 deprecated
104 alias create_variable_identifiers = .create_variable_ids;
105 
106 pure nothrow @safe
107 private immutable (C)[][] create_variable_ids(C)(const C[][] input)
108 
109 	do
110 	{
111 		immutable (C)[][] output = new immutable (C)[][input.length];
112 
113 		for (size_t i = 0; i < input.length; i++) {
114 			output[i] = ('%' ~ input[i] ~ '%').idup;
115 		}
116 
117 		return output;
118 	}
119 
120 enum wstring[] windows_variable_names =
121 [
122 	`ALLUSERSPROFILE`w,
123 	`APPDATA`w,
124 	`CommonProgramFiles`w,
125 	`CommonProgramFiles(x86)`w,
126 	`CommonProgramW6432`w,
127 	`COMPUTERNAME`w,
128 	`ComSpec`w,
129 	`DriverData`w,
130 	`HOMEDRIVE`w,
131 	`HOMEPATH`w,
132 	`LOCALAPPDATA`w,
133 	`LOGONSERVER`w,
134 	`NUMBER_OF_PROCESSORS`w,
135 	`OneDrive`w,
136 	`OS`w,
137 	`Path`w,
138 	`PATHEXT`w,
139 	`PROCESSOR_ARCHITECTURE`w,
140 	`PROCESSOR_ARCHITEW6432`w,
141 	`PROCESSOR_IDENTIFIER`w,
142 	`PROCESSOR_LEVEL`w,
143 	`PROCESSOR_REVISION`w,
144 	`ProgramData`w,
145 	`ProgramFiles`w,
146 	`ProgramFiles(x86)`w,
147 	`ProgramW6432`w,
148 	`PROMPT`w,
149 	`PSModulePath`w,
150 	`PUBLIC`w,
151 	`SESSIONNAME`w,
152 	`SystemDrive`w,
153 	`SystemRoot`w,
154 	`TEMP`w,
155 	`TMP`w,
156 	`USERDOMAIN`w,
157 	`USERDOMAIN_ROAMINGPROFILE`w,
158 	`USERNAME`w,
159 	`USERPROFILE`w,
160 	`windir`w,
161 ];
162 
163 enum wstring[] windows_variable_wnames = c_names!(wchar)(windows_variable_names);
164 enum wstring[] windows_variables = create_variable_ids!(wchar)(windows_variable_names);
165 
166 pure nothrow @safe @nogc
167 private size_t max_length(wstring[] list)
168 
169 	do
170 	{
171 		size_t max_length = 0;
172 
173 		for (size_t i = 0; i < list.length; i++) {
174 			if (list[i].length > max_length) {
175 				max_length = list[i].length;
176 			}
177 		}
178 
179 		return max_length;
180 	}
181 
182 nothrow
183 wstring echo_variables(wstring name)
184 
185 	do
186 	{
187 		enum buf_length = max_length(windows_variable_names) + 1;
188 
189 		core.sys.windows.winnt.WCHAR[buf_length] name_buf = '\0';
190 		core.sys.windows.winnt.WCHAR[.OS_MAX_PATH] buf = '\0';
191 
192 		if (name.length > buf_length) {
193 			return null;
194 		}
195 
196 		npp_api.pluginfunc..string.copy_string(name_buf, name);
197 
198 		core.sys.windows.windef.DWORD Environment_length = core.sys.windows.winbase.GetEnvironmentVariableW(&(name_buf[0]), &(buf[0]), buf.length);
199 
200 		if (Environment_length == 0) {
201 			return null;
202 		}
203 
204 		return buf[0 .. Environment_length].idup;
205 	}
206 
207 nothrow
208 wstring repalce_variables(wstring path)
209 
210 	do
211 	{
212 		if (path == null) {
213 			return path;
214 		}
215 
216 		try {
217 			if (!std.algorithm.canFind(path, '%')) {
218 				return path;
219 			}
220 		} catch (Exception e) {
221 			//ToDo:
222 			return path;
223 		}
224 
225 		core.sys.windows.winnt.WCHAR[.OS_MAX_PATH] buf = '\0';
226 		core.sys.windows.winnt.WCHAR[.OS_MAX_PATH] output_buf = '\0';
227 
228 		for (size_t i = 0; i < windows_variable_wnames.length; i++) {
229 			try {
230 				if (!std.algorithm.canFind(path, windows_variables[i])) {
231 					continue;
232 				}
233 			} catch (Exception e) {
234 				//ToDo:
235 				continue;
236 			}
237 
238 			core.sys.windows.windef.DWORD Environment_length = core.sys.windows.winbase.GetEnvironmentVariableW(&(windows_variable_wnames[i][0]), &(buf[0]), buf.length);
239 
240 			if (Environment_length == 0) {
241 				continue;
242 			}
243 
244 			path = std.array.replace(path, windows_variables[i], buf[0 .. Environment_length]).idup;
245 		}
246 
247 		return path;
248 	}
249 
250 /**
251  * search exe file from "PATH"
252  */
253 nothrow
254 wstring search_exe(const wchar[] exe_name, wstring default_name = null)
255 
256 	in
257 	{
258 		assert(exe_name.length != 0);
259 
260 		for (size_t i = 0; i < exe_name.length; i++) {
261 			assert(exe_name[i] != '\\');
262 		}
263 	}
264 
265 	do
266 	{
267 		//dlang GC Bug?
268 		version (none) {
269 			//ToDo: インストールされたものの中から検索
270 			try {
271 				core.sys.windows.winnt.WCHAR[.OS_MAX_PATH] buf = '\0';
272 				core.sys.windows.windef.DWORD Environment_length = core.sys.windows.winbase.GetEnvironmentVariableW(&(npp_api.pluginfunc..string.c_wstring!(`PATH`w)[0]), &(buf[0]), buf.length);
273 
274 				if (Environment_length == 0) {
275 					return (default_name != null) ? (default_name) : (exe_name.idup);
276 				}
277 
278 				wstring[] PATH_directory = std.array.split(buf[0 .. Environment_length].idup, ';');
279 
280 				foreach (PATH; PATH_directory) {
281 					if ((!std.file.exists(PATH)) || (!std.file.isDir(PATH))) {
282 						continue;
283 					}
284 
285 					wstring file_exe = std.path.buildPath(PATH, exe_name);
286 
287 					if ((!std.file.exists(file_exe)) || (!std.file.isFile(file_exe))) {
288 						continue;
289 					}
290 
291 					return file_exe.idup;
292 				}
293 			} catch (Exception e) {
294 				//ToDo:
295 			}
296 
297 			return (default_name != null) ? (default_name) : (exe_name.idup);
298 		} else {
299 			return (default_name != null) ? (default_name) : (exe_name.idup);
300 		}
301 	}
302 
303 //ToDo: dlang GC bug?
304 @disable
305 nothrow
306 string search_exe(const char[] exe_name, string default_name = null)
307 
308 	in
309 	{
310 		assert(exe_name.length != 0);
311 
312 		for (size_t i = 0; i < exe_name.length; i++) {
313 			assert(exe_name[i] != '\\');
314 		}
315 	}
316 
317 	do
318 	{
319 		try {
320 			string[] PATH_directory = std.array.split(std.process.environment[`PATH`], ';');
321 
322 			foreach (PATH; PATH_directory) {
323 				if ((!std.file.exists(PATH)) || (!std.file.isDir(PATH))) {
324 					continue;
325 				}
326 
327 				string file_exe = std.path.buildPath(PATH, exe_name);
328 
329 				if ((!std.file.exists(file_exe)) || (!std.file.isFile(file_exe))) {
330 					continue;
331 				}
332 
333 				return file_exe.idup;
334 			}
335 		} catch (Exception e) {
336 		}
337 
338 		return (default_name != null) ? (default_name) : (exe_name.idup);
339 	}