1 /********************************************************************/
2 /* */
3 /* setwpath.c Set the search path (PATH variable) under Windows. */
4 /* Copyright (C) 2014, 2017 - 2019 Thomas Mertes */
5 /* */
6 /* This program is free software; you can redistribute it and/or */
7 /* modify it under the terms of the GNU General Public License as */
8 /* published by the Free Software Foundation; either version 2 of */
9 /* the License, or (at your option) any later version. */
10 /* */
11 /* This program is distributed in the hope that it will be useful, */
12 /* but WITHOUT ANY WARRANTY; without even the implied warranty of */
13 /* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */
14 /* GNU General Public License for more details. */
15 /* */
16 /* You should have received a copy of the GNU General Public */
17 /* License along with this program; if not, write to the */
18 /* Free Software Foundation, Inc., 51 Franklin Street, */
19 /* Fifth Floor, Boston, MA 02110-1301, USA. */
20 /* */
21 /* Module: Setwpath */
22 /* File: seed7/src/setwpath.c */
23 /* Changes: 2014, 2017 - 2019 Thomas Mertes */
24 /* Content: Set the search path (PATH variable) under Windows. */
25 /* */
26 /********************************************************************/
27
28 #include "version.h"
29
30 #include "stdio.h"
31 #include "stdlib.h"
32 #include "string.h"
33 #include "wchar.h"
34 #if DIR_LIB == DIRENT_DIRECTORY
35 #include "dirent.h"
36 #elif DIR_LIB == DIRECT_DIRECTORY || DIR_LIB == DIRDOS_DIRECTORY || DIR_LIB == DIRWIN_DIRECTORY
37 #include "direct.h"
38 #endif
39 #include "windows.h"
40
41 #include "os_decls.h"
42
43 #ifdef RENAMED_POSIX_FUNCTIONS
44 #define chdir _chdir
45 #endif
46
47 #define BUFFER_LEN 4096
48
49 #define ENVIRONMENT L"System\\CurrentControlSet\\Control\\Session Manager\\Environment"
50 #define DESTINATION L"Path"
51
52 #define SET_PATH_FAILED 0
53 #define ALREADY_OKAY 1
54 #define CHANGE_DONE 2
55
56 /* The include files of some C compilers do not define DWORD_PTR. */
57 /* Instead of checking, if DWORD_PTR has been defined, we used memSizeType instead. */
58 #if POINTER_SIZE == 32
59 typedef UINT32TYPE memSizeType;
60 #elif POINTER_SIZE == 64
61 typedef UINT64TYPE memSizeType;
62 #endif
63
64
notifySettingChange(void)65 static void notifySettingChange (void)
66
67 {
68 memSizeType /* DWORD_PTR */ result;
69
70 /* notifySettingChange */
71 SendMessageTimeoutW(HWND_BROADCAST, WM_SETTINGCHANGE, 0, (LPARAM) L"Environment",
72 SMTO_NORMAL, 10000, (void *) &result);
73 } /* notifySettingChange */
74
75
set_path(int add_to_path,wchar_t * directory,HKEY key,int read_only)76 static int set_path (int add_to_path, wchar_t *directory, HKEY key, int read_only)
77
78 {
79 size_t directory_len;
80 size_t value_len;
81 DWORD value_type;
82 DWORD size_of_value = 0;
83 wchar_t *value_data;
84 wchar_t *position;
85 int save_value = 0;
86 int success = SET_PATH_FAILED;
87
88 /* set_path */
89 directory_len = wcslen(directory);
90 /* printf("directory: %ls\n", directory);
91 printf("directory_len: %lu\n", directory_len); */
92 if (RegQueryValueExW(key, DESTINATION, NULL, NULL, NULL,
93 &size_of_value) != ERROR_SUCCESS) {
94 if (add_to_path) {
95 if (!read_only) {
96 size_of_value = (directory_len + 1) * sizeof(wchar_t);
97 if (RegSetValueExW(key, DESTINATION, 0, REG_SZ, (BYTE *) directory,
98 size_of_value) != ERROR_SUCCESS) {
99 printf(" *** Unable to set registry value.\n");
100 } else {
101 notifySettingChange();
102 success = CHANGE_DONE;
103 } /* if */
104 } /* if */
105 } /* if */
106 } else {
107 /* printf("size_of_value: %lu\n", size_of_value); */
108 if ((value_data = (wchar_t *)
109 malloc(size_of_value + (1 + directory_len) * sizeof(wchar_t))) == NULL) {
110 printf(" *** Unable to request memory for the registry value.\n");
111 } else {
112 if (RegQueryValueExW(key, DESTINATION, NULL, &value_type, (LPBYTE) value_data,
113 &size_of_value) != ERROR_SUCCESS) {
114 printf(" *** Unable to query the registry value.\n");
115 } else {
116 value_len = wcslen(value_data);
117 /* printf("value_type: %lu\n", value_type);
118 printf("size_of_value: %lu\n", size_of_value);
119 printf("strlen(value_data): %lu\n", value_len);
120 printf("value_data:\n%ls\n", value_data); */
121 position = wcsstr(value_data, directory);
122 while (position != NULL &&
123 ((position != value_data && position[-1] != ';') ||
124 (position[directory_len] != ';' && position[directory_len] != '\0'))) {
125 position = wcsstr(&position[1], directory);
126 } /* while */
127 if (position != NULL) {
128 if (add_to_path) {
129 success = ALREADY_OKAY;
130 } else {
131 if (position != value_data) {
132 if (position[-1] == ';' &&
133 (value_data[directory_len] == ';' || value_data[directory_len] == '\0')) {
134 memmove(&position[-1], &position[directory_len],
135 (&value_data[value_len + 1] - &position[directory_len]) *
136 sizeof(wchar_t));
137 size_of_value -= (1 + directory_len) * sizeof(wchar_t);
138 save_value = 1;
139 } /* if */
140 } else {
141 if (value_data[directory_len] == ';') {
142 memmove(value_data, &value_data[directory_len + 1],
143 (&value_data[value_len + 1] - &value_data[directory_len + 1]) *
144 sizeof(wchar_t));
145 size_of_value -= (directory_len + 1) * sizeof(wchar_t);
146 save_value = 1;
147 } else if (value_data[directory_len] == '\0') {
148 value_data[0] = '\0';
149 size_of_value -= (directory_len) * sizeof(wchar_t);
150 save_value = 1;
151 } /* if */
152 } /* if */
153 } /* if */
154 } else {
155 if (add_to_path) {
156 if (value_len == 0) {
157 memcpy(value_data, directory,
158 (directory_len + 1) * sizeof(wchar_t));
159 size_of_value += (directory_len) * sizeof(wchar_t);
160 } else {
161 value_data[value_len] = ';'; /* delimiter */
162 memcpy(&value_data[value_len + 1], directory,
163 (directory_len + 1) * sizeof(wchar_t));
164 size_of_value += (1 + directory_len) * sizeof(wchar_t);
165 } /* if */
166 save_value = 1;
167 } else {
168 success = ALREADY_OKAY;
169 } /* if */
170 } /* if */
171 if (save_value) {
172 /* printf("size_of_value: %lu\n", size_of_value);
173 printf("strlen(value_data): %lu\n", wcslen(value_data));
174 printf("value_data:\n%ls\n", value_data); */
175 if (!read_only) {
176 if (RegSetValueExW(key, DESTINATION, 0, value_type, (BYTE *) value_data,
177 size_of_value) != ERROR_SUCCESS) {
178 printf(" *** Unable to set registry value.\n");
179 } else {
180 notifySettingChange();
181 success = CHANGE_DONE;
182 } /* if */
183 } /* if */
184 } /* if */
185 } /* if */
186 free(value_data);
187 } /* if */
188 } /* if */
189 return success;
190 } /* set_path */
191
192
set_win_path(int add_to_path,wchar_t * directory)193 static int set_win_path (int add_to_path, wchar_t *directory)
194
195 {
196 HKEY key;
197 int key_open = 1;
198 int read_only = 0;
199 int success = SET_PATH_FAILED;
200
201 /* set_win_path */
202 if (RegOpenKeyExW(HKEY_LOCAL_MACHINE, ENVIRONMENT, 0,
203 KEY_QUERY_VALUE | KEY_SET_VALUE, &key) != ERROR_SUCCESS) {
204 if (RegOpenKeyExW(HKEY_LOCAL_MACHINE, ENVIRONMENT, 0,
205 KEY_QUERY_VALUE, &key) != ERROR_SUCCESS) {
206 key_open = 0;
207 } else {
208 read_only = 1;
209 } /* if */
210 } /* if */
211 if (key_open) {
212 success = set_path(add_to_path, directory, key, read_only);
213 RegCloseKey(key);
214 } /* if */
215 return success;
216 } /* set_win_path */
217
218
set_usr_path(int add_to_path,wchar_t * directory)219 static int set_usr_path (int add_to_path, wchar_t *directory)
220
221 {
222 HKEY key;
223 int key_open = 1;
224 int read_only = 0;
225 int success = SET_PATH_FAILED;
226
227 /* set_usr_path */
228 if (RegOpenKeyExW(HKEY_CURRENT_USER, L"Environment", 0,
229 KEY_QUERY_VALUE | KEY_SET_VALUE, &key) != ERROR_SUCCESS) {
230 if (RegOpenKeyExW(HKEY_CURRENT_USER, L"Environment", 0,
231 KEY_QUERY_VALUE, &key) != ERROR_SUCCESS) {
232 key_open = 0;
233 } else {
234 read_only = 1;
235 } /* if */
236 } /* if */
237 if (key_open) {
238 success = set_path(add_to_path, directory, key, read_only);
239 RegCloseKey(key);
240 } /* if */
241 return success;
242 } /* set_usr_path */
243
244
main(int argc,char * argv[])245 int main (int argc, char *argv[])
246
247 {
248 wchar_t directory[BUFFER_LEN];
249 int win_success;
250 int usr_success;
251
252 /* main */
253 if (argc != 3) {
254 printf(" *** Wrong number of parameters.\n");
255 printf("Usage: setwpath [add | remove] directory\n");
256 } else {
257 /* printf("dir: %s\n", argv[2]); */
258 chdir(argv[2]);
259 os_getcwd(directory, BUFFER_LEN);
260 if (strcmp(argv[1], "add") == 0) {
261 win_success = set_win_path(1, directory);
262 if (win_success == ALREADY_OKAY) {
263 printf("The directory %ls\n", directory);
264 printf("is already in the search path (PATH variable).\n");
265 } else if (win_success == CHANGE_DONE) {
266 printf("The directory %ls\n", directory);
267 printf("has been added to the search path (PATH variable).\n");
268 printf("You need to start a new console "
269 "to see the effect of this change.\n");
270 } else {
271 usr_success = set_usr_path(1, directory);
272 if (usr_success == ALREADY_OKAY) {
273 printf("The directory %ls\n", directory);
274 printf("is already in the search path (PATH variable).\n");
275 } else if (usr_success == CHANGE_DONE) {
276 printf("The directory %ls\n", directory);
277 printf("has been added to the search path (PATH variable).\n");
278 printf("You need to start a new console "
279 "to see the effect of this change.\n");
280 } else {
281 printf(" *** You need administrator rights to change the search path "
282 "(PATH variable).\n");
283 } /* if */
284 } /* if */
285 } else if (strcmp(argv[1], "remove") == 0) {
286 win_success = set_win_path(0, directory);
287 usr_success = set_usr_path(0, directory);
288 if (win_success == ALREADY_OKAY && usr_success == ALREADY_OKAY) {
289 printf("The directory %ls\n", directory);
290 printf("is not part of the search path (PATH variable).\n");
291 } else if (win_success == CHANGE_DONE || usr_success == CHANGE_DONE) {
292 printf("The directory %ls\n", directory);
293 printf("has been removed from the search path (PATH variable).\n");
294 printf("You need to start a new console "
295 "to see the effect of this change.\n");
296 } else {
297 printf(" *** You need administrator rights to change the search path "
298 "(PATH variable).\n");
299 } /* if */
300 } else {
301 printf(" *** Neither 'add' nor 'remove' was specified.\n");
302 } /* if */
303 } /* if */
304 return 0;
305 } /* main */
306