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 deprecated
117 alias create_variable_identifiers = .create_variable_ids;
118 
119 pure nothrow @safe
120 private immutable (C)[][] create_variable_ids(C)(const C[][] input)
121 
122 	do
123 	{
124 		immutable (C)[][] output = new immutable (C)[][input.length];
125 
126 		for (size_t i = 0; i < input.length; i++) {
127 			output[i] = ('%' ~ input[i] ~ '%').idup;
128 		}
129 
130 		return output;
131 	}
132 
133 enum wstring[] windows_variable_names =
134 [
135 	`ALLUSERSPROFILE`w,
136 	`APPDATA`w,
137 	`CommonProgramFiles`w,
138 	`CommonProgramFiles(x86)`w,
139 	`CommonProgramW6432`w,
140 	`COMPUTERNAME`w,
141 	`ComSpec`w,
142 	`DriverData`w,
143 	`HOMEDRIVE`w,
144 	`HOMEPATH`w,
145 	`LOCALAPPDATA`w,
146 	`LOGONSERVER`w,
147 	`NUMBER_OF_PROCESSORS`w,
148 	`OneDrive`w,
149 	`OS`w,
150 	`Path`w,
151 	`PATHEXT`w,
152 	`PROCESSOR_ARCHITECTURE`w,
153 	`PROCESSOR_ARCHITEW6432`w,
154 	`PROCESSOR_IDENTIFIER`w,
155 	`PROCESSOR_LEVEL`w,
156 	`PROCESSOR_REVISION`w,
157 	`ProgramData`w,
158 	`ProgramFiles`w,
159 	`ProgramFiles(x86)`w,
160 	`ProgramW6432`w,
161 	`PROMPT`w,
162 	`PSModulePath`w,
163 	`PUBLIC`w,
164 	`SESSIONNAME`w,
165 	`SystemDrive`w,
166 	`SystemRoot`w,
167 	`TEMP`w,
168 	`TMP`w,
169 	`USERDOMAIN`w,
170 	`USERDOMAIN_ROAMINGPROFILE`w,
171 	`USERNAME`w,
172 	`USERPROFILE`w,
173 	`windir`w,
174 ];
175 
176 enum wstring[] windows_variable_wnames = c_names!(wchar)(windows_variable_names);
177 enum wstring[] windows_variables = create_variable_ids!(wchar)(windows_variable_names);
178 
179 pure nothrow @safe @nogc
180 private size_t max_length(wstring[] list)
181 
182 	do
183 	{
184 		size_t max_length = 0;
185 
186 		for (size_t i = 0; i < list.length; i++) {
187 			if (list[i].length > max_length) {
188 				max_length = list[i].length;
189 			}
190 		}
191 
192 		return max_length;
193 	}
194 
195 nothrow
196 wstring echo_variables(wstring name)
197 
198 	do
199 	{
200 		static import core.sys.windows.winbase;
201 		static import std.algorithm;
202 		static import std.array;
203 		static import npp_api.pluginfunc.string;
204 
205 		enum buf_length = max_length(windows_variable_names) + 1;
206 
207 		core.sys.windows.winnt.WCHAR[buf_length] name_buf = '\0';
208 		core.sys.windows.winnt.WCHAR[.OS_MAX_PATH] buf = '\0';
209 
210 		if (name.length > buf_length) {
211 			return null;
212 		}
213 
214 		npp_api.pluginfunc..string.copy_string(name_buf, name);
215 
216 		core.sys.windows.windef.DWORD Environment_length = core.sys.windows.winbase.GetEnvironmentVariableW(&(name_buf[0]), &(buf[0]), buf.length);
217 
218 		if (Environment_length == 0) {
219 			return null;
220 		}
221 
222 		return buf[0 .. Environment_length].idup;
223 	}
224 
225 nothrow
226 wstring repalce_variables(wstring path)
227 
228 	do
229 	{
230 		static import core.sys.windows.winbase;
231 		static import std.algorithm;
232 		static import std.array;
233 		static import npp_api.pluginfunc.string;
234 
235 		if (path == null) {
236 			return path;
237 		}
238 
239 		try {
240 			if (!std.algorithm.canFind(path, '%')) {
241 				return path;
242 			}
243 		} catch (Exception e) {
244 			//ToDo:
245 			return path;
246 		}
247 
248 		core.sys.windows.winnt.WCHAR[.OS_MAX_PATH] buf = '\0';
249 		core.sys.windows.winnt.WCHAR[.OS_MAX_PATH] output_buf = '\0';
250 
251 		for (size_t i = 0; i < windows_variable_wnames.length; i++) {
252 			try {
253 				if (!std.algorithm.canFind(path, windows_variables[i])) {
254 					continue;
255 				}
256 			} catch (Exception e) {
257 				//ToDo:
258 				continue;
259 			}
260 
261 			core.sys.windows.windef.DWORD Environment_length = core.sys.windows.winbase.GetEnvironmentVariableW(&(windows_variable_wnames[i][0]), &(buf[0]), buf.length);
262 
263 			if (Environment_length == 0) {
264 				continue;
265 			}
266 
267 			path = std.array.replace(path, windows_variables[i], buf[0 .. Environment_length]).idup;
268 		}
269 
270 		return path;
271 	}
272 
273 /**
274  * search exe file from "PATH"
275  */
276 nothrow
277 wstring search_exe(const wchar[] exe_name, wstring default_name = null)
278 
279 	in
280 	{
281 		assert(exe_name.length != 0);
282 
283 		for (size_t i = 0; i < exe_name.length; i++) {
284 			assert(exe_name[i] != '\\');
285 		}
286 	}
287 
288 	do
289 	{
290 		static import core.sys.windows.winnt;
291 		static import core.sys.windows.winbase;
292 		static import std.array;
293 		static import std.file;
294 		static import std.string;
295 		static import std.path;
296 		static import npp_api.pluginfunc.string;
297 
298 		//dlang GC Bug?
299 		version (none) {
300 			//ToDo: インストールされたものの中から検索
301 			try {
302 				core.sys.windows.winnt.WCHAR[.OS_MAX_PATH] buf = '\0';
303 				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);
304 
305 				if (Environment_length == 0) {
306 					return (default_name != null) ? (default_name) : (exe_name.idup);
307 				}
308 
309 				wstring[] PATH_directory = std.array.split(buf[0 .. Environment_length].idup, ';');
310 
311 				foreach (PATH; PATH_directory) {
312 					if ((!std.file.exists(PATH)) || (!std.file.isDir(PATH))) {
313 						continue;
314 					}
315 
316 					wstring file_exe = std.path.buildPath(PATH, exe_name);
317 
318 					if ((!std.file.exists(file_exe)) || (!std.file.isFile(file_exe))) {
319 						continue;
320 					}
321 
322 					return file_exe.idup;
323 				}
324 			} catch (Exception e) {
325 				//ToDo:
326 			}
327 
328 			return (default_name != null) ? (default_name) : (exe_name.idup);
329 		} else {
330 			return (default_name != null) ? (default_name) : (exe_name.idup);
331 		}
332 	}
333 
334 //ToDo: dlang GC bug?
335 @disable
336 nothrow
337 string search_exe(const char[] exe_name, string default_name = null)
338 
339 	in
340 	{
341 		assert(exe_name.length != 0);
342 
343 		for (size_t i = 0; i < exe_name.length; i++) {
344 			assert(exe_name[i] != '\\');
345 		}
346 	}
347 
348 	do
349 	{
350 		static import std.array;
351 		static import std.file;
352 		static import std.string;
353 		static import std.path;
354 		static import std.process;
355 
356 		try {
357 			string[] PATH_directory = std.array.split(std.process.environment[`PATH`], ';');
358 
359 			foreach (PATH; PATH_directory) {
360 				if ((!std.file.exists(PATH)) || (!std.file.isDir(PATH))) {
361 					continue;
362 				}
363 
364 				string file_exe = std.path.buildPath(PATH, exe_name);
365 
366 				if ((!std.file.exists(file_exe)) || (!std.file.isFile(file_exe))) {
367 					continue;
368 				}
369 
370 				return file_exe.idup;
371 			}
372 		} catch (Exception e) {
373 		}
374 
375 		return (default_name != null) ? (default_name) : (exe_name.idup);
376 	}