blob: 8ef72f6f216a7b9de0c12abde2e1597a37393b80 [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 *
13 * Compile with Make_mvc.mak, Make_bc3.mak, Make_bc5.mak or Make_djg.mak.
14 */
15
16/*
17 * Include common code for dosinst.c and uninstal.c.
18 */
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 Moolenaar071d4272004-06-13 20:20:40 +000026/* 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
36int has_vim = 0; /* installable vim.exe exists */
37int has_gvim = 0; /* installable gvim.exe exists */
38
39char oldvimrc[BUFSIZE]; /* name of existing vimrc file */
40char vimrc[BUFSIZE]; /* name of vimrc file to create */
41
42char *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{
52 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 */
57};
58
59struct choice choices[30]; /* choices the user can make */
60int choice_count = 0; /* number of choices available */
61
62#define TABLE_SIZE(s) (int)(sizeof(s) / sizeof(*s))
63
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
126/* non-zero when selected to install the popup menu entry. */
127static int install_popup = 0;
128
129/* non-zero when selected to install the "Open with" entry. */
130static int install_openwith = 0;
131
132/* non-zero when need to add an uninstall entry in the registry */
133static 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
194 /* check for presence of the correct version number in installdir[] */
195 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
207 /* check if filetype.vim is present, which means the runtime archive has
208 * been unpacked */
209 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");
214 printf("You must unpack the runtime archive \"vim%srt.zip\" before installing.\n",
215 VIM_VERSION_NODOT + 3);
216 myexit(1);
217 }
218
219 /* Check if vim.exe or gvim.exe is in the current directory. */
220 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 {
254 /* End of "p": check if "q" also ends or just has a slash. */
255 if (i == plen)
256 {
257 if (i == qlen) /* match */
258 return 0;
259 if (i == qlen - 1 && (q[i] == '\\' || q[i] == '/'))
260 return 0; /* match with trailing slash */
261 return 1; /* no match */
262 }
263
264 /* End of "q": check if "p" also ends or just has a slash. */
265 if (i == qlen)
266 {
267 if (i == plen) /* match */
268 return 0;
269 if (i == plen - 1 && (p[i] == '\\' || p[i] == '/'))
270 return 0; /* match with trailing slash */
271 return 1; /* no match */
272 }
273
274 if (!(mytoupper(p[i]) == mytoupper(q[i])
275 || ((p[i] == '/' || p[i] == '\\')
276 && (q[i] == '/' || q[i] == '\\'))))
277 return 1; /* no match */
278 }
279 /*NOTREACHED*/
280}
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
309 tmpname = alloc((int)strlen(cp) + 1);
310 strcpy(tmpname, cp);
311 tmpname[strlen(tmpname) - 1] = 'x'; /* .exe -> .exx */
312
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 Moolenaar42bbef42006-03-25 22:02:07 +0000350 /* avoid looking in the "installdir" by chdir to system root */
351 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
389 /* First get $VIMRUNTIME. If it's set, remove the tail. */
390 vim = getenv("VIMRUNTIME");
Bram Moolenaar181ace22013-02-13 14:36:44 +0100391 if (vim != NULL && *vim != 0 && strlen(vim) < BUFSIZE)
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 {
402 /* Use the directory from an old uninstall entry. */
403 if (default_vim_dir != NULL)
404 vim = default_vim_dir;
405 else
406 /* Let NSIS know there is no default, it should use
Bram Moolenaarb8017e72007-05-10 18:59:07 +0000407 * $PROGRAMFILES. */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000408 vim = "";
409 }
410 }
411
412 /* NSIS also uses GetTempPath(), thus we should get the same directory
413 * name as where NSIS will look for vimini.ini. */
414 GetTempPath(BUFSIZE, fname);
415 add_pathsep(fname);
416 strcat(fname, "vimini.ini");
417
418 fd = fopen(fname, "w");
419 if (fd != NULL)
420 {
421 /* Make it look like an .ini file, so that NSIS can read it with a
422 * ReadINIStr command. */
423 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 */
440/*ARGSUSED*/
441 static BOOL CALLBACK
442window_cb(HWND hwnd, LPARAM lparam)
443{
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 Moolenaarbbd854d2019-02-18 22:19:33 +0100459 char vimrt_dir[MAX_PATH];
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
472 /* Copy the uninstaller to a temporary exe. */
473 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
486 /* Run the copied uninstaller silently. */
487 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 Moolenaar071d4272004-06-13 20:20:40 +0000509 DWORD local_bufsize = BUFSIZE;
510 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
524 for (key_index = 0;
525 RegEnumKeyEx(key_handle, key_index, subkey_name_buff, &local_bufsize,
526 NULL, NULL, NULL, &temp_pfiletime) != ERROR_NO_MORE_ITEMS;
527 key_index++)
528 {
529 local_bufsize = BUFSIZE;
530 if (strncmp("Vim", subkey_name_buff, 3) == 0)
531 {
532 /* Open the key named Vim* */
Bram Moolenaar760d14a2010-07-31 22:03:44 +0200533 code = RegOpenKeyEx(key_handle, subkey_name_buff, 0,
534 KEY_WOW64_64KEY | KEY_READ, &uninstall_key_handle);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000535 CHECK_REG_ERROR(code);
536
537 /* get the DisplayName out of it to show the user */
538 code = RegQueryValueEx(uninstall_key_handle, "displayname", 0,
539 &value_type, (LPBYTE)temp_string_buffer,
540 &local_bufsize);
541 local_bufsize = BUFSIZE;
542 CHECK_REG_ERROR(code);
543
Bram Moolenaaraf610b82018-12-21 16:22:50 +0100544 allow_silent = 0;
545 if (skip_question)
546 {
547 DWORD varsize = sizeof(DWORD);
548
549 RegQueryValueEx(uninstall_key_handle, "AllowSilent", 0,
550 &value_type, (LPBYTE)&allow_silent,
551 &varsize);
552 }
553
Bram Moolenaar071d4272004-06-13 20:20:40 +0000554 foundone = 1;
555 printf("\n*********************************************************\n");
556 printf("Vim Install found what looks like an existing Vim version.\n");
557 printf("The name of the entry is:\n");
558 printf("\n \"%s\"\n\n", temp_string_buffer);
559
560 printf("Installing the new version will disable part of the existing version.\n");
561 printf("(The batch files used in a console and the \"Edit with Vim\" entry in\n");
562 printf("the popup menu will use the new version)\n");
563
Bram Moolenaar442b4222010-05-24 21:34:22 +0200564 if (skip_question)
565 printf("\nRunning uninstall program for \"%s\"\n", temp_string_buffer);
566 else
567 printf("\nDo you want to uninstall \"%s\" now?\n(y)es/(n)o) ", temp_string_buffer);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000568 fflush(stdout);
569
570 /* get the UninstallString */
571 code = RegQueryValueEx(uninstall_key_handle, "uninstallstring", 0,
572 &value_type, (LPBYTE)temp_string_buffer, &local_bufsize);
573 local_bufsize = BUFSIZE;
574 CHECK_REG_ERROR(code);
575
576 /* Remember the directory, it is used as the default for NSIS. */
577 default_vim_dir = alloc(strlen(temp_string_buffer) + 1);
578 strcpy(default_vim_dir, temp_string_buffer);
579 remove_tail(default_vim_dir);
580 remove_tail(default_vim_dir);
581
582 input = 'n';
583 do
584 {
585 if (input != 'n')
586 printf("%c is an invalid reply. Please enter either 'y' or 'n'\n", input);
587
Bram Moolenaar442b4222010-05-24 21:34:22 +0200588 if (skip_question)
589 input = 'y';
590 else
591 {
592 rewind(stdin);
593 scanf("%c", &input);
594 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000595 switch (input)
596 {
597 case 'y':
598 case 'Y':
599 /* save the number of uninstall keys so we can know if
600 * it changed */
601 RegQueryInfoKey(key_handle, NULL, NULL, NULL,
602 &orig_num_keys, NULL, NULL, NULL,
603 NULL, NULL, NULL, NULL);
604
Bram Moolenaar442b4222010-05-24 21:34:22 +0200605 /* Find existing .bat files before deleting them. */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000606 find_bat_exe(TRUE);
607
Bram Moolenaaraf610b82018-12-21 16:22:50 +0100608 if (allow_silent)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000609 {
Bram Moolenaaraf610b82018-12-21 16:22:50 +0100610 if (run_silent_uninstall(temp_string_buffer)
611 == FAIL)
612 allow_silent = 0; /* Retry with non silent. */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000613 }
Bram Moolenaaraf610b82018-12-21 16:22:50 +0100614 if (!allow_silent)
Bram Moolenaarb230bd52010-05-25 21:02:00 +0200615 {
Bram Moolenaaraf610b82018-12-21 16:22:50 +0100616 /* Execute the uninstall program. Put it in double
617 * quotes if there is an embedded space. */
Bram Moolenaarb230bd52010-05-25 21:02:00 +0200618 {
Bram Moolenaaraf610b82018-12-21 16:22:50 +0100619 char buf[BUFSIZE];
620
621 if (strchr(temp_string_buffer, ' ') != NULL)
622 sprintf(buf, "\"%s\"", temp_string_buffer);
623 else
624 strcpy(buf, temp_string_buffer);
625 run_command(buf);
626 }
627
628 /* Count the number of windows with a title that match
629 * the installer, so that we can check when it's done.
630 * The uninstaller copies itself, executes the copy
631 * and exits, thus we can't wait for the process to
632 * finish. */
633 sleep(1); /* wait for uninstaller to start up */
634 num_windows = 0;
635 EnumWindows(window_cb, 0);
636 if (num_windows == 0)
637 {
638 /* Did not find the uninstaller, ask user to press
639 * Enter when done. Just in case. */
640 printf("Press Enter when the uninstaller is finished\n");
641 rewind(stdin);
642 (void)getchar();
643 }
644 else
645 {
646 printf("Waiting for the uninstaller to finish (press CTRL-C to abort).");
647 do
648 {
649 printf(".");
650 fflush(stdout);
651 sleep(1); /* wait for the uninstaller to finish */
652 num_windows = 0;
653 EnumWindows(window_cb, 0);
654 } while (num_windows > 0);
655 }
Bram Moolenaarb230bd52010-05-25 21:02:00 +0200656 }
657 printf("\nDone!\n");
Bram Moolenaar071d4272004-06-13 20:20:40 +0000658
Bram Moolenaarfff2bee2010-05-15 13:56:02 +0200659 /* Check if an uninstall reg key was deleted.
Bram Moolenaar071d4272004-06-13 20:20:40 +0000660 * if it was, we want to decrement key_index.
661 * if we don't do this, we will skip the key
662 * immediately after any key that we delete. */
663 RegQueryInfoKey(key_handle, NULL, NULL, NULL,
664 &new_num_keys, NULL, NULL, NULL,
665 NULL, NULL, NULL, NULL);
666 if (new_num_keys < orig_num_keys)
667 key_index--;
668
669 input = 'y';
670 break;
671
672 case 'n':
673 case 'N':
674 /* Do not uninstall */
675 input = 'n';
676 break;
677
678 default: /* just drop through and redo the loop */
679 break;
680 }
681
682 } while (input != 'n' && input != 'y');
683
684 RegCloseKey(uninstall_key_handle);
685 }
686 }
687 RegCloseKey(key_handle);
688
689 return foundone;
690}
Bram Moolenaar071d4272004-06-13 20:20:40 +0000691
692/*
693 * Find out information about the system.
694 */
695 static void
696inspect_system(void)
697{
698 char *p;
699 char buf[BUFSIZE];
700 FILE *fd;
701 int i;
702 int foundone;
703
704 /* This may take a little while, let the user know what we're doing. */
705 printf("Inspecting system...\n");
706
707 /*
708 * If $VIM is set, check that it's pointing to our directory.
709 */
710 p = getenv("VIM");
711 if (p != NULL && pathcmp(p, -1, installdir, runtimeidx - 1) != 0)
712 {
713 printf("------------------------------------------------------\n");
714 printf("$VIM is set to \"%s\".\n", p);
715 printf("This is different from where this version of Vim is:\n");
716 strcpy(buf, installdir);
717 *(buf + runtimeidx - 1) = NUL;
718 printf("\"%s\"\n", buf);
719 printf("You must adjust or remove the setting of $VIM,\n");
720 if (interactive)
721 {
722 printf("to be able to use this install program.\n");
723 myexit(1);
724 }
725 printf("otherwise Vim WILL NOT WORK properly!\n");
726 printf("------------------------------------------------------\n");
727 }
728
729 /*
730 * If $VIMRUNTIME is set, check that it's pointing to our runtime directory.
731 */
732 p = getenv("VIMRUNTIME");
733 if (p != NULL && pathcmp(p, -1, installdir, -1) != 0)
734 {
735 printf("------------------------------------------------------\n");
736 printf("$VIMRUNTIME is set to \"%s\".\n", p);
737 printf("This is different from where this version of Vim is:\n");
738 printf("\"%s\"\n", installdir);
739 printf("You must adjust or remove the setting of $VIMRUNTIME,\n");
740 if (interactive)
741 {
742 printf("to be able to use this install program.\n");
743 myexit(1);
744 }
745 printf("otherwise Vim WILL NOT WORK properly!\n");
746 printf("------------------------------------------------------\n");
747 }
748
749 /*
750 * Check if there is a vim.[exe|bat|, gvim.[exe|bat|, etc. in the path.
751 */
752 find_bat_exe(FALSE);
753
754 /*
755 * A .exe in the install directory may be found anyway on Windows 2000.
756 * Check for this situation and find another executable if necessary.
757 * w.briscoe@ponl.com 2001-01-20
758 */
759 foundone = 0;
760 for (i = 1; i < TARGET_COUNT; ++i)
761 {
762 findoldfile(&(targets[i].oldexe));
763 if (targets[i].oldexe != NULL)
764 foundone = 1;
765 }
766
767 if (foundone)
768 {
769 printf("Warning: Found Vim executable(s) in your $PATH:\n");
770 for (i = 1; i < TARGET_COUNT; ++i)
771 if (targets[i].oldexe != NULL)
772 printf("%s\n", targets[i].oldexe);
773 printf("It will be used instead of the version you are installing.\n");
774 printf("Please delete or rename it, or adjust your $PATH setting.\n");
775 }
776
777 /*
778 * Check if there is an existing ../_vimrc or ../.vimrc file.
779 */
780 strcpy(oldvimrc, installdir);
781 strcpy(oldvimrc + runtimeidx, "_vimrc");
782 if ((fd = fopen(oldvimrc, "r")) == NULL)
783 {
784 strcpy(oldvimrc + runtimeidx, "vimrc~1"); /* short version of .vimrc */
785 if ((fd = fopen(oldvimrc, "r")) == NULL)
786 {
787 strcpy(oldvimrc + runtimeidx, ".vimrc");
788 fd = fopen(oldvimrc, "r");
789 }
790 }
791 if (fd != NULL)
792 fclose(fd);
793 else
794 *oldvimrc = NUL;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000795}
796
797/*
798 * Add a dummy choice to avoid that the numbering changes depending on items
799 * in the environment. The user may type a number he remembered without
800 * looking.
801 */
802 static void
803add_dummy_choice(void)
804{
805 choices[choice_count].installfunc = NULL;
806 choices[choice_count].active = 0;
807 choices[choice_count].changefunc = NULL;
Bram Moolenaar25a494c2018-11-16 19:39:50 +0100808 choices[choice_count].text = NULL;
809 choices[choice_count].arg = 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000810 ++choice_count;
811}
812
813/***********************************************
814 * stuff for creating the batch files.
815 */
816
817/*
818 * Install the vim.bat, gvim.bat, etc. files.
819 */
820 static void
821install_bat_choice(int idx)
822{
823 char *batpath = targets[choices[idx].arg].batpath;
824 char *oldname = targets[choices[idx].arg].oldbat;
825 char *exename = targets[choices[idx].arg].exenamearg;
826 char *vimarg = targets[choices[idx].arg].exearg;
827 FILE *fd;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000828
829 if (*batpath != NUL)
830 {
831 fd = fopen(batpath, "w");
832 if (fd == NULL)
833 printf("\nERROR: Cannot open \"%s\" for writing.\n", batpath);
834 else
835 {
836 need_uninstall_entry = 1;
837
838 fprintf(fd, "@echo off\n");
Bram Moolenaar97b2ad32006-03-18 21:40:56 +0000839 fprintf(fd, "rem -- Run Vim --\n");
840 fprintf(fd, "\n");
Bram Moolenaare609ad52016-03-28 23:05:48 +0200841 fprintf(fd, "setlocal\n");
Bram Moolenaar071d4272004-06-13 20:20:40 +0000842
Bram Moolenaar97b2ad32006-03-18 21:40:56 +0000843 /* Don't use double quotes for the "set" argument, also when it
Bram Moolenaar071d4272004-06-13 20:20:40 +0000844 * contains a space. The quotes would be included in the value
Bram Moolenaar97b2ad32006-03-18 21:40:56 +0000845 * for MSDOS and NT.
846 * The order of preference is:
847 * 1. $VIMRUNTIME/vim.exe (user preference)
848 * 2. $VIM/vim70/vim.exe (hard coded version)
849 * 3. installdir/vim.exe (hard coded install directory)
850 */
851 fprintf(fd, "set VIM_EXE_DIR=%s\n", installdir);
852 fprintf(fd, "if exist \"%%VIM%%\\%s\\%s\" set VIM_EXE_DIR=%%VIM%%\\%s\n",
853 VIM_VERSION_NODOT, exename, VIM_VERSION_NODOT);
854 fprintf(fd, "if exist \"%%VIMRUNTIME%%\\%s\" set VIM_EXE_DIR=%%VIMRUNTIME%%\n", exename);
855 fprintf(fd, "\n");
Bram Moolenaar071d4272004-06-13 20:20:40 +0000856
857 /* Give an error message when the executable could not be found. */
Bram Moolenaar97b2ad32006-03-18 21:40:56 +0000858 fprintf(fd, "if exist \"%%VIM_EXE_DIR%%\\%s\" goto havevim\n",
859 exename);
860 fprintf(fd, "echo \"%%VIM_EXE_DIR%%\\%s\" not found\n", exename);
861 fprintf(fd, "goto eof\n");
862 fprintf(fd, "\n");
Bram Moolenaar071d4272004-06-13 20:20:40 +0000863 fprintf(fd, ":havevim\n");
864
865 fprintf(fd, "rem collect the arguments in VIMARGS for Win95\n");
866 fprintf(fd, "set VIMARGS=\n");
867 if (*exename == 'g')
868 fprintf(fd, "set VIMNOFORK=\n");
869 fprintf(fd, ":loopstart\n");
870 fprintf(fd, "if .%%1==. goto loopend\n");
871 if (*exename == 'g')
872 {
Bram Moolenaare609ad52016-03-28 23:05:48 +0200873 fprintf(fd, "if NOT .%%1==.--nofork goto noforklongarg\n");
874 fprintf(fd, "set VIMNOFORK=1\n");
875 fprintf(fd, ":noforklongarg\n");
Bram Moolenaar071d4272004-06-13 20:20:40 +0000876 fprintf(fd, "if NOT .%%1==.-f goto noforkarg\n");
877 fprintf(fd, "set VIMNOFORK=1\n");
878 fprintf(fd, ":noforkarg\n");
879 }
880 fprintf(fd, "set VIMARGS=%%VIMARGS%% %%1\n");
881 fprintf(fd, "shift\n");
Bram Moolenaar97b2ad32006-03-18 21:40:56 +0000882 fprintf(fd, "goto loopstart\n");
Bram Moolenaar071d4272004-06-13 20:20:40 +0000883 fprintf(fd, ":loopend\n");
Bram Moolenaar97b2ad32006-03-18 21:40:56 +0000884 fprintf(fd, "\n");
Bram Moolenaar071d4272004-06-13 20:20:40 +0000885
Bram Moolenaar97b2ad32006-03-18 21:40:56 +0000886 fprintf(fd, "if .%%OS%%==.Windows_NT goto ntaction\n");
887 fprintf(fd, "\n");
Bram Moolenaar071d4272004-06-13 20:20:40 +0000888
889 /* For gvim.exe use "start" to avoid that the console window stays
890 * open. */
891 if (*exename == 'g')
892 {
893 fprintf(fd, "if .%%VIMNOFORK%%==.1 goto nofork\n");
894 fprintf(fd, "start ");
895 }
896
Bram Moolenaar97b2ad32006-03-18 21:40:56 +0000897 /* Always use quotes, $VIM or $VIMRUNTIME might have a space. */
898 fprintf(fd, "\"%%VIM_EXE_DIR%%\\%s\" %s %%VIMARGS%%\n",
899 exename, vimarg);
900 fprintf(fd, "goto eof\n");
901 fprintf(fd, "\n");
Bram Moolenaar071d4272004-06-13 20:20:40 +0000902
903 if (*exename == 'g')
904 {
905 fprintf(fd, ":nofork\n");
906 fprintf(fd, "start /w ");
Bram Moolenaar97b2ad32006-03-18 21:40:56 +0000907 /* Always use quotes, $VIM or $VIMRUNTIME might have a space. */
908 fprintf(fd, "\"%%VIM_EXE_DIR%%\\%s\" %s %%VIMARGS%%\n",
909 exename, vimarg);
910 fprintf(fd, "goto eof\n");
911 fprintf(fd, "\n");
Bram Moolenaar071d4272004-06-13 20:20:40 +0000912 }
913
914 fprintf(fd, ":ntaction\n");
915 fprintf(fd, "rem for WinNT we can use %%*\n");
916
917 /* For gvim.exe use "start /b" to avoid that the console window
918 * stays open. */
919 if (*exename == 'g')
920 {
921 fprintf(fd, "if .%%VIMNOFORK%%==.1 goto noforknt\n");
922 fprintf(fd, "start \"dummy\" /b ");
923 }
924
Bram Moolenaar97b2ad32006-03-18 21:40:56 +0000925 /* Always use quotes, $VIM or $VIMRUNTIME might have a space. */
926 fprintf(fd, "\"%%VIM_EXE_DIR%%\\%s\" %s %%*\n", exename, vimarg);
927 fprintf(fd, "goto eof\n");
928 fprintf(fd, "\n");
Bram Moolenaar071d4272004-06-13 20:20:40 +0000929
930 if (*exename == 'g')
931 {
932 fprintf(fd, ":noforknt\n");
933 fprintf(fd, "start \"dummy\" /b /wait ");
Bram Moolenaar97b2ad32006-03-18 21:40:56 +0000934 /* Always use quotes, $VIM or $VIMRUNTIME might have a space. */
935 fprintf(fd, "\"%%VIM_EXE_DIR%%\\%s\" %s %%*\n",
936 exename, vimarg);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000937 }
938
939 fprintf(fd, "\n:eof\n");
940 fprintf(fd, "set VIMARGS=\n");
941 if (*exename == 'g')
942 fprintf(fd, "set VIMNOFORK=\n");
943
944 fclose(fd);
945 printf("%s has been %s\n", batpath,
946 oldname == NULL ? "created" : "overwritten");
947 }
948 }
949}
950
951/*
952 * Make the text string for choice "idx".
953 * The format "fmt" is must have one %s item, which "arg" is used for.
954 */
955 static void
956alloc_text(int idx, char *fmt, char *arg)
957{
958 if (choices[idx].text != NULL)
959 free(choices[idx].text);
960
961 choices[idx].text = alloc((int)(strlen(fmt) + strlen(arg)) - 1);
962 sprintf(choices[idx].text, fmt, arg);
963}
964
965/*
966 * Toggle the "Overwrite .../vim.bat" to "Don't overwrite".
967 */
968 static void
969toggle_bat_choice(int idx)
970{
971 char *batname = targets[choices[idx].arg].batpath;
972 char *oldname = targets[choices[idx].arg].oldbat;
973
974 if (*batname == NUL)
975 {
976 alloc_text(idx, " Overwrite %s", oldname);
977 strcpy(batname, oldname);
978 }
979 else
980 {
981 alloc_text(idx, " Do NOT overwrite %s", oldname);
982 *batname = NUL;
983 }
984}
985
986/*
987 * Do some work for a batch file entry: Append the batch file name to the path
988 * and set the text for the choice.
989 */
990 static void
991set_bat_text(int idx, char *batpath, char *name)
992{
993 strcat(batpath, name);
994
995 alloc_text(idx, " Create %s", batpath);
996}
997
998/*
999 * Select a directory to write the batch file line.
1000 */
1001 static void
1002change_bat_choice(int idx)
1003{
1004 char *path;
1005 char *batpath;
1006 char *name;
1007 int n;
1008 char *s;
1009 char *p;
1010 int count;
1011 char **names = NULL;
1012 int i;
1013 int target = choices[idx].arg;
1014
1015 name = targets[target].batname;
1016 batpath = targets[target].batpath;
1017
1018 path = getenv("PATH");
1019 if (path == NULL)
1020 {
1021 printf("\nERROR: The variable $PATH is not set\n");
1022 return;
1023 }
1024
1025 /*
1026 * first round: count number of names in path;
1027 * second round: save names to names[].
1028 */
1029 for (;;)
1030 {
1031 count = 1;
1032 for (p = path; *p; )
1033 {
1034 s = strchr(p, ';');
1035 if (s == NULL)
1036 s = p + strlen(p);
1037 if (names != NULL)
1038 {
1039 names[count] = alloc((int)(s - p) + 1);
1040 strncpy(names[count], p, s - p);
1041 names[count][s - p] = NUL;
1042 }
1043 ++count;
1044 p = s;
1045 if (*p != NUL)
1046 ++p;
1047 }
1048 if (names != NULL)
1049 break;
1050 names = alloc((int)(count + 1) * sizeof(char *));
1051 }
1052 names[0] = alloc(50);
1053 sprintf(names[0], "Select directory to create %s in:", name);
1054 names[count] = alloc(50);
1055 if (choices[idx].arg == 0)
1056 sprintf(names[count], "Do not create any .bat file.");
1057 else
1058 sprintf(names[count], "Do not create a %s file.", name);
1059 n = get_choice(names, count + 1);
1060
1061 if (n == count)
1062 {
1063 /* Selected last item, don't create bat file. */
1064 *batpath = NUL;
1065 if (choices[idx].arg != 0)
1066 alloc_text(idx, " Do NOT create %s", name);
1067 }
1068 else
1069 {
1070 /* Selected one of the paths. For the first item only keep the path,
1071 * for the others append the batch file name. */
1072 strcpy(batpath, names[n]);
1073 add_pathsep(batpath);
1074 if (choices[idx].arg != 0)
1075 set_bat_text(idx, batpath, name);
1076 }
1077
1078 for (i = 0; i <= count; ++i)
1079 free(names[i]);
1080 free(names);
1081}
1082
1083char *bat_text_yes = "Install .bat files to use Vim at the command line:";
1084char *bat_text_no = "do NOT install .bat files to use Vim at the command line";
1085
1086 static void
1087change_main_bat_choice(int idx)
1088{
1089 int i;
1090
1091 /* let the user select a default directory or NONE */
1092 change_bat_choice(idx);
1093
1094 if (targets[0].batpath[0] != NUL)
1095 choices[idx].text = bat_text_yes;
1096 else
1097 choices[idx].text = bat_text_no;
1098
1099 /* update the individual batch file selections */
1100 for (i = 1; i < TARGET_COUNT; ++i)
1101 {
1102 /* Only make it active when the first item has a path and the vim.exe
1103 * or gvim.exe exists (there is a changefunc then). */
1104 if (targets[0].batpath[0] != NUL
1105 && choices[idx + i].changefunc != NULL)
1106 {
1107 choices[idx + i].active = 1;
1108 if (choices[idx + i].changefunc == change_bat_choice
1109 && targets[i].batpath[0] != NUL)
1110 {
1111 strcpy(targets[i].batpath, targets[0].batpath);
1112 set_bat_text(idx + i, targets[i].batpath, targets[i].batname);
1113 }
1114 }
1115 else
1116 choices[idx + i].active = 0;
1117 }
1118}
1119
1120/*
1121 * Initialize a choice for creating a batch file.
1122 */
1123 static void
1124init_bat_choice(int target)
1125{
1126 char *batpath = targets[target].batpath;
1127 char *oldbat = targets[target].oldbat;
1128 char *p;
1129 int i;
1130
1131 choices[choice_count].arg = target;
1132 choices[choice_count].installfunc = install_bat_choice;
1133 choices[choice_count].active = 1;
1134 choices[choice_count].text = NULL; /* will be set below */
1135 if (oldbat != NULL)
1136 {
1137 /* A [g]vim.bat exists: Only choice is to overwrite it or not. */
1138 choices[choice_count].changefunc = toggle_bat_choice;
1139 *batpath = NUL;
1140 toggle_bat_choice(choice_count);
1141 }
1142 else
1143 {
1144 if (default_bat_dir != NULL)
1145 /* Prefer using the same path as an existing .bat file. */
1146 strcpy(batpath, default_bat_dir);
1147 else
1148 {
1149 /* No [g]vim.bat exists: Write it to a directory in $PATH. Use
1150 * $WINDIR by default, if it's empty the first item in $PATH. */
1151 p = getenv("WINDIR");
1152 if (p != NULL && *p != NUL)
1153 strcpy(batpath, p);
1154 else
1155 {
1156 p = getenv("PATH");
1157 if (p == NULL || *p == NUL) /* "cannot happen" */
1158 strcpy(batpath, "C:/Windows");
1159 else
1160 {
1161 i = 0;
1162 while (*p != NUL && *p != ';')
1163 batpath[i++] = *p++;
1164 batpath[i] = NUL;
1165 }
1166 }
1167 }
1168 add_pathsep(batpath);
1169 set_bat_text(choice_count, batpath, targets[target].batname);
1170
1171 choices[choice_count].changefunc = change_bat_choice;
1172 }
1173 ++choice_count;
1174}
1175
1176/*
1177 * Set up the choices for installing .bat files.
1178 * For these items "arg" is the index in targets[].
1179 */
1180 static void
1181init_bat_choices(void)
1182{
1183 int i;
1184
1185 /* The first item is used to switch installing batch files on/off and
1186 * setting the default path. */
1187 choices[choice_count].text = bat_text_yes;
1188 choices[choice_count].changefunc = change_main_bat_choice;
1189 choices[choice_count].installfunc = NULL;
1190 choices[choice_count].active = 1;
1191 choices[choice_count].arg = 0;
1192 ++choice_count;
1193
1194 /* Add items for each batch file target. Only used when not disabled by
1195 * the first item. When a .exe exists, don't offer to create a .bat. */
1196 for (i = 1; i < TARGET_COUNT; ++i)
1197 if (targets[i].oldexe == NULL
1198 && (targets[i].exenamearg[0] == 'g' ? has_gvim : has_vim))
1199 init_bat_choice(i);
1200 else
1201 add_dummy_choice();
1202}
1203
1204/*
1205 * Install the vimrc file.
1206 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001207 static void
1208install_vimrc(int idx)
1209{
1210 FILE *fd, *tfd;
1211 char *fname;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001212
1213 /* If an old vimrc file exists, overwrite it.
1214 * Otherwise create a new one. */
1215 if (*oldvimrc != NUL)
1216 fname = oldvimrc;
1217 else
1218 fname = vimrc;
1219
1220 fd = fopen(fname, "w");
1221 if (fd == NULL)
1222 {
1223 printf("\nERROR: Cannot open \"%s\" for writing.\n", fname);
1224 return;
1225 }
1226 switch (compat_choice)
1227 {
1228 case compat_vi:
Bram Moolenaar6cdb2c92018-10-13 17:25:27 +02001229 fprintf(fd, "\" Vi compatible\n");
Bram Moolenaar071d4272004-06-13 20:20:40 +00001230 fprintf(fd, "set compatible\n");
1231 break;
Bram Moolenaar6cdb2c92018-10-13 17:25:27 +02001232 case compat_vim:
1233 fprintf(fd, "\" Vim's default behavior\n");
1234 fprintf(fd, "if &compatible\n");
1235 fprintf(fd, " set nocompatible\n");
1236 fprintf(fd, "endif\n");
1237 break;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001238 case compat_some_enhancements:
Bram Moolenaar6cdb2c92018-10-13 17:25:27 +02001239 fprintf(fd, "\" Vim with some enhancements\n");
Bram Moolenaarc73e4472016-07-29 18:33:38 +02001240 fprintf(fd, "source $VIMRUNTIME/defaults.vim\n");
Bram Moolenaar071d4272004-06-13 20:20:40 +00001241 break;
1242 case compat_all_enhancements:
Bram Moolenaar6cdb2c92018-10-13 17:25:27 +02001243 fprintf(fd, "\" Vim with all enhancements\n");
Bram Moolenaar071d4272004-06-13 20:20:40 +00001244 fprintf(fd, "source $VIMRUNTIME/vimrc_example.vim\n");
1245 break;
1246 }
1247 switch (remap_choice)
1248 {
1249 case remap_no:
1250 break;
1251 case remap_win:
Bram Moolenaar6cdb2c92018-10-13 17:25:27 +02001252 fprintf(fd, "\n");
1253 fprintf(fd, "\" Remap a few keys for Windows behavior\n");
Bram Moolenaar071d4272004-06-13 20:20:40 +00001254 fprintf(fd, "source $VIMRUNTIME/mswin.vim\n");
1255 break;
1256 }
1257 switch (mouse_choice)
1258 {
1259 case mouse_xterm:
Bram Moolenaar6cdb2c92018-10-13 17:25:27 +02001260 fprintf(fd, "\n");
1261 fprintf(fd, "\" Mouse behavior (the Unix way)\n");
Bram Moolenaar071d4272004-06-13 20:20:40 +00001262 fprintf(fd, "behave xterm\n");
1263 break;
1264 case mouse_mswin:
Bram Moolenaar6cdb2c92018-10-13 17:25:27 +02001265 fprintf(fd, "\n");
1266 fprintf(fd, "\" Mouse behavior (the Windows way)\n");
Bram Moolenaar071d4272004-06-13 20:20:40 +00001267 fprintf(fd, "behave mswin\n");
1268 break;
Bram Moolenaarc3fdf7f2017-10-28 18:36:48 +02001269 case mouse_default:
1270 break;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001271 }
1272 if ((tfd = fopen("diff.exe", "r")) != NULL)
1273 {
1274 /* Use the diff.exe that comes with the self-extracting gvim.exe. */
1275 fclose(tfd);
1276 fprintf(fd, "\n");
Bram Moolenaar6cdb2c92018-10-13 17:25:27 +02001277 fprintf(fd, "\" Use the internal diff if available.\n");
1278 fprintf(fd, "\" Otherwise use the special 'diffexpr' for Windows.\n");
1279 fprintf(fd, "if &diffopt !~# 'internal'\n");
1280 fprintf(fd, " set diffexpr=MyDiff()\n");
1281 fprintf(fd, "endif\n");
Bram Moolenaar071d4272004-06-13 20:20:40 +00001282 fprintf(fd, "function MyDiff()\n");
1283 fprintf(fd, " let opt = '-a --binary '\n");
1284 fprintf(fd, " if &diffopt =~ 'icase' | let opt = opt . '-i ' | endif\n");
1285 fprintf(fd, " if &diffopt =~ 'iwhite' | let opt = opt . '-b ' | endif\n");
Bram Moolenaar12365ce2018-05-13 14:45:25 +02001286 /* Use quotes only when needed, they may cause trouble.
1287 * Always escape "!". */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001288 fprintf(fd, " let arg1 = v:fname_in\n");
1289 fprintf(fd, " if arg1 =~ ' ' | let arg1 = '\"' . arg1 . '\"' | endif\n");
Bram Moolenaar12365ce2018-05-13 14:45:25 +02001290 fprintf(fd, " let arg1 = substitute(arg1, '!', '\\!', 'g')\n");
Bram Moolenaar071d4272004-06-13 20:20:40 +00001291 fprintf(fd, " let arg2 = v:fname_new\n");
1292 fprintf(fd, " if arg2 =~ ' ' | let arg2 = '\"' . arg2 . '\"' | endif\n");
Bram Moolenaar12365ce2018-05-13 14:45:25 +02001293 fprintf(fd, " let arg2 = substitute(arg2, '!', '\\!', 'g')\n");
Bram Moolenaar071d4272004-06-13 20:20:40 +00001294 fprintf(fd, " let arg3 = v:fname_out\n");
1295 fprintf(fd, " if arg3 =~ ' ' | let arg3 = '\"' . arg3 . '\"' | endif\n");
Bram Moolenaar12365ce2018-05-13 14:45:25 +02001296 fprintf(fd, " let arg3 = substitute(arg3, '!', '\\!', 'g')\n");
Bram Moolenaar33aec762006-01-22 23:30:12 +00001297
1298 /* If the path has a space: When using cmd.exe (Win NT/2000/XP) put
Bram Moolenaarc62a6442013-11-21 18:13:37 +01001299 * quotes around the diff command and rely on the default value of
Bram Moolenaar792f0e32018-02-27 17:27:13 +01001300 * shellxquote to solve the quoting problem for the whole command.
1301 *
Bram Moolenaar33aec762006-01-22 23:30:12 +00001302 * Otherwise put a double quote just before the space and at the
1303 * end of the command. Putting quotes around the whole thing
1304 * doesn't work on Win 95/98/ME. This is mostly guessed! */
Bram Moolenaar33aec762006-01-22 23:30:12 +00001305 fprintf(fd, " if $VIMRUNTIME =~ ' '\n");
1306 fprintf(fd, " if &sh =~ '\\<cmd'\n");
Bram Moolenaarc62a6442013-11-21 18:13:37 +01001307 fprintf(fd, " if empty(&shellxquote)\n");
1308 fprintf(fd, " let l:shxq_sav = ''\n");
1309 fprintf(fd, " set shellxquote&\n");
1310 fprintf(fd, " endif\n");
1311 fprintf(fd, " let cmd = '\"' . $VIMRUNTIME . '\\diff\"'\n");
Bram Moolenaar33aec762006-01-22 23:30:12 +00001312 fprintf(fd, " else\n");
1313 fprintf(fd, " let cmd = substitute($VIMRUNTIME, ' ', '\" ', '') . '\\diff\"'\n");
1314 fprintf(fd, " endif\n");
1315 fprintf(fd, " else\n");
1316 fprintf(fd, " let cmd = $VIMRUNTIME . '\\diff'\n");
1317 fprintf(fd, " endif\n");
Bram Moolenaar12365ce2018-05-13 14:45:25 +02001318 fprintf(fd, " let cmd = substitute(cmd, '!', '\\!', 'g')\n");
Bram Moolenaarc62a6442013-11-21 18:13:37 +01001319 fprintf(fd, " silent execute '!' . cmd . ' ' . opt . arg1 . ' ' . arg2 . ' > ' . arg3\n");
1320 fprintf(fd, " if exists('l:shxq_sav')\n");
1321 fprintf(fd, " let &shellxquote=l:shxq_sav\n");
1322 fprintf(fd, " endif\n");
Bram Moolenaar071d4272004-06-13 20:20:40 +00001323 fprintf(fd, "endfunction\n");
1324 fprintf(fd, "\n");
1325 }
1326 fclose(fd);
1327 printf("%s has been written\n", fname);
1328}
1329
1330 static void
1331change_vimrc_choice(int idx)
1332{
1333 if (choices[idx].installfunc != NULL)
1334 {
1335 /* Switch to NOT change or create a vimrc file. */
1336 if (*oldvimrc != NUL)
1337 alloc_text(idx, "Do NOT change startup file %s", oldvimrc);
1338 else
1339 alloc_text(idx, "Do NOT create startup file %s", vimrc);
1340 choices[idx].installfunc = NULL;
1341 choices[idx + 1].active = 0;
1342 choices[idx + 2].active = 0;
1343 choices[idx + 3].active = 0;
1344 }
1345 else
1346 {
1347 /* Switch to change or create a vimrc file. */
1348 if (*oldvimrc != NUL)
1349 alloc_text(idx, "Overwrite startup file %s with:", oldvimrc);
1350 else
1351 alloc_text(idx, "Create startup file %s with:", vimrc);
1352 choices[idx].installfunc = install_vimrc;
1353 choices[idx + 1].active = 1;
1354 choices[idx + 2].active = 1;
1355 choices[idx + 3].active = 1;
1356 }
1357}
1358
1359/*
1360 * Change the choice how to run Vim.
1361 */
1362 static void
1363change_run_choice(int idx)
1364{
1365 compat_choice = get_choice(compat_choices, TABLE_SIZE(compat_choices));
1366 alloc_text(idx, compat_text, compat_choices[compat_choice]);
1367}
1368
1369/*
1370 * Change the choice if keys are to be remapped.
1371 */
1372 static void
1373change_remap_choice(int idx)
1374{
1375 remap_choice = get_choice(remap_choices, TABLE_SIZE(remap_choices));
1376 alloc_text(idx, remap_text, remap_choices[remap_choice]);
1377}
1378
1379/*
1380 * Change the choice how to select text.
1381 */
1382 static void
1383change_mouse_choice(int idx)
1384{
1385 mouse_choice = get_choice(mouse_choices, TABLE_SIZE(mouse_choices));
1386 alloc_text(idx, mouse_text, mouse_choices[mouse_choice]);
1387}
1388
1389 static void
1390init_vimrc_choices(void)
1391{
1392 /* set path for a new _vimrc file (also when not used) */
1393 strcpy(vimrc, installdir);
1394 strcpy(vimrc + runtimeidx, "_vimrc");
1395
1396 /* Set opposite value and then toggle it by calling change_vimrc_choice() */
1397 if (*oldvimrc == NUL)
1398 choices[choice_count].installfunc = NULL;
1399 else
1400 choices[choice_count].installfunc = install_vimrc;
1401 choices[choice_count].text = NULL;
1402 change_vimrc_choice(choice_count);
1403 choices[choice_count].changefunc = change_vimrc_choice;
1404 choices[choice_count].active = 1;
1405 ++choice_count;
1406
1407 /* default way to run Vim */
1408 alloc_text(choice_count, compat_text, compat_choices[compat_choice]);
1409 choices[choice_count].changefunc = change_run_choice;
1410 choices[choice_count].installfunc = NULL;
1411 choices[choice_count].active = (*oldvimrc == NUL);
1412 ++choice_count;
1413
1414 /* Whether to remap keys */
1415 alloc_text(choice_count, remap_text , remap_choices[remap_choice]);
1416 choices[choice_count].changefunc = change_remap_choice;
Bram Moolenaar945ec092016-06-08 21:17:43 +02001417 choices[choice_count].installfunc = NULL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001418 choices[choice_count].active = (*oldvimrc == NUL);
1419 ++choice_count;
1420
1421 /* default way to use the mouse */
1422 alloc_text(choice_count, mouse_text, mouse_choices[mouse_choice]);
1423 choices[choice_count].changefunc = change_mouse_choice;
Bram Moolenaar945ec092016-06-08 21:17:43 +02001424 choices[choice_count].installfunc = NULL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001425 choices[choice_count].active = (*oldvimrc == NUL);
1426 ++choice_count;
1427}
1428
Bram Moolenaarccd9ccf2010-07-07 13:19:55 +02001429 static LONG
1430reg_create_key(
1431 HKEY root,
1432 const char *subkey,
Bram Moolenaar6199d432017-10-14 19:05:44 +02001433 PHKEY phKey,
1434 DWORD flag)
Bram Moolenaarccd9ccf2010-07-07 13:19:55 +02001435{
1436 DWORD disp;
1437
1438 *phKey = NULL;
1439 return RegCreateKeyEx(
Bram Moolenaarcc448b32010-07-14 16:52:17 +02001440 root, subkey,
1441 0, NULL, REG_OPTION_NON_VOLATILE,
Bram Moolenaar6199d432017-10-14 19:05:44 +02001442 flag | KEY_WRITE,
Bram Moolenaarcc448b32010-07-14 16:52:17 +02001443 NULL, phKey, &disp);
Bram Moolenaarccd9ccf2010-07-07 13:19:55 +02001444}
1445
1446 static LONG
1447reg_set_string_value(
1448 HKEY hKey,
1449 const char *value_name,
1450 const char *data)
1451{
1452 return RegSetValueEx(hKey, value_name, 0, REG_SZ,
1453 (LPBYTE)data, (DWORD)(1 + strlen(data)));
1454}
1455
1456 static LONG
1457reg_create_key_and_value(
1458 HKEY hRootKey,
1459 const char *subkey,
1460 const char *value_name,
Bram Moolenaar6199d432017-10-14 19:05:44 +02001461 const char *data,
1462 DWORD flag)
Bram Moolenaarccd9ccf2010-07-07 13:19:55 +02001463{
1464 HKEY hKey;
Bram Moolenaar6199d432017-10-14 19:05:44 +02001465 LONG lRet = reg_create_key(hRootKey, subkey, &hKey, flag);
Bram Moolenaarccd9ccf2010-07-07 13:19:55 +02001466
1467 if (ERROR_SUCCESS == lRet)
1468 {
Bram Moolenaarcc448b32010-07-14 16:52:17 +02001469 lRet = reg_set_string_value(hKey, value_name, data);
1470 RegCloseKey(hKey);
Bram Moolenaarccd9ccf2010-07-07 13:19:55 +02001471 }
1472 return lRet;
1473}
1474
1475 static LONG
1476register_inproc_server(
1477 HKEY hRootKey,
1478 const char *clsid,
1479 const char *extname,
1480 const char *module,
Bram Moolenaar6199d432017-10-14 19:05:44 +02001481 const char *threading_model,
1482 DWORD flag)
Bram Moolenaarccd9ccf2010-07-07 13:19:55 +02001483{
1484 CHAR subkey[BUFSIZE];
1485 LONG lRet;
1486
1487 sprintf(subkey, "CLSID\\%s", clsid);
Bram Moolenaar6199d432017-10-14 19:05:44 +02001488 lRet = reg_create_key_and_value(hRootKey, subkey, NULL, extname, flag);
Bram Moolenaarccd9ccf2010-07-07 13:19:55 +02001489 if (ERROR_SUCCESS == lRet)
1490 {
Bram Moolenaarcc448b32010-07-14 16:52:17 +02001491 sprintf(subkey, "CLSID\\%s\\InProcServer32", clsid);
Bram Moolenaar6199d432017-10-14 19:05:44 +02001492 lRet = reg_create_key_and_value(hRootKey, subkey, NULL, module, flag);
Bram Moolenaarcc448b32010-07-14 16:52:17 +02001493 if (ERROR_SUCCESS == lRet)
1494 {
1495 lRet = reg_create_key_and_value(hRootKey, subkey,
Bram Moolenaar6199d432017-10-14 19:05:44 +02001496 "ThreadingModel", threading_model, flag);
Bram Moolenaarcc448b32010-07-14 16:52:17 +02001497 }
Bram Moolenaarccd9ccf2010-07-07 13:19:55 +02001498 }
1499 return lRet;
1500}
1501
1502 static LONG
1503register_shellex(
1504 HKEY hRootKey,
1505 const char *clsid,
1506 const char *name,
Bram Moolenaar6199d432017-10-14 19:05:44 +02001507 const char *exe_path,
1508 DWORD flag)
Bram Moolenaarccd9ccf2010-07-07 13:19:55 +02001509{
1510 LONG lRet = reg_create_key_and_value(
Bram Moolenaarcc448b32010-07-14 16:52:17 +02001511 hRootKey,
1512 "*\\shellex\\ContextMenuHandlers\\gvim",
1513 NULL,
Bram Moolenaar6199d432017-10-14 19:05:44 +02001514 clsid,
1515 flag);
Bram Moolenaarccd9ccf2010-07-07 13:19:55 +02001516
1517 if (ERROR_SUCCESS == lRet)
1518 {
Bram Moolenaarcc448b32010-07-14 16:52:17 +02001519 lRet = reg_create_key_and_value(
1520 HKEY_LOCAL_MACHINE,
1521 "Software\\Microsoft\\Windows\\CurrentVersion\\Shell Extensions\\Approved",
1522 clsid,
Bram Moolenaar6199d432017-10-14 19:05:44 +02001523 name,
1524 flag);
Bram Moolenaarccd9ccf2010-07-07 13:19:55 +02001525
Bram Moolenaarcc448b32010-07-14 16:52:17 +02001526 if (ERROR_SUCCESS == lRet)
1527 {
1528 lRet = reg_create_key_and_value(
1529 HKEY_LOCAL_MACHINE,
1530 "Software\\Vim\\Gvim",
1531 "path",
Bram Moolenaar6199d432017-10-14 19:05:44 +02001532 exe_path,
1533 flag);
Bram Moolenaarcc448b32010-07-14 16:52:17 +02001534 }
Bram Moolenaarccd9ccf2010-07-07 13:19:55 +02001535 }
1536 return lRet;
1537}
1538
1539 static LONG
1540register_openwith(
1541 HKEY hRootKey,
Bram Moolenaar6199d432017-10-14 19:05:44 +02001542 const char *exe_path,
1543 DWORD flag)
Bram Moolenaarccd9ccf2010-07-07 13:19:55 +02001544{
Bram Moolenaar78050042010-07-31 20:53:54 +02001545 char exe_cmd[BUFSIZE];
1546 LONG lRet;
1547
Bram Moolenaarbbdcb482010-08-02 20:45:27 +02001548 sprintf(exe_cmd, "\"%s\" \"%%1\"", exe_path);
Bram Moolenaar78050042010-07-31 20:53:54 +02001549 lRet = reg_create_key_and_value(
Bram Moolenaarcc448b32010-07-14 16:52:17 +02001550 hRootKey,
1551 "Applications\\gvim.exe\\shell\\edit\\command",
1552 NULL,
Bram Moolenaar6199d432017-10-14 19:05:44 +02001553 exe_cmd,
1554 flag);
Bram Moolenaarccd9ccf2010-07-07 13:19:55 +02001555
1556 if (ERROR_SUCCESS == lRet)
1557 {
Bram Moolenaarcc448b32010-07-14 16:52:17 +02001558 int i;
1559 static const char *openwith[] = {
1560 ".htm\\OpenWithList\\gvim.exe",
1561 ".vim\\OpenWithList\\gvim.exe",
1562 "*\\OpenWithList\\gvim.exe",
1563 };
Bram Moolenaarccd9ccf2010-07-07 13:19:55 +02001564
Bram Moolenaarcc448b32010-07-14 16:52:17 +02001565 for (i = 0; ERROR_SUCCESS == lRet
Bram Moolenaarccd9ccf2010-07-07 13:19:55 +02001566 && i < sizeof(openwith) / sizeof(openwith[0]); i++)
Bram Moolenaarcc448b32010-07-14 16:52:17 +02001567 {
Bram Moolenaar6199d432017-10-14 19:05:44 +02001568 lRet = reg_create_key_and_value(hRootKey, openwith[i], NULL, "", flag);
Bram Moolenaarcc448b32010-07-14 16:52:17 +02001569 }
Bram Moolenaarccd9ccf2010-07-07 13:19:55 +02001570 }
1571
1572 return lRet;
1573}
1574
1575 static LONG
1576register_uninstall(
1577 HKEY hRootKey,
1578 const char *appname,
1579 const char *display_name,
Bram Moolenaar6cdb2c92018-10-13 17:25:27 +02001580 const char *uninstall_string,
1581 const char *display_icon,
1582 const char *display_version,
1583 const char *publisher)
Bram Moolenaarccd9ccf2010-07-07 13:19:55 +02001584{
1585 LONG lRet = reg_create_key_and_value(hRootKey, appname,
Bram Moolenaar6199d432017-10-14 19:05:44 +02001586 "DisplayName", display_name, KEY_WOW64_64KEY);
Bram Moolenaarccd9ccf2010-07-07 13:19:55 +02001587
1588 if (ERROR_SUCCESS == lRet)
Bram Moolenaarcc448b32010-07-14 16:52:17 +02001589 lRet = reg_create_key_and_value(hRootKey, appname,
Bram Moolenaar6199d432017-10-14 19:05:44 +02001590 "UninstallString", uninstall_string, KEY_WOW64_64KEY);
Bram Moolenaar6cdb2c92018-10-13 17:25:27 +02001591 if (ERROR_SUCCESS == lRet)
1592 lRet = reg_create_key_and_value(hRootKey, appname,
1593 "DisplayIcon", display_icon, KEY_WOW64_64KEY);
1594 if (ERROR_SUCCESS == lRet)
1595 lRet = reg_create_key_and_value(hRootKey, appname,
1596 "DisplayVersion", display_version, KEY_WOW64_64KEY);
1597 if (ERROR_SUCCESS == lRet)
1598 lRet = reg_create_key_and_value(hRootKey, appname,
1599 "Publisher", publisher, KEY_WOW64_64KEY);
Bram Moolenaarccd9ccf2010-07-07 13:19:55 +02001600 return lRet;
1601}
Bram Moolenaarccd9ccf2010-07-07 13:19:55 +02001602
Bram Moolenaar071d4272004-06-13 20:20:40 +00001603/*
1604 * Add some entries to the registry:
1605 * - to add "Edit with Vim" to the context * menu
1606 * - to add Vim to the "Open with..." list
1607 * - to uninstall Vim
1608 */
1609/*ARGSUSED*/
Bram Moolenaarab8205e2010-07-07 15:14:03 +02001610 static int
Bram Moolenaar071d4272004-06-13 20:20:40 +00001611install_registry(void)
1612{
Bram Moolenaarcc448b32010-07-14 16:52:17 +02001613 LONG lRet = ERROR_SUCCESS;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001614 const char *vim_ext_ThreadingModel = "Apartment";
1615 const char *vim_ext_name = "Vim Shell Extension";
1616 const char *vim_ext_clsid = "{51EEE242-AD87-11d3-9C1E-0090278BBD99}";
Bram Moolenaarbbd854d2019-02-18 22:19:33 +01001617 char vim_exe_path[MAX_PATH];
Bram Moolenaarcc448b32010-07-14 16:52:17 +02001618 char display_name[BUFSIZE];
1619 char uninstall_string[BUFSIZE];
Bram Moolenaar6cdb2c92018-10-13 17:25:27 +02001620 char icon_string[BUFSIZE];
Bram Moolenaar6199d432017-10-14 19:05:44 +02001621 int i;
1622 int loop_count = is_64bit_os() ? 2 : 1;
1623 DWORD flag;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001624
Bram Moolenaarccd9ccf2010-07-07 13:19:55 +02001625 sprintf(vim_exe_path, "%s\\gvim.exe", installdir);
1626
1627 if (install_popup)
1628 {
Bram Moolenaarcc448b32010-07-14 16:52:17 +02001629 char bufg[BUFSIZE];
Bram Moolenaarccd9ccf2010-07-07 13:19:55 +02001630
Bram Moolenaarcc448b32010-07-14 16:52:17 +02001631 printf("Creating \"Edit with Vim\" popup menu entry\n");
Bram Moolenaarccd9ccf2010-07-07 13:19:55 +02001632
Bram Moolenaar6199d432017-10-14 19:05:44 +02001633 for (i = 0; i < loop_count; i++)
1634 {
1635 if (i == 0)
1636 {
1637 sprintf(bufg, "%s\\" GVIMEXT32_PATH, installdir);
1638 flag = KEY_WOW64_32KEY;
1639 }
1640 else
1641 {
1642 sprintf(bufg, "%s\\" GVIMEXT64_PATH, installdir);
1643 flag = KEY_WOW64_64KEY;
1644 }
1645
1646 lRet = register_inproc_server(
1647 HKEY_CLASSES_ROOT, vim_ext_clsid, vim_ext_name,
1648 bufg, vim_ext_ThreadingModel, flag);
1649 if (ERROR_SUCCESS != lRet)
1650 return FAIL;
1651 lRet = register_shellex(
1652 HKEY_CLASSES_ROOT, vim_ext_clsid, vim_ext_name,
1653 vim_exe_path, flag);
1654 if (ERROR_SUCCESS != lRet)
1655 return FAIL;
1656 }
Bram Moolenaarccd9ccf2010-07-07 13:19:55 +02001657 }
1658
1659 if (install_openwith)
1660 {
Bram Moolenaarcc448b32010-07-14 16:52:17 +02001661 printf("Creating \"Open with ...\" list entry\n");
Bram Moolenaarccd9ccf2010-07-07 13:19:55 +02001662
Bram Moolenaar6199d432017-10-14 19:05:44 +02001663 for (i = 0; i < loop_count; i++)
1664 {
1665 if (i == 0)
1666 flag = KEY_WOW64_32KEY;
1667 else
1668 flag = KEY_WOW64_64KEY;
1669
1670 lRet = register_openwith(HKEY_CLASSES_ROOT, vim_exe_path, flag);
1671 if (ERROR_SUCCESS != lRet)
1672 return FAIL;
1673 }
Bram Moolenaarccd9ccf2010-07-07 13:19:55 +02001674 }
1675
1676 printf("Creating an uninstall entry\n");
Bram Moolenaaraf610b82018-12-21 16:22:50 +01001677 sprintf(display_name, "Vim " VIM_VERSION_SHORT
1678#ifdef _WIN64
1679 " (x64)"
1680#endif
1681 );
Bram Moolenaarccd9ccf2010-07-07 13:19:55 +02001682
1683 /* For the NSIS installer use the generated uninstaller. */
1684 if (interactive)
Bram Moolenaar16d79a32010-07-18 22:33:56 +02001685 sprintf(uninstall_string, "%s\\uninstal.exe", installdir);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001686 else
Bram Moolenaar16d79a32010-07-18 22:33:56 +02001687 sprintf(uninstall_string, "%s\\uninstall-gui.exe", installdir);
Bram Moolenaarccd9ccf2010-07-07 13:19:55 +02001688
Bram Moolenaar6cdb2c92018-10-13 17:25:27 +02001689 sprintf(icon_string, "%s\\gvim.exe,0", installdir);
1690
Bram Moolenaarccd9ccf2010-07-07 13:19:55 +02001691 lRet = register_uninstall(
Bram Moolenaarcc448b32010-07-14 16:52:17 +02001692 HKEY_LOCAL_MACHINE,
1693 "Software\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\Vim " VIM_VERSION_SHORT,
1694 display_name,
Bram Moolenaar6cdb2c92018-10-13 17:25:27 +02001695 uninstall_string,
1696 icon_string,
1697 VIM_VERSION_SHORT,
1698 "Bram Moolenaar et al.");
Bram Moolenaarab8205e2010-07-07 15:14:03 +02001699 if (ERROR_SUCCESS != lRet)
1700 return FAIL;
Bram Moolenaarccd9ccf2010-07-07 13:19:55 +02001701
Bram Moolenaarab8205e2010-07-07 15:14:03 +02001702 return OK;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001703}
1704
1705 static void
1706change_popup_choice(int idx)
1707{
1708 if (install_popup == 0)
1709 {
1710 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";
1711 install_popup = 1;
1712 }
1713 else
1714 {
1715 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";
1716 install_popup = 0;
1717 }
1718}
1719
1720/*
1721 * Only add the choice for the popup menu entry when gvim.exe was found and
1722 * both gvimext.dll and regedit.exe exist.
1723 */
1724 static void
1725init_popup_choice(void)
1726{
1727 struct stat st;
1728
1729 if (has_gvim
Bram Moolenaar6199d432017-10-14 19:05:44 +02001730 && (stat(GVIMEXT32_PATH, &st) >= 0
1731 || stat(GVIMEXT64_PATH, &st) >= 0))
Bram Moolenaar071d4272004-06-13 20:20:40 +00001732 {
1733 choices[choice_count].changefunc = change_popup_choice;
1734 choices[choice_count].installfunc = NULL;
1735 choices[choice_count].active = 1;
1736 change_popup_choice(choice_count); /* set the text */
1737 ++choice_count;
1738 }
1739 else
1740 add_dummy_choice();
1741}
1742
1743 static void
1744change_openwith_choice(int idx)
1745{
1746 if (install_openwith == 0)
1747 {
1748 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";
1749 install_openwith = 1;
1750 }
1751 else
1752 {
1753 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";
1754 install_openwith = 0;
1755 }
1756}
1757
1758/*
1759 * Only add the choice for the open-with menu entry when gvim.exe was found
Bram Moolenaar84a05ac2013-05-06 04:24:17 +02001760 * and regedit.exe exist.
Bram Moolenaar071d4272004-06-13 20:20:40 +00001761 */
1762 static void
1763init_openwith_choice(void)
1764{
Bram Moolenaar6199d432017-10-14 19:05:44 +02001765 if (has_gvim)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001766 {
1767 choices[choice_count].changefunc = change_openwith_choice;
1768 choices[choice_count].installfunc = NULL;
1769 choices[choice_count].active = 1;
1770 change_openwith_choice(choice_count); /* set the text */
1771 ++choice_count;
1772 }
1773 else
1774 add_dummy_choice();
1775}
1776
Bram Moolenaar071d4272004-06-13 20:20:40 +00001777/* create_shortcut
1778 *
1779 * Create a shell link.
1780 *
1781 * returns 0 on failure, non-zero on successful completion.
1782 *
1783 * NOTE: Currently untested with mingw.
1784 */
1785 int
1786create_shortcut(
1787 const char *shortcut_name,
1788 const char *iconfile_path,
1789 int iconindex,
1790 const char *shortcut_target,
1791 const char *shortcut_args,
1792 const char *workingdir
1793 )
1794{
1795 IShellLink *shelllink_ptr;
1796 HRESULT hres;
1797 IPersistFile *persistfile_ptr;
1798
1799 /* Initialize COM library */
1800 hres = CoInitialize(NULL);
1801 if (!SUCCEEDED(hres))
1802 {
1803 printf("Error: Could not open the COM library. Not creating shortcut.\n");
1804 return FAIL;
1805 }
1806
1807 /* Instantiate a COM object for the ShellLink, store a pointer to it
1808 * in shelllink_ptr. */
1809 hres = CoCreateInstance(&CLSID_ShellLink,
1810 NULL,
1811 CLSCTX_INPROC_SERVER,
1812 &IID_IShellLink,
1813 (void **) &shelllink_ptr);
1814
1815 if (SUCCEEDED(hres)) /* If the instantiation was successful... */
1816 {
1817 /* ...Then build a PersistFile interface for the ShellLink so we can
1818 * save it as a file after we build it. */
1819 hres = shelllink_ptr->lpVtbl->QueryInterface(shelllink_ptr,
1820 &IID_IPersistFile, (void **) &persistfile_ptr);
1821
1822 if (SUCCEEDED(hres))
1823 {
1824 wchar_t wsz[BUFSIZE];
1825
1826 /* translate the (possibly) multibyte shortcut filename to windows
1827 * Unicode so it can be used as a file name.
1828 */
1829 MultiByteToWideChar(CP_ACP, 0, shortcut_name, -1, wsz, BUFSIZE);
1830
1831 /* set the attributes */
1832 shelllink_ptr->lpVtbl->SetPath(shelllink_ptr, shortcut_target);
1833 shelllink_ptr->lpVtbl->SetWorkingDirectory(shelllink_ptr,
1834 workingdir);
1835 shelllink_ptr->lpVtbl->SetIconLocation(shelllink_ptr,
1836 iconfile_path, iconindex);
1837 shelllink_ptr->lpVtbl->SetArguments(shelllink_ptr, shortcut_args);
1838
1839 /* save the shortcut to a file and return the PersistFile object*/
1840 persistfile_ptr->lpVtbl->Save(persistfile_ptr, wsz, 1);
1841 persistfile_ptr->lpVtbl->Release(persistfile_ptr);
1842 }
1843 else
1844 {
1845 printf("QueryInterface Error\n");
1846 return FAIL;
1847 }
1848
1849 /* Return the ShellLink object */
1850 shelllink_ptr->lpVtbl->Release(shelllink_ptr);
1851 }
1852 else
1853 {
1854 printf("CoCreateInstance Error - hres = %08x\n", (int)hres);
1855 return FAIL;
1856 }
1857
1858 return OK;
1859}
1860
1861/*
1862 * Build a path to where we will put a specified link.
1863 *
1864 * Return 0 on error, non-zero on success
1865 */
1866 int
1867build_link_name(
1868 char *link_path,
1869 const char *link_name,
1870 const char *shell_folder_name)
1871{
Bram Moolenaarbbd854d2019-02-18 22:19:33 +01001872 char shell_folder_path[MAX_PATH];
Bram Moolenaar071d4272004-06-13 20:20:40 +00001873
1874 if (get_shell_folder_path(shell_folder_path, shell_folder_name) == FAIL)
1875 {
1876 printf("An error occurred while attempting to find the path to %s.\n",
1877 shell_folder_name);
1878 return FAIL;
1879 }
1880
1881 /* Make sure the directory exists (create Start Menu\Programs\Vim).
1882 * Ignore errors if it already exists. */
1883 vim_mkdir(shell_folder_path, 0755);
1884
1885 /* build the path to the shortcut and the path to gvim.exe */
1886 sprintf(link_path, "%s\\%s.lnk", shell_folder_path, link_name);
1887
1888 return OK;
1889}
1890
1891 static int
1892build_shortcut(
1893 const char *name, /* Name of the shortcut */
1894 const char *exename, /* Name of the executable (e.g., vim.exe) */
1895 const char *args,
1896 const char *shell_folder,
1897 const char *workingdir)
1898{
1899 char executable_path[BUFSIZE];
1900 char link_name[BUFSIZE];
1901
1902 sprintf(executable_path, "%s\\%s", installdir, exename);
1903
1904 if (build_link_name(link_name, name, shell_folder) == FAIL)
1905 {
1906 printf("An error has occurred. A shortcut to %s will not be created %s.\n",
1907 name,
1908 *shell_folder == 'd' ? "on the desktop" : "in the Start menu");
1909 return FAIL;
1910 }
1911
1912 /* Create the shortcut: */
1913 return create_shortcut(link_name, executable_path, 0,
1914 executable_path, args, workingdir);
1915}
1916
1917/*
1918 * We used to use "homedir" as the working directory, but that is a bad choice
Bram Moolenaar03e228a2013-11-07 04:49:27 +01001919 * on multi-user systems. However, not specifying a directory results in the
1920 * current directory to be c:\Windows\system32 on Windows 7. Use environment
1921 * variables instead.
Bram Moolenaar071d4272004-06-13 20:20:40 +00001922 */
Bram Moolenaar03e228a2013-11-07 04:49:27 +01001923#define WORKDIR "%HOMEDRIVE%%HOMEPATH%"
Bram Moolenaar071d4272004-06-13 20:20:40 +00001924
1925/*
1926 * Create shortcut(s) in the Start Menu\Programs\Vim folder.
1927 */
1928 static void
1929install_start_menu(int idx)
1930{
1931 need_uninstall_entry = 1;
1932 printf("Creating start menu\n");
1933 if (has_vim)
1934 {
1935 if (build_shortcut("Vim", "vim.exe", "",
1936 VIM_STARTMENU, WORKDIR) == FAIL)
1937 return;
1938 if (build_shortcut("Vim Read-only", "vim.exe", "-R",
1939 VIM_STARTMENU, WORKDIR) == FAIL)
1940 return;
1941 if (build_shortcut("Vim Diff", "vim.exe", "-d",
1942 VIM_STARTMENU, WORKDIR) == FAIL)
1943 return;
1944 }
1945 if (has_gvim)
1946 {
1947 if (build_shortcut("gVim", "gvim.exe", "",
1948 VIM_STARTMENU, WORKDIR) == FAIL)
1949 return;
1950 if (build_shortcut("gVim Easy", "gvim.exe", "-y",
1951 VIM_STARTMENU, WORKDIR) == FAIL)
1952 return;
1953 if (build_shortcut("gVim Read-only", "gvim.exe", "-R",
1954 VIM_STARTMENU, WORKDIR) == FAIL)
1955 return;
1956 if (build_shortcut("gVim Diff", "gvim.exe", "-d",
1957 VIM_STARTMENU, WORKDIR) == FAIL)
1958 return;
1959 }
1960 if (build_shortcut("Uninstall",
1961 interactive ? "uninstal.exe" : "uninstall-gui.exe", "",
1962 VIM_STARTMENU, installdir) == FAIL)
1963 return;
1964 /* For Windows NT the working dir of the vimtutor.bat must be right,
1965 * otherwise gvim.exe won't be found and using gvimbat doesn't work. */
1966 if (build_shortcut("Vim tutor", "vimtutor.bat", "",
1967 VIM_STARTMENU, installdir) == FAIL)
1968 return;
1969 if (build_shortcut("Help", has_gvim ? "gvim.exe" : "vim.exe", "-c h",
1970 VIM_STARTMENU, WORKDIR) == FAIL)
1971 return;
1972 {
1973 char shell_folder_path[BUFSIZE];
1974
1975 /* Creating the URL shortcut works a bit differently... */
1976 if (get_shell_folder_path(shell_folder_path, VIM_STARTMENU) == FAIL)
1977 {
1978 printf("Finding the path of the Start menu failed\n");
1979 return ;
1980 }
1981 add_pathsep(shell_folder_path);
1982 strcat(shell_folder_path, "Vim Online.url");
1983 if (!WritePrivateProfileString("InternetShortcut", "URL",
Bram Moolenaarbd87eb32018-06-26 23:18:45 +02001984 "https://www.vim.org/", shell_folder_path))
Bram Moolenaar071d4272004-06-13 20:20:40 +00001985 {
1986 printf("Creating the Vim online URL failed\n");
1987 return;
1988 }
1989 }
1990}
1991
1992 static void
1993toggle_startmenu_choice(int idx)
1994{
1995 if (choices[idx].installfunc == NULL)
1996 {
1997 choices[idx].installfunc = install_start_menu;
1998 choices[idx].text = "Add Vim to the Start menu";
1999 }
2000 else
2001 {
2002 choices[idx].installfunc = NULL;
2003 choices[idx].text = "Do NOT add Vim to the Start menu";
2004 }
2005}
2006
2007/*
2008 * Function to actually create the shortcuts
2009 *
2010 * Currently I am supplying no working directory to the shortcut. This
2011 * means that the initial working dir will be:
2012 * - the location of the shortcut if no file is supplied
2013 * - the location of the file being edited if a file is supplied (ie via
2014 * drag and drop onto the shortcut).
2015 */
2016 void
2017install_shortcut_gvim(int idx)
2018{
2019 /* Create shortcut(s) on the desktop */
2020 if (choices[idx].arg)
2021 {
2022 (void)build_shortcut(icon_names[0], "gvim.exe",
2023 "", "desktop", WORKDIR);
2024 need_uninstall_entry = 1;
2025 }
2026}
2027
2028 void
2029install_shortcut_evim(int idx)
2030{
2031 if (choices[idx].arg)
2032 {
2033 (void)build_shortcut(icon_names[1], "gvim.exe",
2034 "-y", "desktop", WORKDIR);
2035 need_uninstall_entry = 1;
2036 }
2037}
2038
2039 void
2040install_shortcut_gview(int idx)
2041{
2042 if (choices[idx].arg)
2043 {
2044 (void)build_shortcut(icon_names[2], "gvim.exe",
2045 "-R", "desktop", WORKDIR);
2046 need_uninstall_entry = 1;
2047 }
2048}
2049
2050 void
2051toggle_shortcut_choice(int idx)
2052{
2053 char *arg;
2054
2055 if (choices[idx].installfunc == install_shortcut_gvim)
2056 arg = "gVim";
2057 else if (choices[idx].installfunc == install_shortcut_evim)
2058 arg = "gVim Easy";
2059 else
2060 arg = "gVim Read-only";
2061 if (choices[idx].arg)
2062 {
2063 choices[idx].arg = 0;
2064 alloc_text(idx, "Do NOT create a desktop icon for %s", arg);
2065 }
2066 else
2067 {
2068 choices[idx].arg = 1;
2069 alloc_text(idx, "Create a desktop icon for %s", arg);
2070 }
2071}
Bram Moolenaar071d4272004-06-13 20:20:40 +00002072
2073 static void
2074init_startmenu_choice(void)
2075{
Bram Moolenaar071d4272004-06-13 20:20:40 +00002076 /* Start menu */
2077 choices[choice_count].changefunc = toggle_startmenu_choice;
2078 choices[choice_count].installfunc = NULL;
2079 choices[choice_count].active = 1;
2080 toggle_startmenu_choice(choice_count); /* set the text */
2081 ++choice_count;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002082}
2083
2084/*
2085 * Add the choice for the desktop shortcuts.
2086 */
2087 static void
2088init_shortcut_choices(void)
2089{
Bram Moolenaar071d4272004-06-13 20:20:40 +00002090 /* Shortcut to gvim */
2091 choices[choice_count].text = NULL;
2092 choices[choice_count].arg = 0;
2093 choices[choice_count].active = has_gvim;
2094 choices[choice_count].changefunc = toggle_shortcut_choice;
2095 choices[choice_count].installfunc = install_shortcut_gvim;
2096 toggle_shortcut_choice(choice_count);
2097 ++choice_count;
2098
2099 /* Shortcut to evim */
2100 choices[choice_count].text = NULL;
2101 choices[choice_count].arg = 0;
2102 choices[choice_count].active = has_gvim;
2103 choices[choice_count].changefunc = toggle_shortcut_choice;
2104 choices[choice_count].installfunc = install_shortcut_evim;
2105 toggle_shortcut_choice(choice_count);
2106 ++choice_count;
2107
2108 /* Shortcut to gview */
2109 choices[choice_count].text = NULL;
2110 choices[choice_count].arg = 0;
2111 choices[choice_count].active = has_gvim;
2112 choices[choice_count].changefunc = toggle_shortcut_choice;
2113 choices[choice_count].installfunc = install_shortcut_gview;
2114 toggle_shortcut_choice(choice_count);
2115 ++choice_count;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002116}
2117
Bram Moolenaar071d4272004-06-13 20:20:40 +00002118/*
2119 * Attempt to register OLE for Vim.
2120 */
2121 static void
2122install_OLE_register(void)
2123{
2124 char register_command_string[BUFSIZE + 30];
2125
2126 printf("\n--- Attempting to register Vim with OLE ---\n");
2127 printf("(There is no message whether this works or not.)\n");
2128
Bram Moolenaar071d4272004-06-13 20:20:40 +00002129 sprintf(register_command_string, "\"%s\\gvim.exe\" -silent -register", installdir);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002130 system(register_command_string);
2131}
Bram Moolenaar071d4272004-06-13 20:20:40 +00002132
2133/*
2134 * Remove the last part of directory "path[]" to get its parent, and put the
2135 * result in "to[]".
2136 */
2137 static void
2138dir_remove_last(const char *path, char to[BUFSIZE])
2139{
2140 char c;
2141 long last_char_to_copy;
2142 long path_length = strlen(path);
2143
2144 /* skip the last character just in case it is a '\\' */
2145 last_char_to_copy = path_length - 2;
2146 c = path[last_char_to_copy];
2147
2148 while (c != '\\')
2149 {
2150 last_char_to_copy--;
2151 c = path[last_char_to_copy];
2152 }
2153
2154 strncpy(to, path, (size_t)last_char_to_copy);
2155 to[last_char_to_copy] = NUL;
2156}
2157
2158 static void
2159set_directories_text(int idx)
2160{
Bram Moolenaar25a494c2018-11-16 19:39:50 +01002161 int vimfiles_dir_choice = choices[idx].arg;
2162
Bram Moolenaar071d4272004-06-13 20:20:40 +00002163 if (vimfiles_dir_choice == (int)vimfiles_dir_none)
2164 alloc_text(idx, "Do NOT create plugin directories%s", "");
2165 else
2166 alloc_text(idx, "Create plugin directories: %s",
2167 vimfiles_dir_choices[vimfiles_dir_choice]);
2168}
2169
2170/*
Bram Moolenaar25a494c2018-11-16 19:39:50 +01002171 * To get the "real" home directory:
2172 * - get value of $HOME
2173 * - if not found, get value of $HOMEDRIVE$HOMEPATH
2174 * - if not found, get value of $USERPROFILE
2175 *
2176 * This code is based on init_homedir() in misc1.c, keep in sync!
2177 */
2178static char *homedir = NULL;
2179
2180 void
2181init_homedir(void)
2182{
2183 char *var;
2184 char buf[MAX_PATH];
2185
2186 if (homedir != NULL)
2187 {
2188 free(homedir);
2189 homedir = NULL;
2190 }
2191
2192 var = getenv("HOME");
2193
2194 /*
2195 * Typically, $HOME is not defined on Windows, unless the user has
2196 * specifically defined it for Vim's sake. However, on Windows NT
2197 * platforms, $HOMEDRIVE and $HOMEPATH are automatically defined for
2198 * each user. Try constructing $HOME from these.
2199 */
2200 if (var == NULL || *var == NUL)
2201 {
2202 char *homedrive, *homepath;
2203
2204 homedrive = getenv("HOMEDRIVE");
2205 homepath = getenv("HOMEPATH");
2206 if (homepath == NULL || *homepath == NUL)
2207 homepath = "\\";
2208 if (homedrive != NULL
2209 && strlen(homedrive) + strlen(homepath) < MAX_PATH)
2210 {
2211 sprintf(buf, "%s%s", homedrive, homepath);
2212 if (buf[0] != NUL)
2213 var = buf;
2214 }
2215 }
2216
2217 if (var == NULL)
2218 var = getenv("USERPROFILE");
2219
2220 /*
2221 * Weird but true: $HOME may contain an indirect reference to another
2222 * variable, esp. "%USERPROFILE%". Happens when $USERPROFILE isn't set
2223 * when $HOME is being set.
2224 */
2225 if (var != NULL && *var == '%')
2226 {
2227 char *p;
2228 char *exp;
2229
2230 p = strchr(var + 1, '%');
2231 if (p != NULL)
2232 {
2233 strncpy(buf, var + 1, p - (var + 1));
2234 buf[p - (var + 1)] = NUL;
2235 exp = getenv(buf);
2236 if (exp != NULL && *exp != NUL
2237 && strlen(exp) + strlen(p) < MAX_PATH)
2238 {
2239 _snprintf(buf, MAX_PATH, "%s%s", exp, p + 1);
2240 buf[MAX_PATH - 1] = NUL;
2241 var = buf;
2242 }
2243 }
2244 }
2245
2246 if (var != NULL && *var == NUL) // empty is same as not set
2247 var = NULL;
2248
2249 if (var == NULL)
2250 homedir = NULL;
2251 else
2252 homedir = _strdup(var);
2253}
2254
2255/*
Bram Moolenaar071d4272004-06-13 20:20:40 +00002256 * Change the directory that the vim plugin directories will be created in:
2257 * $HOME, $VIM or nowhere.
2258 */
2259 static void
2260change_directories_choice(int idx)
2261{
2262 int choice_count = TABLE_SIZE(vimfiles_dir_choices);
2263
2264 /* Don't offer the $HOME choice if $HOME isn't set. */
Bram Moolenaar25a494c2018-11-16 19:39:50 +01002265 if (homedir == NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002266 --choice_count;
Bram Moolenaar25a494c2018-11-16 19:39:50 +01002267 choices[idx].arg = get_choice(vimfiles_dir_choices, choice_count);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002268 set_directories_text(idx);
2269}
2270
2271/*
2272 * Create the plugin directories...
2273 */
2274/*ARGSUSED*/
2275 static void
2276install_vimfilesdir(int idx)
2277{
2278 int i;
Bram Moolenaar25a494c2018-11-16 19:39:50 +01002279 int vimfiles_dir_choice = choices[idx].arg;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002280 char *p;
Bram Moolenaarbbd854d2019-02-18 22:19:33 +01002281 char vimdir_path[MAX_PATH];
2282 char vimfiles_path[MAX_PATH + 9];
Bram Moolenaar071d4272004-06-13 20:20:40 +00002283 char tmp_dirname[BUFSIZE];
2284
2285 /* switch on the location that the user wants the plugin directories
2286 * built in */
2287 switch (vimfiles_dir_choice)
2288 {
2289 case vimfiles_dir_vim:
2290 {
2291 /* Go to the %VIM% directory - check env first, then go one dir
2292 * below installdir if there is no %VIM% environment variable.
2293 * The accuracy of $VIM is checked in inspect_system(), so we
2294 * can be sure it is ok to use here. */
2295 p = getenv("VIM");
2296 if (p == NULL) /* No $VIM in path */
2297 dir_remove_last(installdir, vimdir_path);
2298 else
2299 strcpy(vimdir_path, p);
2300 break;
2301 }
2302 case vimfiles_dir_home:
2303 {
Bram Moolenaar25a494c2018-11-16 19:39:50 +01002304 // Find the $HOME directory. Its existence was already checked.
2305 p = homedir;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002306 if (p == NULL)
2307 {
2308 printf("Internal error: $HOME is NULL\n");
2309 p = "c:\\";
2310 }
2311 strcpy(vimdir_path, p);
2312 break;
2313 }
2314 case vimfiles_dir_none:
2315 {
Bram Moolenaar25a494c2018-11-16 19:39:50 +01002316 // Do not create vim plugin directory.
Bram Moolenaar071d4272004-06-13 20:20:40 +00002317 return;
2318 }
2319 }
2320
2321 /* Now, just create the directory. If it already exists, it will fail
2322 * silently. */
2323 sprintf(vimfiles_path, "%s\\vimfiles", vimdir_path);
2324 vim_mkdir(vimfiles_path, 0755);
2325
2326 printf("Creating the following directories in \"%s\":\n", vimfiles_path);
2327 for (i = 0; i < TABLE_SIZE(vimfiles_subdirs); i++)
2328 {
2329 sprintf(tmp_dirname, "%s\\%s", vimfiles_path, vimfiles_subdirs[i]);
2330 printf(" %s", vimfiles_subdirs[i]);
2331 vim_mkdir(tmp_dirname, 0755);
2332 }
2333 printf("\n");
2334}
2335
2336/*
2337 * Add the creation of runtime files to the setup sequence.
2338 */
2339 static void
2340init_directories_choice(void)
2341{
2342 struct stat st;
2343 char tmp_dirname[BUFSIZE];
2344 char *p;
Bram Moolenaar25a494c2018-11-16 19:39:50 +01002345 int vimfiles_dir_choice;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002346
2347 choices[choice_count].text = alloc(150);
2348 choices[choice_count].changefunc = change_directories_choice;
2349 choices[choice_count].installfunc = install_vimfilesdir;
2350 choices[choice_count].active = 1;
2351
Bram Moolenaar25a494c2018-11-16 19:39:50 +01002352 // Check if the "compiler" directory already exists. That's a good
2353 // indication that the plugin directories were already created.
Bram Moolenaar071d4272004-06-13 20:20:40 +00002354 if (getenv("HOME") != NULL)
2355 {
2356 vimfiles_dir_choice = (int)vimfiles_dir_home;
2357 sprintf(tmp_dirname, "%s\\vimfiles\\compiler", getenv("HOME"));
2358 if (stat(tmp_dirname, &st) == 0)
2359 vimfiles_dir_choice = (int)vimfiles_dir_none;
2360 }
2361 else
2362 {
2363 vimfiles_dir_choice = (int)vimfiles_dir_vim;
2364 p = getenv("VIM");
Bram Moolenaar25a494c2018-11-16 19:39:50 +01002365 if (p == NULL) // No $VIM in path, use the install dir.
Bram Moolenaar071d4272004-06-13 20:20:40 +00002366 dir_remove_last(installdir, tmp_dirname);
2367 else
2368 strcpy(tmp_dirname, p);
2369 strcat(tmp_dirname, "\\vimfiles\\compiler");
2370 if (stat(tmp_dirname, &st) == 0)
2371 vimfiles_dir_choice = (int)vimfiles_dir_none;
2372 }
2373
Bram Moolenaar25a494c2018-11-16 19:39:50 +01002374 choices[choice_count].arg = vimfiles_dir_choice;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002375 set_directories_text(choice_count);
2376 ++choice_count;
2377}
2378
2379/*
2380 * Setup the choices and the default values.
2381 */
2382 static void
2383setup_choices(void)
2384{
2385 /* install the batch files */
2386 init_bat_choices();
2387
2388 /* (over) write _vimrc file */
2389 init_vimrc_choices();
2390
2391 /* Whether to add Vim to the popup menu */
2392 init_popup_choice();
2393
2394 /* Whether to add Vim to the "Open With..." menu */
2395 init_openwith_choice();
2396
2397 /* Whether to add Vim to the Start Menu. */
2398 init_startmenu_choice();
2399
2400 /* Whether to add shortcuts to the Desktop. */
2401 init_shortcut_choices();
2402
2403 /* Whether to create the runtime directories. */
2404 init_directories_choice();
2405}
2406
2407 static void
2408print_cmd_line_help(void)
2409{
2410 printf("Vim installer non-interactive command line arguments:\n");
2411 printf("\n");
2412 printf("-create-batfiles [vim gvim evim view gview vimdiff gvimdiff]\n");
2413 printf(" Create .bat files for Vim variants in the Windows directory.\n");
2414 printf("-create-vimrc\n");
2415 printf(" Create a default _vimrc file if one does not already exist.\n");
Bram Moolenaarc3fdf7f2017-10-28 18:36:48 +02002416 printf("-vimrc-remap [no|win]\n");
2417 printf(" Remap keys when creating a default _vimrc file.\n");
2418 printf("-vimrc-behave [unix|mswin|default]\n");
2419 printf(" Set mouse behavior when creating a default _vimrc file.\n");
Bram Moolenaar6cdb2c92018-10-13 17:25:27 +02002420 printf("-vimrc-compat [vi|vim|defaults|all]\n");
2421 printf(" Set Vi compatibility when creating a default _vimrc file.\n");
Bram Moolenaar071d4272004-06-13 20:20:40 +00002422 printf("-install-popup\n");
2423 printf(" Install the Edit-with-Vim context menu entry\n");
2424 printf("-install-openwith\n");
2425 printf(" Add Vim to the \"Open With...\" context menu list\n");
Bram Moolenaar071d4272004-06-13 20:20:40 +00002426 printf("-add-start-menu");
2427 printf(" Add Vim to the start menu\n");
2428 printf("-install-icons");
2429 printf(" Create icons for gVim executables on the desktop\n");
Bram Moolenaar071d4272004-06-13 20:20:40 +00002430 printf("-create-directories [vim|home]\n");
2431 printf(" Create runtime directories to drop plugins into; in the $VIM\n");
2432 printf(" or $HOME directory\n");
Bram Moolenaar071d4272004-06-13 20:20:40 +00002433 printf("-register-OLE");
Bram Moolenaarce0842a2005-07-18 21:58:11 +00002434 printf(" Ignored\n");
Bram Moolenaar071d4272004-06-13 20:20:40 +00002435 printf("\n");
2436}
2437
2438/*
2439 * Setup installation choices based on command line switches
2440 */
2441 static void
2442command_line_setup_choices(int argc, char **argv)
2443{
2444 int i, j;
2445
2446 for (i = 1; i < argc; i++)
2447 {
2448 if (strcmp(argv[i], "-create-batfiles") == 0)
2449 {
2450 if (i + 1 == argc)
2451 continue;
2452 while (argv[i + 1][0] != '-' && i < argc)
2453 {
2454 i++;
2455 for (j = 1; j < TARGET_COUNT; ++j)
2456 if ((targets[j].exenamearg[0] == 'g' ? has_gvim : has_vim)
2457 && strcmp(argv[i], targets[j].name) == 0)
2458 {
2459 init_bat_choice(j);
2460 break;
2461 }
2462 if (j == TARGET_COUNT)
2463 printf("%s is not a valid choice for -create-batfiles\n",
2464 argv[i]);
2465
2466 if (i + 1 == argc)
2467 break;
2468 }
2469 }
2470 else if (strcmp(argv[i], "-create-vimrc") == 0)
2471 {
2472 /* Setup default vimrc choices. If there is already a _vimrc file,
2473 * it will NOT be overwritten.
2474 */
2475 init_vimrc_choices();
2476 }
Bram Moolenaarc3fdf7f2017-10-28 18:36:48 +02002477 else if (strcmp(argv[i], "-vimrc-remap") == 0)
2478 {
2479 if (i + 1 == argc)
2480 break;
2481 i++;
2482 if (strcmp(argv[i], "no") == 0)
2483 remap_choice = remap_no;
2484 else if (strcmp(argv[i], "win") == 0)
2485 remap_choice = remap_win;
2486 }
2487 else if (strcmp(argv[i], "-vimrc-behave") == 0)
2488 {
2489 if (i + 1 == argc)
2490 break;
2491 i++;
2492 if (strcmp(argv[i], "unix") == 0)
2493 mouse_choice = mouse_xterm;
2494 else if (strcmp(argv[i], "mswin") == 0)
2495 mouse_choice = mouse_mswin;
2496 else if (strcmp(argv[i], "default") == 0)
2497 mouse_choice = mouse_default;
2498 }
Bram Moolenaar6cdb2c92018-10-13 17:25:27 +02002499 else if (strcmp(argv[i], "-vimrc-compat") == 0)
2500 {
2501 if (i + 1 == argc)
2502 break;
2503 i++;
2504 if (strcmp(argv[i], "vi") == 0)
2505 compat_choice = compat_vi;
2506 else if (strcmp(argv[i], "vim") == 0)
2507 compat_choice = compat_vim;
2508 else if (strcmp(argv[i], "defaults") == 0)
2509 compat_choice = compat_some_enhancements;
2510 else if (strcmp(argv[i], "all") == 0)
2511 compat_choice = compat_all_enhancements;
2512 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00002513 else if (strcmp(argv[i], "-install-popup") == 0)
2514 {
2515 init_popup_choice();
2516 }
2517 else if (strcmp(argv[i], "-install-openwith") == 0)
2518 {
2519 init_openwith_choice();
2520 }
2521 else if (strcmp(argv[i], "-add-start-menu") == 0)
2522 {
2523 init_startmenu_choice();
2524 }
2525 else if (strcmp(argv[i], "-install-icons") == 0)
2526 {
2527 init_shortcut_choices();
2528 }
2529 else if (strcmp(argv[i], "-create-directories") == 0)
2530 {
Bram Moolenaar142a9752018-12-14 19:54:39 +01002531 int vimfiles_dir_choice = (int)vimfiles_dir_none;
Bram Moolenaar25a494c2018-11-16 19:39:50 +01002532
Bram Moolenaar071d4272004-06-13 20:20:40 +00002533 init_directories_choice();
2534 if (argv[i + 1][0] != '-')
2535 {
2536 i++;
2537 if (strcmp(argv[i], "vim") == 0)
2538 vimfiles_dir_choice = (int)vimfiles_dir_vim;
2539 else if (strcmp(argv[i], "home") == 0)
2540 {
Bram Moolenaar25a494c2018-11-16 19:39:50 +01002541 if (homedir == NULL) // No $HOME in environment
2542 vimfiles_dir_choice = (int)vimfiles_dir_none;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002543 else
2544 vimfiles_dir_choice = (int)vimfiles_dir_home;
2545 }
2546 else
2547 {
2548 printf("Unknown argument for -create-directories: %s\n",
2549 argv[i]);
2550 print_cmd_line_help();
2551 }
2552 }
2553 else /* No choice specified, default to vim directory */
2554 vimfiles_dir_choice = (int)vimfiles_dir_vim;
Bram Moolenaar25a494c2018-11-16 19:39:50 +01002555 choices[choice_count - 1].arg = vimfiles_dir_choice;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002556 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00002557 else if (strcmp(argv[i], "-register-OLE") == 0)
2558 {
2559 /* This is always done when gvim is found */
2560 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00002561 else /* Unknown switch */
2562 {
2563 printf("Got unknown argument argv[%d] = %s\n", i, argv[i]);
2564 print_cmd_line_help();
2565 }
2566 }
2567}
2568
2569
2570/*
2571 * Show a few screens full of helpful information.
2572 */
2573 static void
2574show_help(void)
2575{
2576 static char *(items[]) =
2577 {
2578"Installing .bat files\n"
2579"---------------------\n"
2580"The vim.bat file is written in one of the directories in $PATH.\n"
2581"This makes it possible to start Vim from the command line.\n"
2582"If vim.exe can be found in $PATH, the choice for vim.bat will not be\n"
2583"present. It is assumed you will use the existing vim.exe.\n"
2584"If vim.bat can already be found in $PATH this is probably for an old\n"
2585"version of Vim (but this is not checked!). You can overwrite it.\n"
2586"If no vim.bat already exists, you can select one of the directories in\n"
2587"$PATH for creating the batch file, or disable creating a vim.bat file.\n"
2588"\n"
2589"If you choose not to create the vim.bat file, Vim can still be executed\n"
2590"in other ways, but not from the command line.\n"
2591"\n"
2592"The same applies to choices for gvim, evim, (g)view, and (g)vimdiff.\n"
2593"The first item can be used to change the path for all of them.\n"
2594,
2595"Creating a _vimrc file\n"
2596"----------------------\n"
2597"The _vimrc file is used to set options for how Vim behaves.\n"
2598"The install program can create a _vimrc file with a few basic choices.\n"
2599"You can edit this file later to tune your preferences.\n"
2600"If you already have a _vimrc or .vimrc file it can be overwritten.\n"
2601"Don't do that if you have made changes to it.\n"
2602,
2603"Vim features\n"
2604"------------\n"
2605"(this choice is only available when creating a _vimrc file)\n"
2606"1. Vim can run in Vi-compatible mode. Many nice Vim features are then\n"
Bram Moolenaar2b849492018-11-21 13:58:35 +01002607" disabled. Only choose Vi-compatible if you really need full Vi\n"
2608" compatibility.\n"
2609"2. Vim runs in not-Vi-compatible mode. Vim is still mostly Vi compatible,\n"
2610" but adds nice features like multi-level undo.\n"
2611"3. Running Vim with some enhancements is useful when you want some of\n"
Bram Moolenaar071d4272004-06-13 20:20:40 +00002612" the nice Vim features, but have a slow computer and want to keep it\n"
2613" really fast.\n"
Bram Moolenaar2b849492018-11-21 13:58:35 +01002614"4. Syntax highlighting shows many files in color. Not only does this look\n"
Bram Moolenaar071d4272004-06-13 20:20:40 +00002615" nice, it also makes it easier to spot errors and you can work faster.\n"
2616" The other features include editing compressed files.\n"
2617,
2618"Windows key mapping\n"
2619"-------------------\n"
2620"(this choice is only available when creating a _vimrc file)\n"
2621"Under MS-Windows the CTRL-C key copies text to the clipboard and CTRL-V\n"
2622"pastes text from the clipboard. There are a few more keys like these.\n"
2623"Unfortunately, in Vim these keys normally have another meaning.\n"
2624"1. Choose to have the keys like they normally are in Vim (useful if you\n"
2625" also use Vim on other systems).\n"
2626"2. Choose to have the keys work like they are used on MS-Windows (useful\n"
2627" if you mostly work on MS-Windows).\n"
2628,
2629"Mouse use\n"
2630"---------\n"
2631"(this choice is only available when creating a _vimrc file)\n"
2632"The right mouse button can be used in two ways:\n"
2633"1. The Unix way is to extend an existing selection. The popup menu is\n"
2634" not available.\n"
2635"2. The MS-Windows way is to show a popup menu, which allows you to\n"
2636" copy/paste text, undo/redo, etc. Extending the selection can still be\n"
2637" done by keeping SHIFT pressed while using the left mouse button\n"
2638,
2639"Edit-with-Vim context menu entry\n"
2640"--------------------------------\n"
2641"(this choice is only available when gvim.exe and gvimext.dll are present)\n"
2642"You can associate different file types with Vim, so that you can (double)\n"
2643"click on a file to edit it with Vim. This means you have to individually\n"
2644"select each file type.\n"
2645"An alternative is the option offered here: Install an \"Edit with Vim\"\n"
2646"entry in the popup menu for the right mouse button. This means you can\n"
2647"edit any file with Vim.\n"
2648,
2649"\"Open With...\" context menu entry\n"
2650"--------------------------------\n"
2651"(this choice is only available when gvim.exe is present)\n"
2652"This option adds Vim to the \"Open With...\" entry in the popup menu for\n"
2653"the right mouse button. This also makes it possible to edit HTML files\n"
2654"directly from Internet Explorer.\n"
2655,
2656"Add Vim to the Start menu\n"
2657"-------------------------\n"
2658"In Windows 95 and later, Vim can be added to the Start menu. This will\n"
2659"create a submenu with an entry for vim, gvim, evim, vimdiff, etc..\n"
2660,
2661"Icons on the desktop\n"
2662"--------------------\n"
2663"(these choices are only available when installing gvim)\n"
2664"In Windows 95 and later, shortcuts (icons) can be created on the Desktop.\n"
2665,
2666"Create plugin directories\n"
2667"-------------------------\n"
2668"Plugin directories allow extending Vim by dropping a file into a directory.\n"
2669"This choice allows creating them in $HOME (if you have a home directory) or\n"
2670"$VIM (used for everybody on the system).\n"
2671,
2672NULL
2673 };
2674 int i;
2675 int c;
2676
2677 rewind(stdin);
2678 printf("\n");
2679 for (i = 0; items[i] != NULL; ++i)
2680 {
Bram Moolenaarc3fdf7f2017-10-28 18:36:48 +02002681 puts(items[i]);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002682 printf("Hit Enter to continue, b (back) or q (quit help): ");
2683 c = getchar();
2684 rewind(stdin);
2685 if (c == 'b' || c == 'B')
2686 {
2687 if (i == 0)
2688 --i;
2689 else
2690 i -= 2;
2691 }
2692 if (c == 'q' || c == 'Q')
2693 break;
2694 printf("\n");
2695 }
2696}
2697
2698/*
2699 * Install the choices.
2700 */
2701 static void
2702install(void)
2703{
2704 int i;
2705
2706 /* Install the selected choices. */
2707 for (i = 0; i < choice_count; ++i)
2708 if (choices[i].installfunc != NULL && choices[i].active)
2709 (choices[i].installfunc)(i);
2710
2711 /* Add some entries to the registry, if needed. */
2712 if (install_popup
2713 || install_openwith
2714 || (need_uninstall_entry && interactive)
2715 || !interactive)
2716 install_registry();
2717
Bram Moolenaar071d4272004-06-13 20:20:40 +00002718 /* Register gvim with OLE. */
2719 if (has_gvim)
2720 install_OLE_register();
Bram Moolenaar071d4272004-06-13 20:20:40 +00002721}
2722
2723/*
2724 * request_choice
2725 */
2726 static void
2727request_choice(void)
2728{
2729 int i;
2730
2731 printf("\n\nInstall will do for you:\n");
2732 for (i = 0; i < choice_count; ++i)
2733 if (choices[i].active)
2734 printf("%2d %s\n", i + 1, choices[i].text);
2735 printf("To change an item, enter its number\n\n");
2736 printf("Enter item number, h (help), d (do it) or q (quit): ");
2737}
2738
2739 int
2740main(int argc, char **argv)
2741{
2742 int i;
2743 char buf[BUFSIZE];
2744
2745 /*
2746 * Run interactively if there are no command line arguments.
2747 */
2748 if (argc > 1)
2749 interactive = 0;
2750 else
2751 interactive = 1;
2752
2753 /* Initialize this program. */
2754 do_inits(argv);
Bram Moolenaar25a494c2018-11-16 19:39:50 +01002755 init_homedir();
Bram Moolenaar071d4272004-06-13 20:20:40 +00002756
Bram Moolenaar071d4272004-06-13 20:20:40 +00002757 if (argc > 1 && strcmp(argv[1], "-uninstall-check") == 0)
2758 {
2759 /* Only check for already installed Vims. Used by NSIS installer. */
Bram Moolenaar442b4222010-05-24 21:34:22 +02002760 i = uninstall_check(1);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002761
2762 /* Find the value of $VIM, because NSIS isn't able to do this by
2763 * itself. */
2764 get_vim_env();
2765
2766 /* When nothing found exit quietly. If something found wait for
Bram Moolenaarb230bd52010-05-25 21:02:00 +02002767 * a little while, so that the user can read the messages. */
Bram Moolenaar6cdb2c92018-10-13 17:25:27 +02002768 if (i && _isatty(1))
Bram Moolenaarab8205e2010-07-07 15:14:03 +02002769 sleep(3);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002770 exit(0);
2771 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00002772
2773 printf("This program sets up the installation of Vim "
2774 VIM_VERSION_MEDIUM "\n\n");
2775
2776 /* Check if the user unpacked the archives properly. */
2777 check_unpack();
2778
Bram Moolenaar071d4272004-06-13 20:20:40 +00002779 /* Check for already installed Vims. */
2780 if (interactive)
Bram Moolenaar442b4222010-05-24 21:34:22 +02002781 uninstall_check(0);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002782
2783 /* Find out information about the system. */
2784 inspect_system();
2785
2786 if (interactive)
2787 {
2788 /* Setup all the choices. */
2789 setup_choices();
2790
2791 /* Let the user change choices and finally install (or quit). */
2792 for (;;)
2793 {
2794 request_choice();
2795 rewind(stdin);
2796 if (scanf("%99s", buf) == 1)
2797 {
2798 if (isdigit(buf[0]))
2799 {
2800 /* Change a choice. */
2801 i = atoi(buf);
2802 if (i > 0 && i <= choice_count && choices[i - 1].active)
2803 (choices[i - 1].changefunc)(i - 1);
2804 else
2805 printf("\nIllegal choice\n");
2806 }
2807 else if (buf[0] == 'h' || buf[0] == 'H')
2808 {
2809 /* Help */
2810 show_help();
2811 }
2812 else if (buf[0] == 'd' || buf[0] == 'D')
2813 {
2814 /* Install! */
2815 install();
2816 printf("\nThat finishes the installation. Happy Vimming!\n");
2817 break;
2818 }
2819 else if (buf[0] == 'q' || buf[0] == 'Q')
2820 {
2821 /* Quit */
2822 printf("\nExiting without anything done\n");
2823 break;
2824 }
2825 else
2826 printf("\nIllegal choice\n");
2827 }
2828 }
2829 printf("\n");
Bram Moolenaar442b4222010-05-24 21:34:22 +02002830 myexit(0);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002831 }
2832 else
2833 {
2834 /*
2835 * Run non-interactive - setup according to the command line switches
2836 */
2837 command_line_setup_choices(argc, argv);
2838 install();
Bram Moolenaar442b4222010-05-24 21:34:22 +02002839
2840 /* Avoid that the user has to hit Enter, just wait a little bit to
2841 * allow reading the messages. */
Bram Moolenaarab8205e2010-07-07 15:14:03 +02002842 sleep(2);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002843 }
2844
Bram Moolenaar071d4272004-06-13 20:20:40 +00002845 return 0;
2846}