blob: 5b05598872d68133b03f6fe327a6d6e15562a79d [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);
294 char *cp = bp + indir_l;
295 char *tmpname;
296 char *farname;
297
298 /*
299 * No action needed if exe not found or not in this directory.
300 */
301 if (bp == NULL
302 || strnicmp(bp, installdir, indir_l) != 0
303 || strchr("/\\", *cp++) == NULL
304 || strchr(cp, '\\') != NULL
305 || strchr(cp, '/') != NULL)
306 return;
307
308 tmpname = alloc((int)strlen(cp) + 1);
309 strcpy(tmpname, cp);
310 tmpname[strlen(tmpname) - 1] = 'x'; /* .exe -> .exx */
311
312 if (access(tmpname, 0) == 0)
313 {
314 printf("\nERROR: %s and %s clash. Remove or rename %s.\n",
315 tmpname, cp, tmpname);
316 myexit(1);
317 }
318
319 if (rename(cp, tmpname) != 0)
320 {
321 printf("\nERROR: failed to rename %s to %s: %s\n",
322 cp, tmpname, strerror(0));
323 myexit(1);
324 }
325
326 farname = searchpath_save(cp);
327
328 if (rename(tmpname, cp) != 0)
329 {
330 printf("\nERROR: failed to rename %s back to %s: %s\n",
331 tmpname, cp, strerror(0));
332 myexit(1);
333 }
334
335 free(*destination);
336 free(tmpname);
337 *destination = farname;
338}
339
340/*
341 * Check if there is a vim.[exe|bat|, gvim.[exe|bat|, etc. in the path.
342 * When "check_bat_only" is TRUE, only find "default_bat_dir".
343 */
344 static void
345find_bat_exe(int check_bat_only)
346{
347 int i;
348
Bram Moolenaar42bbef42006-03-25 22:02:07 +0000349 /* avoid looking in the "installdir" by chdir to system root */
350 mch_chdir(sysdrive);
351 mch_chdir("\\");
Bram Moolenaar071d4272004-06-13 20:20:40 +0000352
353 for (i = 1; i < TARGET_COUNT; ++i)
354 {
355 targets[i].oldbat = searchpath_save(targets[i].batname);
356 if (!check_bat_only)
357 targets[i].oldexe = searchpath_save(targets[i].exename);
358
359 if (default_bat_dir == NULL && targets[i].oldbat != NULL)
360 {
361 default_bat_dir = alloc(strlen(targets[i].oldbat) + 1);
362 strcpy(default_bat_dir, targets[i].oldbat);
363 remove_tail(default_bat_dir);
364 }
365 if (check_bat_only && targets[i].oldbat != NULL)
Bram Moolenaar42bbef42006-03-25 22:02:07 +0000366 {
Bram Moolenaar071d4272004-06-13 20:20:40 +0000367 free(targets[i].oldbat);
Bram Moolenaar42bbef42006-03-25 22:02:07 +0000368 targets[i].oldbat = NULL;
369 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000370 }
371
372 mch_chdir(installdir);
373}
374
Bram Moolenaar071d4272004-06-13 20:20:40 +0000375/*
376 * Get the value of $VIMRUNTIME or $VIM and write it in $TEMP/vimini.ini, so
377 * that NSIS can read it.
378 * When not set, use the directory of a previously installed Vim.
379 */
380 static void
381get_vim_env(void)
382{
383 char *vim;
384 char buf[BUFSIZE];
385 FILE *fd;
386 char fname[BUFSIZE];
387
388 /* First get $VIMRUNTIME. If it's set, remove the tail. */
389 vim = getenv("VIMRUNTIME");
Bram Moolenaar181ace22013-02-13 14:36:44 +0100390 if (vim != NULL && *vim != 0 && strlen(vim) < BUFSIZE)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000391 {
392 strcpy(buf, vim);
393 remove_tail(buf);
394 vim = buf;
395 }
396 else
397 {
398 vim = getenv("VIM");
399 if (vim == NULL || *vim == 0)
400 {
401 /* Use the directory from an old uninstall entry. */
402 if (default_vim_dir != NULL)
403 vim = default_vim_dir;
404 else
405 /* Let NSIS know there is no default, it should use
Bram Moolenaarb8017e72007-05-10 18:59:07 +0000406 * $PROGRAMFILES. */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000407 vim = "";
408 }
409 }
410
411 /* NSIS also uses GetTempPath(), thus we should get the same directory
412 * name as where NSIS will look for vimini.ini. */
413 GetTempPath(BUFSIZE, fname);
414 add_pathsep(fname);
415 strcat(fname, "vimini.ini");
416
417 fd = fopen(fname, "w");
418 if (fd != NULL)
419 {
420 /* Make it look like an .ini file, so that NSIS can read it with a
421 * ReadINIStr command. */
422 fprintf(fd, "[vimini]\n");
423 fprintf(fd, "dir=\"%s\"\n", vim);
424 fclose(fd);
425 }
426 else
427 {
428 printf("Failed to open %s\n", fname);
Bram Moolenaarab8205e2010-07-07 15:14:03 +0200429 sleep(2);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000430 }
431}
432
Bram Moolenaarb230bd52010-05-25 21:02:00 +0200433static int num_windows;
434
435/*
436 * Callback used for EnumWindows():
437 * Count the window if the title looks like it is for the uninstaller.
438 */
439/*ARGSUSED*/
440 static BOOL CALLBACK
441window_cb(HWND hwnd, LPARAM lparam)
442{
443 char title[256];
444
445 title[0] = 0;
446 GetWindowText(hwnd, title, 256);
Bram Moolenaaraf610b82018-12-21 16:22:50 +0100447 if (strstr(title, "Vim ") != NULL && strstr(title, " Uninstall") != NULL)
Bram Moolenaarb230bd52010-05-25 21:02:00 +0200448 ++num_windows;
449 return TRUE;
450}
451
Bram Moolenaar071d4272004-06-13 20:20:40 +0000452/*
Bram Moolenaaraf610b82018-12-21 16:22:50 +0100453 * Run the uninstaller silently.
454 */
455 static int
456run_silent_uninstall(char *uninst_exe)
457{
458 char vimrt_dir[BUFSIZE];
459 char temp_uninst[BUFSIZE];
460 char temp_dir[MAX_PATH];
461 char buf[BUFSIZE * 2 + 10];
462 int i;
463 DWORD tick;
464
465 strcpy(vimrt_dir, uninst_exe);
466 remove_tail(vimrt_dir);
467
468 if (!GetTempPath(sizeof(temp_dir), temp_dir))
469 return FAIL;
470
471 /* Copy the uninstaller to a temporary exe. */
472 tick = GetTickCount();
473 for (i = 0; ; i++)
474 {
475 sprintf(temp_uninst, "%s\\vimun%04X.exe", temp_dir,
Bram Moolenaar44a7db42019-01-11 20:47:31 +0100476 (unsigned int)((i + tick) & 0xFFFF));
Bram Moolenaaraf610b82018-12-21 16:22:50 +0100477 if (CopyFile(uninst_exe, temp_uninst, TRUE))
478 break;
479 if (GetLastError() != ERROR_FILE_EXISTS)
480 return FAIL;
481 if (i == 65535)
482 return FAIL;
483 }
484
485 /* Run the copied uninstaller silently. */
486 if (strchr(temp_uninst, ' ') != NULL)
487 sprintf(buf, "\"%s\" /S _?=%s", temp_uninst, vimrt_dir);
488 else
489 sprintf(buf, "%s /S _?=%s", temp_uninst, vimrt_dir);
490 run_command(buf);
491
492 DeleteFile(temp_uninst);
493 return OK;
494}
495
496/*
Bram Moolenaar071d4272004-06-13 20:20:40 +0000497 * Check for already installed Vims.
498 * Return non-zero when found one.
499 */
500 static int
Bram Moolenaar442b4222010-05-24 21:34:22 +0200501uninstall_check(int skip_question)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000502{
503 HKEY key_handle;
504 HKEY uninstall_key_handle;
505 char *uninstall_key = "software\\Microsoft\\Windows\\CurrentVersion\\Uninstall";
506 char subkey_name_buff[BUFSIZE];
507 char temp_string_buffer[BUFSIZE];
508 DWORD local_bufsize = BUFSIZE;
509 FILETIME temp_pfiletime;
510 DWORD key_index;
511 char input;
512 long code;
513 DWORD value_type;
514 DWORD orig_num_keys;
515 DWORD new_num_keys;
Bram Moolenaaraf610b82018-12-21 16:22:50 +0100516 DWORD allow_silent;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000517 int foundone = 0;
518
Bram Moolenaar760d14a2010-07-31 22:03:44 +0200519 code = RegOpenKeyEx(HKEY_LOCAL_MACHINE, uninstall_key, 0,
520 KEY_WOW64_64KEY | KEY_READ, &key_handle);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000521 CHECK_REG_ERROR(code);
522
523 for (key_index = 0;
524 RegEnumKeyEx(key_handle, key_index, subkey_name_buff, &local_bufsize,
525 NULL, NULL, NULL, &temp_pfiletime) != ERROR_NO_MORE_ITEMS;
526 key_index++)
527 {
528 local_bufsize = BUFSIZE;
529 if (strncmp("Vim", subkey_name_buff, 3) == 0)
530 {
531 /* Open the key named Vim* */
Bram Moolenaar760d14a2010-07-31 22:03:44 +0200532 code = RegOpenKeyEx(key_handle, subkey_name_buff, 0,
533 KEY_WOW64_64KEY | KEY_READ, &uninstall_key_handle);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000534 CHECK_REG_ERROR(code);
535
536 /* get the DisplayName out of it to show the user */
537 code = RegQueryValueEx(uninstall_key_handle, "displayname", 0,
538 &value_type, (LPBYTE)temp_string_buffer,
539 &local_bufsize);
540 local_bufsize = BUFSIZE;
541 CHECK_REG_ERROR(code);
542
Bram Moolenaaraf610b82018-12-21 16:22:50 +0100543 allow_silent = 0;
544 if (skip_question)
545 {
546 DWORD varsize = sizeof(DWORD);
547
548 RegQueryValueEx(uninstall_key_handle, "AllowSilent", 0,
549 &value_type, (LPBYTE)&allow_silent,
550 &varsize);
551 }
552
Bram Moolenaar071d4272004-06-13 20:20:40 +0000553 foundone = 1;
554 printf("\n*********************************************************\n");
555 printf("Vim Install found what looks like an existing Vim version.\n");
556 printf("The name of the entry is:\n");
557 printf("\n \"%s\"\n\n", temp_string_buffer);
558
559 printf("Installing the new version will disable part of the existing version.\n");
560 printf("(The batch files used in a console and the \"Edit with Vim\" entry in\n");
561 printf("the popup menu will use the new version)\n");
562
Bram Moolenaar442b4222010-05-24 21:34:22 +0200563 if (skip_question)
564 printf("\nRunning uninstall program for \"%s\"\n", temp_string_buffer);
565 else
566 printf("\nDo you want to uninstall \"%s\" now?\n(y)es/(n)o) ", temp_string_buffer);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000567 fflush(stdout);
568
569 /* get the UninstallString */
570 code = RegQueryValueEx(uninstall_key_handle, "uninstallstring", 0,
571 &value_type, (LPBYTE)temp_string_buffer, &local_bufsize);
572 local_bufsize = BUFSIZE;
573 CHECK_REG_ERROR(code);
574
575 /* Remember the directory, it is used as the default for NSIS. */
576 default_vim_dir = alloc(strlen(temp_string_buffer) + 1);
577 strcpy(default_vim_dir, temp_string_buffer);
578 remove_tail(default_vim_dir);
579 remove_tail(default_vim_dir);
580
581 input = 'n';
582 do
583 {
584 if (input != 'n')
585 printf("%c is an invalid reply. Please enter either 'y' or 'n'\n", input);
586
Bram Moolenaar442b4222010-05-24 21:34:22 +0200587 if (skip_question)
588 input = 'y';
589 else
590 {
591 rewind(stdin);
592 scanf("%c", &input);
593 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000594 switch (input)
595 {
596 case 'y':
597 case 'Y':
598 /* save the number of uninstall keys so we can know if
599 * it changed */
600 RegQueryInfoKey(key_handle, NULL, NULL, NULL,
601 &orig_num_keys, NULL, NULL, NULL,
602 NULL, NULL, NULL, NULL);
603
Bram Moolenaar442b4222010-05-24 21:34:22 +0200604 /* Find existing .bat files before deleting them. */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000605 find_bat_exe(TRUE);
606
Bram Moolenaaraf610b82018-12-21 16:22:50 +0100607 if (allow_silent)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000608 {
Bram Moolenaaraf610b82018-12-21 16:22:50 +0100609 if (run_silent_uninstall(temp_string_buffer)
610 == FAIL)
611 allow_silent = 0; /* Retry with non silent. */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000612 }
Bram Moolenaaraf610b82018-12-21 16:22:50 +0100613 if (!allow_silent)
Bram Moolenaarb230bd52010-05-25 21:02:00 +0200614 {
Bram Moolenaaraf610b82018-12-21 16:22:50 +0100615 /* Execute the uninstall program. Put it in double
616 * quotes if there is an embedded space. */
Bram Moolenaarb230bd52010-05-25 21:02:00 +0200617 {
Bram Moolenaaraf610b82018-12-21 16:22:50 +0100618 char buf[BUFSIZE];
619
620 if (strchr(temp_string_buffer, ' ') != NULL)
621 sprintf(buf, "\"%s\"", temp_string_buffer);
622 else
623 strcpy(buf, temp_string_buffer);
624 run_command(buf);
625 }
626
627 /* Count the number of windows with a title that match
628 * the installer, so that we can check when it's done.
629 * The uninstaller copies itself, executes the copy
630 * and exits, thus we can't wait for the process to
631 * finish. */
632 sleep(1); /* wait for uninstaller to start up */
633 num_windows = 0;
634 EnumWindows(window_cb, 0);
635 if (num_windows == 0)
636 {
637 /* Did not find the uninstaller, ask user to press
638 * Enter when done. Just in case. */
639 printf("Press Enter when the uninstaller is finished\n");
640 rewind(stdin);
641 (void)getchar();
642 }
643 else
644 {
645 printf("Waiting for the uninstaller to finish (press CTRL-C to abort).");
646 do
647 {
648 printf(".");
649 fflush(stdout);
650 sleep(1); /* wait for the uninstaller to finish */
651 num_windows = 0;
652 EnumWindows(window_cb, 0);
653 } while (num_windows > 0);
654 }
Bram Moolenaarb230bd52010-05-25 21:02:00 +0200655 }
656 printf("\nDone!\n");
Bram Moolenaar071d4272004-06-13 20:20:40 +0000657
Bram Moolenaarfff2bee2010-05-15 13:56:02 +0200658 /* Check if an uninstall reg key was deleted.
Bram Moolenaar071d4272004-06-13 20:20:40 +0000659 * if it was, we want to decrement key_index.
660 * if we don't do this, we will skip the key
661 * immediately after any key that we delete. */
662 RegQueryInfoKey(key_handle, NULL, NULL, NULL,
663 &new_num_keys, NULL, NULL, NULL,
664 NULL, NULL, NULL, NULL);
665 if (new_num_keys < orig_num_keys)
666 key_index--;
667
668 input = 'y';
669 break;
670
671 case 'n':
672 case 'N':
673 /* Do not uninstall */
674 input = 'n';
675 break;
676
677 default: /* just drop through and redo the loop */
678 break;
679 }
680
681 } while (input != 'n' && input != 'y');
682
683 RegCloseKey(uninstall_key_handle);
684 }
685 }
686 RegCloseKey(key_handle);
687
688 return foundone;
689}
Bram Moolenaar071d4272004-06-13 20:20:40 +0000690
691/*
692 * Find out information about the system.
693 */
694 static void
695inspect_system(void)
696{
697 char *p;
698 char buf[BUFSIZE];
699 FILE *fd;
700 int i;
701 int foundone;
702
703 /* This may take a little while, let the user know what we're doing. */
704 printf("Inspecting system...\n");
705
706 /*
707 * If $VIM is set, check that it's pointing to our directory.
708 */
709 p = getenv("VIM");
710 if (p != NULL && pathcmp(p, -1, installdir, runtimeidx - 1) != 0)
711 {
712 printf("------------------------------------------------------\n");
713 printf("$VIM is set to \"%s\".\n", p);
714 printf("This is different from where this version of Vim is:\n");
715 strcpy(buf, installdir);
716 *(buf + runtimeidx - 1) = NUL;
717 printf("\"%s\"\n", buf);
718 printf("You must adjust or remove the setting of $VIM,\n");
719 if (interactive)
720 {
721 printf("to be able to use this install program.\n");
722 myexit(1);
723 }
724 printf("otherwise Vim WILL NOT WORK properly!\n");
725 printf("------------------------------------------------------\n");
726 }
727
728 /*
729 * If $VIMRUNTIME is set, check that it's pointing to our runtime directory.
730 */
731 p = getenv("VIMRUNTIME");
732 if (p != NULL && pathcmp(p, -1, installdir, -1) != 0)
733 {
734 printf("------------------------------------------------------\n");
735 printf("$VIMRUNTIME is set to \"%s\".\n", p);
736 printf("This is different from where this version of Vim is:\n");
737 printf("\"%s\"\n", installdir);
738 printf("You must adjust or remove the setting of $VIMRUNTIME,\n");
739 if (interactive)
740 {
741 printf("to be able to use this install program.\n");
742 myexit(1);
743 }
744 printf("otherwise Vim WILL NOT WORK properly!\n");
745 printf("------------------------------------------------------\n");
746 }
747
748 /*
749 * Check if there is a vim.[exe|bat|, gvim.[exe|bat|, etc. in the path.
750 */
751 find_bat_exe(FALSE);
752
753 /*
754 * A .exe in the install directory may be found anyway on Windows 2000.
755 * Check for this situation and find another executable if necessary.
756 * w.briscoe@ponl.com 2001-01-20
757 */
758 foundone = 0;
759 for (i = 1; i < TARGET_COUNT; ++i)
760 {
761 findoldfile(&(targets[i].oldexe));
762 if (targets[i].oldexe != NULL)
763 foundone = 1;
764 }
765
766 if (foundone)
767 {
768 printf("Warning: Found Vim executable(s) in your $PATH:\n");
769 for (i = 1; i < TARGET_COUNT; ++i)
770 if (targets[i].oldexe != NULL)
771 printf("%s\n", targets[i].oldexe);
772 printf("It will be used instead of the version you are installing.\n");
773 printf("Please delete or rename it, or adjust your $PATH setting.\n");
774 }
775
776 /*
777 * Check if there is an existing ../_vimrc or ../.vimrc file.
778 */
779 strcpy(oldvimrc, installdir);
780 strcpy(oldvimrc + runtimeidx, "_vimrc");
781 if ((fd = fopen(oldvimrc, "r")) == NULL)
782 {
783 strcpy(oldvimrc + runtimeidx, "vimrc~1"); /* short version of .vimrc */
784 if ((fd = fopen(oldvimrc, "r")) == NULL)
785 {
786 strcpy(oldvimrc + runtimeidx, ".vimrc");
787 fd = fopen(oldvimrc, "r");
788 }
789 }
790 if (fd != NULL)
791 fclose(fd);
792 else
793 *oldvimrc = NUL;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000794}
795
796/*
797 * Add a dummy choice to avoid that the numbering changes depending on items
798 * in the environment. The user may type a number he remembered without
799 * looking.
800 */
801 static void
802add_dummy_choice(void)
803{
804 choices[choice_count].installfunc = NULL;
805 choices[choice_count].active = 0;
806 choices[choice_count].changefunc = NULL;
Bram Moolenaar25a494c2018-11-16 19:39:50 +0100807 choices[choice_count].text = NULL;
808 choices[choice_count].arg = 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000809 ++choice_count;
810}
811
812/***********************************************
813 * stuff for creating the batch files.
814 */
815
816/*
817 * Install the vim.bat, gvim.bat, etc. files.
818 */
819 static void
820install_bat_choice(int idx)
821{
822 char *batpath = targets[choices[idx].arg].batpath;
823 char *oldname = targets[choices[idx].arg].oldbat;
824 char *exename = targets[choices[idx].arg].exenamearg;
825 char *vimarg = targets[choices[idx].arg].exearg;
826 FILE *fd;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000827
828 if (*batpath != NUL)
829 {
830 fd = fopen(batpath, "w");
831 if (fd == NULL)
832 printf("\nERROR: Cannot open \"%s\" for writing.\n", batpath);
833 else
834 {
835 need_uninstall_entry = 1;
836
837 fprintf(fd, "@echo off\n");
Bram Moolenaar97b2ad32006-03-18 21:40:56 +0000838 fprintf(fd, "rem -- Run Vim --\n");
839 fprintf(fd, "\n");
Bram Moolenaare609ad52016-03-28 23:05:48 +0200840 fprintf(fd, "setlocal\n");
Bram Moolenaar071d4272004-06-13 20:20:40 +0000841
Bram Moolenaar97b2ad32006-03-18 21:40:56 +0000842 /* Don't use double quotes for the "set" argument, also when it
Bram Moolenaar071d4272004-06-13 20:20:40 +0000843 * contains a space. The quotes would be included in the value
Bram Moolenaar97b2ad32006-03-18 21:40:56 +0000844 * for MSDOS and NT.
845 * The order of preference is:
846 * 1. $VIMRUNTIME/vim.exe (user preference)
847 * 2. $VIM/vim70/vim.exe (hard coded version)
848 * 3. installdir/vim.exe (hard coded install directory)
849 */
850 fprintf(fd, "set VIM_EXE_DIR=%s\n", installdir);
851 fprintf(fd, "if exist \"%%VIM%%\\%s\\%s\" set VIM_EXE_DIR=%%VIM%%\\%s\n",
852 VIM_VERSION_NODOT, exename, VIM_VERSION_NODOT);
853 fprintf(fd, "if exist \"%%VIMRUNTIME%%\\%s\" set VIM_EXE_DIR=%%VIMRUNTIME%%\n", exename);
854 fprintf(fd, "\n");
Bram Moolenaar071d4272004-06-13 20:20:40 +0000855
856 /* Give an error message when the executable could not be found. */
Bram Moolenaar97b2ad32006-03-18 21:40:56 +0000857 fprintf(fd, "if exist \"%%VIM_EXE_DIR%%\\%s\" goto havevim\n",
858 exename);
859 fprintf(fd, "echo \"%%VIM_EXE_DIR%%\\%s\" not found\n", exename);
860 fprintf(fd, "goto eof\n");
861 fprintf(fd, "\n");
Bram Moolenaar071d4272004-06-13 20:20:40 +0000862 fprintf(fd, ":havevim\n");
863
864 fprintf(fd, "rem collect the arguments in VIMARGS for Win95\n");
865 fprintf(fd, "set VIMARGS=\n");
866 if (*exename == 'g')
867 fprintf(fd, "set VIMNOFORK=\n");
868 fprintf(fd, ":loopstart\n");
869 fprintf(fd, "if .%%1==. goto loopend\n");
870 if (*exename == 'g')
871 {
Bram Moolenaare609ad52016-03-28 23:05:48 +0200872 fprintf(fd, "if NOT .%%1==.--nofork goto noforklongarg\n");
873 fprintf(fd, "set VIMNOFORK=1\n");
874 fprintf(fd, ":noforklongarg\n");
Bram Moolenaar071d4272004-06-13 20:20:40 +0000875 fprintf(fd, "if NOT .%%1==.-f goto noforkarg\n");
876 fprintf(fd, "set VIMNOFORK=1\n");
877 fprintf(fd, ":noforkarg\n");
878 }
879 fprintf(fd, "set VIMARGS=%%VIMARGS%% %%1\n");
880 fprintf(fd, "shift\n");
Bram Moolenaar97b2ad32006-03-18 21:40:56 +0000881 fprintf(fd, "goto loopstart\n");
Bram Moolenaar071d4272004-06-13 20:20:40 +0000882 fprintf(fd, ":loopend\n");
Bram Moolenaar97b2ad32006-03-18 21:40:56 +0000883 fprintf(fd, "\n");
Bram Moolenaar071d4272004-06-13 20:20:40 +0000884
Bram Moolenaar97b2ad32006-03-18 21:40:56 +0000885 fprintf(fd, "if .%%OS%%==.Windows_NT goto ntaction\n");
886 fprintf(fd, "\n");
Bram Moolenaar071d4272004-06-13 20:20:40 +0000887
888 /* For gvim.exe use "start" to avoid that the console window stays
889 * open. */
890 if (*exename == 'g')
891 {
892 fprintf(fd, "if .%%VIMNOFORK%%==.1 goto nofork\n");
893 fprintf(fd, "start ");
894 }
895
Bram Moolenaar97b2ad32006-03-18 21:40:56 +0000896 /* Always use quotes, $VIM or $VIMRUNTIME might have a space. */
897 fprintf(fd, "\"%%VIM_EXE_DIR%%\\%s\" %s %%VIMARGS%%\n",
898 exename, vimarg);
899 fprintf(fd, "goto eof\n");
900 fprintf(fd, "\n");
Bram Moolenaar071d4272004-06-13 20:20:40 +0000901
902 if (*exename == 'g')
903 {
904 fprintf(fd, ":nofork\n");
905 fprintf(fd, "start /w ");
Bram Moolenaar97b2ad32006-03-18 21:40:56 +0000906 /* Always use quotes, $VIM or $VIMRUNTIME might have a space. */
907 fprintf(fd, "\"%%VIM_EXE_DIR%%\\%s\" %s %%VIMARGS%%\n",
908 exename, vimarg);
909 fprintf(fd, "goto eof\n");
910 fprintf(fd, "\n");
Bram Moolenaar071d4272004-06-13 20:20:40 +0000911 }
912
913 fprintf(fd, ":ntaction\n");
914 fprintf(fd, "rem for WinNT we can use %%*\n");
915
916 /* For gvim.exe use "start /b" to avoid that the console window
917 * stays open. */
918 if (*exename == 'g')
919 {
920 fprintf(fd, "if .%%VIMNOFORK%%==.1 goto noforknt\n");
921 fprintf(fd, "start \"dummy\" /b ");
922 }
923
Bram Moolenaar97b2ad32006-03-18 21:40:56 +0000924 /* Always use quotes, $VIM or $VIMRUNTIME might have a space. */
925 fprintf(fd, "\"%%VIM_EXE_DIR%%\\%s\" %s %%*\n", exename, vimarg);
926 fprintf(fd, "goto eof\n");
927 fprintf(fd, "\n");
Bram Moolenaar071d4272004-06-13 20:20:40 +0000928
929 if (*exename == 'g')
930 {
931 fprintf(fd, ":noforknt\n");
932 fprintf(fd, "start \"dummy\" /b /wait ");
Bram Moolenaar97b2ad32006-03-18 21:40:56 +0000933 /* Always use quotes, $VIM or $VIMRUNTIME might have a space. */
934 fprintf(fd, "\"%%VIM_EXE_DIR%%\\%s\" %s %%*\n",
935 exename, vimarg);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000936 }
937
938 fprintf(fd, "\n:eof\n");
939 fprintf(fd, "set VIMARGS=\n");
940 if (*exename == 'g')
941 fprintf(fd, "set VIMNOFORK=\n");
942
943 fclose(fd);
944 printf("%s has been %s\n", batpath,
945 oldname == NULL ? "created" : "overwritten");
946 }
947 }
948}
949
950/*
951 * Make the text string for choice "idx".
952 * The format "fmt" is must have one %s item, which "arg" is used for.
953 */
954 static void
955alloc_text(int idx, char *fmt, char *arg)
956{
957 if (choices[idx].text != NULL)
958 free(choices[idx].text);
959
960 choices[idx].text = alloc((int)(strlen(fmt) + strlen(arg)) - 1);
961 sprintf(choices[idx].text, fmt, arg);
962}
963
964/*
965 * Toggle the "Overwrite .../vim.bat" to "Don't overwrite".
966 */
967 static void
968toggle_bat_choice(int idx)
969{
970 char *batname = targets[choices[idx].arg].batpath;
971 char *oldname = targets[choices[idx].arg].oldbat;
972
973 if (*batname == NUL)
974 {
975 alloc_text(idx, " Overwrite %s", oldname);
976 strcpy(batname, oldname);
977 }
978 else
979 {
980 alloc_text(idx, " Do NOT overwrite %s", oldname);
981 *batname = NUL;
982 }
983}
984
985/*
986 * Do some work for a batch file entry: Append the batch file name to the path
987 * and set the text for the choice.
988 */
989 static void
990set_bat_text(int idx, char *batpath, char *name)
991{
992 strcat(batpath, name);
993
994 alloc_text(idx, " Create %s", batpath);
995}
996
997/*
998 * Select a directory to write the batch file line.
999 */
1000 static void
1001change_bat_choice(int idx)
1002{
1003 char *path;
1004 char *batpath;
1005 char *name;
1006 int n;
1007 char *s;
1008 char *p;
1009 int count;
1010 char **names = NULL;
1011 int i;
1012 int target = choices[idx].arg;
1013
1014 name = targets[target].batname;
1015 batpath = targets[target].batpath;
1016
1017 path = getenv("PATH");
1018 if (path == NULL)
1019 {
1020 printf("\nERROR: The variable $PATH is not set\n");
1021 return;
1022 }
1023
1024 /*
1025 * first round: count number of names in path;
1026 * second round: save names to names[].
1027 */
1028 for (;;)
1029 {
1030 count = 1;
1031 for (p = path; *p; )
1032 {
1033 s = strchr(p, ';');
1034 if (s == NULL)
1035 s = p + strlen(p);
1036 if (names != NULL)
1037 {
1038 names[count] = alloc((int)(s - p) + 1);
1039 strncpy(names[count], p, s - p);
1040 names[count][s - p] = NUL;
1041 }
1042 ++count;
1043 p = s;
1044 if (*p != NUL)
1045 ++p;
1046 }
1047 if (names != NULL)
1048 break;
1049 names = alloc((int)(count + 1) * sizeof(char *));
1050 }
1051 names[0] = alloc(50);
1052 sprintf(names[0], "Select directory to create %s in:", name);
1053 names[count] = alloc(50);
1054 if (choices[idx].arg == 0)
1055 sprintf(names[count], "Do not create any .bat file.");
1056 else
1057 sprintf(names[count], "Do not create a %s file.", name);
1058 n = get_choice(names, count + 1);
1059
1060 if (n == count)
1061 {
1062 /* Selected last item, don't create bat file. */
1063 *batpath = NUL;
1064 if (choices[idx].arg != 0)
1065 alloc_text(idx, " Do NOT create %s", name);
1066 }
1067 else
1068 {
1069 /* Selected one of the paths. For the first item only keep the path,
1070 * for the others append the batch file name. */
1071 strcpy(batpath, names[n]);
1072 add_pathsep(batpath);
1073 if (choices[idx].arg != 0)
1074 set_bat_text(idx, batpath, name);
1075 }
1076
1077 for (i = 0; i <= count; ++i)
1078 free(names[i]);
1079 free(names);
1080}
1081
1082char *bat_text_yes = "Install .bat files to use Vim at the command line:";
1083char *bat_text_no = "do NOT install .bat files to use Vim at the command line";
1084
1085 static void
1086change_main_bat_choice(int idx)
1087{
1088 int i;
1089
1090 /* let the user select a default directory or NONE */
1091 change_bat_choice(idx);
1092
1093 if (targets[0].batpath[0] != NUL)
1094 choices[idx].text = bat_text_yes;
1095 else
1096 choices[idx].text = bat_text_no;
1097
1098 /* update the individual batch file selections */
1099 for (i = 1; i < TARGET_COUNT; ++i)
1100 {
1101 /* Only make it active when the first item has a path and the vim.exe
1102 * or gvim.exe exists (there is a changefunc then). */
1103 if (targets[0].batpath[0] != NUL
1104 && choices[idx + i].changefunc != NULL)
1105 {
1106 choices[idx + i].active = 1;
1107 if (choices[idx + i].changefunc == change_bat_choice
1108 && targets[i].batpath[0] != NUL)
1109 {
1110 strcpy(targets[i].batpath, targets[0].batpath);
1111 set_bat_text(idx + i, targets[i].batpath, targets[i].batname);
1112 }
1113 }
1114 else
1115 choices[idx + i].active = 0;
1116 }
1117}
1118
1119/*
1120 * Initialize a choice for creating a batch file.
1121 */
1122 static void
1123init_bat_choice(int target)
1124{
1125 char *batpath = targets[target].batpath;
1126 char *oldbat = targets[target].oldbat;
1127 char *p;
1128 int i;
1129
1130 choices[choice_count].arg = target;
1131 choices[choice_count].installfunc = install_bat_choice;
1132 choices[choice_count].active = 1;
1133 choices[choice_count].text = NULL; /* will be set below */
1134 if (oldbat != NULL)
1135 {
1136 /* A [g]vim.bat exists: Only choice is to overwrite it or not. */
1137 choices[choice_count].changefunc = toggle_bat_choice;
1138 *batpath = NUL;
1139 toggle_bat_choice(choice_count);
1140 }
1141 else
1142 {
1143 if (default_bat_dir != NULL)
1144 /* Prefer using the same path as an existing .bat file. */
1145 strcpy(batpath, default_bat_dir);
1146 else
1147 {
1148 /* No [g]vim.bat exists: Write it to a directory in $PATH. Use
1149 * $WINDIR by default, if it's empty the first item in $PATH. */
1150 p = getenv("WINDIR");
1151 if (p != NULL && *p != NUL)
1152 strcpy(batpath, p);
1153 else
1154 {
1155 p = getenv("PATH");
1156 if (p == NULL || *p == NUL) /* "cannot happen" */
1157 strcpy(batpath, "C:/Windows");
1158 else
1159 {
1160 i = 0;
1161 while (*p != NUL && *p != ';')
1162 batpath[i++] = *p++;
1163 batpath[i] = NUL;
1164 }
1165 }
1166 }
1167 add_pathsep(batpath);
1168 set_bat_text(choice_count, batpath, targets[target].batname);
1169
1170 choices[choice_count].changefunc = change_bat_choice;
1171 }
1172 ++choice_count;
1173}
1174
1175/*
1176 * Set up the choices for installing .bat files.
1177 * For these items "arg" is the index in targets[].
1178 */
1179 static void
1180init_bat_choices(void)
1181{
1182 int i;
1183
1184 /* The first item is used to switch installing batch files on/off and
1185 * setting the default path. */
1186 choices[choice_count].text = bat_text_yes;
1187 choices[choice_count].changefunc = change_main_bat_choice;
1188 choices[choice_count].installfunc = NULL;
1189 choices[choice_count].active = 1;
1190 choices[choice_count].arg = 0;
1191 ++choice_count;
1192
1193 /* Add items for each batch file target. Only used when not disabled by
1194 * the first item. When a .exe exists, don't offer to create a .bat. */
1195 for (i = 1; i < TARGET_COUNT; ++i)
1196 if (targets[i].oldexe == NULL
1197 && (targets[i].exenamearg[0] == 'g' ? has_gvim : has_vim))
1198 init_bat_choice(i);
1199 else
1200 add_dummy_choice();
1201}
1202
1203/*
1204 * Install the vimrc file.
1205 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001206 static void
1207install_vimrc(int idx)
1208{
1209 FILE *fd, *tfd;
1210 char *fname;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001211
1212 /* If an old vimrc file exists, overwrite it.
1213 * Otherwise create a new one. */
1214 if (*oldvimrc != NUL)
1215 fname = oldvimrc;
1216 else
1217 fname = vimrc;
1218
1219 fd = fopen(fname, "w");
1220 if (fd == NULL)
1221 {
1222 printf("\nERROR: Cannot open \"%s\" for writing.\n", fname);
1223 return;
1224 }
1225 switch (compat_choice)
1226 {
1227 case compat_vi:
Bram Moolenaar6cdb2c92018-10-13 17:25:27 +02001228 fprintf(fd, "\" Vi compatible\n");
Bram Moolenaar071d4272004-06-13 20:20:40 +00001229 fprintf(fd, "set compatible\n");
1230 break;
Bram Moolenaar6cdb2c92018-10-13 17:25:27 +02001231 case compat_vim:
1232 fprintf(fd, "\" Vim's default behavior\n");
1233 fprintf(fd, "if &compatible\n");
1234 fprintf(fd, " set nocompatible\n");
1235 fprintf(fd, "endif\n");
1236 break;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001237 case compat_some_enhancements:
Bram Moolenaar6cdb2c92018-10-13 17:25:27 +02001238 fprintf(fd, "\" Vim with some enhancements\n");
Bram Moolenaarc73e4472016-07-29 18:33:38 +02001239 fprintf(fd, "source $VIMRUNTIME/defaults.vim\n");
Bram Moolenaar071d4272004-06-13 20:20:40 +00001240 break;
1241 case compat_all_enhancements:
Bram Moolenaar6cdb2c92018-10-13 17:25:27 +02001242 fprintf(fd, "\" Vim with all enhancements\n");
Bram Moolenaar071d4272004-06-13 20:20:40 +00001243 fprintf(fd, "source $VIMRUNTIME/vimrc_example.vim\n");
1244 break;
1245 }
1246 switch (remap_choice)
1247 {
1248 case remap_no:
1249 break;
1250 case remap_win:
Bram Moolenaar6cdb2c92018-10-13 17:25:27 +02001251 fprintf(fd, "\n");
1252 fprintf(fd, "\" Remap a few keys for Windows behavior\n");
Bram Moolenaar071d4272004-06-13 20:20:40 +00001253 fprintf(fd, "source $VIMRUNTIME/mswin.vim\n");
1254 break;
1255 }
1256 switch (mouse_choice)
1257 {
1258 case mouse_xterm:
Bram Moolenaar6cdb2c92018-10-13 17:25:27 +02001259 fprintf(fd, "\n");
1260 fprintf(fd, "\" Mouse behavior (the Unix way)\n");
Bram Moolenaar071d4272004-06-13 20:20:40 +00001261 fprintf(fd, "behave xterm\n");
1262 break;
1263 case mouse_mswin:
Bram Moolenaar6cdb2c92018-10-13 17:25:27 +02001264 fprintf(fd, "\n");
1265 fprintf(fd, "\" Mouse behavior (the Windows way)\n");
Bram Moolenaar071d4272004-06-13 20:20:40 +00001266 fprintf(fd, "behave mswin\n");
1267 break;
Bram Moolenaarc3fdf7f2017-10-28 18:36:48 +02001268 case mouse_default:
1269 break;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001270 }
1271 if ((tfd = fopen("diff.exe", "r")) != NULL)
1272 {
1273 /* Use the diff.exe that comes with the self-extracting gvim.exe. */
1274 fclose(tfd);
1275 fprintf(fd, "\n");
Bram Moolenaar6cdb2c92018-10-13 17:25:27 +02001276 fprintf(fd, "\" Use the internal diff if available.\n");
1277 fprintf(fd, "\" Otherwise use the special 'diffexpr' for Windows.\n");
1278 fprintf(fd, "if &diffopt !~# 'internal'\n");
1279 fprintf(fd, " set diffexpr=MyDiff()\n");
1280 fprintf(fd, "endif\n");
Bram Moolenaar071d4272004-06-13 20:20:40 +00001281 fprintf(fd, "function MyDiff()\n");
1282 fprintf(fd, " let opt = '-a --binary '\n");
1283 fprintf(fd, " if &diffopt =~ 'icase' | let opt = opt . '-i ' | endif\n");
1284 fprintf(fd, " if &diffopt =~ 'iwhite' | let opt = opt . '-b ' | endif\n");
Bram Moolenaar12365ce2018-05-13 14:45:25 +02001285 /* Use quotes only when needed, they may cause trouble.
1286 * Always escape "!". */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001287 fprintf(fd, " let arg1 = v:fname_in\n");
1288 fprintf(fd, " if arg1 =~ ' ' | let arg1 = '\"' . arg1 . '\"' | endif\n");
Bram Moolenaar12365ce2018-05-13 14:45:25 +02001289 fprintf(fd, " let arg1 = substitute(arg1, '!', '\\!', 'g')\n");
Bram Moolenaar071d4272004-06-13 20:20:40 +00001290 fprintf(fd, " let arg2 = v:fname_new\n");
1291 fprintf(fd, " if arg2 =~ ' ' | let arg2 = '\"' . arg2 . '\"' | endif\n");
Bram Moolenaar12365ce2018-05-13 14:45:25 +02001292 fprintf(fd, " let arg2 = substitute(arg2, '!', '\\!', 'g')\n");
Bram Moolenaar071d4272004-06-13 20:20:40 +00001293 fprintf(fd, " let arg3 = v:fname_out\n");
1294 fprintf(fd, " if arg3 =~ ' ' | let arg3 = '\"' . arg3 . '\"' | endif\n");
Bram Moolenaar12365ce2018-05-13 14:45:25 +02001295 fprintf(fd, " let arg3 = substitute(arg3, '!', '\\!', 'g')\n");
Bram Moolenaar33aec762006-01-22 23:30:12 +00001296
1297 /* If the path has a space: When using cmd.exe (Win NT/2000/XP) put
Bram Moolenaarc62a6442013-11-21 18:13:37 +01001298 * quotes around the diff command and rely on the default value of
Bram Moolenaar792f0e32018-02-27 17:27:13 +01001299 * shellxquote to solve the quoting problem for the whole command.
1300 *
Bram Moolenaar33aec762006-01-22 23:30:12 +00001301 * Otherwise put a double quote just before the space and at the
1302 * end of the command. Putting quotes around the whole thing
1303 * doesn't work on Win 95/98/ME. This is mostly guessed! */
Bram Moolenaar33aec762006-01-22 23:30:12 +00001304 fprintf(fd, " if $VIMRUNTIME =~ ' '\n");
1305 fprintf(fd, " if &sh =~ '\\<cmd'\n");
Bram Moolenaarc62a6442013-11-21 18:13:37 +01001306 fprintf(fd, " if empty(&shellxquote)\n");
1307 fprintf(fd, " let l:shxq_sav = ''\n");
1308 fprintf(fd, " set shellxquote&\n");
1309 fprintf(fd, " endif\n");
1310 fprintf(fd, " let cmd = '\"' . $VIMRUNTIME . '\\diff\"'\n");
Bram Moolenaar33aec762006-01-22 23:30:12 +00001311 fprintf(fd, " else\n");
1312 fprintf(fd, " let cmd = substitute($VIMRUNTIME, ' ', '\" ', '') . '\\diff\"'\n");
1313 fprintf(fd, " endif\n");
1314 fprintf(fd, " else\n");
1315 fprintf(fd, " let cmd = $VIMRUNTIME . '\\diff'\n");
1316 fprintf(fd, " endif\n");
Bram Moolenaar12365ce2018-05-13 14:45:25 +02001317 fprintf(fd, " let cmd = substitute(cmd, '!', '\\!', 'g')\n");
Bram Moolenaarc62a6442013-11-21 18:13:37 +01001318 fprintf(fd, " silent execute '!' . cmd . ' ' . opt . arg1 . ' ' . arg2 . ' > ' . arg3\n");
1319 fprintf(fd, " if exists('l:shxq_sav')\n");
1320 fprintf(fd, " let &shellxquote=l:shxq_sav\n");
1321 fprintf(fd, " endif\n");
Bram Moolenaar071d4272004-06-13 20:20:40 +00001322 fprintf(fd, "endfunction\n");
1323 fprintf(fd, "\n");
1324 }
1325 fclose(fd);
1326 printf("%s has been written\n", fname);
1327}
1328
1329 static void
1330change_vimrc_choice(int idx)
1331{
1332 if (choices[idx].installfunc != NULL)
1333 {
1334 /* Switch to NOT change or create a vimrc file. */
1335 if (*oldvimrc != NUL)
1336 alloc_text(idx, "Do NOT change startup file %s", oldvimrc);
1337 else
1338 alloc_text(idx, "Do NOT create startup file %s", vimrc);
1339 choices[idx].installfunc = NULL;
1340 choices[idx + 1].active = 0;
1341 choices[idx + 2].active = 0;
1342 choices[idx + 3].active = 0;
1343 }
1344 else
1345 {
1346 /* Switch to change or create a vimrc file. */
1347 if (*oldvimrc != NUL)
1348 alloc_text(idx, "Overwrite startup file %s with:", oldvimrc);
1349 else
1350 alloc_text(idx, "Create startup file %s with:", vimrc);
1351 choices[idx].installfunc = install_vimrc;
1352 choices[idx + 1].active = 1;
1353 choices[idx + 2].active = 1;
1354 choices[idx + 3].active = 1;
1355 }
1356}
1357
1358/*
1359 * Change the choice how to run Vim.
1360 */
1361 static void
1362change_run_choice(int idx)
1363{
1364 compat_choice = get_choice(compat_choices, TABLE_SIZE(compat_choices));
1365 alloc_text(idx, compat_text, compat_choices[compat_choice]);
1366}
1367
1368/*
1369 * Change the choice if keys are to be remapped.
1370 */
1371 static void
1372change_remap_choice(int idx)
1373{
1374 remap_choice = get_choice(remap_choices, TABLE_SIZE(remap_choices));
1375 alloc_text(idx, remap_text, remap_choices[remap_choice]);
1376}
1377
1378/*
1379 * Change the choice how to select text.
1380 */
1381 static void
1382change_mouse_choice(int idx)
1383{
1384 mouse_choice = get_choice(mouse_choices, TABLE_SIZE(mouse_choices));
1385 alloc_text(idx, mouse_text, mouse_choices[mouse_choice]);
1386}
1387
1388 static void
1389init_vimrc_choices(void)
1390{
1391 /* set path for a new _vimrc file (also when not used) */
1392 strcpy(vimrc, installdir);
1393 strcpy(vimrc + runtimeidx, "_vimrc");
1394
1395 /* Set opposite value and then toggle it by calling change_vimrc_choice() */
1396 if (*oldvimrc == NUL)
1397 choices[choice_count].installfunc = NULL;
1398 else
1399 choices[choice_count].installfunc = install_vimrc;
1400 choices[choice_count].text = NULL;
1401 change_vimrc_choice(choice_count);
1402 choices[choice_count].changefunc = change_vimrc_choice;
1403 choices[choice_count].active = 1;
1404 ++choice_count;
1405
1406 /* default way to run Vim */
1407 alloc_text(choice_count, compat_text, compat_choices[compat_choice]);
1408 choices[choice_count].changefunc = change_run_choice;
1409 choices[choice_count].installfunc = NULL;
1410 choices[choice_count].active = (*oldvimrc == NUL);
1411 ++choice_count;
1412
1413 /* Whether to remap keys */
1414 alloc_text(choice_count, remap_text , remap_choices[remap_choice]);
1415 choices[choice_count].changefunc = change_remap_choice;
Bram Moolenaar945ec092016-06-08 21:17:43 +02001416 choices[choice_count].installfunc = NULL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001417 choices[choice_count].active = (*oldvimrc == NUL);
1418 ++choice_count;
1419
1420 /* default way to use the mouse */
1421 alloc_text(choice_count, mouse_text, mouse_choices[mouse_choice]);
1422 choices[choice_count].changefunc = change_mouse_choice;
Bram Moolenaar945ec092016-06-08 21:17:43 +02001423 choices[choice_count].installfunc = NULL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001424 choices[choice_count].active = (*oldvimrc == NUL);
1425 ++choice_count;
1426}
1427
Bram Moolenaarccd9ccf2010-07-07 13:19:55 +02001428 static LONG
1429reg_create_key(
1430 HKEY root,
1431 const char *subkey,
Bram Moolenaar6199d432017-10-14 19:05:44 +02001432 PHKEY phKey,
1433 DWORD flag)
Bram Moolenaarccd9ccf2010-07-07 13:19:55 +02001434{
1435 DWORD disp;
1436
1437 *phKey = NULL;
1438 return RegCreateKeyEx(
Bram Moolenaarcc448b32010-07-14 16:52:17 +02001439 root, subkey,
1440 0, NULL, REG_OPTION_NON_VOLATILE,
Bram Moolenaar6199d432017-10-14 19:05:44 +02001441 flag | KEY_WRITE,
Bram Moolenaarcc448b32010-07-14 16:52:17 +02001442 NULL, phKey, &disp);
Bram Moolenaarccd9ccf2010-07-07 13:19:55 +02001443}
1444
1445 static LONG
1446reg_set_string_value(
1447 HKEY hKey,
1448 const char *value_name,
1449 const char *data)
1450{
1451 return RegSetValueEx(hKey, value_name, 0, REG_SZ,
1452 (LPBYTE)data, (DWORD)(1 + strlen(data)));
1453}
1454
1455 static LONG
1456reg_create_key_and_value(
1457 HKEY hRootKey,
1458 const char *subkey,
1459 const char *value_name,
Bram Moolenaar6199d432017-10-14 19:05:44 +02001460 const char *data,
1461 DWORD flag)
Bram Moolenaarccd9ccf2010-07-07 13:19:55 +02001462{
1463 HKEY hKey;
Bram Moolenaar6199d432017-10-14 19:05:44 +02001464 LONG lRet = reg_create_key(hRootKey, subkey, &hKey, flag);
Bram Moolenaarccd9ccf2010-07-07 13:19:55 +02001465
1466 if (ERROR_SUCCESS == lRet)
1467 {
Bram Moolenaarcc448b32010-07-14 16:52:17 +02001468 lRet = reg_set_string_value(hKey, value_name, data);
1469 RegCloseKey(hKey);
Bram Moolenaarccd9ccf2010-07-07 13:19:55 +02001470 }
1471 return lRet;
1472}
1473
1474 static LONG
1475register_inproc_server(
1476 HKEY hRootKey,
1477 const char *clsid,
1478 const char *extname,
1479 const char *module,
Bram Moolenaar6199d432017-10-14 19:05:44 +02001480 const char *threading_model,
1481 DWORD flag)
Bram Moolenaarccd9ccf2010-07-07 13:19:55 +02001482{
1483 CHAR subkey[BUFSIZE];
1484 LONG lRet;
1485
1486 sprintf(subkey, "CLSID\\%s", clsid);
Bram Moolenaar6199d432017-10-14 19:05:44 +02001487 lRet = reg_create_key_and_value(hRootKey, subkey, NULL, extname, flag);
Bram Moolenaarccd9ccf2010-07-07 13:19:55 +02001488 if (ERROR_SUCCESS == lRet)
1489 {
Bram Moolenaarcc448b32010-07-14 16:52:17 +02001490 sprintf(subkey, "CLSID\\%s\\InProcServer32", clsid);
Bram Moolenaar6199d432017-10-14 19:05:44 +02001491 lRet = reg_create_key_and_value(hRootKey, subkey, NULL, module, flag);
Bram Moolenaarcc448b32010-07-14 16:52:17 +02001492 if (ERROR_SUCCESS == lRet)
1493 {
1494 lRet = reg_create_key_and_value(hRootKey, subkey,
Bram Moolenaar6199d432017-10-14 19:05:44 +02001495 "ThreadingModel", threading_model, flag);
Bram Moolenaarcc448b32010-07-14 16:52:17 +02001496 }
Bram Moolenaarccd9ccf2010-07-07 13:19:55 +02001497 }
1498 return lRet;
1499}
1500
1501 static LONG
1502register_shellex(
1503 HKEY hRootKey,
1504 const char *clsid,
1505 const char *name,
Bram Moolenaar6199d432017-10-14 19:05:44 +02001506 const char *exe_path,
1507 DWORD flag)
Bram Moolenaarccd9ccf2010-07-07 13:19:55 +02001508{
1509 LONG lRet = reg_create_key_and_value(
Bram Moolenaarcc448b32010-07-14 16:52:17 +02001510 hRootKey,
1511 "*\\shellex\\ContextMenuHandlers\\gvim",
1512 NULL,
Bram Moolenaar6199d432017-10-14 19:05:44 +02001513 clsid,
1514 flag);
Bram Moolenaarccd9ccf2010-07-07 13:19:55 +02001515
1516 if (ERROR_SUCCESS == lRet)
1517 {
Bram Moolenaarcc448b32010-07-14 16:52:17 +02001518 lRet = reg_create_key_and_value(
1519 HKEY_LOCAL_MACHINE,
1520 "Software\\Microsoft\\Windows\\CurrentVersion\\Shell Extensions\\Approved",
1521 clsid,
Bram Moolenaar6199d432017-10-14 19:05:44 +02001522 name,
1523 flag);
Bram Moolenaarccd9ccf2010-07-07 13:19:55 +02001524
Bram Moolenaarcc448b32010-07-14 16:52:17 +02001525 if (ERROR_SUCCESS == lRet)
1526 {
1527 lRet = reg_create_key_and_value(
1528 HKEY_LOCAL_MACHINE,
1529 "Software\\Vim\\Gvim",
1530 "path",
Bram Moolenaar6199d432017-10-14 19:05:44 +02001531 exe_path,
1532 flag);
Bram Moolenaarcc448b32010-07-14 16:52:17 +02001533 }
Bram Moolenaarccd9ccf2010-07-07 13:19:55 +02001534 }
1535 return lRet;
1536}
1537
1538 static LONG
1539register_openwith(
1540 HKEY hRootKey,
Bram Moolenaar6199d432017-10-14 19:05:44 +02001541 const char *exe_path,
1542 DWORD flag)
Bram Moolenaarccd9ccf2010-07-07 13:19:55 +02001543{
Bram Moolenaar78050042010-07-31 20:53:54 +02001544 char exe_cmd[BUFSIZE];
1545 LONG lRet;
1546
Bram Moolenaarbbdcb482010-08-02 20:45:27 +02001547 sprintf(exe_cmd, "\"%s\" \"%%1\"", exe_path);
Bram Moolenaar78050042010-07-31 20:53:54 +02001548 lRet = reg_create_key_and_value(
Bram Moolenaarcc448b32010-07-14 16:52:17 +02001549 hRootKey,
1550 "Applications\\gvim.exe\\shell\\edit\\command",
1551 NULL,
Bram Moolenaar6199d432017-10-14 19:05:44 +02001552 exe_cmd,
1553 flag);
Bram Moolenaarccd9ccf2010-07-07 13:19:55 +02001554
1555 if (ERROR_SUCCESS == lRet)
1556 {
Bram Moolenaarcc448b32010-07-14 16:52:17 +02001557 int i;
1558 static const char *openwith[] = {
1559 ".htm\\OpenWithList\\gvim.exe",
1560 ".vim\\OpenWithList\\gvim.exe",
1561 "*\\OpenWithList\\gvim.exe",
1562 };
Bram Moolenaarccd9ccf2010-07-07 13:19:55 +02001563
Bram Moolenaarcc448b32010-07-14 16:52:17 +02001564 for (i = 0; ERROR_SUCCESS == lRet
Bram Moolenaarccd9ccf2010-07-07 13:19:55 +02001565 && i < sizeof(openwith) / sizeof(openwith[0]); i++)
Bram Moolenaarcc448b32010-07-14 16:52:17 +02001566 {
Bram Moolenaar6199d432017-10-14 19:05:44 +02001567 lRet = reg_create_key_and_value(hRootKey, openwith[i], NULL, "", flag);
Bram Moolenaarcc448b32010-07-14 16:52:17 +02001568 }
Bram Moolenaarccd9ccf2010-07-07 13:19:55 +02001569 }
1570
1571 return lRet;
1572}
1573
1574 static LONG
1575register_uninstall(
1576 HKEY hRootKey,
1577 const char *appname,
1578 const char *display_name,
Bram Moolenaar6cdb2c92018-10-13 17:25:27 +02001579 const char *uninstall_string,
1580 const char *display_icon,
1581 const char *display_version,
1582 const char *publisher)
Bram Moolenaarccd9ccf2010-07-07 13:19:55 +02001583{
1584 LONG lRet = reg_create_key_and_value(hRootKey, appname,
Bram Moolenaar6199d432017-10-14 19:05:44 +02001585 "DisplayName", display_name, KEY_WOW64_64KEY);
Bram Moolenaarccd9ccf2010-07-07 13:19:55 +02001586
1587 if (ERROR_SUCCESS == lRet)
Bram Moolenaarcc448b32010-07-14 16:52:17 +02001588 lRet = reg_create_key_and_value(hRootKey, appname,
Bram Moolenaar6199d432017-10-14 19:05:44 +02001589 "UninstallString", uninstall_string, KEY_WOW64_64KEY);
Bram Moolenaar6cdb2c92018-10-13 17:25:27 +02001590 if (ERROR_SUCCESS == lRet)
1591 lRet = reg_create_key_and_value(hRootKey, appname,
1592 "DisplayIcon", display_icon, KEY_WOW64_64KEY);
1593 if (ERROR_SUCCESS == lRet)
1594 lRet = reg_create_key_and_value(hRootKey, appname,
1595 "DisplayVersion", display_version, KEY_WOW64_64KEY);
1596 if (ERROR_SUCCESS == lRet)
1597 lRet = reg_create_key_and_value(hRootKey, appname,
1598 "Publisher", publisher, KEY_WOW64_64KEY);
Bram Moolenaarccd9ccf2010-07-07 13:19:55 +02001599 return lRet;
1600}
Bram Moolenaarccd9ccf2010-07-07 13:19:55 +02001601
Bram Moolenaar071d4272004-06-13 20:20:40 +00001602/*
1603 * Add some entries to the registry:
1604 * - to add "Edit with Vim" to the context * menu
1605 * - to add Vim to the "Open with..." list
1606 * - to uninstall Vim
1607 */
1608/*ARGSUSED*/
Bram Moolenaarab8205e2010-07-07 15:14:03 +02001609 static int
Bram Moolenaar071d4272004-06-13 20:20:40 +00001610install_registry(void)
1611{
Bram Moolenaarcc448b32010-07-14 16:52:17 +02001612 LONG lRet = ERROR_SUCCESS;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001613 const char *vim_ext_ThreadingModel = "Apartment";
1614 const char *vim_ext_name = "Vim Shell Extension";
1615 const char *vim_ext_clsid = "{51EEE242-AD87-11d3-9C1E-0090278BBD99}";
Bram Moolenaarccd9ccf2010-07-07 13:19:55 +02001616 char vim_exe_path[BUFSIZE];
Bram Moolenaarcc448b32010-07-14 16:52:17 +02001617 char display_name[BUFSIZE];
1618 char uninstall_string[BUFSIZE];
Bram Moolenaar6cdb2c92018-10-13 17:25:27 +02001619 char icon_string[BUFSIZE];
Bram Moolenaar6199d432017-10-14 19:05:44 +02001620 int i;
1621 int loop_count = is_64bit_os() ? 2 : 1;
1622 DWORD flag;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001623
Bram Moolenaarccd9ccf2010-07-07 13:19:55 +02001624 sprintf(vim_exe_path, "%s\\gvim.exe", installdir);
1625
1626 if (install_popup)
1627 {
Bram Moolenaarcc448b32010-07-14 16:52:17 +02001628 char bufg[BUFSIZE];
Bram Moolenaarccd9ccf2010-07-07 13:19:55 +02001629
Bram Moolenaarcc448b32010-07-14 16:52:17 +02001630 printf("Creating \"Edit with Vim\" popup menu entry\n");
Bram Moolenaarccd9ccf2010-07-07 13:19:55 +02001631
Bram Moolenaar6199d432017-10-14 19:05:44 +02001632 for (i = 0; i < loop_count; i++)
1633 {
1634 if (i == 0)
1635 {
1636 sprintf(bufg, "%s\\" GVIMEXT32_PATH, installdir);
1637 flag = KEY_WOW64_32KEY;
1638 }
1639 else
1640 {
1641 sprintf(bufg, "%s\\" GVIMEXT64_PATH, installdir);
1642 flag = KEY_WOW64_64KEY;
1643 }
1644
1645 lRet = register_inproc_server(
1646 HKEY_CLASSES_ROOT, vim_ext_clsid, vim_ext_name,
1647 bufg, vim_ext_ThreadingModel, flag);
1648 if (ERROR_SUCCESS != lRet)
1649 return FAIL;
1650 lRet = register_shellex(
1651 HKEY_CLASSES_ROOT, vim_ext_clsid, vim_ext_name,
1652 vim_exe_path, flag);
1653 if (ERROR_SUCCESS != lRet)
1654 return FAIL;
1655 }
Bram Moolenaarccd9ccf2010-07-07 13:19:55 +02001656 }
1657
1658 if (install_openwith)
1659 {
Bram Moolenaarcc448b32010-07-14 16:52:17 +02001660 printf("Creating \"Open with ...\" list entry\n");
Bram Moolenaarccd9ccf2010-07-07 13:19:55 +02001661
Bram Moolenaar6199d432017-10-14 19:05:44 +02001662 for (i = 0; i < loop_count; i++)
1663 {
1664 if (i == 0)
1665 flag = KEY_WOW64_32KEY;
1666 else
1667 flag = KEY_WOW64_64KEY;
1668
1669 lRet = register_openwith(HKEY_CLASSES_ROOT, vim_exe_path, flag);
1670 if (ERROR_SUCCESS != lRet)
1671 return FAIL;
1672 }
Bram Moolenaarccd9ccf2010-07-07 13:19:55 +02001673 }
1674
1675 printf("Creating an uninstall entry\n");
Bram Moolenaaraf610b82018-12-21 16:22:50 +01001676 sprintf(display_name, "Vim " VIM_VERSION_SHORT
1677#ifdef _WIN64
1678 " (x64)"
1679#endif
1680 );
Bram Moolenaarccd9ccf2010-07-07 13:19:55 +02001681
1682 /* For the NSIS installer use the generated uninstaller. */
1683 if (interactive)
Bram Moolenaar16d79a32010-07-18 22:33:56 +02001684 sprintf(uninstall_string, "%s\\uninstal.exe", installdir);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001685 else
Bram Moolenaar16d79a32010-07-18 22:33:56 +02001686 sprintf(uninstall_string, "%s\\uninstall-gui.exe", installdir);
Bram Moolenaarccd9ccf2010-07-07 13:19:55 +02001687
Bram Moolenaar6cdb2c92018-10-13 17:25:27 +02001688 sprintf(icon_string, "%s\\gvim.exe,0", installdir);
1689
Bram Moolenaarccd9ccf2010-07-07 13:19:55 +02001690 lRet = register_uninstall(
Bram Moolenaarcc448b32010-07-14 16:52:17 +02001691 HKEY_LOCAL_MACHINE,
1692 "Software\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\Vim " VIM_VERSION_SHORT,
1693 display_name,
Bram Moolenaar6cdb2c92018-10-13 17:25:27 +02001694 uninstall_string,
1695 icon_string,
1696 VIM_VERSION_SHORT,
1697 "Bram Moolenaar et al.");
Bram Moolenaarab8205e2010-07-07 15:14:03 +02001698 if (ERROR_SUCCESS != lRet)
1699 return FAIL;
Bram Moolenaarccd9ccf2010-07-07 13:19:55 +02001700
Bram Moolenaarab8205e2010-07-07 15:14:03 +02001701 return OK;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001702}
1703
1704 static void
1705change_popup_choice(int idx)
1706{
1707 if (install_popup == 0)
1708 {
1709 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";
1710 install_popup = 1;
1711 }
1712 else
1713 {
1714 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";
1715 install_popup = 0;
1716 }
1717}
1718
1719/*
1720 * Only add the choice for the popup menu entry when gvim.exe was found and
1721 * both gvimext.dll and regedit.exe exist.
1722 */
1723 static void
1724init_popup_choice(void)
1725{
1726 struct stat st;
1727
1728 if (has_gvim
Bram Moolenaar6199d432017-10-14 19:05:44 +02001729 && (stat(GVIMEXT32_PATH, &st) >= 0
1730 || stat(GVIMEXT64_PATH, &st) >= 0))
Bram Moolenaar071d4272004-06-13 20:20:40 +00001731 {
1732 choices[choice_count].changefunc = change_popup_choice;
1733 choices[choice_count].installfunc = NULL;
1734 choices[choice_count].active = 1;
1735 change_popup_choice(choice_count); /* set the text */
1736 ++choice_count;
1737 }
1738 else
1739 add_dummy_choice();
1740}
1741
1742 static void
1743change_openwith_choice(int idx)
1744{
1745 if (install_openwith == 0)
1746 {
1747 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";
1748 install_openwith = 1;
1749 }
1750 else
1751 {
1752 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";
1753 install_openwith = 0;
1754 }
1755}
1756
1757/*
1758 * Only add the choice for the open-with menu entry when gvim.exe was found
Bram Moolenaar84a05ac2013-05-06 04:24:17 +02001759 * and regedit.exe exist.
Bram Moolenaar071d4272004-06-13 20:20:40 +00001760 */
1761 static void
1762init_openwith_choice(void)
1763{
Bram Moolenaar6199d432017-10-14 19:05:44 +02001764 if (has_gvim)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001765 {
1766 choices[choice_count].changefunc = change_openwith_choice;
1767 choices[choice_count].installfunc = NULL;
1768 choices[choice_count].active = 1;
1769 change_openwith_choice(choice_count); /* set the text */
1770 ++choice_count;
1771 }
1772 else
1773 add_dummy_choice();
1774}
1775
Bram Moolenaar071d4272004-06-13 20:20:40 +00001776/* create_shortcut
1777 *
1778 * Create a shell link.
1779 *
1780 * returns 0 on failure, non-zero on successful completion.
1781 *
1782 * NOTE: Currently untested with mingw.
1783 */
1784 int
1785create_shortcut(
1786 const char *shortcut_name,
1787 const char *iconfile_path,
1788 int iconindex,
1789 const char *shortcut_target,
1790 const char *shortcut_args,
1791 const char *workingdir
1792 )
1793{
1794 IShellLink *shelllink_ptr;
1795 HRESULT hres;
1796 IPersistFile *persistfile_ptr;
1797
1798 /* Initialize COM library */
1799 hres = CoInitialize(NULL);
1800 if (!SUCCEEDED(hres))
1801 {
1802 printf("Error: Could not open the COM library. Not creating shortcut.\n");
1803 return FAIL;
1804 }
1805
1806 /* Instantiate a COM object for the ShellLink, store a pointer to it
1807 * in shelllink_ptr. */
1808 hres = CoCreateInstance(&CLSID_ShellLink,
1809 NULL,
1810 CLSCTX_INPROC_SERVER,
1811 &IID_IShellLink,
1812 (void **) &shelllink_ptr);
1813
1814 if (SUCCEEDED(hres)) /* If the instantiation was successful... */
1815 {
1816 /* ...Then build a PersistFile interface for the ShellLink so we can
1817 * save it as a file after we build it. */
1818 hres = shelllink_ptr->lpVtbl->QueryInterface(shelllink_ptr,
1819 &IID_IPersistFile, (void **) &persistfile_ptr);
1820
1821 if (SUCCEEDED(hres))
1822 {
1823 wchar_t wsz[BUFSIZE];
1824
1825 /* translate the (possibly) multibyte shortcut filename to windows
1826 * Unicode so it can be used as a file name.
1827 */
1828 MultiByteToWideChar(CP_ACP, 0, shortcut_name, -1, wsz, BUFSIZE);
1829
1830 /* set the attributes */
1831 shelllink_ptr->lpVtbl->SetPath(shelllink_ptr, shortcut_target);
1832 shelllink_ptr->lpVtbl->SetWorkingDirectory(shelllink_ptr,
1833 workingdir);
1834 shelllink_ptr->lpVtbl->SetIconLocation(shelllink_ptr,
1835 iconfile_path, iconindex);
1836 shelllink_ptr->lpVtbl->SetArguments(shelllink_ptr, shortcut_args);
1837
1838 /* save the shortcut to a file and return the PersistFile object*/
1839 persistfile_ptr->lpVtbl->Save(persistfile_ptr, wsz, 1);
1840 persistfile_ptr->lpVtbl->Release(persistfile_ptr);
1841 }
1842 else
1843 {
1844 printf("QueryInterface Error\n");
1845 return FAIL;
1846 }
1847
1848 /* Return the ShellLink object */
1849 shelllink_ptr->lpVtbl->Release(shelllink_ptr);
1850 }
1851 else
1852 {
1853 printf("CoCreateInstance Error - hres = %08x\n", (int)hres);
1854 return FAIL;
1855 }
1856
1857 return OK;
1858}
1859
1860/*
1861 * Build a path to where we will put a specified link.
1862 *
1863 * Return 0 on error, non-zero on success
1864 */
1865 int
1866build_link_name(
1867 char *link_path,
1868 const char *link_name,
1869 const char *shell_folder_name)
1870{
1871 char shell_folder_path[BUFSIZE];
1872
1873 if (get_shell_folder_path(shell_folder_path, shell_folder_name) == FAIL)
1874 {
1875 printf("An error occurred while attempting to find the path to %s.\n",
1876 shell_folder_name);
1877 return FAIL;
1878 }
1879
1880 /* Make sure the directory exists (create Start Menu\Programs\Vim).
1881 * Ignore errors if it already exists. */
1882 vim_mkdir(shell_folder_path, 0755);
1883
1884 /* build the path to the shortcut and the path to gvim.exe */
1885 sprintf(link_path, "%s\\%s.lnk", shell_folder_path, link_name);
1886
1887 return OK;
1888}
1889
1890 static int
1891build_shortcut(
1892 const char *name, /* Name of the shortcut */
1893 const char *exename, /* Name of the executable (e.g., vim.exe) */
1894 const char *args,
1895 const char *shell_folder,
1896 const char *workingdir)
1897{
1898 char executable_path[BUFSIZE];
1899 char link_name[BUFSIZE];
1900
1901 sprintf(executable_path, "%s\\%s", installdir, exename);
1902
1903 if (build_link_name(link_name, name, shell_folder) == FAIL)
1904 {
1905 printf("An error has occurred. A shortcut to %s will not be created %s.\n",
1906 name,
1907 *shell_folder == 'd' ? "on the desktop" : "in the Start menu");
1908 return FAIL;
1909 }
1910
1911 /* Create the shortcut: */
1912 return create_shortcut(link_name, executable_path, 0,
1913 executable_path, args, workingdir);
1914}
1915
1916/*
1917 * We used to use "homedir" as the working directory, but that is a bad choice
Bram Moolenaar03e228a2013-11-07 04:49:27 +01001918 * on multi-user systems. However, not specifying a directory results in the
1919 * current directory to be c:\Windows\system32 on Windows 7. Use environment
1920 * variables instead.
Bram Moolenaar071d4272004-06-13 20:20:40 +00001921 */
Bram Moolenaar03e228a2013-11-07 04:49:27 +01001922#define WORKDIR "%HOMEDRIVE%%HOMEPATH%"
Bram Moolenaar071d4272004-06-13 20:20:40 +00001923
1924/*
1925 * Create shortcut(s) in the Start Menu\Programs\Vim folder.
1926 */
1927 static void
1928install_start_menu(int idx)
1929{
1930 need_uninstall_entry = 1;
1931 printf("Creating start menu\n");
1932 if (has_vim)
1933 {
1934 if (build_shortcut("Vim", "vim.exe", "",
1935 VIM_STARTMENU, WORKDIR) == FAIL)
1936 return;
1937 if (build_shortcut("Vim Read-only", "vim.exe", "-R",
1938 VIM_STARTMENU, WORKDIR) == FAIL)
1939 return;
1940 if (build_shortcut("Vim Diff", "vim.exe", "-d",
1941 VIM_STARTMENU, WORKDIR) == FAIL)
1942 return;
1943 }
1944 if (has_gvim)
1945 {
1946 if (build_shortcut("gVim", "gvim.exe", "",
1947 VIM_STARTMENU, WORKDIR) == FAIL)
1948 return;
1949 if (build_shortcut("gVim Easy", "gvim.exe", "-y",
1950 VIM_STARTMENU, WORKDIR) == FAIL)
1951 return;
1952 if (build_shortcut("gVim Read-only", "gvim.exe", "-R",
1953 VIM_STARTMENU, WORKDIR) == FAIL)
1954 return;
1955 if (build_shortcut("gVim Diff", "gvim.exe", "-d",
1956 VIM_STARTMENU, WORKDIR) == FAIL)
1957 return;
1958 }
1959 if (build_shortcut("Uninstall",
1960 interactive ? "uninstal.exe" : "uninstall-gui.exe", "",
1961 VIM_STARTMENU, installdir) == FAIL)
1962 return;
1963 /* For Windows NT the working dir of the vimtutor.bat must be right,
1964 * otherwise gvim.exe won't be found and using gvimbat doesn't work. */
1965 if (build_shortcut("Vim tutor", "vimtutor.bat", "",
1966 VIM_STARTMENU, installdir) == FAIL)
1967 return;
1968 if (build_shortcut("Help", has_gvim ? "gvim.exe" : "vim.exe", "-c h",
1969 VIM_STARTMENU, WORKDIR) == FAIL)
1970 return;
1971 {
1972 char shell_folder_path[BUFSIZE];
1973
1974 /* Creating the URL shortcut works a bit differently... */
1975 if (get_shell_folder_path(shell_folder_path, VIM_STARTMENU) == FAIL)
1976 {
1977 printf("Finding the path of the Start menu failed\n");
1978 return ;
1979 }
1980 add_pathsep(shell_folder_path);
1981 strcat(shell_folder_path, "Vim Online.url");
1982 if (!WritePrivateProfileString("InternetShortcut", "URL",
Bram Moolenaarbd87eb32018-06-26 23:18:45 +02001983 "https://www.vim.org/", shell_folder_path))
Bram Moolenaar071d4272004-06-13 20:20:40 +00001984 {
1985 printf("Creating the Vim online URL failed\n");
1986 return;
1987 }
1988 }
1989}
1990
1991 static void
1992toggle_startmenu_choice(int idx)
1993{
1994 if (choices[idx].installfunc == NULL)
1995 {
1996 choices[idx].installfunc = install_start_menu;
1997 choices[idx].text = "Add Vim to the Start menu";
1998 }
1999 else
2000 {
2001 choices[idx].installfunc = NULL;
2002 choices[idx].text = "Do NOT add Vim to the Start menu";
2003 }
2004}
2005
2006/*
2007 * Function to actually create the shortcuts
2008 *
2009 * Currently I am supplying no working directory to the shortcut. This
2010 * means that the initial working dir will be:
2011 * - the location of the shortcut if no file is supplied
2012 * - the location of the file being edited if a file is supplied (ie via
2013 * drag and drop onto the shortcut).
2014 */
2015 void
2016install_shortcut_gvim(int idx)
2017{
2018 /* Create shortcut(s) on the desktop */
2019 if (choices[idx].arg)
2020 {
2021 (void)build_shortcut(icon_names[0], "gvim.exe",
2022 "", "desktop", WORKDIR);
2023 need_uninstall_entry = 1;
2024 }
2025}
2026
2027 void
2028install_shortcut_evim(int idx)
2029{
2030 if (choices[idx].arg)
2031 {
2032 (void)build_shortcut(icon_names[1], "gvim.exe",
2033 "-y", "desktop", WORKDIR);
2034 need_uninstall_entry = 1;
2035 }
2036}
2037
2038 void
2039install_shortcut_gview(int idx)
2040{
2041 if (choices[idx].arg)
2042 {
2043 (void)build_shortcut(icon_names[2], "gvim.exe",
2044 "-R", "desktop", WORKDIR);
2045 need_uninstall_entry = 1;
2046 }
2047}
2048
2049 void
2050toggle_shortcut_choice(int idx)
2051{
2052 char *arg;
2053
2054 if (choices[idx].installfunc == install_shortcut_gvim)
2055 arg = "gVim";
2056 else if (choices[idx].installfunc == install_shortcut_evim)
2057 arg = "gVim Easy";
2058 else
2059 arg = "gVim Read-only";
2060 if (choices[idx].arg)
2061 {
2062 choices[idx].arg = 0;
2063 alloc_text(idx, "Do NOT create a desktop icon for %s", arg);
2064 }
2065 else
2066 {
2067 choices[idx].arg = 1;
2068 alloc_text(idx, "Create a desktop icon for %s", arg);
2069 }
2070}
Bram Moolenaar071d4272004-06-13 20:20:40 +00002071
2072 static void
2073init_startmenu_choice(void)
2074{
Bram Moolenaar071d4272004-06-13 20:20:40 +00002075 /* Start menu */
2076 choices[choice_count].changefunc = toggle_startmenu_choice;
2077 choices[choice_count].installfunc = NULL;
2078 choices[choice_count].active = 1;
2079 toggle_startmenu_choice(choice_count); /* set the text */
2080 ++choice_count;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002081}
2082
2083/*
2084 * Add the choice for the desktop shortcuts.
2085 */
2086 static void
2087init_shortcut_choices(void)
2088{
Bram Moolenaar071d4272004-06-13 20:20:40 +00002089 /* Shortcut to gvim */
2090 choices[choice_count].text = NULL;
2091 choices[choice_count].arg = 0;
2092 choices[choice_count].active = has_gvim;
2093 choices[choice_count].changefunc = toggle_shortcut_choice;
2094 choices[choice_count].installfunc = install_shortcut_gvim;
2095 toggle_shortcut_choice(choice_count);
2096 ++choice_count;
2097
2098 /* Shortcut to evim */
2099 choices[choice_count].text = NULL;
2100 choices[choice_count].arg = 0;
2101 choices[choice_count].active = has_gvim;
2102 choices[choice_count].changefunc = toggle_shortcut_choice;
2103 choices[choice_count].installfunc = install_shortcut_evim;
2104 toggle_shortcut_choice(choice_count);
2105 ++choice_count;
2106
2107 /* Shortcut to gview */
2108 choices[choice_count].text = NULL;
2109 choices[choice_count].arg = 0;
2110 choices[choice_count].active = has_gvim;
2111 choices[choice_count].changefunc = toggle_shortcut_choice;
2112 choices[choice_count].installfunc = install_shortcut_gview;
2113 toggle_shortcut_choice(choice_count);
2114 ++choice_count;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002115}
2116
Bram Moolenaar071d4272004-06-13 20:20:40 +00002117/*
2118 * Attempt to register OLE for Vim.
2119 */
2120 static void
2121install_OLE_register(void)
2122{
2123 char register_command_string[BUFSIZE + 30];
2124
2125 printf("\n--- Attempting to register Vim with OLE ---\n");
2126 printf("(There is no message whether this works or not.)\n");
2127
Bram Moolenaar071d4272004-06-13 20:20:40 +00002128 sprintf(register_command_string, "\"%s\\gvim.exe\" -silent -register", installdir);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002129 system(register_command_string);
2130}
Bram Moolenaar071d4272004-06-13 20:20:40 +00002131
2132/*
2133 * Remove the last part of directory "path[]" to get its parent, and put the
2134 * result in "to[]".
2135 */
2136 static void
2137dir_remove_last(const char *path, char to[BUFSIZE])
2138{
2139 char c;
2140 long last_char_to_copy;
2141 long path_length = strlen(path);
2142
2143 /* skip the last character just in case it is a '\\' */
2144 last_char_to_copy = path_length - 2;
2145 c = path[last_char_to_copy];
2146
2147 while (c != '\\')
2148 {
2149 last_char_to_copy--;
2150 c = path[last_char_to_copy];
2151 }
2152
2153 strncpy(to, path, (size_t)last_char_to_copy);
2154 to[last_char_to_copy] = NUL;
2155}
2156
2157 static void
2158set_directories_text(int idx)
2159{
Bram Moolenaar25a494c2018-11-16 19:39:50 +01002160 int vimfiles_dir_choice = choices[idx].arg;
2161
Bram Moolenaar071d4272004-06-13 20:20:40 +00002162 if (vimfiles_dir_choice == (int)vimfiles_dir_none)
2163 alloc_text(idx, "Do NOT create plugin directories%s", "");
2164 else
2165 alloc_text(idx, "Create plugin directories: %s",
2166 vimfiles_dir_choices[vimfiles_dir_choice]);
2167}
2168
2169/*
Bram Moolenaar25a494c2018-11-16 19:39:50 +01002170 * To get the "real" home directory:
2171 * - get value of $HOME
2172 * - if not found, get value of $HOMEDRIVE$HOMEPATH
2173 * - if not found, get value of $USERPROFILE
2174 *
2175 * This code is based on init_homedir() in misc1.c, keep in sync!
2176 */
2177static char *homedir = NULL;
2178
2179 void
2180init_homedir(void)
2181{
2182 char *var;
2183 char buf[MAX_PATH];
2184
2185 if (homedir != NULL)
2186 {
2187 free(homedir);
2188 homedir = NULL;
2189 }
2190
2191 var = getenv("HOME");
2192
2193 /*
2194 * Typically, $HOME is not defined on Windows, unless the user has
2195 * specifically defined it for Vim's sake. However, on Windows NT
2196 * platforms, $HOMEDRIVE and $HOMEPATH are automatically defined for
2197 * each user. Try constructing $HOME from these.
2198 */
2199 if (var == NULL || *var == NUL)
2200 {
2201 char *homedrive, *homepath;
2202
2203 homedrive = getenv("HOMEDRIVE");
2204 homepath = getenv("HOMEPATH");
2205 if (homepath == NULL || *homepath == NUL)
2206 homepath = "\\";
2207 if (homedrive != NULL
2208 && strlen(homedrive) + strlen(homepath) < MAX_PATH)
2209 {
2210 sprintf(buf, "%s%s", homedrive, homepath);
2211 if (buf[0] != NUL)
2212 var = buf;
2213 }
2214 }
2215
2216 if (var == NULL)
2217 var = getenv("USERPROFILE");
2218
2219 /*
2220 * Weird but true: $HOME may contain an indirect reference to another
2221 * variable, esp. "%USERPROFILE%". Happens when $USERPROFILE isn't set
2222 * when $HOME is being set.
2223 */
2224 if (var != NULL && *var == '%')
2225 {
2226 char *p;
2227 char *exp;
2228
2229 p = strchr(var + 1, '%');
2230 if (p != NULL)
2231 {
2232 strncpy(buf, var + 1, p - (var + 1));
2233 buf[p - (var + 1)] = NUL;
2234 exp = getenv(buf);
2235 if (exp != NULL && *exp != NUL
2236 && strlen(exp) + strlen(p) < MAX_PATH)
2237 {
2238 _snprintf(buf, MAX_PATH, "%s%s", exp, p + 1);
2239 buf[MAX_PATH - 1] = NUL;
2240 var = buf;
2241 }
2242 }
2243 }
2244
2245 if (var != NULL && *var == NUL) // empty is same as not set
2246 var = NULL;
2247
2248 if (var == NULL)
2249 homedir = NULL;
2250 else
2251 homedir = _strdup(var);
2252}
2253
2254/*
Bram Moolenaar071d4272004-06-13 20:20:40 +00002255 * Change the directory that the vim plugin directories will be created in:
2256 * $HOME, $VIM or nowhere.
2257 */
2258 static void
2259change_directories_choice(int idx)
2260{
2261 int choice_count = TABLE_SIZE(vimfiles_dir_choices);
2262
2263 /* Don't offer the $HOME choice if $HOME isn't set. */
Bram Moolenaar25a494c2018-11-16 19:39:50 +01002264 if (homedir == NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002265 --choice_count;
Bram Moolenaar25a494c2018-11-16 19:39:50 +01002266 choices[idx].arg = get_choice(vimfiles_dir_choices, choice_count);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002267 set_directories_text(idx);
2268}
2269
2270/*
2271 * Create the plugin directories...
2272 */
2273/*ARGSUSED*/
2274 static void
2275install_vimfilesdir(int idx)
2276{
2277 int i;
Bram Moolenaar25a494c2018-11-16 19:39:50 +01002278 int vimfiles_dir_choice = choices[idx].arg;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002279 char *p;
2280 char vimdir_path[BUFSIZE];
2281 char vimfiles_path[BUFSIZE];
2282 char tmp_dirname[BUFSIZE];
2283
2284 /* switch on the location that the user wants the plugin directories
2285 * built in */
2286 switch (vimfiles_dir_choice)
2287 {
2288 case vimfiles_dir_vim:
2289 {
2290 /* Go to the %VIM% directory - check env first, then go one dir
2291 * below installdir if there is no %VIM% environment variable.
2292 * The accuracy of $VIM is checked in inspect_system(), so we
2293 * can be sure it is ok to use here. */
2294 p = getenv("VIM");
2295 if (p == NULL) /* No $VIM in path */
2296 dir_remove_last(installdir, vimdir_path);
2297 else
2298 strcpy(vimdir_path, p);
2299 break;
2300 }
2301 case vimfiles_dir_home:
2302 {
Bram Moolenaar25a494c2018-11-16 19:39:50 +01002303 // Find the $HOME directory. Its existence was already checked.
2304 p = homedir;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002305 if (p == NULL)
2306 {
2307 printf("Internal error: $HOME is NULL\n");
2308 p = "c:\\";
2309 }
2310 strcpy(vimdir_path, p);
2311 break;
2312 }
2313 case vimfiles_dir_none:
2314 {
Bram Moolenaar25a494c2018-11-16 19:39:50 +01002315 // Do not create vim plugin directory.
Bram Moolenaar071d4272004-06-13 20:20:40 +00002316 return;
2317 }
2318 }
2319
2320 /* Now, just create the directory. If it already exists, it will fail
2321 * silently. */
2322 sprintf(vimfiles_path, "%s\\vimfiles", vimdir_path);
2323 vim_mkdir(vimfiles_path, 0755);
2324
2325 printf("Creating the following directories in \"%s\":\n", vimfiles_path);
2326 for (i = 0; i < TABLE_SIZE(vimfiles_subdirs); i++)
2327 {
2328 sprintf(tmp_dirname, "%s\\%s", vimfiles_path, vimfiles_subdirs[i]);
2329 printf(" %s", vimfiles_subdirs[i]);
2330 vim_mkdir(tmp_dirname, 0755);
2331 }
2332 printf("\n");
2333}
2334
2335/*
2336 * Add the creation of runtime files to the setup sequence.
2337 */
2338 static void
2339init_directories_choice(void)
2340{
2341 struct stat st;
2342 char tmp_dirname[BUFSIZE];
2343 char *p;
Bram Moolenaar25a494c2018-11-16 19:39:50 +01002344 int vimfiles_dir_choice;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002345
2346 choices[choice_count].text = alloc(150);
2347 choices[choice_count].changefunc = change_directories_choice;
2348 choices[choice_count].installfunc = install_vimfilesdir;
2349 choices[choice_count].active = 1;
2350
Bram Moolenaar25a494c2018-11-16 19:39:50 +01002351 // Check if the "compiler" directory already exists. That's a good
2352 // indication that the plugin directories were already created.
Bram Moolenaar071d4272004-06-13 20:20:40 +00002353 if (getenv("HOME") != NULL)
2354 {
2355 vimfiles_dir_choice = (int)vimfiles_dir_home;
2356 sprintf(tmp_dirname, "%s\\vimfiles\\compiler", getenv("HOME"));
2357 if (stat(tmp_dirname, &st) == 0)
2358 vimfiles_dir_choice = (int)vimfiles_dir_none;
2359 }
2360 else
2361 {
2362 vimfiles_dir_choice = (int)vimfiles_dir_vim;
2363 p = getenv("VIM");
Bram Moolenaar25a494c2018-11-16 19:39:50 +01002364 if (p == NULL) // No $VIM in path, use the install dir.
Bram Moolenaar071d4272004-06-13 20:20:40 +00002365 dir_remove_last(installdir, tmp_dirname);
2366 else
2367 strcpy(tmp_dirname, p);
2368 strcat(tmp_dirname, "\\vimfiles\\compiler");
2369 if (stat(tmp_dirname, &st) == 0)
2370 vimfiles_dir_choice = (int)vimfiles_dir_none;
2371 }
2372
Bram Moolenaar25a494c2018-11-16 19:39:50 +01002373 choices[choice_count].arg = vimfiles_dir_choice;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002374 set_directories_text(choice_count);
2375 ++choice_count;
2376}
2377
2378/*
2379 * Setup the choices and the default values.
2380 */
2381 static void
2382setup_choices(void)
2383{
2384 /* install the batch files */
2385 init_bat_choices();
2386
2387 /* (over) write _vimrc file */
2388 init_vimrc_choices();
2389
2390 /* Whether to add Vim to the popup menu */
2391 init_popup_choice();
2392
2393 /* Whether to add Vim to the "Open With..." menu */
2394 init_openwith_choice();
2395
2396 /* Whether to add Vim to the Start Menu. */
2397 init_startmenu_choice();
2398
2399 /* Whether to add shortcuts to the Desktop. */
2400 init_shortcut_choices();
2401
2402 /* Whether to create the runtime directories. */
2403 init_directories_choice();
2404}
2405
2406 static void
2407print_cmd_line_help(void)
2408{
2409 printf("Vim installer non-interactive command line arguments:\n");
2410 printf("\n");
2411 printf("-create-batfiles [vim gvim evim view gview vimdiff gvimdiff]\n");
2412 printf(" Create .bat files for Vim variants in the Windows directory.\n");
2413 printf("-create-vimrc\n");
2414 printf(" Create a default _vimrc file if one does not already exist.\n");
Bram Moolenaarc3fdf7f2017-10-28 18:36:48 +02002415 printf("-vimrc-remap [no|win]\n");
2416 printf(" Remap keys when creating a default _vimrc file.\n");
2417 printf("-vimrc-behave [unix|mswin|default]\n");
2418 printf(" Set mouse behavior when creating a default _vimrc file.\n");
Bram Moolenaar6cdb2c92018-10-13 17:25:27 +02002419 printf("-vimrc-compat [vi|vim|defaults|all]\n");
2420 printf(" Set Vi compatibility when creating a default _vimrc file.\n");
Bram Moolenaar071d4272004-06-13 20:20:40 +00002421 printf("-install-popup\n");
2422 printf(" Install the Edit-with-Vim context menu entry\n");
2423 printf("-install-openwith\n");
2424 printf(" Add Vim to the \"Open With...\" context menu list\n");
Bram Moolenaar071d4272004-06-13 20:20:40 +00002425 printf("-add-start-menu");
2426 printf(" Add Vim to the start menu\n");
2427 printf("-install-icons");
2428 printf(" Create icons for gVim executables on the desktop\n");
Bram Moolenaar071d4272004-06-13 20:20:40 +00002429 printf("-create-directories [vim|home]\n");
2430 printf(" Create runtime directories to drop plugins into; in the $VIM\n");
2431 printf(" or $HOME directory\n");
Bram Moolenaar071d4272004-06-13 20:20:40 +00002432 printf("-register-OLE");
Bram Moolenaarce0842a2005-07-18 21:58:11 +00002433 printf(" Ignored\n");
Bram Moolenaar071d4272004-06-13 20:20:40 +00002434 printf("\n");
2435}
2436
2437/*
2438 * Setup installation choices based on command line switches
2439 */
2440 static void
2441command_line_setup_choices(int argc, char **argv)
2442{
2443 int i, j;
2444
2445 for (i = 1; i < argc; i++)
2446 {
2447 if (strcmp(argv[i], "-create-batfiles") == 0)
2448 {
2449 if (i + 1 == argc)
2450 continue;
2451 while (argv[i + 1][0] != '-' && i < argc)
2452 {
2453 i++;
2454 for (j = 1; j < TARGET_COUNT; ++j)
2455 if ((targets[j].exenamearg[0] == 'g' ? has_gvim : has_vim)
2456 && strcmp(argv[i], targets[j].name) == 0)
2457 {
2458 init_bat_choice(j);
2459 break;
2460 }
2461 if (j == TARGET_COUNT)
2462 printf("%s is not a valid choice for -create-batfiles\n",
2463 argv[i]);
2464
2465 if (i + 1 == argc)
2466 break;
2467 }
2468 }
2469 else if (strcmp(argv[i], "-create-vimrc") == 0)
2470 {
2471 /* Setup default vimrc choices. If there is already a _vimrc file,
2472 * it will NOT be overwritten.
2473 */
2474 init_vimrc_choices();
2475 }
Bram Moolenaarc3fdf7f2017-10-28 18:36:48 +02002476 else if (strcmp(argv[i], "-vimrc-remap") == 0)
2477 {
2478 if (i + 1 == argc)
2479 break;
2480 i++;
2481 if (strcmp(argv[i], "no") == 0)
2482 remap_choice = remap_no;
2483 else if (strcmp(argv[i], "win") == 0)
2484 remap_choice = remap_win;
2485 }
2486 else if (strcmp(argv[i], "-vimrc-behave") == 0)
2487 {
2488 if (i + 1 == argc)
2489 break;
2490 i++;
2491 if (strcmp(argv[i], "unix") == 0)
2492 mouse_choice = mouse_xterm;
2493 else if (strcmp(argv[i], "mswin") == 0)
2494 mouse_choice = mouse_mswin;
2495 else if (strcmp(argv[i], "default") == 0)
2496 mouse_choice = mouse_default;
2497 }
Bram Moolenaar6cdb2c92018-10-13 17:25:27 +02002498 else if (strcmp(argv[i], "-vimrc-compat") == 0)
2499 {
2500 if (i + 1 == argc)
2501 break;
2502 i++;
2503 if (strcmp(argv[i], "vi") == 0)
2504 compat_choice = compat_vi;
2505 else if (strcmp(argv[i], "vim") == 0)
2506 compat_choice = compat_vim;
2507 else if (strcmp(argv[i], "defaults") == 0)
2508 compat_choice = compat_some_enhancements;
2509 else if (strcmp(argv[i], "all") == 0)
2510 compat_choice = compat_all_enhancements;
2511 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00002512 else if (strcmp(argv[i], "-install-popup") == 0)
2513 {
2514 init_popup_choice();
2515 }
2516 else if (strcmp(argv[i], "-install-openwith") == 0)
2517 {
2518 init_openwith_choice();
2519 }
2520 else if (strcmp(argv[i], "-add-start-menu") == 0)
2521 {
2522 init_startmenu_choice();
2523 }
2524 else if (strcmp(argv[i], "-install-icons") == 0)
2525 {
2526 init_shortcut_choices();
2527 }
2528 else if (strcmp(argv[i], "-create-directories") == 0)
2529 {
Bram Moolenaar142a9752018-12-14 19:54:39 +01002530 int vimfiles_dir_choice = (int)vimfiles_dir_none;
Bram Moolenaar25a494c2018-11-16 19:39:50 +01002531
Bram Moolenaar071d4272004-06-13 20:20:40 +00002532 init_directories_choice();
2533 if (argv[i + 1][0] != '-')
2534 {
2535 i++;
2536 if (strcmp(argv[i], "vim") == 0)
2537 vimfiles_dir_choice = (int)vimfiles_dir_vim;
2538 else if (strcmp(argv[i], "home") == 0)
2539 {
Bram Moolenaar25a494c2018-11-16 19:39:50 +01002540 if (homedir == NULL) // No $HOME in environment
2541 vimfiles_dir_choice = (int)vimfiles_dir_none;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002542 else
2543 vimfiles_dir_choice = (int)vimfiles_dir_home;
2544 }
2545 else
2546 {
2547 printf("Unknown argument for -create-directories: %s\n",
2548 argv[i]);
2549 print_cmd_line_help();
2550 }
2551 }
2552 else /* No choice specified, default to vim directory */
2553 vimfiles_dir_choice = (int)vimfiles_dir_vim;
Bram Moolenaar25a494c2018-11-16 19:39:50 +01002554 choices[choice_count - 1].arg = vimfiles_dir_choice;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002555 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00002556 else if (strcmp(argv[i], "-register-OLE") == 0)
2557 {
2558 /* This is always done when gvim is found */
2559 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00002560 else /* Unknown switch */
2561 {
2562 printf("Got unknown argument argv[%d] = %s\n", i, argv[i]);
2563 print_cmd_line_help();
2564 }
2565 }
2566}
2567
2568
2569/*
2570 * Show a few screens full of helpful information.
2571 */
2572 static void
2573show_help(void)
2574{
2575 static char *(items[]) =
2576 {
2577"Installing .bat files\n"
2578"---------------------\n"
2579"The vim.bat file is written in one of the directories in $PATH.\n"
2580"This makes it possible to start Vim from the command line.\n"
2581"If vim.exe can be found in $PATH, the choice for vim.bat will not be\n"
2582"present. It is assumed you will use the existing vim.exe.\n"
2583"If vim.bat can already be found in $PATH this is probably for an old\n"
2584"version of Vim (but this is not checked!). You can overwrite it.\n"
2585"If no vim.bat already exists, you can select one of the directories in\n"
2586"$PATH for creating the batch file, or disable creating a vim.bat file.\n"
2587"\n"
2588"If you choose not to create the vim.bat file, Vim can still be executed\n"
2589"in other ways, but not from the command line.\n"
2590"\n"
2591"The same applies to choices for gvim, evim, (g)view, and (g)vimdiff.\n"
2592"The first item can be used to change the path for all of them.\n"
2593,
2594"Creating a _vimrc file\n"
2595"----------------------\n"
2596"The _vimrc file is used to set options for how Vim behaves.\n"
2597"The install program can create a _vimrc file with a few basic choices.\n"
2598"You can edit this file later to tune your preferences.\n"
2599"If you already have a _vimrc or .vimrc file it can be overwritten.\n"
2600"Don't do that if you have made changes to it.\n"
2601,
2602"Vim features\n"
2603"------------\n"
2604"(this choice is only available when creating a _vimrc file)\n"
2605"1. Vim can run in Vi-compatible mode. Many nice Vim features are then\n"
Bram Moolenaar2b849492018-11-21 13:58:35 +01002606" disabled. Only choose Vi-compatible if you really need full Vi\n"
2607" compatibility.\n"
2608"2. Vim runs in not-Vi-compatible mode. Vim is still mostly Vi compatible,\n"
2609" but adds nice features like multi-level undo.\n"
2610"3. Running Vim with some enhancements is useful when you want some of\n"
Bram Moolenaar071d4272004-06-13 20:20:40 +00002611" the nice Vim features, but have a slow computer and want to keep it\n"
2612" really fast.\n"
Bram Moolenaar2b849492018-11-21 13:58:35 +01002613"4. Syntax highlighting shows many files in color. Not only does this look\n"
Bram Moolenaar071d4272004-06-13 20:20:40 +00002614" nice, it also makes it easier to spot errors and you can work faster.\n"
2615" The other features include editing compressed files.\n"
2616,
2617"Windows key mapping\n"
2618"-------------------\n"
2619"(this choice is only available when creating a _vimrc file)\n"
2620"Under MS-Windows the CTRL-C key copies text to the clipboard and CTRL-V\n"
2621"pastes text from the clipboard. There are a few more keys like these.\n"
2622"Unfortunately, in Vim these keys normally have another meaning.\n"
2623"1. Choose to have the keys like they normally are in Vim (useful if you\n"
2624" also use Vim on other systems).\n"
2625"2. Choose to have the keys work like they are used on MS-Windows (useful\n"
2626" if you mostly work on MS-Windows).\n"
2627,
2628"Mouse use\n"
2629"---------\n"
2630"(this choice is only available when creating a _vimrc file)\n"
2631"The right mouse button can be used in two ways:\n"
2632"1. The Unix way is to extend an existing selection. The popup menu is\n"
2633" not available.\n"
2634"2. The MS-Windows way is to show a popup menu, which allows you to\n"
2635" copy/paste text, undo/redo, etc. Extending the selection can still be\n"
2636" done by keeping SHIFT pressed while using the left mouse button\n"
2637,
2638"Edit-with-Vim context menu entry\n"
2639"--------------------------------\n"
2640"(this choice is only available when gvim.exe and gvimext.dll are present)\n"
2641"You can associate different file types with Vim, so that you can (double)\n"
2642"click on a file to edit it with Vim. This means you have to individually\n"
2643"select each file type.\n"
2644"An alternative is the option offered here: Install an \"Edit with Vim\"\n"
2645"entry in the popup menu for the right mouse button. This means you can\n"
2646"edit any file with Vim.\n"
2647,
2648"\"Open With...\" context menu entry\n"
2649"--------------------------------\n"
2650"(this choice is only available when gvim.exe is present)\n"
2651"This option adds Vim to the \"Open With...\" entry in the popup menu for\n"
2652"the right mouse button. This also makes it possible to edit HTML files\n"
2653"directly from Internet Explorer.\n"
2654,
2655"Add Vim to the Start menu\n"
2656"-------------------------\n"
2657"In Windows 95 and later, Vim can be added to the Start menu. This will\n"
2658"create a submenu with an entry for vim, gvim, evim, vimdiff, etc..\n"
2659,
2660"Icons on the desktop\n"
2661"--------------------\n"
2662"(these choices are only available when installing gvim)\n"
2663"In Windows 95 and later, shortcuts (icons) can be created on the Desktop.\n"
2664,
2665"Create plugin directories\n"
2666"-------------------------\n"
2667"Plugin directories allow extending Vim by dropping a file into a directory.\n"
2668"This choice allows creating them in $HOME (if you have a home directory) or\n"
2669"$VIM (used for everybody on the system).\n"
2670,
2671NULL
2672 };
2673 int i;
2674 int c;
2675
2676 rewind(stdin);
2677 printf("\n");
2678 for (i = 0; items[i] != NULL; ++i)
2679 {
Bram Moolenaarc3fdf7f2017-10-28 18:36:48 +02002680 puts(items[i]);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002681 printf("Hit Enter to continue, b (back) or q (quit help): ");
2682 c = getchar();
2683 rewind(stdin);
2684 if (c == 'b' || c == 'B')
2685 {
2686 if (i == 0)
2687 --i;
2688 else
2689 i -= 2;
2690 }
2691 if (c == 'q' || c == 'Q')
2692 break;
2693 printf("\n");
2694 }
2695}
2696
2697/*
2698 * Install the choices.
2699 */
2700 static void
2701install(void)
2702{
2703 int i;
2704
2705 /* Install the selected choices. */
2706 for (i = 0; i < choice_count; ++i)
2707 if (choices[i].installfunc != NULL && choices[i].active)
2708 (choices[i].installfunc)(i);
2709
2710 /* Add some entries to the registry, if needed. */
2711 if (install_popup
2712 || install_openwith
2713 || (need_uninstall_entry && interactive)
2714 || !interactive)
2715 install_registry();
2716
Bram Moolenaar071d4272004-06-13 20:20:40 +00002717 /* Register gvim with OLE. */
2718 if (has_gvim)
2719 install_OLE_register();
Bram Moolenaar071d4272004-06-13 20:20:40 +00002720}
2721
2722/*
2723 * request_choice
2724 */
2725 static void
2726request_choice(void)
2727{
2728 int i;
2729
2730 printf("\n\nInstall will do for you:\n");
2731 for (i = 0; i < choice_count; ++i)
2732 if (choices[i].active)
2733 printf("%2d %s\n", i + 1, choices[i].text);
2734 printf("To change an item, enter its number\n\n");
2735 printf("Enter item number, h (help), d (do it) or q (quit): ");
2736}
2737
2738 int
2739main(int argc, char **argv)
2740{
2741 int i;
2742 char buf[BUFSIZE];
2743
2744 /*
2745 * Run interactively if there are no command line arguments.
2746 */
2747 if (argc > 1)
2748 interactive = 0;
2749 else
2750 interactive = 1;
2751
2752 /* Initialize this program. */
2753 do_inits(argv);
Bram Moolenaar25a494c2018-11-16 19:39:50 +01002754 init_homedir();
Bram Moolenaar071d4272004-06-13 20:20:40 +00002755
Bram Moolenaar071d4272004-06-13 20:20:40 +00002756 if (argc > 1 && strcmp(argv[1], "-uninstall-check") == 0)
2757 {
2758 /* Only check for already installed Vims. Used by NSIS installer. */
Bram Moolenaar442b4222010-05-24 21:34:22 +02002759 i = uninstall_check(1);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002760
2761 /* Find the value of $VIM, because NSIS isn't able to do this by
2762 * itself. */
2763 get_vim_env();
2764
2765 /* When nothing found exit quietly. If something found wait for
Bram Moolenaarb230bd52010-05-25 21:02:00 +02002766 * a little while, so that the user can read the messages. */
Bram Moolenaar6cdb2c92018-10-13 17:25:27 +02002767 if (i && _isatty(1))
Bram Moolenaarab8205e2010-07-07 15:14:03 +02002768 sleep(3);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002769 exit(0);
2770 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00002771
2772 printf("This program sets up the installation of Vim "
2773 VIM_VERSION_MEDIUM "\n\n");
2774
2775 /* Check if the user unpacked the archives properly. */
2776 check_unpack();
2777
Bram Moolenaar071d4272004-06-13 20:20:40 +00002778 /* Check for already installed Vims. */
2779 if (interactive)
Bram Moolenaar442b4222010-05-24 21:34:22 +02002780 uninstall_check(0);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002781
2782 /* Find out information about the system. */
2783 inspect_system();
2784
2785 if (interactive)
2786 {
2787 /* Setup all the choices. */
2788 setup_choices();
2789
2790 /* Let the user change choices and finally install (or quit). */
2791 for (;;)
2792 {
2793 request_choice();
2794 rewind(stdin);
2795 if (scanf("%99s", buf) == 1)
2796 {
2797 if (isdigit(buf[0]))
2798 {
2799 /* Change a choice. */
2800 i = atoi(buf);
2801 if (i > 0 && i <= choice_count && choices[i - 1].active)
2802 (choices[i - 1].changefunc)(i - 1);
2803 else
2804 printf("\nIllegal choice\n");
2805 }
2806 else if (buf[0] == 'h' || buf[0] == 'H')
2807 {
2808 /* Help */
2809 show_help();
2810 }
2811 else if (buf[0] == 'd' || buf[0] == 'D')
2812 {
2813 /* Install! */
2814 install();
2815 printf("\nThat finishes the installation. Happy Vimming!\n");
2816 break;
2817 }
2818 else if (buf[0] == 'q' || buf[0] == 'Q')
2819 {
2820 /* Quit */
2821 printf("\nExiting without anything done\n");
2822 break;
2823 }
2824 else
2825 printf("\nIllegal choice\n");
2826 }
2827 }
2828 printf("\n");
Bram Moolenaar442b4222010-05-24 21:34:22 +02002829 myexit(0);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002830 }
2831 else
2832 {
2833 /*
2834 * Run non-interactive - setup according to the command line switches
2835 */
2836 command_line_setup_choices(argc, argv);
2837 install();
Bram Moolenaar442b4222010-05-24 21:34:22 +02002838
2839 /* Avoid that the user has to hit Enter, just wait a little bit to
2840 * allow reading the messages. */
Bram Moolenaarab8205e2010-07-07 15:14:03 +02002841 sleep(2);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002842 }
2843
Bram Moolenaar071d4272004-06-13 20:20:40 +00002844 return 0;
2845}