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