blob: 3c2dc157208b9f06cf57973a244dca169e53441d [file] [log] [blame]
Bram Moolenaaredf3f972016-08-29 22:49:24 +02001/* vi:set ts=8 sts=4 sw=4 noet:
Bram Moolenaar071d4272004-06-13 20:20:40 +00002 *
3 * VIM - Vi IMproved by Bram Moolenaar
4 *
5 * Do ":help uganda" in Vim to read copying and usage conditions.
6 * Do ":help credits" in Vim to see a list of people who contributed.
7 * See README.txt for an overview of the Vim source code.
8 */
9
10/*
11 * dosinst.c: Install program for Vim on MS-DOS and MS-Windows
12 *
Bram Moolenaareae1b912019-05-09 15:12:55 +020013 * Compile with Make_mvc.mak, Make_cyg.mak or Make_ming.mak.
Bram Moolenaar071d4272004-06-13 20:20:40 +000014 */
15
16/*
Bram Moolenaar30e8e732019-09-27 13:08:36 +020017 * Include common code for dosinst.c and uninstall.c.
Bram Moolenaar071d4272004-06-13 20:20:40 +000018 */
19#define DOSINST
20#include "dosinst.h"
Bram Moolenaar6cdb2c92018-10-13 17:25:27 +020021#include <io.h>
Bram Moolenaar071d4272004-06-13 20:20:40 +000022
Bram Moolenaar6199d432017-10-14 19:05:44 +020023#define GVIMEXT64_PATH "GvimExt64\\gvimext.dll"
24#define GVIMEXT32_PATH "GvimExt32\\gvimext.dll"
25
Bram Moolenaar5d18efe2019-12-01 21:11:22 +010026// Macro to do an error check I was typing over and over
Bram Moolenaar6f470022018-04-10 18:47:20 +020027#define CHECK_REG_ERROR(code) \
28 do { \
29 if (code != ERROR_SUCCESS) \
30 { \
31 printf("%ld error number: %ld\n", (long)__LINE__, (long)code); \
32 return 1; \
33 } \
34 } while (0)
Bram Moolenaar071d4272004-06-13 20:20:40 +000035
Bram Moolenaar5d18efe2019-12-01 21:11:22 +010036int has_vim = 0; // installable vim.exe exists
37int has_gvim = 0; // installable gvim.exe exists
Bram Moolenaar071d4272004-06-13 20:20:40 +000038
Bram Moolenaar5d18efe2019-12-01 21:11:22 +010039char oldvimrc[BUFSIZE]; // name of existing vimrc file
40char vimrc[BUFSIZE]; // name of vimrc file to create
Bram Moolenaar071d4272004-06-13 20:20:40 +000041
Bram Moolenaar5d18efe2019-12-01 21:11:22 +010042char *default_bat_dir = NULL; // when not NULL, use this as the default
43 // directory to write .bat files in
44char *default_vim_dir = NULL; // when not NULL, use this as the default
45 // install dir for NSIS
Bram Moolenaar071d4272004-06-13 20:20:40 +000046
47/*
48 * Structure used for each choice the user can make.
49 */
50struct choice
51{
Bram Moolenaar5d18efe2019-12-01 21:11:22 +010052 int active; // non-zero when choice is active
53 char *text; // text displayed for this choice
54 void (*changefunc)(int idx); // function to change this choice
55 int arg; // argument for function
56 void (*installfunc)(int idx); // function to install this choice
Bram Moolenaar071d4272004-06-13 20:20:40 +000057};
58
Bram Moolenaar5d18efe2019-12-01 21:11:22 +010059struct choice choices[30]; // choices the user can make
60int choice_count = 0; // number of choices available
Bram Moolenaar071d4272004-06-13 20:20:40 +000061
K.Takataeeec2542021-06-02 13:28:16 +020062#define TABLE_SIZE(s) (int)ARRAYSIZE(s)
Bram Moolenaar071d4272004-06-13 20:20:40 +000063
64enum
65{
66 compat_vi = 1,
Bram Moolenaar6cdb2c92018-10-13 17:25:27 +020067 compat_vim,
Bram Moolenaar071d4272004-06-13 20:20:40 +000068 compat_some_enhancements,
69 compat_all_enhancements
70};
71char *(compat_choices[]) =
72{
73 "\nChoose the default way to run Vim:",
74 "Vi compatible",
Bram Moolenaar6cdb2c92018-10-13 17:25:27 +020075 "Vim default",
Bram Moolenaarfff2bee2010-05-15 13:56:02 +020076 "with some Vim enhancements",
Bram Moolenaar071d4272004-06-13 20:20:40 +000077 "with syntax highlighting and other features switched on",
78};
79int compat_choice = (int)compat_all_enhancements;
80char *compat_text = "- run Vim %s";
81
82enum
83{
84 remap_no = 1,
85 remap_win
86};
87char *(remap_choices[]) =
88{
89 "\nChoose:",
90 "Do not remap keys for Windows behavior",
Bram Moolenaar6199d432017-10-14 19:05:44 +020091 "Remap a few keys for Windows behavior (CTRL-V, CTRL-C, CTRL-F, etc)",
Bram Moolenaar071d4272004-06-13 20:20:40 +000092};
Bram Moolenaarc3fdf7f2017-10-28 18:36:48 +020093int remap_choice = (int)remap_no;
Bram Moolenaar071d4272004-06-13 20:20:40 +000094char *remap_text = "- %s";
95
96enum
97{
98 mouse_xterm = 1,
Bram Moolenaarb9fce6c2017-10-28 18:50:01 +020099 mouse_mswin,
Bram Moolenaarc3fdf7f2017-10-28 18:36:48 +0200100 mouse_default
Bram Moolenaar071d4272004-06-13 20:20:40 +0000101};
102char *(mouse_choices[]) =
103{
104 "\nChoose the way how Vim uses the mouse:",
105 "right button extends selection (the Unix way)",
Bram Moolenaarc3fdf7f2017-10-28 18:36:48 +0200106 "right button has a popup menu, left button starts select mode (the Windows way)",
107 "right button has a popup menu, left button starts visual mode",
Bram Moolenaar071d4272004-06-13 20:20:40 +0000108};
Bram Moolenaarc3fdf7f2017-10-28 18:36:48 +0200109int mouse_choice = (int)mouse_default;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000110char *mouse_text = "- The mouse %s";
111
112enum
113{
114 vimfiles_dir_none = 1,
115 vimfiles_dir_vim,
116 vimfiles_dir_home
117};
Bram Moolenaar25a494c2018-11-16 19:39:50 +0100118static char *(vimfiles_dir_choices[]) =
Bram Moolenaar071d4272004-06-13 20:20:40 +0000119{
120 "\nCreate plugin directories:",
121 "No",
122 "In the VIM directory",
123 "In your HOME directory",
124};
Bram Moolenaar071d4272004-06-13 20:20:40 +0000125
Bram Moolenaar5d18efe2019-12-01 21:11:22 +0100126// non-zero when selected to install the popup menu entry.
Bram Moolenaar071d4272004-06-13 20:20:40 +0000127static int install_popup = 0;
128
Bram Moolenaar5d18efe2019-12-01 21:11:22 +0100129// non-zero when selected to install the "Open with" entry.
Bram Moolenaar071d4272004-06-13 20:20:40 +0000130static int install_openwith = 0;
131
Bram Moolenaar5d18efe2019-12-01 21:11:22 +0100132// non-zero when need to add an uninstall entry in the registry
Bram Moolenaar071d4272004-06-13 20:20:40 +0000133static int need_uninstall_entry = 0;
134
135/*
136 * Definitions of the directory name (under $VIM) of the vimfiles directory
137 * and its subdirectories:
138 */
139static char *(vimfiles_subdirs[]) =
140{
141 "colors",
142 "compiler",
143 "doc",
144 "ftdetect",
145 "ftplugin",
146 "indent",
147 "keymap",
148 "plugin",
149 "syntax",
150};
151
152/*
Bram Moolenaar071d4272004-06-13 20:20:40 +0000153 * Obtain a choice from a table.
154 * First entry is a question, others are choices.
155 */
156 static int
157get_choice(char **table, int entries)
158{
159 int answer;
160 int idx;
161 char dummy[100];
162
163 do
164 {
165 for (idx = 0; idx < entries; ++idx)
166 {
167 if (idx)
168 printf("%2d ", idx);
Bram Moolenaarc3fdf7f2017-10-28 18:36:48 +0200169 puts(table[idx]);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000170 }
171 printf("Choice: ");
172 if (scanf("%d", &answer) != 1)
173 {
174 scanf("%99s", dummy);
175 answer = 0;
176 }
177 }
178 while (answer < 1 || answer >= entries);
179
180 return answer;
181}
182
183/*
184 * Check if the user unpacked the archives properly.
185 * Sets "runtimeidx".
186 */
187 static void
188check_unpack(void)
189{
190 char buf[BUFSIZE];
191 FILE *fd;
192 struct stat st;
193
Bram Moolenaar5d18efe2019-12-01 21:11:22 +0100194 // check for presence of the correct version number in installdir[]
Bram Moolenaar071d4272004-06-13 20:20:40 +0000195 runtimeidx = strlen(installdir) - strlen(VIM_VERSION_NODOT);
196 if (runtimeidx <= 0
197 || stricmp(installdir + runtimeidx, VIM_VERSION_NODOT) != 0
198 || (installdir[runtimeidx - 1] != '/'
199 && installdir[runtimeidx - 1] != '\\'))
200 {
201 printf("ERROR: Install program not in directory \"%s\"\n",
202 VIM_VERSION_NODOT);
203 printf("This program can only work when it is located in its original directory\n");
204 myexit(1);
205 }
206
Bram Moolenaar5d18efe2019-12-01 21:11:22 +0100207 // check if filetype.vim is present, which means the runtime archive has
208 // been unpacked
Bram Moolenaar071d4272004-06-13 20:20:40 +0000209 sprintf(buf, "%s\\filetype.vim", installdir);
210 if (stat(buf, &st) < 0)
211 {
212 printf("ERROR: Cannot find filetype.vim in \"%s\"\n", installdir);
213 printf("It looks like you did not unpack the runtime archive.\n");
Yegappan Lakshmananebb01bd2022-06-08 15:14:09 +0100214 printf("You must unpack the runtime archive \"%srt.zip\" before installing.\n",
215 VIM_VERSION_NODOT);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000216 myexit(1);
217 }
218
Bram Moolenaar5d18efe2019-12-01 21:11:22 +0100219 // Check if vim.exe or gvim.exe is in the current directory.
Bram Moolenaar071d4272004-06-13 20:20:40 +0000220 if ((fd = fopen("gvim.exe", "r")) != NULL)
221 {
222 fclose(fd);
223 has_gvim = 1;
224 }
225 if ((fd = fopen("vim.exe", "r")) != NULL)
226 {
227 fclose(fd);
228 has_vim = 1;
229 }
230 if (!has_gvim && !has_vim)
231 {
232 printf("ERROR: Cannot find any Vim executables in \"%s\"\n\n",
233 installdir);
234 myexit(1);
235 }
236}
237
238/*
239 * Compare paths "p[plen]" to "q[qlen]". Return 0 if they match.
240 * Ignores case and differences between '/' and '\'.
241 * "plen" and "qlen" can be negative, strlen() is used then.
242 */
243 static int
244pathcmp(char *p, int plen, char *q, int qlen)
245{
246 int i;
247
248 if (plen < 0)
249 plen = strlen(p);
250 if (qlen < 0)
251 qlen = strlen(q);
252 for (i = 0; ; ++i)
253 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +0100254 // End of "p": check if "q" also ends or just has a slash.
Bram Moolenaar071d4272004-06-13 20:20:40 +0000255 if (i == plen)
256 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +0100257 if (i == qlen) // match
Bram Moolenaar071d4272004-06-13 20:20:40 +0000258 return 0;
259 if (i == qlen - 1 && (q[i] == '\\' || q[i] == '/'))
Bram Moolenaar5d18efe2019-12-01 21:11:22 +0100260 return 0; // match with trailing slash
261 return 1; // no match
Bram Moolenaar071d4272004-06-13 20:20:40 +0000262 }
263
Bram Moolenaar5d18efe2019-12-01 21:11:22 +0100264 // End of "q": check if "p" also ends or just has a slash.
Bram Moolenaar071d4272004-06-13 20:20:40 +0000265 if (i == qlen)
266 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +0100267 if (i == plen) // match
Bram Moolenaar071d4272004-06-13 20:20:40 +0000268 return 0;
269 if (i == plen - 1 && (p[i] == '\\' || p[i] == '/'))
Bram Moolenaar5d18efe2019-12-01 21:11:22 +0100270 return 0; // match with trailing slash
271 return 1; // no match
Bram Moolenaar071d4272004-06-13 20:20:40 +0000272 }
273
274 if (!(mytoupper(p[i]) == mytoupper(q[i])
275 || ((p[i] == '/' || p[i] == '\\')
276 && (q[i] == '/' || q[i] == '\\'))))
Bram Moolenaar5d18efe2019-12-01 21:11:22 +0100277 return 1; // no match
Bram Moolenaar071d4272004-06-13 20:20:40 +0000278 }
Bram Moolenaar5d18efe2019-12-01 21:11:22 +0100279 //NOTREACHED
Bram Moolenaar071d4272004-06-13 20:20:40 +0000280}
281
282/*
283 * If the executable "**destination" is in the install directory, find another
284 * one in $PATH.
285 * On input "**destination" is the path of an executable in allocated memory
286 * (or NULL).
287 * "*destination" is set to NULL or the location of the file.
288 */
289 static void
290findoldfile(char **destination)
291{
292 char *bp = *destination;
293 size_t indir_l = strlen(installdir);
Bram Moolenaarb7633612019-02-10 21:48:25 +0100294 char *cp;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000295 char *tmpname;
296 char *farname;
297
298 /*
299 * No action needed if exe not found or not in this directory.
300 */
Bram Moolenaarb7633612019-02-10 21:48:25 +0100301 if (bp == NULL || strnicmp(bp, installdir, indir_l) != 0)
302 return;
303 cp = bp + indir_l;
304 if (strchr("/\\", *cp++) == NULL
Bram Moolenaar071d4272004-06-13 20:20:40 +0000305 || strchr(cp, '\\') != NULL
306 || strchr(cp, '/') != NULL)
307 return;
308
Bram Moolenaar51e14382019-05-25 20:21:28 +0200309 tmpname = alloc(strlen(cp) + 1);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000310 strcpy(tmpname, cp);
Bram Moolenaar5d18efe2019-12-01 21:11:22 +0100311 tmpname[strlen(tmpname) - 1] = 'x'; // .exe -> .exx
Bram Moolenaar071d4272004-06-13 20:20:40 +0000312
313 if (access(tmpname, 0) == 0)
314 {
315 printf("\nERROR: %s and %s clash. Remove or rename %s.\n",
316 tmpname, cp, tmpname);
317 myexit(1);
318 }
319
320 if (rename(cp, tmpname) != 0)
321 {
322 printf("\nERROR: failed to rename %s to %s: %s\n",
323 cp, tmpname, strerror(0));
324 myexit(1);
325 }
326
327 farname = searchpath_save(cp);
328
329 if (rename(tmpname, cp) != 0)
330 {
331 printf("\nERROR: failed to rename %s back to %s: %s\n",
332 tmpname, cp, strerror(0));
333 myexit(1);
334 }
335
336 free(*destination);
337 free(tmpname);
338 *destination = farname;
339}
340
341/*
342 * Check if there is a vim.[exe|bat|, gvim.[exe|bat|, etc. in the path.
343 * When "check_bat_only" is TRUE, only find "default_bat_dir".
344 */
345 static void
346find_bat_exe(int check_bat_only)
347{
348 int i;
349
Bram Moolenaar5d18efe2019-12-01 21:11:22 +0100350 // avoid looking in the "installdir" by chdir to system root
Bram Moolenaar42bbef42006-03-25 22:02:07 +0000351 mch_chdir(sysdrive);
352 mch_chdir("\\");
Bram Moolenaar071d4272004-06-13 20:20:40 +0000353
354 for (i = 1; i < TARGET_COUNT; ++i)
355 {
356 targets[i].oldbat = searchpath_save(targets[i].batname);
357 if (!check_bat_only)
358 targets[i].oldexe = searchpath_save(targets[i].exename);
359
360 if (default_bat_dir == NULL && targets[i].oldbat != NULL)
361 {
362 default_bat_dir = alloc(strlen(targets[i].oldbat) + 1);
363 strcpy(default_bat_dir, targets[i].oldbat);
364 remove_tail(default_bat_dir);
365 }
366 if (check_bat_only && targets[i].oldbat != NULL)
Bram Moolenaar42bbef42006-03-25 22:02:07 +0000367 {
Bram Moolenaar071d4272004-06-13 20:20:40 +0000368 free(targets[i].oldbat);
Bram Moolenaar42bbef42006-03-25 22:02:07 +0000369 targets[i].oldbat = NULL;
370 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000371 }
372
373 mch_chdir(installdir);
374}
375
Bram Moolenaar071d4272004-06-13 20:20:40 +0000376/*
377 * Get the value of $VIMRUNTIME or $VIM and write it in $TEMP/vimini.ini, so
378 * that NSIS can read it.
379 * When not set, use the directory of a previously installed Vim.
380 */
381 static void
382get_vim_env(void)
383{
384 char *vim;
385 char buf[BUFSIZE];
386 FILE *fd;
387 char fname[BUFSIZE];
388
Bram Moolenaar5d18efe2019-12-01 21:11:22 +0100389 // First get $VIMRUNTIME. If it's set, remove the tail.
Bram Moolenaar071d4272004-06-13 20:20:40 +0000390 vim = getenv("VIMRUNTIME");
Bram Moolenaare4963c52019-02-22 19:41:08 +0100391 if (vim != NULL && *vim != 0 && strlen(vim) < sizeof(buf))
Bram Moolenaar071d4272004-06-13 20:20:40 +0000392 {
393 strcpy(buf, vim);
394 remove_tail(buf);
395 vim = buf;
396 }
397 else
398 {
399 vim = getenv("VIM");
400 if (vim == NULL || *vim == 0)
401 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +0100402 // Use the directory from an old uninstall entry.
Bram Moolenaar071d4272004-06-13 20:20:40 +0000403 if (default_vim_dir != NULL)
404 vim = default_vim_dir;
405 else
Bram Moolenaar5d18efe2019-12-01 21:11:22 +0100406 // Let NSIS know there is no default, it should use
407 // $PROGRAMFILES.
Bram Moolenaar071d4272004-06-13 20:20:40 +0000408 vim = "";
409 }
410 }
411
Bram Moolenaar5d18efe2019-12-01 21:11:22 +0100412 // NSIS also uses GetTempPath(), thus we should get the same directory
413 // name as where NSIS will look for vimini.ini.
Bram Moolenaare4963c52019-02-22 19:41:08 +0100414 GetTempPath(sizeof(fname) - 12, fname);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000415 add_pathsep(fname);
416 strcat(fname, "vimini.ini");
417
418 fd = fopen(fname, "w");
419 if (fd != NULL)
420 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +0100421 // Make it look like an .ini file, so that NSIS can read it with a
422 // ReadINIStr command.
Bram Moolenaar071d4272004-06-13 20:20:40 +0000423 fprintf(fd, "[vimini]\n");
424 fprintf(fd, "dir=\"%s\"\n", vim);
425 fclose(fd);
426 }
427 else
428 {
429 printf("Failed to open %s\n", fname);
Bram Moolenaarab8205e2010-07-07 15:14:03 +0200430 sleep(2);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000431 }
432}
433
Bram Moolenaarb230bd52010-05-25 21:02:00 +0200434static int num_windows;
435
436/*
437 * Callback used for EnumWindows():
438 * Count the window if the title looks like it is for the uninstaller.
439 */
Bram Moolenaar5d18efe2019-12-01 21:11:22 +0100440//ARGSUSED
Bram Moolenaarb230bd52010-05-25 21:02:00 +0200441 static BOOL CALLBACK
Bram Moolenaar35d7a2f2022-06-09 20:53:54 +0100442window_cb(HWND hwnd, LPARAM lparam UNUSED)
Bram Moolenaarb230bd52010-05-25 21:02:00 +0200443{
444 char title[256];
445
446 title[0] = 0;
447 GetWindowText(hwnd, title, 256);
Bram Moolenaaraf610b82018-12-21 16:22:50 +0100448 if (strstr(title, "Vim ") != NULL && strstr(title, " Uninstall") != NULL)
Bram Moolenaarb230bd52010-05-25 21:02:00 +0200449 ++num_windows;
450 return TRUE;
451}
452
Bram Moolenaar071d4272004-06-13 20:20:40 +0000453/*
Bram Moolenaaraf610b82018-12-21 16:22:50 +0100454 * Run the uninstaller silently.
455 */
456 static int
457run_silent_uninstall(char *uninst_exe)
458{
Bram Moolenaare4963c52019-02-22 19:41:08 +0100459 char vimrt_dir[BUFSIZE];
Bram Moolenaaraf610b82018-12-21 16:22:50 +0100460 char temp_uninst[BUFSIZE];
461 char temp_dir[MAX_PATH];
462 char buf[BUFSIZE * 2 + 10];
463 int i;
464 DWORD tick;
465
466 strcpy(vimrt_dir, uninst_exe);
467 remove_tail(vimrt_dir);
468
469 if (!GetTempPath(sizeof(temp_dir), temp_dir))
470 return FAIL;
471
Bram Moolenaar5d18efe2019-12-01 21:11:22 +0100472 // Copy the uninstaller to a temporary exe.
Bram Moolenaaraf610b82018-12-21 16:22:50 +0100473 tick = GetTickCount();
474 for (i = 0; ; i++)
475 {
476 sprintf(temp_uninst, "%s\\vimun%04X.exe", temp_dir,
Bram Moolenaar44a7db42019-01-11 20:47:31 +0100477 (unsigned int)((i + tick) & 0xFFFF));
Bram Moolenaaraf610b82018-12-21 16:22:50 +0100478 if (CopyFile(uninst_exe, temp_uninst, TRUE))
479 break;
480 if (GetLastError() != ERROR_FILE_EXISTS)
481 return FAIL;
482 if (i == 65535)
483 return FAIL;
484 }
485
Bram Moolenaar5d18efe2019-12-01 21:11:22 +0100486 // Run the copied uninstaller silently.
Bram Moolenaaraf610b82018-12-21 16:22:50 +0100487 if (strchr(temp_uninst, ' ') != NULL)
488 sprintf(buf, "\"%s\" /S _?=%s", temp_uninst, vimrt_dir);
489 else
490 sprintf(buf, "%s /S _?=%s", temp_uninst, vimrt_dir);
491 run_command(buf);
492
493 DeleteFile(temp_uninst);
494 return OK;
495}
496
497/*
Bram Moolenaar071d4272004-06-13 20:20:40 +0000498 * Check for already installed Vims.
499 * Return non-zero when found one.
500 */
501 static int
Bram Moolenaar442b4222010-05-24 21:34:22 +0200502uninstall_check(int skip_question)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000503{
504 HKEY key_handle;
505 HKEY uninstall_key_handle;
506 char *uninstall_key = "software\\Microsoft\\Windows\\CurrentVersion\\Uninstall";
507 char subkey_name_buff[BUFSIZE];
Bram Moolenaarbbd854d2019-02-18 22:19:33 +0100508 char temp_string_buffer[BUFSIZE-2];
Bram Moolenaare4963c52019-02-22 19:41:08 +0100509 DWORD local_bufsize;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000510 FILETIME temp_pfiletime;
511 DWORD key_index;
512 char input;
513 long code;
514 DWORD value_type;
515 DWORD orig_num_keys;
516 DWORD new_num_keys;
Bram Moolenaaraf610b82018-12-21 16:22:50 +0100517 DWORD allow_silent;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000518 int foundone = 0;
519
Bram Moolenaar760d14a2010-07-31 22:03:44 +0200520 code = RegOpenKeyEx(HKEY_LOCAL_MACHINE, uninstall_key, 0,
521 KEY_WOW64_64KEY | KEY_READ, &key_handle);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000522 CHECK_REG_ERROR(code);
523
Bram Moolenaare4963c52019-02-22 19:41:08 +0100524 key_index = 0;
525 while (TRUE)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000526 {
Bram Moolenaare4963c52019-02-22 19:41:08 +0100527 local_bufsize = sizeof(subkey_name_buff);
528 if (RegEnumKeyEx(key_handle, key_index, subkey_name_buff, &local_bufsize,
529 NULL, NULL, NULL, &temp_pfiletime) == ERROR_NO_MORE_ITEMS)
530 break;
531
Bram Moolenaar071d4272004-06-13 20:20:40 +0000532 if (strncmp("Vim", subkey_name_buff, 3) == 0)
533 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +0100534 // Open the key named Vim*
Bram Moolenaar760d14a2010-07-31 22:03:44 +0200535 code = RegOpenKeyEx(key_handle, subkey_name_buff, 0,
536 KEY_WOW64_64KEY | KEY_READ, &uninstall_key_handle);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000537 CHECK_REG_ERROR(code);
538
Bram Moolenaar5d18efe2019-12-01 21:11:22 +0100539 // get the DisplayName out of it to show the user
Bram Moolenaare4963c52019-02-22 19:41:08 +0100540 local_bufsize = sizeof(temp_string_buffer);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000541 code = RegQueryValueEx(uninstall_key_handle, "displayname", 0,
542 &value_type, (LPBYTE)temp_string_buffer,
543 &local_bufsize);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000544 CHECK_REG_ERROR(code);
545
Bram Moolenaaraf610b82018-12-21 16:22:50 +0100546 allow_silent = 0;
547 if (skip_question)
548 {
549 DWORD varsize = sizeof(DWORD);
550
551 RegQueryValueEx(uninstall_key_handle, "AllowSilent", 0,
552 &value_type, (LPBYTE)&allow_silent,
553 &varsize);
554 }
555
Bram Moolenaar071d4272004-06-13 20:20:40 +0000556 foundone = 1;
557 printf("\n*********************************************************\n");
558 printf("Vim Install found what looks like an existing Vim version.\n");
559 printf("The name of the entry is:\n");
560 printf("\n \"%s\"\n\n", temp_string_buffer);
561
562 printf("Installing the new version will disable part of the existing version.\n");
563 printf("(The batch files used in a console and the \"Edit with Vim\" entry in\n");
564 printf("the popup menu will use the new version)\n");
565
Bram Moolenaar442b4222010-05-24 21:34:22 +0200566 if (skip_question)
567 printf("\nRunning uninstall program for \"%s\"\n", temp_string_buffer);
568 else
569 printf("\nDo you want to uninstall \"%s\" now?\n(y)es/(n)o) ", temp_string_buffer);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000570 fflush(stdout);
571
Bram Moolenaar5d18efe2019-12-01 21:11:22 +0100572 // get the UninstallString
Bram Moolenaare4963c52019-02-22 19:41:08 +0100573 local_bufsize = sizeof(temp_string_buffer);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000574 code = RegQueryValueEx(uninstall_key_handle, "uninstallstring", 0,
575 &value_type, (LPBYTE)temp_string_buffer, &local_bufsize);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000576 CHECK_REG_ERROR(code);
577
Bram Moolenaar5d18efe2019-12-01 21:11:22 +0100578 // Remember the directory, it is used as the default for NSIS.
Bram Moolenaar071d4272004-06-13 20:20:40 +0000579 default_vim_dir = alloc(strlen(temp_string_buffer) + 1);
580 strcpy(default_vim_dir, temp_string_buffer);
581 remove_tail(default_vim_dir);
582 remove_tail(default_vim_dir);
583
584 input = 'n';
585 do
586 {
587 if (input != 'n')
588 printf("%c is an invalid reply. Please enter either 'y' or 'n'\n", input);
589
Bram Moolenaar442b4222010-05-24 21:34:22 +0200590 if (skip_question)
591 input = 'y';
592 else
593 {
594 rewind(stdin);
595 scanf("%c", &input);
596 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000597 switch (input)
598 {
599 case 'y':
600 case 'Y':
Bram Moolenaar5d18efe2019-12-01 21:11:22 +0100601 // save the number of uninstall keys so we can know if
602 // it changed
Bram Moolenaar071d4272004-06-13 20:20:40 +0000603 RegQueryInfoKey(key_handle, NULL, NULL, NULL,
604 &orig_num_keys, NULL, NULL, NULL,
605 NULL, NULL, NULL, NULL);
606
Bram Moolenaar5d18efe2019-12-01 21:11:22 +0100607 // Find existing .bat files before deleting them.
Bram Moolenaar071d4272004-06-13 20:20:40 +0000608 find_bat_exe(TRUE);
609
Bram Moolenaaraf610b82018-12-21 16:22:50 +0100610 if (allow_silent)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000611 {
Bram Moolenaaraf610b82018-12-21 16:22:50 +0100612 if (run_silent_uninstall(temp_string_buffer)
613 == FAIL)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +0100614 allow_silent = 0; // Retry with non silent.
Bram Moolenaar071d4272004-06-13 20:20:40 +0000615 }
Bram Moolenaaraf610b82018-12-21 16:22:50 +0100616 if (!allow_silent)
Bram Moolenaarb230bd52010-05-25 21:02:00 +0200617 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +0100618 // Execute the uninstall program. Put it in double
619 // quotes if there is an embedded space.
Bram Moolenaarb230bd52010-05-25 21:02:00 +0200620 {
Bram Moolenaaraf610b82018-12-21 16:22:50 +0100621 char buf[BUFSIZE];
622
623 if (strchr(temp_string_buffer, ' ') != NULL)
624 sprintf(buf, "\"%s\"", temp_string_buffer);
625 else
626 strcpy(buf, temp_string_buffer);
627 run_command(buf);
628 }
629
Bram Moolenaar5d18efe2019-12-01 21:11:22 +0100630 // Count the number of windows with a title that
631 // match the installer, so that we can check when
632 // it's done. The uninstaller copies itself,
633 // executes the copy and exits, thus we can't wait
634 // for the process to finish.
635 sleep(1); // wait for uninstaller to start up
Bram Moolenaaraf610b82018-12-21 16:22:50 +0100636 num_windows = 0;
637 EnumWindows(window_cb, 0);
638 if (num_windows == 0)
639 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +0100640 // Did not find the uninstaller, ask user to
641 // press Enter when done. Just in case.
Bram Moolenaaraf610b82018-12-21 16:22:50 +0100642 printf("Press Enter when the uninstaller is finished\n");
643 rewind(stdin);
644 (void)getchar();
645 }
646 else
647 {
648 printf("Waiting for the uninstaller to finish (press CTRL-C to abort).");
649 do
650 {
651 printf(".");
652 fflush(stdout);
Bram Moolenaar5d18efe2019-12-01 21:11:22 +0100653 sleep(1); // wait for the uninstaller to
654 // finish
Bram Moolenaaraf610b82018-12-21 16:22:50 +0100655 num_windows = 0;
656 EnumWindows(window_cb, 0);
657 } while (num_windows > 0);
658 }
Bram Moolenaarb230bd52010-05-25 21:02:00 +0200659 }
660 printf("\nDone!\n");
Bram Moolenaar071d4272004-06-13 20:20:40 +0000661
Bram Moolenaar5d18efe2019-12-01 21:11:22 +0100662 // Check if an uninstall reg key was deleted.
663 // if it was, we want to decrement key_index.
664 // if we don't do this, we will skip the key
665 // immediately after any key that we delete.
Bram Moolenaar071d4272004-06-13 20:20:40 +0000666 RegQueryInfoKey(key_handle, NULL, NULL, NULL,
667 &new_num_keys, NULL, NULL, NULL,
668 NULL, NULL, NULL, NULL);
669 if (new_num_keys < orig_num_keys)
670 key_index--;
671
672 input = 'y';
673 break;
674
675 case 'n':
676 case 'N':
Bram Moolenaar5d18efe2019-12-01 21:11:22 +0100677 // Do not uninstall
Bram Moolenaar071d4272004-06-13 20:20:40 +0000678 input = 'n';
679 break;
680
Bram Moolenaar5d18efe2019-12-01 21:11:22 +0100681 default: // just drop through and redo the loop
Bram Moolenaar071d4272004-06-13 20:20:40 +0000682 break;
683 }
684
685 } while (input != 'n' && input != 'y');
686
687 RegCloseKey(uninstall_key_handle);
688 }
Bram Moolenaare4963c52019-02-22 19:41:08 +0100689
690 key_index++;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000691 }
692 RegCloseKey(key_handle);
693
694 return foundone;
695}
Bram Moolenaar071d4272004-06-13 20:20:40 +0000696
697/*
698 * Find out information about the system.
699 */
700 static void
701inspect_system(void)
702{
703 char *p;
704 char buf[BUFSIZE];
705 FILE *fd;
706 int i;
707 int foundone;
708
Bram Moolenaar5d18efe2019-12-01 21:11:22 +0100709 // This may take a little while, let the user know what we're doing.
Bram Moolenaar071d4272004-06-13 20:20:40 +0000710 printf("Inspecting system...\n");
711
712 /*
713 * If $VIM is set, check that it's pointing to our directory.
714 */
715 p = getenv("VIM");
716 if (p != NULL && pathcmp(p, -1, installdir, runtimeidx - 1) != 0)
717 {
718 printf("------------------------------------------------------\n");
719 printf("$VIM is set to \"%s\".\n", p);
720 printf("This is different from where this version of Vim is:\n");
721 strcpy(buf, installdir);
722 *(buf + runtimeidx - 1) = NUL;
723 printf("\"%s\"\n", buf);
724 printf("You must adjust or remove the setting of $VIM,\n");
725 if (interactive)
726 {
727 printf("to be able to use this install program.\n");
728 myexit(1);
729 }
730 printf("otherwise Vim WILL NOT WORK properly!\n");
731 printf("------------------------------------------------------\n");
732 }
733
734 /*
735 * If $VIMRUNTIME is set, check that it's pointing to our runtime directory.
736 */
737 p = getenv("VIMRUNTIME");
738 if (p != NULL && pathcmp(p, -1, installdir, -1) != 0)
739 {
740 printf("------------------------------------------------------\n");
741 printf("$VIMRUNTIME is set to \"%s\".\n", p);
742 printf("This is different from where this version of Vim is:\n");
743 printf("\"%s\"\n", installdir);
744 printf("You must adjust or remove the setting of $VIMRUNTIME,\n");
745 if (interactive)
746 {
747 printf("to be able to use this install program.\n");
748 myexit(1);
749 }
750 printf("otherwise Vim WILL NOT WORK properly!\n");
751 printf("------------------------------------------------------\n");
752 }
753
754 /*
755 * Check if there is a vim.[exe|bat|, gvim.[exe|bat|, etc. in the path.
756 */
757 find_bat_exe(FALSE);
758
759 /*
760 * A .exe in the install directory may be found anyway on Windows 2000.
761 * Check for this situation and find another executable if necessary.
762 * w.briscoe@ponl.com 2001-01-20
763 */
764 foundone = 0;
765 for (i = 1; i < TARGET_COUNT; ++i)
766 {
767 findoldfile(&(targets[i].oldexe));
768 if (targets[i].oldexe != NULL)
769 foundone = 1;
770 }
771
772 if (foundone)
773 {
774 printf("Warning: Found Vim executable(s) in your $PATH:\n");
775 for (i = 1; i < TARGET_COUNT; ++i)
776 if (targets[i].oldexe != NULL)
777 printf("%s\n", targets[i].oldexe);
778 printf("It will be used instead of the version you are installing.\n");
779 printf("Please delete or rename it, or adjust your $PATH setting.\n");
780 }
781
782 /*
783 * Check if there is an existing ../_vimrc or ../.vimrc file.
784 */
785 strcpy(oldvimrc, installdir);
786 strcpy(oldvimrc + runtimeidx, "_vimrc");
787 if ((fd = fopen(oldvimrc, "r")) == NULL)
788 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +0100789 strcpy(oldvimrc + runtimeidx, "vimrc~1"); // short version of .vimrc
Bram Moolenaar071d4272004-06-13 20:20:40 +0000790 if ((fd = fopen(oldvimrc, "r")) == NULL)
791 {
792 strcpy(oldvimrc + runtimeidx, ".vimrc");
793 fd = fopen(oldvimrc, "r");
794 }
795 }
796 if (fd != NULL)
797 fclose(fd);
798 else
799 *oldvimrc = NUL;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000800}
801
802/*
803 * Add a dummy choice to avoid that the numbering changes depending on items
804 * in the environment. The user may type a number he remembered without
805 * looking.
806 */
807 static void
808add_dummy_choice(void)
809{
810 choices[choice_count].installfunc = NULL;
811 choices[choice_count].active = 0;
812 choices[choice_count].changefunc = NULL;
Bram Moolenaar25a494c2018-11-16 19:39:50 +0100813 choices[choice_count].text = NULL;
814 choices[choice_count].arg = 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000815 ++choice_count;
816}
817
Bram Moolenaar5d18efe2019-12-01 21:11:22 +0100818////////////////////////////////////////////////
819// stuff for creating the batch files.
Bram Moolenaar071d4272004-06-13 20:20:40 +0000820
821/*
822 * Install the vim.bat, gvim.bat, etc. files.
823 */
824 static void
825install_bat_choice(int idx)
826{
827 char *batpath = targets[choices[idx].arg].batpath;
828 char *oldname = targets[choices[idx].arg].oldbat;
829 char *exename = targets[choices[idx].arg].exenamearg;
830 char *vimarg = targets[choices[idx].arg].exearg;
831 FILE *fd;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000832
Yegappan Lakshmanandc4daa32023-01-02 16:54:53 +0000833 if (*batpath == NUL)
834 return;
835
836 fd = fopen(batpath, "w");
837 if (fd == NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000838 {
Yegappan Lakshmanandc4daa32023-01-02 16:54:53 +0000839 printf("\nERROR: Cannot open \"%s\" for writing.\n", batpath);
840 return;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000841 }
Yegappan Lakshmanandc4daa32023-01-02 16:54:53 +0000842
843 need_uninstall_entry = 1;
844
845 fprintf(fd, "@echo off\n");
846 fprintf(fd, "rem -- Run Vim --\n");
847 fprintf(fd, VIMBAT_UNINSTKEY "\n");
848 fprintf(fd, "\n");
849 fprintf(fd, "setlocal\n");
850
851 /*
852 * Don't use double quotes for the "set" argument, also when it
853 * contains a space. The quotes would be included in the value.
854 * The order of preference is:
855 * 1. $VIMRUNTIME/vim.exe (user preference)
856 * 2. $VIM/vim81/vim.exe (hard coded version)
857 * 3. installdir/vim.exe (hard coded install directory)
858 */
859 fprintf(fd, "set VIM_EXE_DIR=%s\n", installdir);
860 fprintf(fd, "if exist \"%%VIM%%\\%s\\%s\" set VIM_EXE_DIR=%%VIM%%\\%s\n",
861 VIM_VERSION_NODOT, exename, VIM_VERSION_NODOT);
862 fprintf(fd, "if exist \"%%VIMRUNTIME%%\\%s\" set VIM_EXE_DIR=%%VIMRUNTIME%%\n", exename);
863 fprintf(fd, "\n");
864
865 // Give an error message when the executable could not be found.
866 fprintf(fd, "if not exist \"%%VIM_EXE_DIR%%\\%s\" (\n", exename);
867 fprintf(fd, " echo \"%%VIM_EXE_DIR%%\\%s\" not found\n", exename);
868 fprintf(fd, " goto :eof\n");
869 fprintf(fd, ")\n");
870 fprintf(fd, "\n");
871
872 if (*exename == 'g')
873 {
874 fprintf(fd, "rem check --nofork argument\n");
875 fprintf(fd, "set VIMNOFORK=\n");
876 fprintf(fd, ":loopstart\n");
877 fprintf(fd, "if .%%1==. goto loopend\n");
878 fprintf(fd, "if .%%1==.--nofork (\n");
879 fprintf(fd, " set VIMNOFORK=1\n");
880 fprintf(fd, ") else if .%%1==.-f (\n");
881 fprintf(fd, " set VIMNOFORK=1\n");
882 fprintf(fd, ")\n");
883 fprintf(fd, "shift\n");
884 fprintf(fd, "goto loopstart\n");
885 fprintf(fd, ":loopend\n");
886 fprintf(fd, "\n");
887 }
888
889 if (*exename == 'g')
890 {
891 // For gvim.exe use "start /b" to avoid that the console window
892 // stays open.
893 fprintf(fd, "if .%%VIMNOFORK%%==.1 (\n");
894 fprintf(fd, " start \"dummy\" /b /wait ");
895 // Always use quotes, $VIM or $VIMRUNTIME might have a space.
896 fprintf(fd, "\"%%VIM_EXE_DIR%%\\%s\" %s %%*\n",
897 exename, vimarg);
898 fprintf(fd, ") else (\n");
899 fprintf(fd, " start \"dummy\" /b ");
900 // Always use quotes, $VIM or $VIMRUNTIME might have a space.
901 fprintf(fd, "\"%%VIM_EXE_DIR%%\\%s\" %s %%*\n",
902 exename, vimarg);
903 fprintf(fd, ")\n");
904 }
905 else
906 {
907 // Always use quotes, $VIM or $VIMRUNTIME might have a space.
908 fprintf(fd, "\"%%VIM_EXE_DIR%%\\%s\" %s %%*\n",
909 exename, vimarg);
910 }
911
912 fclose(fd);
913 printf("%s has been %s\n", batpath,
914 oldname == NULL ? "created" : "overwritten");
Bram Moolenaar071d4272004-06-13 20:20:40 +0000915}
916
917/*
918 * Make the text string for choice "idx".
919 * The format "fmt" is must have one %s item, which "arg" is used for.
920 */
921 static void
922alloc_text(int idx, char *fmt, char *arg)
923{
924 if (choices[idx].text != NULL)
925 free(choices[idx].text);
926
Bram Moolenaar51e14382019-05-25 20:21:28 +0200927 choices[idx].text = alloc(strlen(fmt) + strlen(arg) - 1);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000928 sprintf(choices[idx].text, fmt, arg);
929}
930
931/*
932 * Toggle the "Overwrite .../vim.bat" to "Don't overwrite".
933 */
934 static void
935toggle_bat_choice(int idx)
936{
937 char *batname = targets[choices[idx].arg].batpath;
938 char *oldname = targets[choices[idx].arg].oldbat;
939
940 if (*batname == NUL)
941 {
942 alloc_text(idx, " Overwrite %s", oldname);
943 strcpy(batname, oldname);
944 }
945 else
946 {
947 alloc_text(idx, " Do NOT overwrite %s", oldname);
948 *batname = NUL;
949 }
950}
951
952/*
953 * Do some work for a batch file entry: Append the batch file name to the path
954 * and set the text for the choice.
955 */
956 static void
957set_bat_text(int idx, char *batpath, char *name)
958{
959 strcat(batpath, name);
960
961 alloc_text(idx, " Create %s", batpath);
962}
963
964/*
965 * Select a directory to write the batch file line.
966 */
967 static void
968change_bat_choice(int idx)
969{
970 char *path;
971 char *batpath;
972 char *name;
973 int n;
974 char *s;
975 char *p;
976 int count;
977 char **names = NULL;
978 int i;
979 int target = choices[idx].arg;
980
981 name = targets[target].batname;
982 batpath = targets[target].batpath;
983
984 path = getenv("PATH");
985 if (path == NULL)
986 {
987 printf("\nERROR: The variable $PATH is not set\n");
988 return;
989 }
990
991 /*
992 * first round: count number of names in path;
993 * second round: save names to names[].
994 */
995 for (;;)
996 {
997 count = 1;
998 for (p = path; *p; )
999 {
1000 s = strchr(p, ';');
1001 if (s == NULL)
1002 s = p + strlen(p);
1003 if (names != NULL)
1004 {
Bram Moolenaar51e14382019-05-25 20:21:28 +02001005 names[count] = alloc(s - p + 1);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001006 strncpy(names[count], p, s - p);
1007 names[count][s - p] = NUL;
1008 }
1009 ++count;
1010 p = s;
1011 if (*p != NUL)
1012 ++p;
1013 }
1014 if (names != NULL)
1015 break;
Bram Moolenaar51e14382019-05-25 20:21:28 +02001016 names = alloc((count + 1) * sizeof(char *));
Bram Moolenaar071d4272004-06-13 20:20:40 +00001017 }
1018 names[0] = alloc(50);
1019 sprintf(names[0], "Select directory to create %s in:", name);
1020 names[count] = alloc(50);
1021 if (choices[idx].arg == 0)
1022 sprintf(names[count], "Do not create any .bat file.");
1023 else
1024 sprintf(names[count], "Do not create a %s file.", name);
1025 n = get_choice(names, count + 1);
1026
1027 if (n == count)
1028 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01001029 // Selected last item, don't create bat file.
Bram Moolenaar071d4272004-06-13 20:20:40 +00001030 *batpath = NUL;
1031 if (choices[idx].arg != 0)
1032 alloc_text(idx, " Do NOT create %s", name);
1033 }
1034 else
1035 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01001036 // Selected one of the paths. For the first item only keep the path,
1037 // for the others append the batch file name.
Bram Moolenaar071d4272004-06-13 20:20:40 +00001038 strcpy(batpath, names[n]);
1039 add_pathsep(batpath);
1040 if (choices[idx].arg != 0)
1041 set_bat_text(idx, batpath, name);
1042 }
1043
1044 for (i = 0; i <= count; ++i)
1045 free(names[i]);
1046 free(names);
1047}
1048
1049char *bat_text_yes = "Install .bat files to use Vim at the command line:";
1050char *bat_text_no = "do NOT install .bat files to use Vim at the command line";
1051
1052 static void
1053change_main_bat_choice(int idx)
1054{
1055 int i;
1056
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01001057 // let the user select a default directory or NONE
Bram Moolenaar071d4272004-06-13 20:20:40 +00001058 change_bat_choice(idx);
1059
1060 if (targets[0].batpath[0] != NUL)
1061 choices[idx].text = bat_text_yes;
1062 else
1063 choices[idx].text = bat_text_no;
1064
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01001065 // update the individual batch file selections
Bram Moolenaar071d4272004-06-13 20:20:40 +00001066 for (i = 1; i < TARGET_COUNT; ++i)
1067 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01001068 // Only make it active when the first item has a path and the vim.exe
1069 // or gvim.exe exists (there is a changefunc then).
Bram Moolenaar071d4272004-06-13 20:20:40 +00001070 if (targets[0].batpath[0] != NUL
1071 && choices[idx + i].changefunc != NULL)
1072 {
1073 choices[idx + i].active = 1;
1074 if (choices[idx + i].changefunc == change_bat_choice
1075 && targets[i].batpath[0] != NUL)
1076 {
1077 strcpy(targets[i].batpath, targets[0].batpath);
1078 set_bat_text(idx + i, targets[i].batpath, targets[i].batname);
1079 }
1080 }
1081 else
1082 choices[idx + i].active = 0;
1083 }
1084}
1085
1086/*
1087 * Initialize a choice for creating a batch file.
1088 */
1089 static void
1090init_bat_choice(int target)
1091{
1092 char *batpath = targets[target].batpath;
1093 char *oldbat = targets[target].oldbat;
1094 char *p;
1095 int i;
1096
1097 choices[choice_count].arg = target;
1098 choices[choice_count].installfunc = install_bat_choice;
1099 choices[choice_count].active = 1;
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01001100 choices[choice_count].text = NULL; // will be set below
Bram Moolenaar071d4272004-06-13 20:20:40 +00001101 if (oldbat != NULL)
1102 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01001103 // A [g]vim.bat exists: Only choice is to overwrite it or not.
Bram Moolenaar071d4272004-06-13 20:20:40 +00001104 choices[choice_count].changefunc = toggle_bat_choice;
1105 *batpath = NUL;
1106 toggle_bat_choice(choice_count);
1107 }
1108 else
1109 {
1110 if (default_bat_dir != NULL)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01001111 // Prefer using the same path as an existing .bat file.
Bram Moolenaar071d4272004-06-13 20:20:40 +00001112 strcpy(batpath, default_bat_dir);
1113 else
1114 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01001115 // No [g]vim.bat exists: Write it to a directory in $PATH. Use
1116 // $WINDIR by default, if it's empty the first item in $PATH.
Bram Moolenaar071d4272004-06-13 20:20:40 +00001117 p = getenv("WINDIR");
1118 if (p != NULL && *p != NUL)
1119 strcpy(batpath, p);
1120 else
1121 {
1122 p = getenv("PATH");
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01001123 if (p == NULL || *p == NUL) // "cannot happen"
Bram Moolenaar071d4272004-06-13 20:20:40 +00001124 strcpy(batpath, "C:/Windows");
1125 else
1126 {
1127 i = 0;
1128 while (*p != NUL && *p != ';')
1129 batpath[i++] = *p++;
1130 batpath[i] = NUL;
1131 }
1132 }
1133 }
1134 add_pathsep(batpath);
1135 set_bat_text(choice_count, batpath, targets[target].batname);
1136
1137 choices[choice_count].changefunc = change_bat_choice;
1138 }
1139 ++choice_count;
1140}
1141
1142/*
1143 * Set up the choices for installing .bat files.
1144 * For these items "arg" is the index in targets[].
1145 */
1146 static void
1147init_bat_choices(void)
1148{
1149 int i;
1150
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01001151 // The first item is used to switch installing batch files on/off and
1152 // setting the default path.
Bram Moolenaar071d4272004-06-13 20:20:40 +00001153 choices[choice_count].text = bat_text_yes;
1154 choices[choice_count].changefunc = change_main_bat_choice;
1155 choices[choice_count].installfunc = NULL;
1156 choices[choice_count].active = 1;
1157 choices[choice_count].arg = 0;
1158 ++choice_count;
1159
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01001160 // Add items for each batch file target. Only used when not disabled by
1161 // the first item. When a .exe exists, don't offer to create a .bat.
Bram Moolenaar071d4272004-06-13 20:20:40 +00001162 for (i = 1; i < TARGET_COUNT; ++i)
1163 if (targets[i].oldexe == NULL
1164 && (targets[i].exenamearg[0] == 'g' ? has_gvim : has_vim))
1165 init_bat_choice(i);
1166 else
1167 add_dummy_choice();
1168}
1169
1170/*
1171 * Install the vimrc file.
1172 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001173 static void
Bram Moolenaar35d7a2f2022-06-09 20:53:54 +01001174install_vimrc(int idx UNUSED)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001175{
1176 FILE *fd, *tfd;
1177 char *fname;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001178
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01001179 // If an old vimrc file exists, overwrite it.
1180 // Otherwise create a new one.
Bram Moolenaar071d4272004-06-13 20:20:40 +00001181 if (*oldvimrc != NUL)
1182 fname = oldvimrc;
1183 else
1184 fname = vimrc;
1185
1186 fd = fopen(fname, "w");
1187 if (fd == NULL)
1188 {
1189 printf("\nERROR: Cannot open \"%s\" for writing.\n", fname);
1190 return;
1191 }
1192 switch (compat_choice)
1193 {
1194 case compat_vi:
Bram Moolenaar6cdb2c92018-10-13 17:25:27 +02001195 fprintf(fd, "\" Vi compatible\n");
Bram Moolenaar071d4272004-06-13 20:20:40 +00001196 fprintf(fd, "set compatible\n");
1197 break;
Bram Moolenaar6cdb2c92018-10-13 17:25:27 +02001198 case compat_vim:
1199 fprintf(fd, "\" Vim's default behavior\n");
1200 fprintf(fd, "if &compatible\n");
1201 fprintf(fd, " set nocompatible\n");
1202 fprintf(fd, "endif\n");
1203 break;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001204 case compat_some_enhancements:
Bram Moolenaar6cdb2c92018-10-13 17:25:27 +02001205 fprintf(fd, "\" Vim with some enhancements\n");
Bram Moolenaarc73e4472016-07-29 18:33:38 +02001206 fprintf(fd, "source $VIMRUNTIME/defaults.vim\n");
Bram Moolenaar071d4272004-06-13 20:20:40 +00001207 break;
1208 case compat_all_enhancements:
Bram Moolenaar6cdb2c92018-10-13 17:25:27 +02001209 fprintf(fd, "\" Vim with all enhancements\n");
Bram Moolenaar071d4272004-06-13 20:20:40 +00001210 fprintf(fd, "source $VIMRUNTIME/vimrc_example.vim\n");
1211 break;
1212 }
1213 switch (remap_choice)
1214 {
1215 case remap_no:
1216 break;
1217 case remap_win:
Bram Moolenaar6cdb2c92018-10-13 17:25:27 +02001218 fprintf(fd, "\n");
1219 fprintf(fd, "\" Remap a few keys for Windows behavior\n");
Bram Moolenaar071d4272004-06-13 20:20:40 +00001220 fprintf(fd, "source $VIMRUNTIME/mswin.vim\n");
1221 break;
1222 }
1223 switch (mouse_choice)
1224 {
1225 case mouse_xterm:
Bram Moolenaar6cdb2c92018-10-13 17:25:27 +02001226 fprintf(fd, "\n");
1227 fprintf(fd, "\" Mouse behavior (the Unix way)\n");
Bram Moolenaar071d4272004-06-13 20:20:40 +00001228 fprintf(fd, "behave xterm\n");
1229 break;
1230 case mouse_mswin:
Bram Moolenaar6cdb2c92018-10-13 17:25:27 +02001231 fprintf(fd, "\n");
1232 fprintf(fd, "\" Mouse behavior (the Windows way)\n");
Bram Moolenaar071d4272004-06-13 20:20:40 +00001233 fprintf(fd, "behave mswin\n");
1234 break;
Bram Moolenaarc3fdf7f2017-10-28 18:36:48 +02001235 case mouse_default:
1236 break;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001237 }
1238 if ((tfd = fopen("diff.exe", "r")) != NULL)
1239 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01001240 // Use the diff.exe that comes with the self-extracting gvim.exe.
Bram Moolenaar071d4272004-06-13 20:20:40 +00001241 fclose(tfd);
1242 fprintf(fd, "\n");
Bram Moolenaar6cdb2c92018-10-13 17:25:27 +02001243 fprintf(fd, "\" Use the internal diff if available.\n");
1244 fprintf(fd, "\" Otherwise use the special 'diffexpr' for Windows.\n");
1245 fprintf(fd, "if &diffopt !~# 'internal'\n");
1246 fprintf(fd, " set diffexpr=MyDiff()\n");
1247 fprintf(fd, "endif\n");
Bram Moolenaar071d4272004-06-13 20:20:40 +00001248 fprintf(fd, "function MyDiff()\n");
1249 fprintf(fd, " let opt = '-a --binary '\n");
1250 fprintf(fd, " if &diffopt =~ 'icase' | let opt = opt . '-i ' | endif\n");
1251 fprintf(fd, " if &diffopt =~ 'iwhite' | let opt = opt . '-b ' | endif\n");
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01001252 // Use quotes only when needed, they may cause trouble.
1253 // Always escape "!".
Bram Moolenaar071d4272004-06-13 20:20:40 +00001254 fprintf(fd, " let arg1 = v:fname_in\n");
1255 fprintf(fd, " if arg1 =~ ' ' | let arg1 = '\"' . arg1 . '\"' | endif\n");
Bram Moolenaar12365ce2018-05-13 14:45:25 +02001256 fprintf(fd, " let arg1 = substitute(arg1, '!', '\\!', 'g')\n");
Bram Moolenaar071d4272004-06-13 20:20:40 +00001257 fprintf(fd, " let arg2 = v:fname_new\n");
1258 fprintf(fd, " if arg2 =~ ' ' | let arg2 = '\"' . arg2 . '\"' | endif\n");
Bram Moolenaar12365ce2018-05-13 14:45:25 +02001259 fprintf(fd, " let arg2 = substitute(arg2, '!', '\\!', 'g')\n");
Bram Moolenaar071d4272004-06-13 20:20:40 +00001260 fprintf(fd, " let arg3 = v:fname_out\n");
1261 fprintf(fd, " if arg3 =~ ' ' | let arg3 = '\"' . arg3 . '\"' | endif\n");
Bram Moolenaar12365ce2018-05-13 14:45:25 +02001262 fprintf(fd, " let arg3 = substitute(arg3, '!', '\\!', 'g')\n");
Bram Moolenaar33aec762006-01-22 23:30:12 +00001263
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01001264 // If the path has a space: When using cmd.exe (Win NT/2000/XP) put
1265 // quotes around the diff command and rely on the default value of
1266 // shellxquote to solve the quoting problem for the whole command.
1267 //
1268 // Otherwise put a double quote just before the space and at the
1269 // end of the command. Putting quotes around the whole thing
1270 // doesn't work on Win 95/98/ME. This is mostly guessed!
Bram Moolenaar33aec762006-01-22 23:30:12 +00001271 fprintf(fd, " if $VIMRUNTIME =~ ' '\n");
1272 fprintf(fd, " if &sh =~ '\\<cmd'\n");
Bram Moolenaarc62a6442013-11-21 18:13:37 +01001273 fprintf(fd, " if empty(&shellxquote)\n");
1274 fprintf(fd, " let l:shxq_sav = ''\n");
1275 fprintf(fd, " set shellxquote&\n");
1276 fprintf(fd, " endif\n");
1277 fprintf(fd, " let cmd = '\"' . $VIMRUNTIME . '\\diff\"'\n");
Bram Moolenaar33aec762006-01-22 23:30:12 +00001278 fprintf(fd, " else\n");
1279 fprintf(fd, " let cmd = substitute($VIMRUNTIME, ' ', '\" ', '') . '\\diff\"'\n");
1280 fprintf(fd, " endif\n");
1281 fprintf(fd, " else\n");
1282 fprintf(fd, " let cmd = $VIMRUNTIME . '\\diff'\n");
1283 fprintf(fd, " endif\n");
Bram Moolenaar12365ce2018-05-13 14:45:25 +02001284 fprintf(fd, " let cmd = substitute(cmd, '!', '\\!', 'g')\n");
Bram Moolenaarc62a6442013-11-21 18:13:37 +01001285 fprintf(fd, " silent execute '!' . cmd . ' ' . opt . arg1 . ' ' . arg2 . ' > ' . arg3\n");
1286 fprintf(fd, " if exists('l:shxq_sav')\n");
1287 fprintf(fd, " let &shellxquote=l:shxq_sav\n");
1288 fprintf(fd, " endif\n");
Bram Moolenaar071d4272004-06-13 20:20:40 +00001289 fprintf(fd, "endfunction\n");
1290 fprintf(fd, "\n");
1291 }
1292 fclose(fd);
1293 printf("%s has been written\n", fname);
1294}
1295
1296 static void
1297change_vimrc_choice(int idx)
1298{
1299 if (choices[idx].installfunc != NULL)
1300 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01001301 // Switch to NOT change or create a vimrc file.
Bram Moolenaar071d4272004-06-13 20:20:40 +00001302 if (*oldvimrc != NUL)
1303 alloc_text(idx, "Do NOT change startup file %s", oldvimrc);
1304 else
1305 alloc_text(idx, "Do NOT create startup file %s", vimrc);
1306 choices[idx].installfunc = NULL;
1307 choices[idx + 1].active = 0;
1308 choices[idx + 2].active = 0;
1309 choices[idx + 3].active = 0;
1310 }
1311 else
1312 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01001313 // Switch to change or create a vimrc file.
Bram Moolenaar071d4272004-06-13 20:20:40 +00001314 if (*oldvimrc != NUL)
1315 alloc_text(idx, "Overwrite startup file %s with:", oldvimrc);
1316 else
1317 alloc_text(idx, "Create startup file %s with:", vimrc);
1318 choices[idx].installfunc = install_vimrc;
1319 choices[idx + 1].active = 1;
1320 choices[idx + 2].active = 1;
1321 choices[idx + 3].active = 1;
1322 }
1323}
1324
1325/*
1326 * Change the choice how to run Vim.
1327 */
1328 static void
1329change_run_choice(int idx)
1330{
1331 compat_choice = get_choice(compat_choices, TABLE_SIZE(compat_choices));
1332 alloc_text(idx, compat_text, compat_choices[compat_choice]);
1333}
1334
1335/*
1336 * Change the choice if keys are to be remapped.
1337 */
1338 static void
1339change_remap_choice(int idx)
1340{
1341 remap_choice = get_choice(remap_choices, TABLE_SIZE(remap_choices));
1342 alloc_text(idx, remap_text, remap_choices[remap_choice]);
1343}
1344
1345/*
1346 * Change the choice how to select text.
1347 */
1348 static void
1349change_mouse_choice(int idx)
1350{
1351 mouse_choice = get_choice(mouse_choices, TABLE_SIZE(mouse_choices));
1352 alloc_text(idx, mouse_text, mouse_choices[mouse_choice]);
1353}
1354
1355 static void
1356init_vimrc_choices(void)
1357{
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01001358 // set path for a new _vimrc file (also when not used)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001359 strcpy(vimrc, installdir);
1360 strcpy(vimrc + runtimeidx, "_vimrc");
1361
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01001362 // Set opposite value and then toggle it by calling change_vimrc_choice()
Bram Moolenaar071d4272004-06-13 20:20:40 +00001363 if (*oldvimrc == NUL)
1364 choices[choice_count].installfunc = NULL;
1365 else
1366 choices[choice_count].installfunc = install_vimrc;
1367 choices[choice_count].text = NULL;
1368 change_vimrc_choice(choice_count);
1369 choices[choice_count].changefunc = change_vimrc_choice;
1370 choices[choice_count].active = 1;
1371 ++choice_count;
1372
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01001373 // default way to run Vim
Bram Moolenaar071d4272004-06-13 20:20:40 +00001374 alloc_text(choice_count, compat_text, compat_choices[compat_choice]);
1375 choices[choice_count].changefunc = change_run_choice;
1376 choices[choice_count].installfunc = NULL;
1377 choices[choice_count].active = (*oldvimrc == NUL);
1378 ++choice_count;
1379
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01001380 // Whether to remap keys
Bram Moolenaar071d4272004-06-13 20:20:40 +00001381 alloc_text(choice_count, remap_text , remap_choices[remap_choice]);
1382 choices[choice_count].changefunc = change_remap_choice;
Bram Moolenaar945ec092016-06-08 21:17:43 +02001383 choices[choice_count].installfunc = NULL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001384 choices[choice_count].active = (*oldvimrc == NUL);
1385 ++choice_count;
1386
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01001387 // default way to use the mouse
Bram Moolenaar071d4272004-06-13 20:20:40 +00001388 alloc_text(choice_count, mouse_text, mouse_choices[mouse_choice]);
1389 choices[choice_count].changefunc = change_mouse_choice;
Bram Moolenaar945ec092016-06-08 21:17:43 +02001390 choices[choice_count].installfunc = NULL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001391 choices[choice_count].active = (*oldvimrc == NUL);
1392 ++choice_count;
1393}
1394
Bram Moolenaarccd9ccf2010-07-07 13:19:55 +02001395 static LONG
1396reg_create_key(
1397 HKEY root,
1398 const char *subkey,
Bram Moolenaar6199d432017-10-14 19:05:44 +02001399 PHKEY phKey,
1400 DWORD flag)
Bram Moolenaarccd9ccf2010-07-07 13:19:55 +02001401{
1402 DWORD disp;
1403
1404 *phKey = NULL;
1405 return RegCreateKeyEx(
Bram Moolenaarcc448b32010-07-14 16:52:17 +02001406 root, subkey,
1407 0, NULL, REG_OPTION_NON_VOLATILE,
Bram Moolenaar6199d432017-10-14 19:05:44 +02001408 flag | KEY_WRITE,
Bram Moolenaarcc448b32010-07-14 16:52:17 +02001409 NULL, phKey, &disp);
Bram Moolenaarccd9ccf2010-07-07 13:19:55 +02001410}
1411
1412 static LONG
1413reg_set_string_value(
1414 HKEY hKey,
1415 const char *value_name,
1416 const char *data)
1417{
1418 return RegSetValueEx(hKey, value_name, 0, REG_SZ,
1419 (LPBYTE)data, (DWORD)(1 + strlen(data)));
1420}
1421
1422 static LONG
1423reg_create_key_and_value(
1424 HKEY hRootKey,
1425 const char *subkey,
1426 const char *value_name,
Bram Moolenaar6199d432017-10-14 19:05:44 +02001427 const char *data,
1428 DWORD flag)
Bram Moolenaarccd9ccf2010-07-07 13:19:55 +02001429{
1430 HKEY hKey;
Bram Moolenaar6199d432017-10-14 19:05:44 +02001431 LONG lRet = reg_create_key(hRootKey, subkey, &hKey, flag);
Bram Moolenaarccd9ccf2010-07-07 13:19:55 +02001432
1433 if (ERROR_SUCCESS == lRet)
1434 {
Bram Moolenaarcc448b32010-07-14 16:52:17 +02001435 lRet = reg_set_string_value(hKey, value_name, data);
1436 RegCloseKey(hKey);
Bram Moolenaarccd9ccf2010-07-07 13:19:55 +02001437 }
1438 return lRet;
1439}
1440
1441 static LONG
1442register_inproc_server(
1443 HKEY hRootKey,
1444 const char *clsid,
1445 const char *extname,
1446 const char *module,
Bram Moolenaar6199d432017-10-14 19:05:44 +02001447 const char *threading_model,
1448 DWORD flag)
Bram Moolenaarccd9ccf2010-07-07 13:19:55 +02001449{
1450 CHAR subkey[BUFSIZE];
1451 LONG lRet;
1452
1453 sprintf(subkey, "CLSID\\%s", clsid);
Bram Moolenaar6199d432017-10-14 19:05:44 +02001454 lRet = reg_create_key_and_value(hRootKey, subkey, NULL, extname, flag);
Bram Moolenaarccd9ccf2010-07-07 13:19:55 +02001455 if (ERROR_SUCCESS == lRet)
1456 {
Bram Moolenaarcc448b32010-07-14 16:52:17 +02001457 sprintf(subkey, "CLSID\\%s\\InProcServer32", clsid);
Bram Moolenaar6199d432017-10-14 19:05:44 +02001458 lRet = reg_create_key_and_value(hRootKey, subkey, NULL, module, flag);
Bram Moolenaarcc448b32010-07-14 16:52:17 +02001459 if (ERROR_SUCCESS == lRet)
1460 {
1461 lRet = reg_create_key_and_value(hRootKey, subkey,
Bram Moolenaar6199d432017-10-14 19:05:44 +02001462 "ThreadingModel", threading_model, flag);
Bram Moolenaarcc448b32010-07-14 16:52:17 +02001463 }
Bram Moolenaarccd9ccf2010-07-07 13:19:55 +02001464 }
1465 return lRet;
1466}
1467
1468 static LONG
1469register_shellex(
1470 HKEY hRootKey,
1471 const char *clsid,
1472 const char *name,
Bram Moolenaar6199d432017-10-14 19:05:44 +02001473 const char *exe_path,
1474 DWORD flag)
Bram Moolenaarccd9ccf2010-07-07 13:19:55 +02001475{
1476 LONG lRet = reg_create_key_and_value(
Bram Moolenaarcc448b32010-07-14 16:52:17 +02001477 hRootKey,
1478 "*\\shellex\\ContextMenuHandlers\\gvim",
1479 NULL,
Bram Moolenaar6199d432017-10-14 19:05:44 +02001480 clsid,
1481 flag);
Bram Moolenaarccd9ccf2010-07-07 13:19:55 +02001482
1483 if (ERROR_SUCCESS == lRet)
1484 {
Bram Moolenaarcc448b32010-07-14 16:52:17 +02001485 lRet = reg_create_key_and_value(
1486 HKEY_LOCAL_MACHINE,
1487 "Software\\Microsoft\\Windows\\CurrentVersion\\Shell Extensions\\Approved",
1488 clsid,
Bram Moolenaar6199d432017-10-14 19:05:44 +02001489 name,
1490 flag);
Bram Moolenaarccd9ccf2010-07-07 13:19:55 +02001491
Bram Moolenaarcc448b32010-07-14 16:52:17 +02001492 if (ERROR_SUCCESS == lRet)
1493 {
1494 lRet = reg_create_key_and_value(
1495 HKEY_LOCAL_MACHINE,
1496 "Software\\Vim\\Gvim",
1497 "path",
Bram Moolenaar6199d432017-10-14 19:05:44 +02001498 exe_path,
1499 flag);
Bram Moolenaarcc448b32010-07-14 16:52:17 +02001500 }
Bram Moolenaarccd9ccf2010-07-07 13:19:55 +02001501 }
1502 return lRet;
1503}
1504
1505 static LONG
1506register_openwith(
1507 HKEY hRootKey,
Bram Moolenaar6199d432017-10-14 19:05:44 +02001508 const char *exe_path,
1509 DWORD flag)
Bram Moolenaarccd9ccf2010-07-07 13:19:55 +02001510{
Bram Moolenaar78050042010-07-31 20:53:54 +02001511 char exe_cmd[BUFSIZE];
1512 LONG lRet;
1513
Bram Moolenaarbbdcb482010-08-02 20:45:27 +02001514 sprintf(exe_cmd, "\"%s\" \"%%1\"", exe_path);
Bram Moolenaar78050042010-07-31 20:53:54 +02001515 lRet = reg_create_key_and_value(
Bram Moolenaarcc448b32010-07-14 16:52:17 +02001516 hRootKey,
1517 "Applications\\gvim.exe\\shell\\edit\\command",
1518 NULL,
Bram Moolenaar6199d432017-10-14 19:05:44 +02001519 exe_cmd,
1520 flag);
Bram Moolenaarccd9ccf2010-07-07 13:19:55 +02001521
1522 if (ERROR_SUCCESS == lRet)
1523 {
Bram Moolenaarcc448b32010-07-14 16:52:17 +02001524 int i;
1525 static const char *openwith[] = {
1526 ".htm\\OpenWithList\\gvim.exe",
1527 ".vim\\OpenWithList\\gvim.exe",
1528 "*\\OpenWithList\\gvim.exe",
1529 };
Bram Moolenaarccd9ccf2010-07-07 13:19:55 +02001530
Yegappan Lakshmanana34b4462022-06-11 10:43:26 +01001531 for (i = 0; ERROR_SUCCESS == lRet && i < (int)ARRAYSIZE(openwith); i++)
Bram Moolenaar6199d432017-10-14 19:05:44 +02001532 lRet = reg_create_key_and_value(hRootKey, openwith[i], NULL, "", flag);
Bram Moolenaarccd9ccf2010-07-07 13:19:55 +02001533 }
1534
1535 return lRet;
1536}
1537
1538 static LONG
1539register_uninstall(
1540 HKEY hRootKey,
1541 const char *appname,
1542 const char *display_name,
Bram Moolenaar6cdb2c92018-10-13 17:25:27 +02001543 const char *uninstall_string,
1544 const char *display_icon,
1545 const char *display_version,
1546 const char *publisher)
Bram Moolenaarccd9ccf2010-07-07 13:19:55 +02001547{
1548 LONG lRet = reg_create_key_and_value(hRootKey, appname,
Bram Moolenaar6199d432017-10-14 19:05:44 +02001549 "DisplayName", display_name, KEY_WOW64_64KEY);
Bram Moolenaarccd9ccf2010-07-07 13:19:55 +02001550
1551 if (ERROR_SUCCESS == lRet)
Bram Moolenaarcc448b32010-07-14 16:52:17 +02001552 lRet = reg_create_key_and_value(hRootKey, appname,
Bram Moolenaar6199d432017-10-14 19:05:44 +02001553 "UninstallString", uninstall_string, KEY_WOW64_64KEY);
Bram Moolenaar6cdb2c92018-10-13 17:25:27 +02001554 if (ERROR_SUCCESS == lRet)
1555 lRet = reg_create_key_and_value(hRootKey, appname,
1556 "DisplayIcon", display_icon, KEY_WOW64_64KEY);
1557 if (ERROR_SUCCESS == lRet)
1558 lRet = reg_create_key_and_value(hRootKey, appname,
1559 "DisplayVersion", display_version, KEY_WOW64_64KEY);
1560 if (ERROR_SUCCESS == lRet)
1561 lRet = reg_create_key_and_value(hRootKey, appname,
1562 "Publisher", publisher, KEY_WOW64_64KEY);
Bram Moolenaarccd9ccf2010-07-07 13:19:55 +02001563 return lRet;
1564}
Bram Moolenaarccd9ccf2010-07-07 13:19:55 +02001565
Bram Moolenaar071d4272004-06-13 20:20:40 +00001566/*
1567 * Add some entries to the registry:
1568 * - to add "Edit with Vim" to the context * menu
1569 * - to add Vim to the "Open with..." list
1570 * - to uninstall Vim
1571 */
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01001572//ARGSUSED
Bram Moolenaarab8205e2010-07-07 15:14:03 +02001573 static int
Bram Moolenaar071d4272004-06-13 20:20:40 +00001574install_registry(void)
1575{
Bram Moolenaarcc448b32010-07-14 16:52:17 +02001576 LONG lRet = ERROR_SUCCESS;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001577 const char *vim_ext_ThreadingModel = "Apartment";
1578 const char *vim_ext_name = "Vim Shell Extension";
1579 const char *vim_ext_clsid = "{51EEE242-AD87-11d3-9C1E-0090278BBD99}";
Bram Moolenaarbbd854d2019-02-18 22:19:33 +01001580 char vim_exe_path[MAX_PATH];
Bram Moolenaarcc448b32010-07-14 16:52:17 +02001581 char display_name[BUFSIZE];
1582 char uninstall_string[BUFSIZE];
Bram Moolenaar6cdb2c92018-10-13 17:25:27 +02001583 char icon_string[BUFSIZE];
Bram Moolenaar0894e0d2021-07-15 14:14:30 +02001584 char version_string[BUFSIZE];
Bram Moolenaar6199d432017-10-14 19:05:44 +02001585 int i;
1586 int loop_count = is_64bit_os() ? 2 : 1;
1587 DWORD flag;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001588
Bram Moolenaarccd9ccf2010-07-07 13:19:55 +02001589 sprintf(vim_exe_path, "%s\\gvim.exe", installdir);
1590
1591 if (install_popup)
1592 {
Bram Moolenaarcc448b32010-07-14 16:52:17 +02001593 char bufg[BUFSIZE];
Bram Moolenaarccd9ccf2010-07-07 13:19:55 +02001594
Bram Moolenaarcc448b32010-07-14 16:52:17 +02001595 printf("Creating \"Edit with Vim\" popup menu entry\n");
Bram Moolenaarccd9ccf2010-07-07 13:19:55 +02001596
Bram Moolenaar6199d432017-10-14 19:05:44 +02001597 for (i = 0; i < loop_count; i++)
1598 {
1599 if (i == 0)
1600 {
1601 sprintf(bufg, "%s\\" GVIMEXT32_PATH, installdir);
1602 flag = KEY_WOW64_32KEY;
1603 }
1604 else
1605 {
1606 sprintf(bufg, "%s\\" GVIMEXT64_PATH, installdir);
1607 flag = KEY_WOW64_64KEY;
1608 }
1609
1610 lRet = register_inproc_server(
1611 HKEY_CLASSES_ROOT, vim_ext_clsid, vim_ext_name,
1612 bufg, vim_ext_ThreadingModel, flag);
1613 if (ERROR_SUCCESS != lRet)
1614 return FAIL;
1615 lRet = register_shellex(
1616 HKEY_CLASSES_ROOT, vim_ext_clsid, vim_ext_name,
1617 vim_exe_path, flag);
1618 if (ERROR_SUCCESS != lRet)
1619 return FAIL;
1620 }
Bram Moolenaarccd9ccf2010-07-07 13:19:55 +02001621 }
1622
1623 if (install_openwith)
1624 {
Bram Moolenaarcc448b32010-07-14 16:52:17 +02001625 printf("Creating \"Open with ...\" list entry\n");
Bram Moolenaarccd9ccf2010-07-07 13:19:55 +02001626
Bram Moolenaar6199d432017-10-14 19:05:44 +02001627 for (i = 0; i < loop_count; i++)
1628 {
1629 if (i == 0)
1630 flag = KEY_WOW64_32KEY;
1631 else
1632 flag = KEY_WOW64_64KEY;
1633
1634 lRet = register_openwith(HKEY_CLASSES_ROOT, vim_exe_path, flag);
1635 if (ERROR_SUCCESS != lRet)
1636 return FAIL;
1637 }
Bram Moolenaarccd9ccf2010-07-07 13:19:55 +02001638 }
1639
1640 printf("Creating an uninstall entry\n");
Bram Moolenaaraf610b82018-12-21 16:22:50 +01001641 sprintf(display_name, "Vim " VIM_VERSION_SHORT
Bram Moolenaar577fadf2019-04-04 20:32:24 +02001642#ifdef _M_ARM64
1643 " (arm64)"
1644#elif _M_X64
Bram Moolenaaraf610b82018-12-21 16:22:50 +01001645 " (x64)"
1646#endif
1647 );
Bram Moolenaarccd9ccf2010-07-07 13:19:55 +02001648
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01001649 // For the NSIS installer use the generated uninstaller.
Bram Moolenaarccd9ccf2010-07-07 13:19:55 +02001650 if (interactive)
Bram Moolenaar30e8e732019-09-27 13:08:36 +02001651 sprintf(uninstall_string, "%s\\uninstall.exe", installdir);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001652 else
Bram Moolenaar16d79a32010-07-18 22:33:56 +02001653 sprintf(uninstall_string, "%s\\uninstall-gui.exe", installdir);
Bram Moolenaarccd9ccf2010-07-07 13:19:55 +02001654
Bram Moolenaar6cdb2c92018-10-13 17:25:27 +02001655 sprintf(icon_string, "%s\\gvim.exe,0", installdir);
1656
Bram Moolenaar0894e0d2021-07-15 14:14:30 +02001657 sprintf(version_string, VIM_VERSION_SHORT "." VIM_VERSION_PATCHLEVEL_STR);
1658
Bram Moolenaarccd9ccf2010-07-07 13:19:55 +02001659 lRet = register_uninstall(
Bram Moolenaarcc448b32010-07-14 16:52:17 +02001660 HKEY_LOCAL_MACHINE,
1661 "Software\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\Vim " VIM_VERSION_SHORT,
1662 display_name,
Bram Moolenaar6cdb2c92018-10-13 17:25:27 +02001663 uninstall_string,
1664 icon_string,
Bram Moolenaar0894e0d2021-07-15 14:14:30 +02001665 version_string,
RestorerZec67ee02024-04-25 21:25:19 +02001666 "The Vim Project");
Bram Moolenaarab8205e2010-07-07 15:14:03 +02001667 if (ERROR_SUCCESS != lRet)
1668 return FAIL;
Bram Moolenaarccd9ccf2010-07-07 13:19:55 +02001669
Bram Moolenaarab8205e2010-07-07 15:14:03 +02001670 return OK;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001671}
1672
1673 static void
1674change_popup_choice(int idx)
1675{
1676 if (install_popup == 0)
1677 {
1678 choices[idx].text = "Install an entry for Vim in the popup menu for the right\n mouse button so that you can edit any file with Vim";
1679 install_popup = 1;
1680 }
1681 else
1682 {
1683 choices[idx].text = "Do NOT install an entry for Vim in the popup menu for the\n right mouse button to edit any file with Vim";
1684 install_popup = 0;
1685 }
1686}
1687
1688/*
1689 * Only add the choice for the popup menu entry when gvim.exe was found and
1690 * both gvimext.dll and regedit.exe exist.
1691 */
1692 static void
1693init_popup_choice(void)
1694{
1695 struct stat st;
1696
1697 if (has_gvim
Bram Moolenaar6199d432017-10-14 19:05:44 +02001698 && (stat(GVIMEXT32_PATH, &st) >= 0
1699 || stat(GVIMEXT64_PATH, &st) >= 0))
Bram Moolenaar071d4272004-06-13 20:20:40 +00001700 {
1701 choices[choice_count].changefunc = change_popup_choice;
1702 choices[choice_count].installfunc = NULL;
1703 choices[choice_count].active = 1;
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01001704 change_popup_choice(choice_count); // set the text
Bram Moolenaar071d4272004-06-13 20:20:40 +00001705 ++choice_count;
1706 }
1707 else
1708 add_dummy_choice();
1709}
1710
1711 static void
1712change_openwith_choice(int idx)
1713{
1714 if (install_openwith == 0)
1715 {
1716 choices[idx].text = "Add Vim to the \"Open With...\" list in the popup menu for the right\n mouse button so that you can edit any file with Vim";
1717 install_openwith = 1;
1718 }
1719 else
1720 {
1721 choices[idx].text = "Do NOT add Vim to the \"Open With...\" list in the popup menu for the\n right mouse button to edit any file with Vim";
1722 install_openwith = 0;
1723 }
1724}
1725
1726/*
1727 * Only add the choice for the open-with menu entry when gvim.exe was found
Bram Moolenaar84a05ac2013-05-06 04:24:17 +02001728 * and regedit.exe exist.
Bram Moolenaar071d4272004-06-13 20:20:40 +00001729 */
1730 static void
1731init_openwith_choice(void)
1732{
Bram Moolenaar6199d432017-10-14 19:05:44 +02001733 if (has_gvim)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001734 {
1735 choices[choice_count].changefunc = change_openwith_choice;
1736 choices[choice_count].installfunc = NULL;
1737 choices[choice_count].active = 1;
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01001738 change_openwith_choice(choice_count); // set the text
Bram Moolenaar071d4272004-06-13 20:20:40 +00001739 ++choice_count;
1740 }
1741 else
1742 add_dummy_choice();
1743}
1744
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01001745/*
Bram Moolenaar071d4272004-06-13 20:20:40 +00001746 * Create a shell link.
1747 *
1748 * returns 0 on failure, non-zero on successful completion.
1749 *
1750 * NOTE: Currently untested with mingw.
1751 */
1752 int
1753create_shortcut(
1754 const char *shortcut_name,
1755 const char *iconfile_path,
1756 int iconindex,
1757 const char *shortcut_target,
1758 const char *shortcut_args,
1759 const char *workingdir
1760 )
1761{
1762 IShellLink *shelllink_ptr;
1763 HRESULT hres;
1764 IPersistFile *persistfile_ptr;
1765
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01001766 // Initialize COM library
Bram Moolenaar071d4272004-06-13 20:20:40 +00001767 hres = CoInitialize(NULL);
1768 if (!SUCCEEDED(hres))
1769 {
1770 printf("Error: Could not open the COM library. Not creating shortcut.\n");
1771 return FAIL;
1772 }
1773
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01001774 // Instantiate a COM object for the ShellLink, store a pointer to it
1775 // in shelllink_ptr.
Bram Moolenaar071d4272004-06-13 20:20:40 +00001776 hres = CoCreateInstance(&CLSID_ShellLink,
1777 NULL,
1778 CLSCTX_INPROC_SERVER,
1779 &IID_IShellLink,
1780 (void **) &shelllink_ptr);
1781
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01001782 if (SUCCEEDED(hres)) // If the instantiation was successful...
Bram Moolenaar071d4272004-06-13 20:20:40 +00001783 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01001784 // ...Then build a PersistFile interface for the ShellLink so we can
1785 // save it as a file after we build it.
Bram Moolenaar071d4272004-06-13 20:20:40 +00001786 hres = shelllink_ptr->lpVtbl->QueryInterface(shelllink_ptr,
1787 &IID_IPersistFile, (void **) &persistfile_ptr);
1788
1789 if (SUCCEEDED(hres))
1790 {
1791 wchar_t wsz[BUFSIZE];
1792
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01001793 // translate the (possibly) multibyte shortcut filename to windows
1794 // Unicode so it can be used as a file name.
Bram Moolenaare4963c52019-02-22 19:41:08 +01001795 MultiByteToWideChar(CP_ACP, 0, shortcut_name, -1, wsz, sizeof(wsz)/sizeof(wsz[0]));
Bram Moolenaar071d4272004-06-13 20:20:40 +00001796
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01001797 // set the attributes
Bram Moolenaar071d4272004-06-13 20:20:40 +00001798 shelllink_ptr->lpVtbl->SetPath(shelllink_ptr, shortcut_target);
1799 shelllink_ptr->lpVtbl->SetWorkingDirectory(shelllink_ptr,
1800 workingdir);
1801 shelllink_ptr->lpVtbl->SetIconLocation(shelllink_ptr,
1802 iconfile_path, iconindex);
1803 shelllink_ptr->lpVtbl->SetArguments(shelllink_ptr, shortcut_args);
1804
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01001805 // save the shortcut to a file and return the PersistFile object
Bram Moolenaar071d4272004-06-13 20:20:40 +00001806 persistfile_ptr->lpVtbl->Save(persistfile_ptr, wsz, 1);
1807 persistfile_ptr->lpVtbl->Release(persistfile_ptr);
1808 }
1809 else
1810 {
1811 printf("QueryInterface Error\n");
1812 return FAIL;
1813 }
1814
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01001815 // Return the ShellLink object
Bram Moolenaar071d4272004-06-13 20:20:40 +00001816 shelllink_ptr->lpVtbl->Release(shelllink_ptr);
1817 }
1818 else
1819 {
1820 printf("CoCreateInstance Error - hres = %08x\n", (int)hres);
1821 return FAIL;
1822 }
1823
1824 return OK;
1825}
1826
1827/*
1828 * Build a path to where we will put a specified link.
1829 *
1830 * Return 0 on error, non-zero on success
1831 */
1832 int
1833build_link_name(
1834 char *link_path,
1835 const char *link_name,
1836 const char *shell_folder_name)
1837{
Bram Moolenaarbbd854d2019-02-18 22:19:33 +01001838 char shell_folder_path[MAX_PATH];
Bram Moolenaar071d4272004-06-13 20:20:40 +00001839
1840 if (get_shell_folder_path(shell_folder_path, shell_folder_name) == FAIL)
1841 {
1842 printf("An error occurred while attempting to find the path to %s.\n",
1843 shell_folder_name);
1844 return FAIL;
1845 }
1846
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01001847 // Make sure the directory exists (create Start Menu\Programs\Vim).
1848 // Ignore errors if it already exists.
Bram Moolenaar071d4272004-06-13 20:20:40 +00001849 vim_mkdir(shell_folder_path, 0755);
1850
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01001851 // build the path to the shortcut and the path to gvim.exe
Bram Moolenaar071d4272004-06-13 20:20:40 +00001852 sprintf(link_path, "%s\\%s.lnk", shell_folder_path, link_name);
1853
1854 return OK;
1855}
1856
1857 static int
1858build_shortcut(
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01001859 const char *name, // Name of the shortcut
1860 const char *exename, // Name of the executable (e.g., vim.exe)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001861 const char *args,
1862 const char *shell_folder,
1863 const char *workingdir)
1864{
1865 char executable_path[BUFSIZE];
1866 char link_name[BUFSIZE];
1867
1868 sprintf(executable_path, "%s\\%s", installdir, exename);
1869
1870 if (build_link_name(link_name, name, shell_folder) == FAIL)
1871 {
1872 printf("An error has occurred. A shortcut to %s will not be created %s.\n",
1873 name,
1874 *shell_folder == 'd' ? "on the desktop" : "in the Start menu");
1875 return FAIL;
1876 }
1877
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01001878 // Create the shortcut:
Bram Moolenaar071d4272004-06-13 20:20:40 +00001879 return create_shortcut(link_name, executable_path, 0,
1880 executable_path, args, workingdir);
1881}
1882
1883/*
1884 * We used to use "homedir" as the working directory, but that is a bad choice
Bram Moolenaar03e228a2013-11-07 04:49:27 +01001885 * on multi-user systems. However, not specifying a directory results in the
1886 * current directory to be c:\Windows\system32 on Windows 7. Use environment
1887 * variables instead.
Bram Moolenaar071d4272004-06-13 20:20:40 +00001888 */
Bram Moolenaar03e228a2013-11-07 04:49:27 +01001889#define WORKDIR "%HOMEDRIVE%%HOMEPATH%"
Bram Moolenaar071d4272004-06-13 20:20:40 +00001890
1891/*
1892 * Create shortcut(s) in the Start Menu\Programs\Vim folder.
1893 */
1894 static void
Bram Moolenaar35d7a2f2022-06-09 20:53:54 +01001895install_start_menu(int idx UNUSED)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001896{
1897 need_uninstall_entry = 1;
1898 printf("Creating start menu\n");
1899 if (has_vim)
1900 {
1901 if (build_shortcut("Vim", "vim.exe", "",
1902 VIM_STARTMENU, WORKDIR) == FAIL)
1903 return;
1904 if (build_shortcut("Vim Read-only", "vim.exe", "-R",
1905 VIM_STARTMENU, WORKDIR) == FAIL)
1906 return;
1907 if (build_shortcut("Vim Diff", "vim.exe", "-d",
1908 VIM_STARTMENU, WORKDIR) == FAIL)
1909 return;
1910 }
1911 if (has_gvim)
1912 {
1913 if (build_shortcut("gVim", "gvim.exe", "",
1914 VIM_STARTMENU, WORKDIR) == FAIL)
1915 return;
1916 if (build_shortcut("gVim Easy", "gvim.exe", "-y",
1917 VIM_STARTMENU, WORKDIR) == FAIL)
1918 return;
1919 if (build_shortcut("gVim Read-only", "gvim.exe", "-R",
1920 VIM_STARTMENU, WORKDIR) == FAIL)
1921 return;
1922 if (build_shortcut("gVim Diff", "gvim.exe", "-d",
1923 VIM_STARTMENU, WORKDIR) == FAIL)
1924 return;
1925 }
1926 if (build_shortcut("Uninstall",
Bram Moolenaar30e8e732019-09-27 13:08:36 +02001927 interactive ? "uninstall.exe" : "uninstall-gui.exe", "",
Bram Moolenaar071d4272004-06-13 20:20:40 +00001928 VIM_STARTMENU, installdir) == FAIL)
1929 return;
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01001930 // For Windows NT the working dir of the vimtutor.bat must be right,
1931 // otherwise gvim.exe won't be found and using gvimbat doesn't work.
Bram Moolenaar071d4272004-06-13 20:20:40 +00001932 if (build_shortcut("Vim tutor", "vimtutor.bat", "",
1933 VIM_STARTMENU, installdir) == FAIL)
1934 return;
1935 if (build_shortcut("Help", has_gvim ? "gvim.exe" : "vim.exe", "-c h",
1936 VIM_STARTMENU, WORKDIR) == FAIL)
1937 return;
1938 {
1939 char shell_folder_path[BUFSIZE];
1940
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01001941 // Creating the URL shortcut works a bit differently...
Bram Moolenaar071d4272004-06-13 20:20:40 +00001942 if (get_shell_folder_path(shell_folder_path, VIM_STARTMENU) == FAIL)
1943 {
1944 printf("Finding the path of the Start menu failed\n");
1945 return ;
1946 }
1947 add_pathsep(shell_folder_path);
1948 strcat(shell_folder_path, "Vim Online.url");
1949 if (!WritePrivateProfileString("InternetShortcut", "URL",
Bram Moolenaarbd87eb32018-06-26 23:18:45 +02001950 "https://www.vim.org/", shell_folder_path))
Bram Moolenaar071d4272004-06-13 20:20:40 +00001951 {
1952 printf("Creating the Vim online URL failed\n");
1953 return;
1954 }
1955 }
1956}
1957
1958 static void
1959toggle_startmenu_choice(int idx)
1960{
1961 if (choices[idx].installfunc == NULL)
1962 {
1963 choices[idx].installfunc = install_start_menu;
1964 choices[idx].text = "Add Vim to the Start menu";
1965 }
1966 else
1967 {
1968 choices[idx].installfunc = NULL;
1969 choices[idx].text = "Do NOT add Vim to the Start menu";
1970 }
1971}
1972
1973/*
1974 * Function to actually create the shortcuts
1975 *
1976 * Currently I am supplying no working directory to the shortcut. This
1977 * means that the initial working dir will be:
1978 * - the location of the shortcut if no file is supplied
1979 * - the location of the file being edited if a file is supplied (ie via
1980 * drag and drop onto the shortcut).
1981 */
1982 void
1983install_shortcut_gvim(int idx)
1984{
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01001985 // Create shortcut(s) on the desktop
Bram Moolenaar071d4272004-06-13 20:20:40 +00001986 if (choices[idx].arg)
1987 {
1988 (void)build_shortcut(icon_names[0], "gvim.exe",
1989 "", "desktop", WORKDIR);
1990 need_uninstall_entry = 1;
1991 }
1992}
1993
1994 void
1995install_shortcut_evim(int idx)
1996{
1997 if (choices[idx].arg)
1998 {
1999 (void)build_shortcut(icon_names[1], "gvim.exe",
2000 "-y", "desktop", WORKDIR);
2001 need_uninstall_entry = 1;
2002 }
2003}
2004
2005 void
2006install_shortcut_gview(int idx)
2007{
2008 if (choices[idx].arg)
2009 {
2010 (void)build_shortcut(icon_names[2], "gvim.exe",
2011 "-R", "desktop", WORKDIR);
2012 need_uninstall_entry = 1;
2013 }
2014}
2015
2016 void
2017toggle_shortcut_choice(int idx)
2018{
2019 char *arg;
2020
2021 if (choices[idx].installfunc == install_shortcut_gvim)
2022 arg = "gVim";
2023 else if (choices[idx].installfunc == install_shortcut_evim)
2024 arg = "gVim Easy";
2025 else
2026 arg = "gVim Read-only";
2027 if (choices[idx].arg)
2028 {
2029 choices[idx].arg = 0;
2030 alloc_text(idx, "Do NOT create a desktop icon for %s", arg);
2031 }
2032 else
2033 {
2034 choices[idx].arg = 1;
2035 alloc_text(idx, "Create a desktop icon for %s", arg);
2036 }
2037}
Bram Moolenaar071d4272004-06-13 20:20:40 +00002038
2039 static void
2040init_startmenu_choice(void)
2041{
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002042 // Start menu
Bram Moolenaar071d4272004-06-13 20:20:40 +00002043 choices[choice_count].changefunc = toggle_startmenu_choice;
2044 choices[choice_count].installfunc = NULL;
2045 choices[choice_count].active = 1;
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002046 toggle_startmenu_choice(choice_count); // set the text
Bram Moolenaar071d4272004-06-13 20:20:40 +00002047 ++choice_count;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002048}
2049
2050/*
2051 * Add the choice for the desktop shortcuts.
2052 */
2053 static void
2054init_shortcut_choices(void)
2055{
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002056 // Shortcut to gvim
Bram Moolenaar071d4272004-06-13 20:20:40 +00002057 choices[choice_count].text = NULL;
2058 choices[choice_count].arg = 0;
2059 choices[choice_count].active = has_gvim;
2060 choices[choice_count].changefunc = toggle_shortcut_choice;
2061 choices[choice_count].installfunc = install_shortcut_gvim;
2062 toggle_shortcut_choice(choice_count);
2063 ++choice_count;
2064
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002065 // Shortcut to evim
Bram Moolenaar071d4272004-06-13 20:20:40 +00002066 choices[choice_count].text = NULL;
2067 choices[choice_count].arg = 0;
2068 choices[choice_count].active = has_gvim;
2069 choices[choice_count].changefunc = toggle_shortcut_choice;
2070 choices[choice_count].installfunc = install_shortcut_evim;
2071 toggle_shortcut_choice(choice_count);
2072 ++choice_count;
2073
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002074 // Shortcut to gview
Bram Moolenaar071d4272004-06-13 20:20:40 +00002075 choices[choice_count].text = NULL;
2076 choices[choice_count].arg = 0;
2077 choices[choice_count].active = has_gvim;
2078 choices[choice_count].changefunc = toggle_shortcut_choice;
2079 choices[choice_count].installfunc = install_shortcut_gview;
2080 toggle_shortcut_choice(choice_count);
2081 ++choice_count;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002082}
2083
Bram Moolenaar071d4272004-06-13 20:20:40 +00002084/*
2085 * Attempt to register OLE for Vim.
2086 */
2087 static void
2088install_OLE_register(void)
2089{
2090 char register_command_string[BUFSIZE + 30];
2091
2092 printf("\n--- Attempting to register Vim with OLE ---\n");
2093 printf("(There is no message whether this works or not.)\n");
2094
Bram Moolenaar071d4272004-06-13 20:20:40 +00002095 sprintf(register_command_string, "\"%s\\gvim.exe\" -silent -register", installdir);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002096 system(register_command_string);
2097}
Bram Moolenaar071d4272004-06-13 20:20:40 +00002098
2099/*
2100 * Remove the last part of directory "path[]" to get its parent, and put the
2101 * result in "to[]".
2102 */
2103 static void
Bram Moolenaare4963c52019-02-22 19:41:08 +01002104dir_remove_last(const char *path, char to[MAX_PATH])
Bram Moolenaar071d4272004-06-13 20:20:40 +00002105{
2106 char c;
2107 long last_char_to_copy;
2108 long path_length = strlen(path);
2109
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002110 // skip the last character just in case it is a '\\'
Bram Moolenaar071d4272004-06-13 20:20:40 +00002111 last_char_to_copy = path_length - 2;
2112 c = path[last_char_to_copy];
2113
2114 while (c != '\\')
2115 {
2116 last_char_to_copy--;
2117 c = path[last_char_to_copy];
2118 }
2119
2120 strncpy(to, path, (size_t)last_char_to_copy);
2121 to[last_char_to_copy] = NUL;
2122}
2123
2124 static void
2125set_directories_text(int idx)
2126{
Bram Moolenaar25a494c2018-11-16 19:39:50 +01002127 int vimfiles_dir_choice = choices[idx].arg;
2128
Bram Moolenaar071d4272004-06-13 20:20:40 +00002129 if (vimfiles_dir_choice == (int)vimfiles_dir_none)
2130 alloc_text(idx, "Do NOT create plugin directories%s", "");
2131 else
2132 alloc_text(idx, "Create plugin directories: %s",
2133 vimfiles_dir_choices[vimfiles_dir_choice]);
2134}
2135
2136/*
Bram Moolenaar25a494c2018-11-16 19:39:50 +01002137 * To get the "real" home directory:
2138 * - get value of $HOME
2139 * - if not found, get value of $HOMEDRIVE$HOMEPATH
2140 * - if not found, get value of $USERPROFILE
2141 *
2142 * This code is based on init_homedir() in misc1.c, keep in sync!
2143 */
2144static char *homedir = NULL;
2145
2146 void
2147init_homedir(void)
2148{
2149 char *var;
2150 char buf[MAX_PATH];
2151
2152 if (homedir != NULL)
2153 {
2154 free(homedir);
2155 homedir = NULL;
2156 }
2157
2158 var = getenv("HOME");
2159
2160 /*
2161 * Typically, $HOME is not defined on Windows, unless the user has
2162 * specifically defined it for Vim's sake. However, on Windows NT
2163 * platforms, $HOMEDRIVE and $HOMEPATH are automatically defined for
2164 * each user. Try constructing $HOME from these.
2165 */
2166 if (var == NULL || *var == NUL)
2167 {
2168 char *homedrive, *homepath;
2169
2170 homedrive = getenv("HOMEDRIVE");
2171 homepath = getenv("HOMEPATH");
2172 if (homepath == NULL || *homepath == NUL)
2173 homepath = "\\";
2174 if (homedrive != NULL
Bram Moolenaare4963c52019-02-22 19:41:08 +01002175 && strlen(homedrive) + strlen(homepath) < sizeof(buf))
Bram Moolenaar25a494c2018-11-16 19:39:50 +01002176 {
2177 sprintf(buf, "%s%s", homedrive, homepath);
2178 if (buf[0] != NUL)
2179 var = buf;
2180 }
2181 }
2182
2183 if (var == NULL)
2184 var = getenv("USERPROFILE");
2185
2186 /*
2187 * Weird but true: $HOME may contain an indirect reference to another
2188 * variable, esp. "%USERPROFILE%". Happens when $USERPROFILE isn't set
2189 * when $HOME is being set.
2190 */
2191 if (var != NULL && *var == '%')
2192 {
2193 char *p;
2194 char *exp;
2195
2196 p = strchr(var + 1, '%');
2197 if (p != NULL)
2198 {
2199 strncpy(buf, var + 1, p - (var + 1));
2200 buf[p - (var + 1)] = NUL;
2201 exp = getenv(buf);
2202 if (exp != NULL && *exp != NUL
Bram Moolenaare4963c52019-02-22 19:41:08 +01002203 && strlen(exp) + strlen(p) < sizeof(buf))
Bram Moolenaar25a494c2018-11-16 19:39:50 +01002204 {
Bram Moolenaare4963c52019-02-22 19:41:08 +01002205 sprintf(buf, "%s%s", exp, p + 1);
Bram Moolenaar25a494c2018-11-16 19:39:50 +01002206 var = buf;
2207 }
2208 }
2209 }
2210
2211 if (var != NULL && *var == NUL) // empty is same as not set
2212 var = NULL;
2213
2214 if (var == NULL)
2215 homedir = NULL;
2216 else
2217 homedir = _strdup(var);
2218}
2219
2220/*
Bram Moolenaar071d4272004-06-13 20:20:40 +00002221 * Change the directory that the vim plugin directories will be created in:
2222 * $HOME, $VIM or nowhere.
2223 */
2224 static void
2225change_directories_choice(int idx)
2226{
2227 int choice_count = TABLE_SIZE(vimfiles_dir_choices);
2228
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002229 // Don't offer the $HOME choice if $HOME isn't set.
Bram Moolenaar25a494c2018-11-16 19:39:50 +01002230 if (homedir == NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002231 --choice_count;
Bram Moolenaar25a494c2018-11-16 19:39:50 +01002232 choices[idx].arg = get_choice(vimfiles_dir_choices, choice_count);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002233 set_directories_text(idx);
2234}
2235
2236/*
2237 * Create the plugin directories...
2238 */
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002239//ARGSUSED
Bram Moolenaar071d4272004-06-13 20:20:40 +00002240 static void
2241install_vimfilesdir(int idx)
2242{
2243 int i;
Bram Moolenaar25a494c2018-11-16 19:39:50 +01002244 int vimfiles_dir_choice = choices[idx].arg;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002245 char *p;
Bram Moolenaarbbd854d2019-02-18 22:19:33 +01002246 char vimdir_path[MAX_PATH];
2247 char vimfiles_path[MAX_PATH + 9];
Bram Moolenaar071d4272004-06-13 20:20:40 +00002248 char tmp_dirname[BUFSIZE];
2249
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002250 // switch on the location that the user wants the plugin directories
2251 // built in
Bram Moolenaar071d4272004-06-13 20:20:40 +00002252 switch (vimfiles_dir_choice)
2253 {
2254 case vimfiles_dir_vim:
2255 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002256 // Go to the %VIM% directory - check env first, then go one dir
2257 // below installdir if there is no %VIM% environment variable.
2258 // The accuracy of $VIM is checked in inspect_system(), so we
2259 // can be sure it is ok to use here.
Bram Moolenaar071d4272004-06-13 20:20:40 +00002260 p = getenv("VIM");
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002261 if (p == NULL) // No $VIM in path
Bram Moolenaar071d4272004-06-13 20:20:40 +00002262 dir_remove_last(installdir, vimdir_path);
2263 else
2264 strcpy(vimdir_path, p);
2265 break;
2266 }
2267 case vimfiles_dir_home:
2268 {
Bram Moolenaar25a494c2018-11-16 19:39:50 +01002269 // Find the $HOME directory. Its existence was already checked.
2270 p = homedir;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002271 if (p == NULL)
2272 {
2273 printf("Internal error: $HOME is NULL\n");
2274 p = "c:\\";
2275 }
2276 strcpy(vimdir_path, p);
2277 break;
2278 }
2279 case vimfiles_dir_none:
2280 {
Bram Moolenaar25a494c2018-11-16 19:39:50 +01002281 // Do not create vim plugin directory.
Bram Moolenaar071d4272004-06-13 20:20:40 +00002282 return;
2283 }
2284 }
2285
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002286 // Now, just create the directory. If it already exists, it will fail
2287 // silently.
Bram Moolenaar071d4272004-06-13 20:20:40 +00002288 sprintf(vimfiles_path, "%s\\vimfiles", vimdir_path);
2289 vim_mkdir(vimfiles_path, 0755);
2290
2291 printf("Creating the following directories in \"%s\":\n", vimfiles_path);
2292 for (i = 0; i < TABLE_SIZE(vimfiles_subdirs); i++)
2293 {
2294 sprintf(tmp_dirname, "%s\\%s", vimfiles_path, vimfiles_subdirs[i]);
2295 printf(" %s", vimfiles_subdirs[i]);
2296 vim_mkdir(tmp_dirname, 0755);
2297 }
2298 printf("\n");
2299}
2300
2301/*
2302 * Add the creation of runtime files to the setup sequence.
2303 */
2304 static void
2305init_directories_choice(void)
2306{
2307 struct stat st;
2308 char tmp_dirname[BUFSIZE];
2309 char *p;
Bram Moolenaar25a494c2018-11-16 19:39:50 +01002310 int vimfiles_dir_choice;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002311
2312 choices[choice_count].text = alloc(150);
2313 choices[choice_count].changefunc = change_directories_choice;
2314 choices[choice_count].installfunc = install_vimfilesdir;
2315 choices[choice_count].active = 1;
2316
Bram Moolenaar25a494c2018-11-16 19:39:50 +01002317 // Check if the "compiler" directory already exists. That's a good
2318 // indication that the plugin directories were already created.
Bram Moolenaare4963c52019-02-22 19:41:08 +01002319 p = getenv("HOME");
2320 if (p != NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002321 {
2322 vimfiles_dir_choice = (int)vimfiles_dir_home;
Bram Moolenaare4963c52019-02-22 19:41:08 +01002323 sprintf(tmp_dirname, "%s\\vimfiles\\compiler", p);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002324 if (stat(tmp_dirname, &st) == 0)
2325 vimfiles_dir_choice = (int)vimfiles_dir_none;
2326 }
2327 else
2328 {
2329 vimfiles_dir_choice = (int)vimfiles_dir_vim;
2330 p = getenv("VIM");
Bram Moolenaar25a494c2018-11-16 19:39:50 +01002331 if (p == NULL) // No $VIM in path, use the install dir.
Bram Moolenaar071d4272004-06-13 20:20:40 +00002332 dir_remove_last(installdir, tmp_dirname);
2333 else
2334 strcpy(tmp_dirname, p);
2335 strcat(tmp_dirname, "\\vimfiles\\compiler");
2336 if (stat(tmp_dirname, &st) == 0)
2337 vimfiles_dir_choice = (int)vimfiles_dir_none;
2338 }
2339
Bram Moolenaar25a494c2018-11-16 19:39:50 +01002340 choices[choice_count].arg = vimfiles_dir_choice;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002341 set_directories_text(choice_count);
2342 ++choice_count;
2343}
2344
2345/*
2346 * Setup the choices and the default values.
2347 */
2348 static void
2349setup_choices(void)
2350{
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002351 // install the batch files
Bram Moolenaar071d4272004-06-13 20:20:40 +00002352 init_bat_choices();
2353
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002354 // (over) write _vimrc file
Bram Moolenaar071d4272004-06-13 20:20:40 +00002355 init_vimrc_choices();
2356
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002357 // Whether to add Vim to the popup menu
Bram Moolenaar071d4272004-06-13 20:20:40 +00002358 init_popup_choice();
2359
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002360 // Whether to add Vim to the "Open With..." menu
Bram Moolenaar071d4272004-06-13 20:20:40 +00002361 init_openwith_choice();
2362
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002363 // Whether to add Vim to the Start Menu.
Bram Moolenaar071d4272004-06-13 20:20:40 +00002364 init_startmenu_choice();
2365
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002366 // Whether to add shortcuts to the Desktop.
Bram Moolenaar071d4272004-06-13 20:20:40 +00002367 init_shortcut_choices();
2368
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002369 // Whether to create the runtime directories.
Bram Moolenaar071d4272004-06-13 20:20:40 +00002370 init_directories_choice();
2371}
2372
2373 static void
2374print_cmd_line_help(void)
2375{
2376 printf("Vim installer non-interactive command line arguments:\n");
2377 printf("\n");
2378 printf("-create-batfiles [vim gvim evim view gview vimdiff gvimdiff]\n");
2379 printf(" Create .bat files for Vim variants in the Windows directory.\n");
2380 printf("-create-vimrc\n");
2381 printf(" Create a default _vimrc file if one does not already exist.\n");
Bram Moolenaarc3fdf7f2017-10-28 18:36:48 +02002382 printf("-vimrc-remap [no|win]\n");
2383 printf(" Remap keys when creating a default _vimrc file.\n");
2384 printf("-vimrc-behave [unix|mswin|default]\n");
2385 printf(" Set mouse behavior when creating a default _vimrc file.\n");
Bram Moolenaar6cdb2c92018-10-13 17:25:27 +02002386 printf("-vimrc-compat [vi|vim|defaults|all]\n");
2387 printf(" Set Vi compatibility when creating a default _vimrc file.\n");
Bram Moolenaar071d4272004-06-13 20:20:40 +00002388 printf("-install-popup\n");
2389 printf(" Install the Edit-with-Vim context menu entry\n");
2390 printf("-install-openwith\n");
2391 printf(" Add Vim to the \"Open With...\" context menu list\n");
Bram Moolenaar071d4272004-06-13 20:20:40 +00002392 printf("-add-start-menu");
2393 printf(" Add Vim to the start menu\n");
2394 printf("-install-icons");
2395 printf(" Create icons for gVim executables on the desktop\n");
Bram Moolenaar071d4272004-06-13 20:20:40 +00002396 printf("-create-directories [vim|home]\n");
2397 printf(" Create runtime directories to drop plugins into; in the $VIM\n");
2398 printf(" or $HOME directory\n");
Bram Moolenaar071d4272004-06-13 20:20:40 +00002399 printf("-register-OLE");
Bram Moolenaarce0842a2005-07-18 21:58:11 +00002400 printf(" Ignored\n");
Bram Moolenaar071d4272004-06-13 20:20:40 +00002401 printf("\n");
2402}
2403
2404/*
2405 * Setup installation choices based on command line switches
2406 */
2407 static void
2408command_line_setup_choices(int argc, char **argv)
2409{
2410 int i, j;
2411
2412 for (i = 1; i < argc; i++)
2413 {
2414 if (strcmp(argv[i], "-create-batfiles") == 0)
2415 {
2416 if (i + 1 == argc)
2417 continue;
2418 while (argv[i + 1][0] != '-' && i < argc)
2419 {
2420 i++;
2421 for (j = 1; j < TARGET_COUNT; ++j)
2422 if ((targets[j].exenamearg[0] == 'g' ? has_gvim : has_vim)
2423 && strcmp(argv[i], targets[j].name) == 0)
2424 {
2425 init_bat_choice(j);
2426 break;
2427 }
2428 if (j == TARGET_COUNT)
2429 printf("%s is not a valid choice for -create-batfiles\n",
2430 argv[i]);
2431
2432 if (i + 1 == argc)
2433 break;
2434 }
2435 }
2436 else if (strcmp(argv[i], "-create-vimrc") == 0)
2437 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002438 // Setup default vimrc choices. If there is already a _vimrc file,
2439 // it will NOT be overwritten.
Bram Moolenaar071d4272004-06-13 20:20:40 +00002440 init_vimrc_choices();
2441 }
Bram Moolenaarc3fdf7f2017-10-28 18:36:48 +02002442 else if (strcmp(argv[i], "-vimrc-remap") == 0)
2443 {
2444 if (i + 1 == argc)
2445 break;
2446 i++;
2447 if (strcmp(argv[i], "no") == 0)
2448 remap_choice = remap_no;
2449 else if (strcmp(argv[i], "win") == 0)
2450 remap_choice = remap_win;
2451 }
2452 else if (strcmp(argv[i], "-vimrc-behave") == 0)
2453 {
2454 if (i + 1 == argc)
2455 break;
2456 i++;
2457 if (strcmp(argv[i], "unix") == 0)
2458 mouse_choice = mouse_xterm;
2459 else if (strcmp(argv[i], "mswin") == 0)
2460 mouse_choice = mouse_mswin;
2461 else if (strcmp(argv[i], "default") == 0)
2462 mouse_choice = mouse_default;
2463 }
Bram Moolenaar6cdb2c92018-10-13 17:25:27 +02002464 else if (strcmp(argv[i], "-vimrc-compat") == 0)
2465 {
2466 if (i + 1 == argc)
2467 break;
2468 i++;
2469 if (strcmp(argv[i], "vi") == 0)
2470 compat_choice = compat_vi;
2471 else if (strcmp(argv[i], "vim") == 0)
2472 compat_choice = compat_vim;
2473 else if (strcmp(argv[i], "defaults") == 0)
2474 compat_choice = compat_some_enhancements;
2475 else if (strcmp(argv[i], "all") == 0)
2476 compat_choice = compat_all_enhancements;
2477 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00002478 else if (strcmp(argv[i], "-install-popup") == 0)
2479 {
2480 init_popup_choice();
2481 }
2482 else if (strcmp(argv[i], "-install-openwith") == 0)
2483 {
2484 init_openwith_choice();
2485 }
2486 else if (strcmp(argv[i], "-add-start-menu") == 0)
2487 {
2488 init_startmenu_choice();
2489 }
2490 else if (strcmp(argv[i], "-install-icons") == 0)
2491 {
2492 init_shortcut_choices();
2493 }
2494 else if (strcmp(argv[i], "-create-directories") == 0)
2495 {
Bram Moolenaar142a9752018-12-14 19:54:39 +01002496 int vimfiles_dir_choice = (int)vimfiles_dir_none;
Bram Moolenaar25a494c2018-11-16 19:39:50 +01002497
Bram Moolenaar071d4272004-06-13 20:20:40 +00002498 init_directories_choice();
Cam Sinclair5c6edf42022-02-25 17:42:23 +00002499 if (i + 1 < argc && argv[i + 1][0] != '-')
Bram Moolenaar071d4272004-06-13 20:20:40 +00002500 {
2501 i++;
2502 if (strcmp(argv[i], "vim") == 0)
2503 vimfiles_dir_choice = (int)vimfiles_dir_vim;
2504 else if (strcmp(argv[i], "home") == 0)
2505 {
Bram Moolenaar25a494c2018-11-16 19:39:50 +01002506 if (homedir == NULL) // No $HOME in environment
2507 vimfiles_dir_choice = (int)vimfiles_dir_none;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002508 else
2509 vimfiles_dir_choice = (int)vimfiles_dir_home;
2510 }
2511 else
2512 {
2513 printf("Unknown argument for -create-directories: %s\n",
2514 argv[i]);
2515 print_cmd_line_help();
2516 }
2517 }
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002518 else // No choice specified, default to vim directory
Bram Moolenaar071d4272004-06-13 20:20:40 +00002519 vimfiles_dir_choice = (int)vimfiles_dir_vim;
Bram Moolenaar25a494c2018-11-16 19:39:50 +01002520 choices[choice_count - 1].arg = vimfiles_dir_choice;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002521 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00002522 else if (strcmp(argv[i], "-register-OLE") == 0)
2523 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002524 // This is always done when gvim is found
Bram Moolenaar071d4272004-06-13 20:20:40 +00002525 }
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002526 else // Unknown switch
Bram Moolenaar071d4272004-06-13 20:20:40 +00002527 {
2528 printf("Got unknown argument argv[%d] = %s\n", i, argv[i]);
2529 print_cmd_line_help();
2530 }
2531 }
2532}
2533
2534
2535/*
2536 * Show a few screens full of helpful information.
2537 */
2538 static void
2539show_help(void)
2540{
2541 static char *(items[]) =
2542 {
2543"Installing .bat files\n"
2544"---------------------\n"
2545"The vim.bat file is written in one of the directories in $PATH.\n"
2546"This makes it possible to start Vim from the command line.\n"
2547"If vim.exe can be found in $PATH, the choice for vim.bat will not be\n"
2548"present. It is assumed you will use the existing vim.exe.\n"
2549"If vim.bat can already be found in $PATH this is probably for an old\n"
2550"version of Vim (but this is not checked!). You can overwrite it.\n"
2551"If no vim.bat already exists, you can select one of the directories in\n"
2552"$PATH for creating the batch file, or disable creating a vim.bat file.\n"
2553"\n"
2554"If you choose not to create the vim.bat file, Vim can still be executed\n"
2555"in other ways, but not from the command line.\n"
2556"\n"
2557"The same applies to choices for gvim, evim, (g)view, and (g)vimdiff.\n"
2558"The first item can be used to change the path for all of them.\n"
2559,
2560"Creating a _vimrc file\n"
2561"----------------------\n"
2562"The _vimrc file is used to set options for how Vim behaves.\n"
2563"The install program can create a _vimrc file with a few basic choices.\n"
2564"You can edit this file later to tune your preferences.\n"
2565"If you already have a _vimrc or .vimrc file it can be overwritten.\n"
2566"Don't do that if you have made changes to it.\n"
2567,
2568"Vim features\n"
2569"------------\n"
2570"(this choice is only available when creating a _vimrc file)\n"
2571"1. Vim can run in Vi-compatible mode. Many nice Vim features are then\n"
Bram Moolenaar2b849492018-11-21 13:58:35 +01002572" disabled. Only choose Vi-compatible if you really need full Vi\n"
2573" compatibility.\n"
2574"2. Vim runs in not-Vi-compatible mode. Vim is still mostly Vi compatible,\n"
2575" but adds nice features like multi-level undo.\n"
2576"3. Running Vim with some enhancements is useful when you want some of\n"
Bram Moolenaar071d4272004-06-13 20:20:40 +00002577" the nice Vim features, but have a slow computer and want to keep it\n"
2578" really fast.\n"
Bram Moolenaar2b849492018-11-21 13:58:35 +01002579"4. Syntax highlighting shows many files in color. Not only does this look\n"
Bram Moolenaar071d4272004-06-13 20:20:40 +00002580" nice, it also makes it easier to spot errors and you can work faster.\n"
2581" The other features include editing compressed files.\n"
2582,
2583"Windows key mapping\n"
2584"-------------------\n"
2585"(this choice is only available when creating a _vimrc file)\n"
2586"Under MS-Windows the CTRL-C key copies text to the clipboard and CTRL-V\n"
2587"pastes text from the clipboard. There are a few more keys like these.\n"
2588"Unfortunately, in Vim these keys normally have another meaning.\n"
2589"1. Choose to have the keys like they normally are in Vim (useful if you\n"
2590" also use Vim on other systems).\n"
2591"2. Choose to have the keys work like they are used on MS-Windows (useful\n"
2592" if you mostly work on MS-Windows).\n"
2593,
2594"Mouse use\n"
2595"---------\n"
2596"(this choice is only available when creating a _vimrc file)\n"
2597"The right mouse button can be used in two ways:\n"
2598"1. The Unix way is to extend an existing selection. The popup menu is\n"
2599" not available.\n"
2600"2. The MS-Windows way is to show a popup menu, which allows you to\n"
2601" copy/paste text, undo/redo, etc. Extending the selection can still be\n"
2602" done by keeping SHIFT pressed while using the left mouse button\n"
2603,
2604"Edit-with-Vim context menu entry\n"
2605"--------------------------------\n"
2606"(this choice is only available when gvim.exe and gvimext.dll are present)\n"
2607"You can associate different file types with Vim, so that you can (double)\n"
2608"click on a file to edit it with Vim. This means you have to individually\n"
2609"select each file type.\n"
2610"An alternative is the option offered here: Install an \"Edit with Vim\"\n"
2611"entry in the popup menu for the right mouse button. This means you can\n"
2612"edit any file with Vim.\n"
2613,
2614"\"Open With...\" context menu entry\n"
2615"--------------------------------\n"
2616"(this choice is only available when gvim.exe is present)\n"
2617"This option adds Vim to the \"Open With...\" entry in the popup menu for\n"
2618"the right mouse button. This also makes it possible to edit HTML files\n"
2619"directly from Internet Explorer.\n"
2620,
2621"Add Vim to the Start menu\n"
2622"-------------------------\n"
2623"In Windows 95 and later, Vim can be added to the Start menu. This will\n"
2624"create a submenu with an entry for vim, gvim, evim, vimdiff, etc..\n"
2625,
2626"Icons on the desktop\n"
2627"--------------------\n"
2628"(these choices are only available when installing gvim)\n"
2629"In Windows 95 and later, shortcuts (icons) can be created on the Desktop.\n"
2630,
2631"Create plugin directories\n"
2632"-------------------------\n"
2633"Plugin directories allow extending Vim by dropping a file into a directory.\n"
2634"This choice allows creating them in $HOME (if you have a home directory) or\n"
2635"$VIM (used for everybody on the system).\n"
2636,
2637NULL
2638 };
2639 int i;
2640 int c;
2641
2642 rewind(stdin);
2643 printf("\n");
2644 for (i = 0; items[i] != NULL; ++i)
2645 {
Bram Moolenaarc3fdf7f2017-10-28 18:36:48 +02002646 puts(items[i]);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002647 printf("Hit Enter to continue, b (back) or q (quit help): ");
2648 c = getchar();
2649 rewind(stdin);
2650 if (c == 'b' || c == 'B')
2651 {
2652 if (i == 0)
2653 --i;
2654 else
2655 i -= 2;
2656 }
2657 if (c == 'q' || c == 'Q')
2658 break;
2659 printf("\n");
2660 }
2661}
2662
2663/*
2664 * Install the choices.
2665 */
2666 static void
2667install(void)
2668{
2669 int i;
2670
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002671 // Install the selected choices.
Bram Moolenaar071d4272004-06-13 20:20:40 +00002672 for (i = 0; i < choice_count; ++i)
2673 if (choices[i].installfunc != NULL && choices[i].active)
2674 (choices[i].installfunc)(i);
2675
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002676 // Add some entries to the registry, if needed.
Bram Moolenaar071d4272004-06-13 20:20:40 +00002677 if (install_popup
2678 || install_openwith
2679 || (need_uninstall_entry && interactive)
2680 || !interactive)
2681 install_registry();
2682
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002683 // Register gvim with OLE.
Bram Moolenaar071d4272004-06-13 20:20:40 +00002684 if (has_gvim)
2685 install_OLE_register();
Bram Moolenaar071d4272004-06-13 20:20:40 +00002686}
2687
2688/*
2689 * request_choice
2690 */
2691 static void
2692request_choice(void)
2693{
2694 int i;
2695
2696 printf("\n\nInstall will do for you:\n");
2697 for (i = 0; i < choice_count; ++i)
Yegappan Lakshmanane89aef32025-05-14 20:31:55 +02002698 if (choices[i].active)
2699 printf("%2d %s\n", i + 1, choices[i].text);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002700 printf("To change an item, enter its number\n\n");
2701 printf("Enter item number, h (help), d (do it) or q (quit): ");
2702}
2703
2704 int
2705main(int argc, char **argv)
2706{
2707 int i;
2708 char buf[BUFSIZE];
2709
2710 /*
2711 * Run interactively if there are no command line arguments.
2712 */
2713 if (argc > 1)
2714 interactive = 0;
2715 else
2716 interactive = 1;
2717
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002718 // Initialize this program.
Bram Moolenaar071d4272004-06-13 20:20:40 +00002719 do_inits(argv);
Bram Moolenaar25a494c2018-11-16 19:39:50 +01002720 init_homedir();
Bram Moolenaar071d4272004-06-13 20:20:40 +00002721
Bram Moolenaar071d4272004-06-13 20:20:40 +00002722 if (argc > 1 && strcmp(argv[1], "-uninstall-check") == 0)
2723 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002724 // Only check for already installed Vims. Used by NSIS installer.
Bram Moolenaar442b4222010-05-24 21:34:22 +02002725 i = uninstall_check(1);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002726
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002727 // Find the value of $VIM, because NSIS isn't able to do this by
2728 // itself.
Bram Moolenaar071d4272004-06-13 20:20:40 +00002729 get_vim_env();
2730
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002731 // When nothing found exit quietly. If something found wait for
2732 // a little while, so that the user can read the messages.
Bram Moolenaar6cdb2c92018-10-13 17:25:27 +02002733 if (i && _isatty(1))
Bram Moolenaarab8205e2010-07-07 15:14:03 +02002734 sleep(3);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002735 exit(0);
2736 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00002737
2738 printf("This program sets up the installation of Vim "
2739 VIM_VERSION_MEDIUM "\n\n");
2740
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002741 // Check if the user unpacked the archives properly.
Bram Moolenaar071d4272004-06-13 20:20:40 +00002742 check_unpack();
2743
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002744 // Check for already installed Vims.
Bram Moolenaar071d4272004-06-13 20:20:40 +00002745 if (interactive)
Bram Moolenaar442b4222010-05-24 21:34:22 +02002746 uninstall_check(0);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002747
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002748 // Find out information about the system.
Bram Moolenaar071d4272004-06-13 20:20:40 +00002749 inspect_system();
2750
2751 if (interactive)
2752 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002753 // Setup all the choices.
Bram Moolenaar071d4272004-06-13 20:20:40 +00002754 setup_choices();
2755
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002756 // Let the user change choices and finally install (or quit).
Bram Moolenaar071d4272004-06-13 20:20:40 +00002757 for (;;)
2758 {
2759 request_choice();
2760 rewind(stdin);
2761 if (scanf("%99s", buf) == 1)
2762 {
Keith Thompson184f71c2024-01-04 21:19:04 +01002763 if (isdigit((unsigned char)buf[0]))
Bram Moolenaar071d4272004-06-13 20:20:40 +00002764 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002765 // Change a choice.
Bram Moolenaar071d4272004-06-13 20:20:40 +00002766 i = atoi(buf);
2767 if (i > 0 && i <= choice_count && choices[i - 1].active)
2768 (choices[i - 1].changefunc)(i - 1);
2769 else
2770 printf("\nIllegal choice\n");
2771 }
2772 else if (buf[0] == 'h' || buf[0] == 'H')
2773 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002774 // Help
Bram Moolenaar071d4272004-06-13 20:20:40 +00002775 show_help();
2776 }
2777 else if (buf[0] == 'd' || buf[0] == 'D')
2778 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002779 // Install!
Bram Moolenaar071d4272004-06-13 20:20:40 +00002780 install();
2781 printf("\nThat finishes the installation. Happy Vimming!\n");
2782 break;
2783 }
2784 else if (buf[0] == 'q' || buf[0] == 'Q')
2785 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002786 // Quit
Bram Moolenaar071d4272004-06-13 20:20:40 +00002787 printf("\nExiting without anything done\n");
2788 break;
2789 }
2790 else
2791 printf("\nIllegal choice\n");
2792 }
2793 }
2794 printf("\n");
Bram Moolenaar442b4222010-05-24 21:34:22 +02002795 myexit(0);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002796 }
2797 else
2798 {
2799 /*
2800 * Run non-interactive - setup according to the command line switches
2801 */
2802 command_line_setup_choices(argc, argv);
2803 install();
Bram Moolenaar442b4222010-05-24 21:34:22 +02002804
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002805 // Avoid that the user has to hit Enter, just wait a little bit to
2806 // allow reading the messages.
Bram Moolenaarab8205e2010-07-07 15:14:03 +02002807 sleep(2);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002808 }
2809
Bram Moolenaar071d4272004-06-13 20:20:40 +00002810 return 0;
2811}