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 std.algorithm;
33 private static import std.array;
34 private static import std.file;
35 private static import std.string;
36 private static import std.path;
37 private static import std.process;
38 private static import npp_api.powereditor.misc.pluginsmanager.plugininterface;
39 private static import npp_api.pluginfunc.npp_msgs;
40 private static import npp_api.pluginfunc.string;
41 private static import std.process;
42 
43 enum OS_MAX_PATH = 32768;
44 
45 /**
46  * get file path
47  */
48 nothrow @nogc
49 bool get_full_current_path(core.sys.windows.windef.HWND _nppHandle, ref core.sys.windows.winnt.WCHAR[.OS_MAX_PATH] path_temp)
50 
51 	do
52 	{
53 		static import core.sys.windows.windef;
54 		static import npp_api.powereditor.misc.pluginsmanager.plugininterface;
55 		static import npp_api.pluginfunc.npp_msgs;
56 
57 		path_temp[] = '\0';
58 
59 		if (npp_api.pluginfunc.npp_msgs.send_NPPM_GETFULLCURRENTPATH(_nppHandle, .OS_MAX_PATH, &(path_temp[0])) == core.sys.windows.windef.TRUE) {
60 			return true;
61 		} else {
62 			return false;
63 		}
64 	}
65 
66 nothrow
67 wstring get_file_path(core.sys.windows.windef.HWND _nppHandle)
68 
69 	do
70 	{
71 		static import core.sys.windows.winnt;
72 		static import npp_api.pluginfunc.string;
73 
74 		core.sys.windows.winnt.WCHAR[.OS_MAX_PATH] path_temp;
75 
76 		if (.get_full_current_path(_nppHandle, path_temp)) {
77 			return npp_api.pluginfunc..string.from_stringz(path_temp);
78 		} else {
79 			return null;
80 		}
81 	}
82 
83 nothrow
84 wstring get_directory_path(core.sys.windows.windef.HWND _nppHandle)
85 
86 	do
87 	{
88 		static import core.sys.windows.windef;
89 		static import core.sys.windows.winnt;
90 		static import npp_api.pluginfunc.string;
91 		static import npp_api.pluginfunc.npp_msgs;
92 
93 		core.sys.windows.winnt.WCHAR[.OS_MAX_PATH] path_temp;
94 
95 		if (npp_api.pluginfunc.npp_msgs.send_NPPM_GETCURRENTDIRECTORY(_nppHandle, .OS_MAX_PATH, &(path_temp[0])) == core.sys.windows.windef.TRUE) {
96 			return npp_api.pluginfunc..string.from_stringz(path_temp);
97 		} else {
98 			return null;
99 		}
100 	}
101 
102 pure nothrow @safe
103 private immutable (C)[][] c_names(C)(const C[][] input)
104 
105 	do
106 	{
107 		immutable (C)[][] output = new immutable (C)[][input.length];
108 
109 		for (size_t i = 0; i < input.length; i++) {
110 			output[i] = (input[i] ~ '\0').idup;
111 		}
112 
113 		return output;
114 	}
115 
116 pure nothrow @safe
117 private immutable (C)[][] create_variable_identifiers(C)(const C[][] input)
118 
119 	do
120 	{
121 		immutable (C)[][] output = new immutable (C)[][input.length];
122 
123 		for (size_t i = 0; i < input.length; i++) {
124 			output[i] = ('%' ~ input[i] ~ '%').idup;
125 		}
126 
127 		return output;
128 	}
129 
130 enum wstring[] windows_variable_names =
131 [
132 	`ALLUSERSPROFILE`w,
133 	`APPDATA`w,
134 	`CommonProgramFiles`w,
135 	`CommonProgramFiles(x86)`w,
136 	`CommonProgramW6432`w,
137 	`COMPUTERNAME`w,
138 	`ComSpec`w,
139 	`DriverData`w,
140 	`HOMEDRIVE`w,
141 	`HOMEPATH`w,
142 	`LOCALAPPDATA`w,
143 	`LOGONSERVER`w,
144 	`NUMBER_OF_PROCESSORS`w,
145 	`OneDrive`w,
146 	`OS`w,
147 	`Path`w,
148 	`PATHEXT`w,
149 	`PROCESSOR_ARCHITECTURE`w,
150 	`PROCESSOR_ARCHITEW6432`w,
151 	`PROCESSOR_IDENTIFIER`w,
152 	`PROCESSOR_LEVEL`w,
153 	`PROCESSOR_REVISION`w,
154 	`ProgramData`w,
155 	`ProgramFiles`w,
156 	`ProgramFiles(x86)`w,
157 	`ProgramW6432`w,
158 	`PROMPT`w,
159 	`PSModulePath`w,
160 	`PUBLIC`w,
161 	`SESSIONNAME`w,
162 	`SystemDrive`w,
163 	`SystemRoot`w,
164 	`TEMP`w,
165 	`TMP`w,
166 	`USERDOMAIN`w,
167 	`USERDOMAIN_ROAMINGPROFILE`w,
168 	`USERNAME`w,
169 	`USERPROFILE`w,
170 	`windir`w,
171 ];
172 
173 enum wstring[] windows_variable_wnames = c_names!(wchar)(windows_variable_names);
174 enum wstring[] windows_variables = create_variable_identifiers!(wchar)(windows_variable_names);
175 
176 pure nothrow @safe @nogc
177 private size_t max_length(wstring[] list)
178 
179 	do
180 	{
181 		size_t max_length = 0;
182 
183 		for (size_t i = 0; i < list.length; i++) {
184 			if (list[i].length > max_length) {
185 				max_length = list[i].length;
186 			}
187 		}
188 
189 		return max_length;
190 	}
191 
192 nothrow
193 wstring echo_variables(wstring name)
194 
195 	do
196 	{
197 		static import core.sys.windows.winbase;
198 		static import std.algorithm;
199 		static import std.array;
200 		static import npp_api.pluginfunc.string;
201 
202 		enum buf_length = max_length(windows_variable_names) + 1;
203 
204 		core.sys.windows.winnt.WCHAR[buf_length] name_buf = '\0';
205 		core.sys.windows.winnt.WCHAR[.OS_MAX_PATH] buf = '\0';
206 
207 		if (name.length > buf_length) {
208 			return null;
209 		}
210 
211 		npp_api.pluginfunc..string.copy_string(name_buf, name);
212 
213 		core.sys.windows.windef.DWORD Environment_length = core.sys.windows.winbase.GetEnvironmentVariableW(&(name_buf[0]), &(buf[0]), buf.length);
214 
215 		if (Environment_length == 0) {
216 			return null;
217 		}
218 
219 		return buf[0 .. Environment_length].idup;
220 	}
221 
222 nothrow
223 wstring repalce_variables(wstring path)
224 
225 	do
226 	{
227 		static import core.sys.windows.winbase;
228 		static import std.algorithm;
229 		static import std.array;
230 		static import npp_api.pluginfunc.string;
231 
232 		if (path == null) {
233 			return path;
234 		}
235 
236 		try {
237 			if (!std.algorithm.canFind(path, '%')) {
238 				return path;
239 			}
240 		} catch (Exception e) {
241 			//ToDo:
242 			return path;
243 		}
244 
245 		core.sys.windows.winnt.WCHAR[.OS_MAX_PATH] buf = '\0';
246 		core.sys.windows.winnt.WCHAR[.OS_MAX_PATH] output_buf = '\0';
247 
248 		for (size_t i = 0; i < windows_variable_wnames.length; i++) {
249 			try {
250 				if (!std.algorithm.canFind(path, windows_variables[i])) {
251 					continue;
252 				}
253 			} catch (Exception e) {
254 				//ToDo:
255 				continue;
256 			}
257 
258 			core.sys.windows.windef.DWORD Environment_length = core.sys.windows.winbase.GetEnvironmentVariableW(&(windows_variable_wnames[i][0]), &(buf[0]), buf.length);
259 
260 			if (Environment_length == 0) {
261 				continue;
262 			}
263 
264 			path = std.array.replace(path, windows_variables[i], buf[0 .. Environment_length]).idup;
265 		}
266 
267 		return path;
268 	}
269 
270 /**
271  * search exe file from "PATH"
272  */
273 nothrow
274 wstring search_exe(const wchar[] exe_name, wstring default_name = null)
275 
276 	in
277 	{
278 		assert(exe_name.length != 0);
279 
280 		for (size_t i = 0; i < exe_name.length; i++) {
281 			assert(exe_name[i] != '\\');
282 		}
283 	}
284 
285 	do
286 	{
287 		static import core.sys.windows.winnt;
288 		static import core.sys.windows.winbase;
289 		static import std.array;
290 		static import std.file;
291 		static import std.string;
292 		static import std.path;
293 		static import npp_api.pluginfunc.string;
294 
295 		//dlang GC Bug?
296 		version (none) {
297 			//ToDo: インストールされたものの中から検索
298 			try {
299 				core.sys.windows.winnt.WCHAR[.OS_MAX_PATH] buf = '\0';
300 				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);
301 
302 				if (Environment_length == 0) {
303 					return (default_name != null) ? (default_name) : (exe_name.idup);
304 				}
305 
306 				wstring[] PATH_directory = std.array.split(buf[0 .. Environment_length].idup, ';');
307 
308 				foreach (PATH; PATH_directory) {
309 					if ((!std.file.exists(PATH)) || (!std.file.isDir(PATH))) {
310 						continue;
311 					}
312 
313 					wstring file_exe = std.path.buildPath(PATH, exe_name);
314 
315 					if ((!std.file.exists(file_exe)) || (!std.file.isFile(file_exe))) {
316 						continue;
317 					}
318 
319 					return file_exe.idup;
320 				}
321 			} catch (Exception e) {
322 				//ToDo:
323 			}
324 
325 			return (default_name != null) ? (default_name) : (exe_name.idup);
326 		} else {
327 			return (default_name != null) ? (default_name) : (exe_name.idup);
328 		}
329 	}
330 
331 //ToDo: dlang GC bug?
332 @disable
333 nothrow
334 string search_exe(const char[] exe_name, string default_name = null)
335 
336 	in
337 	{
338 		assert(exe_name.length != 0);
339 
340 		for (size_t i = 0; i < exe_name.length; i++) {
341 			assert(exe_name[i] != '\\');
342 		}
343 	}
344 
345 	do
346 	{
347 		static import std.array;
348 		static import std.file;
349 		static import std.string;
350 		static import std.path;
351 		static import std.process;
352 
353 		try {
354 			string[] PATH_directory = std.array.split(std.process.environment[`PATH`], ';');
355 
356 			foreach (PATH; PATH_directory) {
357 				if ((!std.file.exists(PATH)) || (!std.file.isDir(PATH))) {
358 					continue;
359 				}
360 
361 				string file_exe = std.path.buildPath(PATH, exe_name);
362 
363 				if ((!std.file.exists(file_exe)) || (!std.file.isFile(file_exe))) {
364 					continue;
365 				}
366 
367 				return file_exe.idup;
368 			}
369 		} catch (Exception e) {
370 		}
371 
372 		return (default_name != null) ? (default_name) : (exe_name.idup);
373 	}