blob: 002bae4cbd1444085e74e93d795111e673ebf82e [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);
447 if (strstr(title, "Vim ") != NULL && strstr(title, "Uninstall:") != NULL)
448 ++num_windows;
449 return TRUE;
450}
451
Bram Moolenaar071d4272004-06-13 20:20:40 +0000452/*
453 * Check for already installed Vims.
454 * Return non-zero when found one.
455 */
456 static int
Bram Moolenaar442b4222010-05-24 21:34:22 +0200457uninstall_check(int skip_question)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000458{
459 HKEY key_handle;
460 HKEY uninstall_key_handle;
461 char *uninstall_key = "software\\Microsoft\\Windows\\CurrentVersion\\Uninstall";
462 char subkey_name_buff[BUFSIZE];
463 char temp_string_buffer[BUFSIZE];
464 DWORD local_bufsize = BUFSIZE;
465 FILETIME temp_pfiletime;
466 DWORD key_index;
467 char input;
468 long code;
469 DWORD value_type;
470 DWORD orig_num_keys;
471 DWORD new_num_keys;
472 int foundone = 0;
473
Bram Moolenaar760d14a2010-07-31 22:03:44 +0200474 code = RegOpenKeyEx(HKEY_LOCAL_MACHINE, uninstall_key, 0,
475 KEY_WOW64_64KEY | KEY_READ, &key_handle);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000476 CHECK_REG_ERROR(code);
477
478 for (key_index = 0;
479 RegEnumKeyEx(key_handle, key_index, subkey_name_buff, &local_bufsize,
480 NULL, NULL, NULL, &temp_pfiletime) != ERROR_NO_MORE_ITEMS;
481 key_index++)
482 {
483 local_bufsize = BUFSIZE;
484 if (strncmp("Vim", subkey_name_buff, 3) == 0)
485 {
486 /* Open the key named Vim* */
Bram Moolenaar760d14a2010-07-31 22:03:44 +0200487 code = RegOpenKeyEx(key_handle, subkey_name_buff, 0,
488 KEY_WOW64_64KEY | KEY_READ, &uninstall_key_handle);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000489 CHECK_REG_ERROR(code);
490
491 /* get the DisplayName out of it to show the user */
492 code = RegQueryValueEx(uninstall_key_handle, "displayname", 0,
493 &value_type, (LPBYTE)temp_string_buffer,
494 &local_bufsize);
495 local_bufsize = BUFSIZE;
496 CHECK_REG_ERROR(code);
497
498 foundone = 1;
499 printf("\n*********************************************************\n");
500 printf("Vim Install found what looks like an existing Vim version.\n");
501 printf("The name of the entry is:\n");
502 printf("\n \"%s\"\n\n", temp_string_buffer);
503
504 printf("Installing the new version will disable part of the existing version.\n");
505 printf("(The batch files used in a console and the \"Edit with Vim\" entry in\n");
506 printf("the popup menu will use the new version)\n");
507
Bram Moolenaar442b4222010-05-24 21:34:22 +0200508 if (skip_question)
509 printf("\nRunning uninstall program for \"%s\"\n", temp_string_buffer);
510 else
511 printf("\nDo you want to uninstall \"%s\" now?\n(y)es/(n)o) ", temp_string_buffer);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000512 fflush(stdout);
513
514 /* get the UninstallString */
515 code = RegQueryValueEx(uninstall_key_handle, "uninstallstring", 0,
516 &value_type, (LPBYTE)temp_string_buffer, &local_bufsize);
517 local_bufsize = BUFSIZE;
518 CHECK_REG_ERROR(code);
519
520 /* Remember the directory, it is used as the default for NSIS. */
521 default_vim_dir = alloc(strlen(temp_string_buffer) + 1);
522 strcpy(default_vim_dir, temp_string_buffer);
523 remove_tail(default_vim_dir);
524 remove_tail(default_vim_dir);
525
526 input = 'n';
527 do
528 {
529 if (input != 'n')
530 printf("%c is an invalid reply. Please enter either 'y' or 'n'\n", input);
531
Bram Moolenaar442b4222010-05-24 21:34:22 +0200532 if (skip_question)
533 input = 'y';
534 else
535 {
536 rewind(stdin);
537 scanf("%c", &input);
538 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000539 switch (input)
540 {
541 case 'y':
542 case 'Y':
543 /* save the number of uninstall keys so we can know if
544 * it changed */
545 RegQueryInfoKey(key_handle, NULL, NULL, NULL,
546 &orig_num_keys, NULL, NULL, NULL,
547 NULL, NULL, NULL, NULL);
548
Bram Moolenaar442b4222010-05-24 21:34:22 +0200549 /* Find existing .bat files before deleting them. */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000550 find_bat_exe(TRUE);
551
552 /* Execute the uninstall program. Put it in double
553 * quotes if there is an embedded space. */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000554 {
555 char buf[BUFSIZE];
556
Bram Moolenaarb230bd52010-05-25 21:02:00 +0200557 if (strchr(temp_string_buffer, ' ') != NULL)
558 sprintf(buf, "\"%s\"", temp_string_buffer);
559 else
560 strcpy(buf, temp_string_buffer);
561 run_command(buf);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000562 }
Bram Moolenaarb230bd52010-05-25 21:02:00 +0200563
564 /* Count the number of windows with a title that match
565 * the installer, so that we can check when it's done.
566 * The uninstaller copies itself, executes the copy
567 * and exits, thus we can't wait for the process to
568 * finish. */
Bram Moolenaarab8205e2010-07-07 15:14:03 +0200569 sleep(1); /* wait for uninstaller to start up */
Bram Moolenaarb230bd52010-05-25 21:02:00 +0200570 num_windows = 0;
571 EnumWindows(window_cb, 0);
Bram Moolenaarb230bd52010-05-25 21:02:00 +0200572 if (num_windows == 0)
573 {
574 /* Did not find the uninstaller, ask user to press
575 * Enter when done. Just in case. */
576 printf("Press Enter when the uninstaller is finished\n");
577 rewind(stdin);
578 (void)getchar();
579 }
580 else
581 {
582 printf("Waiting for the uninstaller to finish (press CTRL-C to abort).");
583 do
584 {
585 printf(".");
586 fflush(stdout);
Bram Moolenaar6cdb2c92018-10-13 17:25:27 +0200587 sleep(1); /* wait for the uninstaller to finish */
Bram Moolenaarb230bd52010-05-25 21:02:00 +0200588 num_windows = 0;
589 EnumWindows(window_cb, 0);
Bram Moolenaarb230bd52010-05-25 21:02:00 +0200590 } while (num_windows > 0);
591 }
592 printf("\nDone!\n");
Bram Moolenaar071d4272004-06-13 20:20:40 +0000593
Bram Moolenaarfff2bee2010-05-15 13:56:02 +0200594 /* Check if an uninstall reg key was deleted.
Bram Moolenaar071d4272004-06-13 20:20:40 +0000595 * if it was, we want to decrement key_index.
596 * if we don't do this, we will skip the key
597 * immediately after any key that we delete. */
598 RegQueryInfoKey(key_handle, NULL, NULL, NULL,
599 &new_num_keys, NULL, NULL, NULL,
600 NULL, NULL, NULL, NULL);
601 if (new_num_keys < orig_num_keys)
602 key_index--;
603
604 input = 'y';
605 break;
606
607 case 'n':
608 case 'N':
609 /* Do not uninstall */
610 input = 'n';
611 break;
612
613 default: /* just drop through and redo the loop */
614 break;
615 }
616
617 } while (input != 'n' && input != 'y');
618
619 RegCloseKey(uninstall_key_handle);
620 }
621 }
622 RegCloseKey(key_handle);
623
624 return foundone;
625}
Bram Moolenaar071d4272004-06-13 20:20:40 +0000626
627/*
628 * Find out information about the system.
629 */
630 static void
631inspect_system(void)
632{
633 char *p;
634 char buf[BUFSIZE];
635 FILE *fd;
636 int i;
637 int foundone;
638
639 /* This may take a little while, let the user know what we're doing. */
640 printf("Inspecting system...\n");
641
642 /*
643 * If $VIM is set, check that it's pointing to our directory.
644 */
645 p = getenv("VIM");
646 if (p != NULL && pathcmp(p, -1, installdir, runtimeidx - 1) != 0)
647 {
648 printf("------------------------------------------------------\n");
649 printf("$VIM is set to \"%s\".\n", p);
650 printf("This is different from where this version of Vim is:\n");
651 strcpy(buf, installdir);
652 *(buf + runtimeidx - 1) = NUL;
653 printf("\"%s\"\n", buf);
654 printf("You must adjust or remove the setting of $VIM,\n");
655 if (interactive)
656 {
657 printf("to be able to use this install program.\n");
658 myexit(1);
659 }
660 printf("otherwise Vim WILL NOT WORK properly!\n");
661 printf("------------------------------------------------------\n");
662 }
663
664 /*
665 * If $VIMRUNTIME is set, check that it's pointing to our runtime directory.
666 */
667 p = getenv("VIMRUNTIME");
668 if (p != NULL && pathcmp(p, -1, installdir, -1) != 0)
669 {
670 printf("------------------------------------------------------\n");
671 printf("$VIMRUNTIME is set to \"%s\".\n", p);
672 printf("This is different from where this version of Vim is:\n");
673 printf("\"%s\"\n", installdir);
674 printf("You must adjust or remove the setting of $VIMRUNTIME,\n");
675 if (interactive)
676 {
677 printf("to be able to use this install program.\n");
678 myexit(1);
679 }
680 printf("otherwise Vim WILL NOT WORK properly!\n");
681 printf("------------------------------------------------------\n");
682 }
683
684 /*
685 * Check if there is a vim.[exe|bat|, gvim.[exe|bat|, etc. in the path.
686 */
687 find_bat_exe(FALSE);
688
689 /*
690 * A .exe in the install directory may be found anyway on Windows 2000.
691 * Check for this situation and find another executable if necessary.
692 * w.briscoe@ponl.com 2001-01-20
693 */
694 foundone = 0;
695 for (i = 1; i < TARGET_COUNT; ++i)
696 {
697 findoldfile(&(targets[i].oldexe));
698 if (targets[i].oldexe != NULL)
699 foundone = 1;
700 }
701
702 if (foundone)
703 {
704 printf("Warning: Found Vim executable(s) in your $PATH:\n");
705 for (i = 1; i < TARGET_COUNT; ++i)
706 if (targets[i].oldexe != NULL)
707 printf("%s\n", targets[i].oldexe);
708 printf("It will be used instead of the version you are installing.\n");
709 printf("Please delete or rename it, or adjust your $PATH setting.\n");
710 }
711
712 /*
713 * Check if there is an existing ../_vimrc or ../.vimrc file.
714 */
715 strcpy(oldvimrc, installdir);
716 strcpy(oldvimrc + runtimeidx, "_vimrc");
717 if ((fd = fopen(oldvimrc, "r")) == NULL)
718 {
719 strcpy(oldvimrc + runtimeidx, "vimrc~1"); /* short version of .vimrc */
720 if ((fd = fopen(oldvimrc, "r")) == NULL)
721 {
722 strcpy(oldvimrc + runtimeidx, ".vimrc");
723 fd = fopen(oldvimrc, "r");
724 }
725 }
726 if (fd != NULL)
727 fclose(fd);
728 else
729 *oldvimrc = NUL;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000730}
731
732/*
733 * Add a dummy choice to avoid that the numbering changes depending on items
734 * in the environment. The user may type a number he remembered without
735 * looking.
736 */
737 static void
738add_dummy_choice(void)
739{
740 choices[choice_count].installfunc = NULL;
741 choices[choice_count].active = 0;
742 choices[choice_count].changefunc = NULL;
Bram Moolenaar25a494c2018-11-16 19:39:50 +0100743 choices[choice_count].text = NULL;
744 choices[choice_count].arg = 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000745 ++choice_count;
746}
747
748/***********************************************
749 * stuff for creating the batch files.
750 */
751
752/*
753 * Install the vim.bat, gvim.bat, etc. files.
754 */
755 static void
756install_bat_choice(int idx)
757{
758 char *batpath = targets[choices[idx].arg].batpath;
759 char *oldname = targets[choices[idx].arg].oldbat;
760 char *exename = targets[choices[idx].arg].exenamearg;
761 char *vimarg = targets[choices[idx].arg].exearg;
762 FILE *fd;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000763
764 if (*batpath != NUL)
765 {
766 fd = fopen(batpath, "w");
767 if (fd == NULL)
768 printf("\nERROR: Cannot open \"%s\" for writing.\n", batpath);
769 else
770 {
771 need_uninstall_entry = 1;
772
773 fprintf(fd, "@echo off\n");
Bram Moolenaar97b2ad32006-03-18 21:40:56 +0000774 fprintf(fd, "rem -- Run Vim --\n");
775 fprintf(fd, "\n");
Bram Moolenaare609ad52016-03-28 23:05:48 +0200776 fprintf(fd, "setlocal\n");
Bram Moolenaar071d4272004-06-13 20:20:40 +0000777
Bram Moolenaar97b2ad32006-03-18 21:40:56 +0000778 /* Don't use double quotes for the "set" argument, also when it
Bram Moolenaar071d4272004-06-13 20:20:40 +0000779 * contains a space. The quotes would be included in the value
Bram Moolenaar97b2ad32006-03-18 21:40:56 +0000780 * for MSDOS and NT.
781 * The order of preference is:
782 * 1. $VIMRUNTIME/vim.exe (user preference)
783 * 2. $VIM/vim70/vim.exe (hard coded version)
784 * 3. installdir/vim.exe (hard coded install directory)
785 */
786 fprintf(fd, "set VIM_EXE_DIR=%s\n", installdir);
787 fprintf(fd, "if exist \"%%VIM%%\\%s\\%s\" set VIM_EXE_DIR=%%VIM%%\\%s\n",
788 VIM_VERSION_NODOT, exename, VIM_VERSION_NODOT);
789 fprintf(fd, "if exist \"%%VIMRUNTIME%%\\%s\" set VIM_EXE_DIR=%%VIMRUNTIME%%\n", exename);
790 fprintf(fd, "\n");
Bram Moolenaar071d4272004-06-13 20:20:40 +0000791
792 /* Give an error message when the executable could not be found. */
Bram Moolenaar97b2ad32006-03-18 21:40:56 +0000793 fprintf(fd, "if exist \"%%VIM_EXE_DIR%%\\%s\" goto havevim\n",
794 exename);
795 fprintf(fd, "echo \"%%VIM_EXE_DIR%%\\%s\" not found\n", exename);
796 fprintf(fd, "goto eof\n");
797 fprintf(fd, "\n");
Bram Moolenaar071d4272004-06-13 20:20:40 +0000798 fprintf(fd, ":havevim\n");
799
800 fprintf(fd, "rem collect the arguments in VIMARGS for Win95\n");
801 fprintf(fd, "set VIMARGS=\n");
802 if (*exename == 'g')
803 fprintf(fd, "set VIMNOFORK=\n");
804 fprintf(fd, ":loopstart\n");
805 fprintf(fd, "if .%%1==. goto loopend\n");
806 if (*exename == 'g')
807 {
Bram Moolenaare609ad52016-03-28 23:05:48 +0200808 fprintf(fd, "if NOT .%%1==.--nofork goto noforklongarg\n");
809 fprintf(fd, "set VIMNOFORK=1\n");
810 fprintf(fd, ":noforklongarg\n");
Bram Moolenaar071d4272004-06-13 20:20:40 +0000811 fprintf(fd, "if NOT .%%1==.-f goto noforkarg\n");
812 fprintf(fd, "set VIMNOFORK=1\n");
813 fprintf(fd, ":noforkarg\n");
814 }
815 fprintf(fd, "set VIMARGS=%%VIMARGS%% %%1\n");
816 fprintf(fd, "shift\n");
Bram Moolenaar97b2ad32006-03-18 21:40:56 +0000817 fprintf(fd, "goto loopstart\n");
Bram Moolenaar071d4272004-06-13 20:20:40 +0000818 fprintf(fd, ":loopend\n");
Bram Moolenaar97b2ad32006-03-18 21:40:56 +0000819 fprintf(fd, "\n");
Bram Moolenaar071d4272004-06-13 20:20:40 +0000820
Bram Moolenaar97b2ad32006-03-18 21:40:56 +0000821 fprintf(fd, "if .%%OS%%==.Windows_NT goto ntaction\n");
822 fprintf(fd, "\n");
Bram Moolenaar071d4272004-06-13 20:20:40 +0000823
824 /* For gvim.exe use "start" to avoid that the console window stays
825 * open. */
826 if (*exename == 'g')
827 {
828 fprintf(fd, "if .%%VIMNOFORK%%==.1 goto nofork\n");
829 fprintf(fd, "start ");
830 }
831
Bram Moolenaar97b2ad32006-03-18 21:40:56 +0000832 /* Always use quotes, $VIM or $VIMRUNTIME might have a space. */
833 fprintf(fd, "\"%%VIM_EXE_DIR%%\\%s\" %s %%VIMARGS%%\n",
834 exename, vimarg);
835 fprintf(fd, "goto eof\n");
836 fprintf(fd, "\n");
Bram Moolenaar071d4272004-06-13 20:20:40 +0000837
838 if (*exename == 'g')
839 {
840 fprintf(fd, ":nofork\n");
841 fprintf(fd, "start /w ");
Bram Moolenaar97b2ad32006-03-18 21:40:56 +0000842 /* Always use quotes, $VIM or $VIMRUNTIME might have a space. */
843 fprintf(fd, "\"%%VIM_EXE_DIR%%\\%s\" %s %%VIMARGS%%\n",
844 exename, vimarg);
845 fprintf(fd, "goto eof\n");
846 fprintf(fd, "\n");
Bram Moolenaar071d4272004-06-13 20:20:40 +0000847 }
848
849 fprintf(fd, ":ntaction\n");
850 fprintf(fd, "rem for WinNT we can use %%*\n");
851
852 /* For gvim.exe use "start /b" to avoid that the console window
853 * stays open. */
854 if (*exename == 'g')
855 {
856 fprintf(fd, "if .%%VIMNOFORK%%==.1 goto noforknt\n");
857 fprintf(fd, "start \"dummy\" /b ");
858 }
859
Bram Moolenaar97b2ad32006-03-18 21:40:56 +0000860 /* Always use quotes, $VIM or $VIMRUNTIME might have a space. */
861 fprintf(fd, "\"%%VIM_EXE_DIR%%\\%s\" %s %%*\n", exename, vimarg);
862 fprintf(fd, "goto eof\n");
863 fprintf(fd, "\n");
Bram Moolenaar071d4272004-06-13 20:20:40 +0000864
865 if (*exename == 'g')
866 {
867 fprintf(fd, ":noforknt\n");
868 fprintf(fd, "start \"dummy\" /b /wait ");
Bram Moolenaar97b2ad32006-03-18 21:40:56 +0000869 /* Always use quotes, $VIM or $VIMRUNTIME might have a space. */
870 fprintf(fd, "\"%%VIM_EXE_DIR%%\\%s\" %s %%*\n",
871 exename, vimarg);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000872 }
873
874 fprintf(fd, "\n:eof\n");
875 fprintf(fd, "set VIMARGS=\n");
876 if (*exename == 'g')
877 fprintf(fd, "set VIMNOFORK=\n");
878
879 fclose(fd);
880 printf("%s has been %s\n", batpath,
881 oldname == NULL ? "created" : "overwritten");
882 }
883 }
884}
885
886/*
887 * Make the text string for choice "idx".
888 * The format "fmt" is must have one %s item, which "arg" is used for.
889 */
890 static void
891alloc_text(int idx, char *fmt, char *arg)
892{
893 if (choices[idx].text != NULL)
894 free(choices[idx].text);
895
896 choices[idx].text = alloc((int)(strlen(fmt) + strlen(arg)) - 1);
897 sprintf(choices[idx].text, fmt, arg);
898}
899
900/*
901 * Toggle the "Overwrite .../vim.bat" to "Don't overwrite".
902 */
903 static void
904toggle_bat_choice(int idx)
905{
906 char *batname = targets[choices[idx].arg].batpath;
907 char *oldname = targets[choices[idx].arg].oldbat;
908
909 if (*batname == NUL)
910 {
911 alloc_text(idx, " Overwrite %s", oldname);
912 strcpy(batname, oldname);
913 }
914 else
915 {
916 alloc_text(idx, " Do NOT overwrite %s", oldname);
917 *batname = NUL;
918 }
919}
920
921/*
922 * Do some work for a batch file entry: Append the batch file name to the path
923 * and set the text for the choice.
924 */
925 static void
926set_bat_text(int idx, char *batpath, char *name)
927{
928 strcat(batpath, name);
929
930 alloc_text(idx, " Create %s", batpath);
931}
932
933/*
934 * Select a directory to write the batch file line.
935 */
936 static void
937change_bat_choice(int idx)
938{
939 char *path;
940 char *batpath;
941 char *name;
942 int n;
943 char *s;
944 char *p;
945 int count;
946 char **names = NULL;
947 int i;
948 int target = choices[idx].arg;
949
950 name = targets[target].batname;
951 batpath = targets[target].batpath;
952
953 path = getenv("PATH");
954 if (path == NULL)
955 {
956 printf("\nERROR: The variable $PATH is not set\n");
957 return;
958 }
959
960 /*
961 * first round: count number of names in path;
962 * second round: save names to names[].
963 */
964 for (;;)
965 {
966 count = 1;
967 for (p = path; *p; )
968 {
969 s = strchr(p, ';');
970 if (s == NULL)
971 s = p + strlen(p);
972 if (names != NULL)
973 {
974 names[count] = alloc((int)(s - p) + 1);
975 strncpy(names[count], p, s - p);
976 names[count][s - p] = NUL;
977 }
978 ++count;
979 p = s;
980 if (*p != NUL)
981 ++p;
982 }
983 if (names != NULL)
984 break;
985 names = alloc((int)(count + 1) * sizeof(char *));
986 }
987 names[0] = alloc(50);
988 sprintf(names[0], "Select directory to create %s in:", name);
989 names[count] = alloc(50);
990 if (choices[idx].arg == 0)
991 sprintf(names[count], "Do not create any .bat file.");
992 else
993 sprintf(names[count], "Do not create a %s file.", name);
994 n = get_choice(names, count + 1);
995
996 if (n == count)
997 {
998 /* Selected last item, don't create bat file. */
999 *batpath = NUL;
1000 if (choices[idx].arg != 0)
1001 alloc_text(idx, " Do NOT create %s", name);
1002 }
1003 else
1004 {
1005 /* Selected one of the paths. For the first item only keep the path,
1006 * for the others append the batch file name. */
1007 strcpy(batpath, names[n]);
1008 add_pathsep(batpath);
1009 if (choices[idx].arg != 0)
1010 set_bat_text(idx, batpath, name);
1011 }
1012
1013 for (i = 0; i <= count; ++i)
1014 free(names[i]);
1015 free(names);
1016}
1017
1018char *bat_text_yes = "Install .bat files to use Vim at the command line:";
1019char *bat_text_no = "do NOT install .bat files to use Vim at the command line";
1020
1021 static void
1022change_main_bat_choice(int idx)
1023{
1024 int i;
1025
1026 /* let the user select a default directory or NONE */
1027 change_bat_choice(idx);
1028
1029 if (targets[0].batpath[0] != NUL)
1030 choices[idx].text = bat_text_yes;
1031 else
1032 choices[idx].text = bat_text_no;
1033
1034 /* update the individual batch file selections */
1035 for (i = 1; i < TARGET_COUNT; ++i)
1036 {
1037 /* Only make it active when the first item has a path and the vim.exe
1038 * or gvim.exe exists (there is a changefunc then). */
1039 if (targets[0].batpath[0] != NUL
1040 && choices[idx + i].changefunc != NULL)
1041 {
1042 choices[idx + i].active = 1;
1043 if (choices[idx + i].changefunc == change_bat_choice
1044 && targets[i].batpath[0] != NUL)
1045 {
1046 strcpy(targets[i].batpath, targets[0].batpath);
1047 set_bat_text(idx + i, targets[i].batpath, targets[i].batname);
1048 }
1049 }
1050 else
1051 choices[idx + i].active = 0;
1052 }
1053}
1054
1055/*
1056 * Initialize a choice for creating a batch file.
1057 */
1058 static void
1059init_bat_choice(int target)
1060{
1061 char *batpath = targets[target].batpath;
1062 char *oldbat = targets[target].oldbat;
1063 char *p;
1064 int i;
1065
1066 choices[choice_count].arg = target;
1067 choices[choice_count].installfunc = install_bat_choice;
1068 choices[choice_count].active = 1;
1069 choices[choice_count].text = NULL; /* will be set below */
1070 if (oldbat != NULL)
1071 {
1072 /* A [g]vim.bat exists: Only choice is to overwrite it or not. */
1073 choices[choice_count].changefunc = toggle_bat_choice;
1074 *batpath = NUL;
1075 toggle_bat_choice(choice_count);
1076 }
1077 else
1078 {
1079 if (default_bat_dir != NULL)
1080 /* Prefer using the same path as an existing .bat file. */
1081 strcpy(batpath, default_bat_dir);
1082 else
1083 {
1084 /* No [g]vim.bat exists: Write it to a directory in $PATH. Use
1085 * $WINDIR by default, if it's empty the first item in $PATH. */
1086 p = getenv("WINDIR");
1087 if (p != NULL && *p != NUL)
1088 strcpy(batpath, p);
1089 else
1090 {
1091 p = getenv("PATH");
1092 if (p == NULL || *p == NUL) /* "cannot happen" */
1093 strcpy(batpath, "C:/Windows");
1094 else
1095 {
1096 i = 0;
1097 while (*p != NUL && *p != ';')
1098 batpath[i++] = *p++;
1099 batpath[i] = NUL;
1100 }
1101 }
1102 }
1103 add_pathsep(batpath);
1104 set_bat_text(choice_count, batpath, targets[target].batname);
1105
1106 choices[choice_count].changefunc = change_bat_choice;
1107 }
1108 ++choice_count;
1109}
1110
1111/*
1112 * Set up the choices for installing .bat files.
1113 * For these items "arg" is the index in targets[].
1114 */
1115 static void
1116init_bat_choices(void)
1117{
1118 int i;
1119
1120 /* The first item is used to switch installing batch files on/off and
1121 * setting the default path. */
1122 choices[choice_count].text = bat_text_yes;
1123 choices[choice_count].changefunc = change_main_bat_choice;
1124 choices[choice_count].installfunc = NULL;
1125 choices[choice_count].active = 1;
1126 choices[choice_count].arg = 0;
1127 ++choice_count;
1128
1129 /* Add items for each batch file target. Only used when not disabled by
1130 * the first item. When a .exe exists, don't offer to create a .bat. */
1131 for (i = 1; i < TARGET_COUNT; ++i)
1132 if (targets[i].oldexe == NULL
1133 && (targets[i].exenamearg[0] == 'g' ? has_gvim : has_vim))
1134 init_bat_choice(i);
1135 else
1136 add_dummy_choice();
1137}
1138
1139/*
1140 * Install the vimrc file.
1141 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001142 static void
1143install_vimrc(int idx)
1144{
1145 FILE *fd, *tfd;
1146 char *fname;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001147
1148 /* If an old vimrc file exists, overwrite it.
1149 * Otherwise create a new one. */
1150 if (*oldvimrc != NUL)
1151 fname = oldvimrc;
1152 else
1153 fname = vimrc;
1154
1155 fd = fopen(fname, "w");
1156 if (fd == NULL)
1157 {
1158 printf("\nERROR: Cannot open \"%s\" for writing.\n", fname);
1159 return;
1160 }
1161 switch (compat_choice)
1162 {
1163 case compat_vi:
Bram Moolenaar6cdb2c92018-10-13 17:25:27 +02001164 fprintf(fd, "\" Vi compatible\n");
Bram Moolenaar071d4272004-06-13 20:20:40 +00001165 fprintf(fd, "set compatible\n");
1166 break;
Bram Moolenaar6cdb2c92018-10-13 17:25:27 +02001167 case compat_vim:
1168 fprintf(fd, "\" Vim's default behavior\n");
1169 fprintf(fd, "if &compatible\n");
1170 fprintf(fd, " set nocompatible\n");
1171 fprintf(fd, "endif\n");
1172 break;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001173 case compat_some_enhancements:
Bram Moolenaar6cdb2c92018-10-13 17:25:27 +02001174 fprintf(fd, "\" Vim with some enhancements\n");
Bram Moolenaarc73e4472016-07-29 18:33:38 +02001175 fprintf(fd, "source $VIMRUNTIME/defaults.vim\n");
Bram Moolenaar071d4272004-06-13 20:20:40 +00001176 break;
1177 case compat_all_enhancements:
Bram Moolenaar6cdb2c92018-10-13 17:25:27 +02001178 fprintf(fd, "\" Vim with all enhancements\n");
Bram Moolenaar071d4272004-06-13 20:20:40 +00001179 fprintf(fd, "source $VIMRUNTIME/vimrc_example.vim\n");
1180 break;
1181 }
1182 switch (remap_choice)
1183 {
1184 case remap_no:
1185 break;
1186 case remap_win:
Bram Moolenaar6cdb2c92018-10-13 17:25:27 +02001187 fprintf(fd, "\n");
1188 fprintf(fd, "\" Remap a few keys for Windows behavior\n");
Bram Moolenaar071d4272004-06-13 20:20:40 +00001189 fprintf(fd, "source $VIMRUNTIME/mswin.vim\n");
1190 break;
1191 }
1192 switch (mouse_choice)
1193 {
1194 case mouse_xterm:
Bram Moolenaar6cdb2c92018-10-13 17:25:27 +02001195 fprintf(fd, "\n");
1196 fprintf(fd, "\" Mouse behavior (the Unix way)\n");
Bram Moolenaar071d4272004-06-13 20:20:40 +00001197 fprintf(fd, "behave xterm\n");
1198 break;
1199 case mouse_mswin:
Bram Moolenaar6cdb2c92018-10-13 17:25:27 +02001200 fprintf(fd, "\n");
1201 fprintf(fd, "\" Mouse behavior (the Windows way)\n");
Bram Moolenaar071d4272004-06-13 20:20:40 +00001202 fprintf(fd, "behave mswin\n");
1203 break;
Bram Moolenaarc3fdf7f2017-10-28 18:36:48 +02001204 case mouse_default:
1205 break;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001206 }
1207 if ((tfd = fopen("diff.exe", "r")) != NULL)
1208 {
1209 /* Use the diff.exe that comes with the self-extracting gvim.exe. */
1210 fclose(tfd);
1211 fprintf(fd, "\n");
Bram Moolenaar6cdb2c92018-10-13 17:25:27 +02001212 fprintf(fd, "\" Use the internal diff if available.\n");
1213 fprintf(fd, "\" Otherwise use the special 'diffexpr' for Windows.\n");
1214 fprintf(fd, "if &diffopt !~# 'internal'\n");
1215 fprintf(fd, " set diffexpr=MyDiff()\n");
1216 fprintf(fd, "endif\n");
Bram Moolenaar071d4272004-06-13 20:20:40 +00001217 fprintf(fd, "function MyDiff()\n");
1218 fprintf(fd, " let opt = '-a --binary '\n");
1219 fprintf(fd, " if &diffopt =~ 'icase' | let opt = opt . '-i ' | endif\n");
1220 fprintf(fd, " if &diffopt =~ 'iwhite' | let opt = opt . '-b ' | endif\n");
Bram Moolenaar12365ce2018-05-13 14:45:25 +02001221 /* Use quotes only when needed, they may cause trouble.
1222 * Always escape "!". */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001223 fprintf(fd, " let arg1 = v:fname_in\n");
1224 fprintf(fd, " if arg1 =~ ' ' | let arg1 = '\"' . arg1 . '\"' | endif\n");
Bram Moolenaar12365ce2018-05-13 14:45:25 +02001225 fprintf(fd, " let arg1 = substitute(arg1, '!', '\\!', 'g')\n");
Bram Moolenaar071d4272004-06-13 20:20:40 +00001226 fprintf(fd, " let arg2 = v:fname_new\n");
1227 fprintf(fd, " if arg2 =~ ' ' | let arg2 = '\"' . arg2 . '\"' | endif\n");
Bram Moolenaar12365ce2018-05-13 14:45:25 +02001228 fprintf(fd, " let arg2 = substitute(arg2, '!', '\\!', 'g')\n");
Bram Moolenaar071d4272004-06-13 20:20:40 +00001229 fprintf(fd, " let arg3 = v:fname_out\n");
1230 fprintf(fd, " if arg3 =~ ' ' | let arg3 = '\"' . arg3 . '\"' | endif\n");
Bram Moolenaar12365ce2018-05-13 14:45:25 +02001231 fprintf(fd, " let arg3 = substitute(arg3, '!', '\\!', 'g')\n");
Bram Moolenaar33aec762006-01-22 23:30:12 +00001232
1233 /* If the path has a space: When using cmd.exe (Win NT/2000/XP) put
Bram Moolenaarc62a6442013-11-21 18:13:37 +01001234 * quotes around the diff command and rely on the default value of
Bram Moolenaar792f0e32018-02-27 17:27:13 +01001235 * shellxquote to solve the quoting problem for the whole command.
1236 *
Bram Moolenaar33aec762006-01-22 23:30:12 +00001237 * Otherwise put a double quote just before the space and at the
1238 * end of the command. Putting quotes around the whole thing
1239 * doesn't work on Win 95/98/ME. This is mostly guessed! */
Bram Moolenaar33aec762006-01-22 23:30:12 +00001240 fprintf(fd, " if $VIMRUNTIME =~ ' '\n");
1241 fprintf(fd, " if &sh =~ '\\<cmd'\n");
Bram Moolenaarc62a6442013-11-21 18:13:37 +01001242 fprintf(fd, " if empty(&shellxquote)\n");
1243 fprintf(fd, " let l:shxq_sav = ''\n");
1244 fprintf(fd, " set shellxquote&\n");
1245 fprintf(fd, " endif\n");
1246 fprintf(fd, " let cmd = '\"' . $VIMRUNTIME . '\\diff\"'\n");
Bram Moolenaar33aec762006-01-22 23:30:12 +00001247 fprintf(fd, " else\n");
1248 fprintf(fd, " let cmd = substitute($VIMRUNTIME, ' ', '\" ', '') . '\\diff\"'\n");
1249 fprintf(fd, " endif\n");
1250 fprintf(fd, " else\n");
1251 fprintf(fd, " let cmd = $VIMRUNTIME . '\\diff'\n");
1252 fprintf(fd, " endif\n");
Bram Moolenaar12365ce2018-05-13 14:45:25 +02001253 fprintf(fd, " let cmd = substitute(cmd, '!', '\\!', 'g')\n");
Bram Moolenaarc62a6442013-11-21 18:13:37 +01001254 fprintf(fd, " silent execute '!' . cmd . ' ' . opt . arg1 . ' ' . arg2 . ' > ' . arg3\n");
1255 fprintf(fd, " if exists('l:shxq_sav')\n");
1256 fprintf(fd, " let &shellxquote=l:shxq_sav\n");
1257 fprintf(fd, " endif\n");
Bram Moolenaar071d4272004-06-13 20:20:40 +00001258 fprintf(fd, "endfunction\n");
1259 fprintf(fd, "\n");
1260 }
1261 fclose(fd);
1262 printf("%s has been written\n", fname);
1263}
1264
1265 static void
1266change_vimrc_choice(int idx)
1267{
1268 if (choices[idx].installfunc != NULL)
1269 {
1270 /* Switch to NOT change or create a vimrc file. */
1271 if (*oldvimrc != NUL)
1272 alloc_text(idx, "Do NOT change startup file %s", oldvimrc);
1273 else
1274 alloc_text(idx, "Do NOT create startup file %s", vimrc);
1275 choices[idx].installfunc = NULL;
1276 choices[idx + 1].active = 0;
1277 choices[idx + 2].active = 0;
1278 choices[idx + 3].active = 0;
1279 }
1280 else
1281 {
1282 /* Switch to change or create a vimrc file. */
1283 if (*oldvimrc != NUL)
1284 alloc_text(idx, "Overwrite startup file %s with:", oldvimrc);
1285 else
1286 alloc_text(idx, "Create startup file %s with:", vimrc);
1287 choices[idx].installfunc = install_vimrc;
1288 choices[idx + 1].active = 1;
1289 choices[idx + 2].active = 1;
1290 choices[idx + 3].active = 1;
1291 }
1292}
1293
1294/*
1295 * Change the choice how to run Vim.
1296 */
1297 static void
1298change_run_choice(int idx)
1299{
1300 compat_choice = get_choice(compat_choices, TABLE_SIZE(compat_choices));
1301 alloc_text(idx, compat_text, compat_choices[compat_choice]);
1302}
1303
1304/*
1305 * Change the choice if keys are to be remapped.
1306 */
1307 static void
1308change_remap_choice(int idx)
1309{
1310 remap_choice = get_choice(remap_choices, TABLE_SIZE(remap_choices));
1311 alloc_text(idx, remap_text, remap_choices[remap_choice]);
1312}
1313
1314/*
1315 * Change the choice how to select text.
1316 */
1317 static void
1318change_mouse_choice(int idx)
1319{
1320 mouse_choice = get_choice(mouse_choices, TABLE_SIZE(mouse_choices));
1321 alloc_text(idx, mouse_text, mouse_choices[mouse_choice]);
1322}
1323
1324 static void
1325init_vimrc_choices(void)
1326{
1327 /* set path for a new _vimrc file (also when not used) */
1328 strcpy(vimrc, installdir);
1329 strcpy(vimrc + runtimeidx, "_vimrc");
1330
1331 /* Set opposite value and then toggle it by calling change_vimrc_choice() */
1332 if (*oldvimrc == NUL)
1333 choices[choice_count].installfunc = NULL;
1334 else
1335 choices[choice_count].installfunc = install_vimrc;
1336 choices[choice_count].text = NULL;
1337 change_vimrc_choice(choice_count);
1338 choices[choice_count].changefunc = change_vimrc_choice;
1339 choices[choice_count].active = 1;
1340 ++choice_count;
1341
1342 /* default way to run Vim */
1343 alloc_text(choice_count, compat_text, compat_choices[compat_choice]);
1344 choices[choice_count].changefunc = change_run_choice;
1345 choices[choice_count].installfunc = NULL;
1346 choices[choice_count].active = (*oldvimrc == NUL);
1347 ++choice_count;
1348
1349 /* Whether to remap keys */
1350 alloc_text(choice_count, remap_text , remap_choices[remap_choice]);
1351 choices[choice_count].changefunc = change_remap_choice;
Bram Moolenaar945ec092016-06-08 21:17:43 +02001352 choices[choice_count].installfunc = NULL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001353 choices[choice_count].active = (*oldvimrc == NUL);
1354 ++choice_count;
1355
1356 /* default way to use the mouse */
1357 alloc_text(choice_count, mouse_text, mouse_choices[mouse_choice]);
1358 choices[choice_count].changefunc = change_mouse_choice;
Bram Moolenaar945ec092016-06-08 21:17:43 +02001359 choices[choice_count].installfunc = NULL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001360 choices[choice_count].active = (*oldvimrc == NUL);
1361 ++choice_count;
1362}
1363
Bram Moolenaarccd9ccf2010-07-07 13:19:55 +02001364 static LONG
1365reg_create_key(
1366 HKEY root,
1367 const char *subkey,
Bram Moolenaar6199d432017-10-14 19:05:44 +02001368 PHKEY phKey,
1369 DWORD flag)
Bram Moolenaarccd9ccf2010-07-07 13:19:55 +02001370{
1371 DWORD disp;
1372
1373 *phKey = NULL;
1374 return RegCreateKeyEx(
Bram Moolenaarcc448b32010-07-14 16:52:17 +02001375 root, subkey,
1376 0, NULL, REG_OPTION_NON_VOLATILE,
Bram Moolenaar6199d432017-10-14 19:05:44 +02001377 flag | KEY_WRITE,
Bram Moolenaarcc448b32010-07-14 16:52:17 +02001378 NULL, phKey, &disp);
Bram Moolenaarccd9ccf2010-07-07 13:19:55 +02001379}
1380
1381 static LONG
1382reg_set_string_value(
1383 HKEY hKey,
1384 const char *value_name,
1385 const char *data)
1386{
1387 return RegSetValueEx(hKey, value_name, 0, REG_SZ,
1388 (LPBYTE)data, (DWORD)(1 + strlen(data)));
1389}
1390
1391 static LONG
1392reg_create_key_and_value(
1393 HKEY hRootKey,
1394 const char *subkey,
1395 const char *value_name,
Bram Moolenaar6199d432017-10-14 19:05:44 +02001396 const char *data,
1397 DWORD flag)
Bram Moolenaarccd9ccf2010-07-07 13:19:55 +02001398{
1399 HKEY hKey;
Bram Moolenaar6199d432017-10-14 19:05:44 +02001400 LONG lRet = reg_create_key(hRootKey, subkey, &hKey, flag);
Bram Moolenaarccd9ccf2010-07-07 13:19:55 +02001401
1402 if (ERROR_SUCCESS == lRet)
1403 {
Bram Moolenaarcc448b32010-07-14 16:52:17 +02001404 lRet = reg_set_string_value(hKey, value_name, data);
1405 RegCloseKey(hKey);
Bram Moolenaarccd9ccf2010-07-07 13:19:55 +02001406 }
1407 return lRet;
1408}
1409
1410 static LONG
1411register_inproc_server(
1412 HKEY hRootKey,
1413 const char *clsid,
1414 const char *extname,
1415 const char *module,
Bram Moolenaar6199d432017-10-14 19:05:44 +02001416 const char *threading_model,
1417 DWORD flag)
Bram Moolenaarccd9ccf2010-07-07 13:19:55 +02001418{
1419 CHAR subkey[BUFSIZE];
1420 LONG lRet;
1421
1422 sprintf(subkey, "CLSID\\%s", clsid);
Bram Moolenaar6199d432017-10-14 19:05:44 +02001423 lRet = reg_create_key_and_value(hRootKey, subkey, NULL, extname, flag);
Bram Moolenaarccd9ccf2010-07-07 13:19:55 +02001424 if (ERROR_SUCCESS == lRet)
1425 {
Bram Moolenaarcc448b32010-07-14 16:52:17 +02001426 sprintf(subkey, "CLSID\\%s\\InProcServer32", clsid);
Bram Moolenaar6199d432017-10-14 19:05:44 +02001427 lRet = reg_create_key_and_value(hRootKey, subkey, NULL, module, flag);
Bram Moolenaarcc448b32010-07-14 16:52:17 +02001428 if (ERROR_SUCCESS == lRet)
1429 {
1430 lRet = reg_create_key_and_value(hRootKey, subkey,
Bram Moolenaar6199d432017-10-14 19:05:44 +02001431 "ThreadingModel", threading_model, flag);
Bram Moolenaarcc448b32010-07-14 16:52:17 +02001432 }
Bram Moolenaarccd9ccf2010-07-07 13:19:55 +02001433 }
1434 return lRet;
1435}
1436
1437 static LONG
1438register_shellex(
1439 HKEY hRootKey,
1440 const char *clsid,
1441 const char *name,
Bram Moolenaar6199d432017-10-14 19:05:44 +02001442 const char *exe_path,
1443 DWORD flag)
Bram Moolenaarccd9ccf2010-07-07 13:19:55 +02001444{
1445 LONG lRet = reg_create_key_and_value(
Bram Moolenaarcc448b32010-07-14 16:52:17 +02001446 hRootKey,
1447 "*\\shellex\\ContextMenuHandlers\\gvim",
1448 NULL,
Bram Moolenaar6199d432017-10-14 19:05:44 +02001449 clsid,
1450 flag);
Bram Moolenaarccd9ccf2010-07-07 13:19:55 +02001451
1452 if (ERROR_SUCCESS == lRet)
1453 {
Bram Moolenaarcc448b32010-07-14 16:52:17 +02001454 lRet = reg_create_key_and_value(
1455 HKEY_LOCAL_MACHINE,
1456 "Software\\Microsoft\\Windows\\CurrentVersion\\Shell Extensions\\Approved",
1457 clsid,
Bram Moolenaar6199d432017-10-14 19:05:44 +02001458 name,
1459 flag);
Bram Moolenaarccd9ccf2010-07-07 13:19:55 +02001460
Bram Moolenaarcc448b32010-07-14 16:52:17 +02001461 if (ERROR_SUCCESS == lRet)
1462 {
1463 lRet = reg_create_key_and_value(
1464 HKEY_LOCAL_MACHINE,
1465 "Software\\Vim\\Gvim",
1466 "path",
Bram Moolenaar6199d432017-10-14 19:05:44 +02001467 exe_path,
1468 flag);
Bram Moolenaarcc448b32010-07-14 16:52:17 +02001469 }
Bram Moolenaarccd9ccf2010-07-07 13:19:55 +02001470 }
1471 return lRet;
1472}
1473
1474 static LONG
1475register_openwith(
1476 HKEY hRootKey,
Bram Moolenaar6199d432017-10-14 19:05:44 +02001477 const char *exe_path,
1478 DWORD flag)
Bram Moolenaarccd9ccf2010-07-07 13:19:55 +02001479{
Bram Moolenaar78050042010-07-31 20:53:54 +02001480 char exe_cmd[BUFSIZE];
1481 LONG lRet;
1482
Bram Moolenaarbbdcb482010-08-02 20:45:27 +02001483 sprintf(exe_cmd, "\"%s\" \"%%1\"", exe_path);
Bram Moolenaar78050042010-07-31 20:53:54 +02001484 lRet = reg_create_key_and_value(
Bram Moolenaarcc448b32010-07-14 16:52:17 +02001485 hRootKey,
1486 "Applications\\gvim.exe\\shell\\edit\\command",
1487 NULL,
Bram Moolenaar6199d432017-10-14 19:05:44 +02001488 exe_cmd,
1489 flag);
Bram Moolenaarccd9ccf2010-07-07 13:19:55 +02001490
1491 if (ERROR_SUCCESS == lRet)
1492 {
Bram Moolenaarcc448b32010-07-14 16:52:17 +02001493 int i;
1494 static const char *openwith[] = {
1495 ".htm\\OpenWithList\\gvim.exe",
1496 ".vim\\OpenWithList\\gvim.exe",
1497 "*\\OpenWithList\\gvim.exe",
1498 };
Bram Moolenaarccd9ccf2010-07-07 13:19:55 +02001499
Bram Moolenaarcc448b32010-07-14 16:52:17 +02001500 for (i = 0; ERROR_SUCCESS == lRet
Bram Moolenaarccd9ccf2010-07-07 13:19:55 +02001501 && i < sizeof(openwith) / sizeof(openwith[0]); i++)
Bram Moolenaarcc448b32010-07-14 16:52:17 +02001502 {
Bram Moolenaar6199d432017-10-14 19:05:44 +02001503 lRet = reg_create_key_and_value(hRootKey, openwith[i], NULL, "", flag);
Bram Moolenaarcc448b32010-07-14 16:52:17 +02001504 }
Bram Moolenaarccd9ccf2010-07-07 13:19:55 +02001505 }
1506
1507 return lRet;
1508}
1509
1510 static LONG
1511register_uninstall(
1512 HKEY hRootKey,
1513 const char *appname,
1514 const char *display_name,
Bram Moolenaar6cdb2c92018-10-13 17:25:27 +02001515 const char *uninstall_string,
1516 const char *display_icon,
1517 const char *display_version,
1518 const char *publisher)
Bram Moolenaarccd9ccf2010-07-07 13:19:55 +02001519{
1520 LONG lRet = reg_create_key_and_value(hRootKey, appname,
Bram Moolenaar6199d432017-10-14 19:05:44 +02001521 "DisplayName", display_name, KEY_WOW64_64KEY);
Bram Moolenaarccd9ccf2010-07-07 13:19:55 +02001522
1523 if (ERROR_SUCCESS == lRet)
Bram Moolenaarcc448b32010-07-14 16:52:17 +02001524 lRet = reg_create_key_and_value(hRootKey, appname,
Bram Moolenaar6199d432017-10-14 19:05:44 +02001525 "UninstallString", uninstall_string, KEY_WOW64_64KEY);
Bram Moolenaar6cdb2c92018-10-13 17:25:27 +02001526 if (ERROR_SUCCESS == lRet)
1527 lRet = reg_create_key_and_value(hRootKey, appname,
1528 "DisplayIcon", display_icon, KEY_WOW64_64KEY);
1529 if (ERROR_SUCCESS == lRet)
1530 lRet = reg_create_key_and_value(hRootKey, appname,
1531 "DisplayVersion", display_version, KEY_WOW64_64KEY);
1532 if (ERROR_SUCCESS == lRet)
1533 lRet = reg_create_key_and_value(hRootKey, appname,
1534 "Publisher", publisher, KEY_WOW64_64KEY);
Bram Moolenaarccd9ccf2010-07-07 13:19:55 +02001535 return lRet;
1536}
Bram Moolenaarccd9ccf2010-07-07 13:19:55 +02001537
Bram Moolenaar071d4272004-06-13 20:20:40 +00001538/*
1539 * Add some entries to the registry:
1540 * - to add "Edit with Vim" to the context * menu
1541 * - to add Vim to the "Open with..." list
1542 * - to uninstall Vim
1543 */
1544/*ARGSUSED*/
Bram Moolenaarab8205e2010-07-07 15:14:03 +02001545 static int
Bram Moolenaar071d4272004-06-13 20:20:40 +00001546install_registry(void)
1547{
Bram Moolenaarcc448b32010-07-14 16:52:17 +02001548 LONG lRet = ERROR_SUCCESS;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001549 const char *vim_ext_ThreadingModel = "Apartment";
1550 const char *vim_ext_name = "Vim Shell Extension";
1551 const char *vim_ext_clsid = "{51EEE242-AD87-11d3-9C1E-0090278BBD99}";
Bram Moolenaarccd9ccf2010-07-07 13:19:55 +02001552 char vim_exe_path[BUFSIZE];
Bram Moolenaarcc448b32010-07-14 16:52:17 +02001553 char display_name[BUFSIZE];
1554 char uninstall_string[BUFSIZE];
Bram Moolenaar6cdb2c92018-10-13 17:25:27 +02001555 char icon_string[BUFSIZE];
Bram Moolenaar6199d432017-10-14 19:05:44 +02001556 int i;
1557 int loop_count = is_64bit_os() ? 2 : 1;
1558 DWORD flag;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001559
Bram Moolenaarccd9ccf2010-07-07 13:19:55 +02001560 sprintf(vim_exe_path, "%s\\gvim.exe", installdir);
1561
1562 if (install_popup)
1563 {
Bram Moolenaarcc448b32010-07-14 16:52:17 +02001564 char bufg[BUFSIZE];
Bram Moolenaarccd9ccf2010-07-07 13:19:55 +02001565
Bram Moolenaarcc448b32010-07-14 16:52:17 +02001566 printf("Creating \"Edit with Vim\" popup menu entry\n");
Bram Moolenaarccd9ccf2010-07-07 13:19:55 +02001567
Bram Moolenaar6199d432017-10-14 19:05:44 +02001568 for (i = 0; i < loop_count; i++)
1569 {
1570 if (i == 0)
1571 {
1572 sprintf(bufg, "%s\\" GVIMEXT32_PATH, installdir);
1573 flag = KEY_WOW64_32KEY;
1574 }
1575 else
1576 {
1577 sprintf(bufg, "%s\\" GVIMEXT64_PATH, installdir);
1578 flag = KEY_WOW64_64KEY;
1579 }
1580
1581 lRet = register_inproc_server(
1582 HKEY_CLASSES_ROOT, vim_ext_clsid, vim_ext_name,
1583 bufg, vim_ext_ThreadingModel, flag);
1584 if (ERROR_SUCCESS != lRet)
1585 return FAIL;
1586 lRet = register_shellex(
1587 HKEY_CLASSES_ROOT, vim_ext_clsid, vim_ext_name,
1588 vim_exe_path, flag);
1589 if (ERROR_SUCCESS != lRet)
1590 return FAIL;
1591 }
Bram Moolenaarccd9ccf2010-07-07 13:19:55 +02001592 }
1593
1594 if (install_openwith)
1595 {
Bram Moolenaarcc448b32010-07-14 16:52:17 +02001596 printf("Creating \"Open with ...\" list entry\n");
Bram Moolenaarccd9ccf2010-07-07 13:19:55 +02001597
Bram Moolenaar6199d432017-10-14 19:05:44 +02001598 for (i = 0; i < loop_count; i++)
1599 {
1600 if (i == 0)
1601 flag = KEY_WOW64_32KEY;
1602 else
1603 flag = KEY_WOW64_64KEY;
1604
1605 lRet = register_openwith(HKEY_CLASSES_ROOT, vim_exe_path, flag);
1606 if (ERROR_SUCCESS != lRet)
1607 return FAIL;
1608 }
Bram Moolenaarccd9ccf2010-07-07 13:19:55 +02001609 }
1610
1611 printf("Creating an uninstall entry\n");
Bram Moolenaar9bc1eac2018-08-18 19:04:37 +02001612 sprintf(display_name, "Vim " VIM_VERSION_SHORT);
Bram Moolenaarccd9ccf2010-07-07 13:19:55 +02001613
1614 /* For the NSIS installer use the generated uninstaller. */
1615 if (interactive)
Bram Moolenaar16d79a32010-07-18 22:33:56 +02001616 sprintf(uninstall_string, "%s\\uninstal.exe", installdir);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001617 else
Bram Moolenaar16d79a32010-07-18 22:33:56 +02001618 sprintf(uninstall_string, "%s\\uninstall-gui.exe", installdir);
Bram Moolenaarccd9ccf2010-07-07 13:19:55 +02001619
Bram Moolenaar6cdb2c92018-10-13 17:25:27 +02001620 sprintf(icon_string, "%s\\gvim.exe,0", installdir);
1621
Bram Moolenaarccd9ccf2010-07-07 13:19:55 +02001622 lRet = register_uninstall(
Bram Moolenaarcc448b32010-07-14 16:52:17 +02001623 HKEY_LOCAL_MACHINE,
1624 "Software\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\Vim " VIM_VERSION_SHORT,
1625 display_name,
Bram Moolenaar6cdb2c92018-10-13 17:25:27 +02001626 uninstall_string,
1627 icon_string,
1628 VIM_VERSION_SHORT,
1629 "Bram Moolenaar et al.");
Bram Moolenaarab8205e2010-07-07 15:14:03 +02001630 if (ERROR_SUCCESS != lRet)
1631 return FAIL;
Bram Moolenaarccd9ccf2010-07-07 13:19:55 +02001632
Bram Moolenaarab8205e2010-07-07 15:14:03 +02001633 return OK;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001634}
1635
1636 static void
1637change_popup_choice(int idx)
1638{
1639 if (install_popup == 0)
1640 {
1641 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";
1642 install_popup = 1;
1643 }
1644 else
1645 {
1646 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";
1647 install_popup = 0;
1648 }
1649}
1650
1651/*
1652 * Only add the choice for the popup menu entry when gvim.exe was found and
1653 * both gvimext.dll and regedit.exe exist.
1654 */
1655 static void
1656init_popup_choice(void)
1657{
1658 struct stat st;
1659
1660 if (has_gvim
Bram Moolenaar6199d432017-10-14 19:05:44 +02001661 && (stat(GVIMEXT32_PATH, &st) >= 0
1662 || stat(GVIMEXT64_PATH, &st) >= 0))
Bram Moolenaar071d4272004-06-13 20:20:40 +00001663 {
1664 choices[choice_count].changefunc = change_popup_choice;
1665 choices[choice_count].installfunc = NULL;
1666 choices[choice_count].active = 1;
1667 change_popup_choice(choice_count); /* set the text */
1668 ++choice_count;
1669 }
1670 else
1671 add_dummy_choice();
1672}
1673
1674 static void
1675change_openwith_choice(int idx)
1676{
1677 if (install_openwith == 0)
1678 {
1679 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";
1680 install_openwith = 1;
1681 }
1682 else
1683 {
1684 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";
1685 install_openwith = 0;
1686 }
1687}
1688
1689/*
1690 * Only add the choice for the open-with menu entry when gvim.exe was found
Bram Moolenaar84a05ac2013-05-06 04:24:17 +02001691 * and regedit.exe exist.
Bram Moolenaar071d4272004-06-13 20:20:40 +00001692 */
1693 static void
1694init_openwith_choice(void)
1695{
Bram Moolenaar6199d432017-10-14 19:05:44 +02001696 if (has_gvim)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001697 {
1698 choices[choice_count].changefunc = change_openwith_choice;
1699 choices[choice_count].installfunc = NULL;
1700 choices[choice_count].active = 1;
1701 change_openwith_choice(choice_count); /* set the text */
1702 ++choice_count;
1703 }
1704 else
1705 add_dummy_choice();
1706}
1707
Bram Moolenaar071d4272004-06-13 20:20:40 +00001708/* create_shortcut
1709 *
1710 * Create a shell link.
1711 *
1712 * returns 0 on failure, non-zero on successful completion.
1713 *
1714 * NOTE: Currently untested with mingw.
1715 */
1716 int
1717create_shortcut(
1718 const char *shortcut_name,
1719 const char *iconfile_path,
1720 int iconindex,
1721 const char *shortcut_target,
1722 const char *shortcut_args,
1723 const char *workingdir
1724 )
1725{
1726 IShellLink *shelllink_ptr;
1727 HRESULT hres;
1728 IPersistFile *persistfile_ptr;
1729
1730 /* Initialize COM library */
1731 hres = CoInitialize(NULL);
1732 if (!SUCCEEDED(hres))
1733 {
1734 printf("Error: Could not open the COM library. Not creating shortcut.\n");
1735 return FAIL;
1736 }
1737
1738 /* Instantiate a COM object for the ShellLink, store a pointer to it
1739 * in shelllink_ptr. */
1740 hres = CoCreateInstance(&CLSID_ShellLink,
1741 NULL,
1742 CLSCTX_INPROC_SERVER,
1743 &IID_IShellLink,
1744 (void **) &shelllink_ptr);
1745
1746 if (SUCCEEDED(hres)) /* If the instantiation was successful... */
1747 {
1748 /* ...Then build a PersistFile interface for the ShellLink so we can
1749 * save it as a file after we build it. */
1750 hres = shelllink_ptr->lpVtbl->QueryInterface(shelllink_ptr,
1751 &IID_IPersistFile, (void **) &persistfile_ptr);
1752
1753 if (SUCCEEDED(hres))
1754 {
1755 wchar_t wsz[BUFSIZE];
1756
1757 /* translate the (possibly) multibyte shortcut filename to windows
1758 * Unicode so it can be used as a file name.
1759 */
1760 MultiByteToWideChar(CP_ACP, 0, shortcut_name, -1, wsz, BUFSIZE);
1761
1762 /* set the attributes */
1763 shelllink_ptr->lpVtbl->SetPath(shelllink_ptr, shortcut_target);
1764 shelllink_ptr->lpVtbl->SetWorkingDirectory(shelllink_ptr,
1765 workingdir);
1766 shelllink_ptr->lpVtbl->SetIconLocation(shelllink_ptr,
1767 iconfile_path, iconindex);
1768 shelllink_ptr->lpVtbl->SetArguments(shelllink_ptr, shortcut_args);
1769
1770 /* save the shortcut to a file and return the PersistFile object*/
1771 persistfile_ptr->lpVtbl->Save(persistfile_ptr, wsz, 1);
1772 persistfile_ptr->lpVtbl->Release(persistfile_ptr);
1773 }
1774 else
1775 {
1776 printf("QueryInterface Error\n");
1777 return FAIL;
1778 }
1779
1780 /* Return the ShellLink object */
1781 shelllink_ptr->lpVtbl->Release(shelllink_ptr);
1782 }
1783 else
1784 {
1785 printf("CoCreateInstance Error - hres = %08x\n", (int)hres);
1786 return FAIL;
1787 }
1788
1789 return OK;
1790}
1791
1792/*
1793 * Build a path to where we will put a specified link.
1794 *
1795 * Return 0 on error, non-zero on success
1796 */
1797 int
1798build_link_name(
1799 char *link_path,
1800 const char *link_name,
1801 const char *shell_folder_name)
1802{
1803 char shell_folder_path[BUFSIZE];
1804
1805 if (get_shell_folder_path(shell_folder_path, shell_folder_name) == FAIL)
1806 {
1807 printf("An error occurred while attempting to find the path to %s.\n",
1808 shell_folder_name);
1809 return FAIL;
1810 }
1811
1812 /* Make sure the directory exists (create Start Menu\Programs\Vim).
1813 * Ignore errors if it already exists. */
1814 vim_mkdir(shell_folder_path, 0755);
1815
1816 /* build the path to the shortcut and the path to gvim.exe */
1817 sprintf(link_path, "%s\\%s.lnk", shell_folder_path, link_name);
1818
1819 return OK;
1820}
1821
1822 static int
1823build_shortcut(
1824 const char *name, /* Name of the shortcut */
1825 const char *exename, /* Name of the executable (e.g., vim.exe) */
1826 const char *args,
1827 const char *shell_folder,
1828 const char *workingdir)
1829{
1830 char executable_path[BUFSIZE];
1831 char link_name[BUFSIZE];
1832
1833 sprintf(executable_path, "%s\\%s", installdir, exename);
1834
1835 if (build_link_name(link_name, name, shell_folder) == FAIL)
1836 {
1837 printf("An error has occurred. A shortcut to %s will not be created %s.\n",
1838 name,
1839 *shell_folder == 'd' ? "on the desktop" : "in the Start menu");
1840 return FAIL;
1841 }
1842
1843 /* Create the shortcut: */
1844 return create_shortcut(link_name, executable_path, 0,
1845 executable_path, args, workingdir);
1846}
1847
1848/*
1849 * We used to use "homedir" as the working directory, but that is a bad choice
Bram Moolenaar03e228a2013-11-07 04:49:27 +01001850 * on multi-user systems. However, not specifying a directory results in the
1851 * current directory to be c:\Windows\system32 on Windows 7. Use environment
1852 * variables instead.
Bram Moolenaar071d4272004-06-13 20:20:40 +00001853 */
Bram Moolenaar03e228a2013-11-07 04:49:27 +01001854#define WORKDIR "%HOMEDRIVE%%HOMEPATH%"
Bram Moolenaar071d4272004-06-13 20:20:40 +00001855
1856/*
1857 * Create shortcut(s) in the Start Menu\Programs\Vim folder.
1858 */
1859 static void
1860install_start_menu(int idx)
1861{
1862 need_uninstall_entry = 1;
1863 printf("Creating start menu\n");
1864 if (has_vim)
1865 {
1866 if (build_shortcut("Vim", "vim.exe", "",
1867 VIM_STARTMENU, WORKDIR) == FAIL)
1868 return;
1869 if (build_shortcut("Vim Read-only", "vim.exe", "-R",
1870 VIM_STARTMENU, WORKDIR) == FAIL)
1871 return;
1872 if (build_shortcut("Vim Diff", "vim.exe", "-d",
1873 VIM_STARTMENU, WORKDIR) == FAIL)
1874 return;
1875 }
1876 if (has_gvim)
1877 {
1878 if (build_shortcut("gVim", "gvim.exe", "",
1879 VIM_STARTMENU, WORKDIR) == FAIL)
1880 return;
1881 if (build_shortcut("gVim Easy", "gvim.exe", "-y",
1882 VIM_STARTMENU, WORKDIR) == FAIL)
1883 return;
1884 if (build_shortcut("gVim Read-only", "gvim.exe", "-R",
1885 VIM_STARTMENU, WORKDIR) == FAIL)
1886 return;
1887 if (build_shortcut("gVim Diff", "gvim.exe", "-d",
1888 VIM_STARTMENU, WORKDIR) == FAIL)
1889 return;
1890 }
1891 if (build_shortcut("Uninstall",
1892 interactive ? "uninstal.exe" : "uninstall-gui.exe", "",
1893 VIM_STARTMENU, installdir) == FAIL)
1894 return;
1895 /* For Windows NT the working dir of the vimtutor.bat must be right,
1896 * otherwise gvim.exe won't be found and using gvimbat doesn't work. */
1897 if (build_shortcut("Vim tutor", "vimtutor.bat", "",
1898 VIM_STARTMENU, installdir) == FAIL)
1899 return;
1900 if (build_shortcut("Help", has_gvim ? "gvim.exe" : "vim.exe", "-c h",
1901 VIM_STARTMENU, WORKDIR) == FAIL)
1902 return;
1903 {
1904 char shell_folder_path[BUFSIZE];
1905
1906 /* Creating the URL shortcut works a bit differently... */
1907 if (get_shell_folder_path(shell_folder_path, VIM_STARTMENU) == FAIL)
1908 {
1909 printf("Finding the path of the Start menu failed\n");
1910 return ;
1911 }
1912 add_pathsep(shell_folder_path);
1913 strcat(shell_folder_path, "Vim Online.url");
1914 if (!WritePrivateProfileString("InternetShortcut", "URL",
Bram Moolenaarbd87eb32018-06-26 23:18:45 +02001915 "https://www.vim.org/", shell_folder_path))
Bram Moolenaar071d4272004-06-13 20:20:40 +00001916 {
1917 printf("Creating the Vim online URL failed\n");
1918 return;
1919 }
1920 }
1921}
1922
1923 static void
1924toggle_startmenu_choice(int idx)
1925{
1926 if (choices[idx].installfunc == NULL)
1927 {
1928 choices[idx].installfunc = install_start_menu;
1929 choices[idx].text = "Add Vim to the Start menu";
1930 }
1931 else
1932 {
1933 choices[idx].installfunc = NULL;
1934 choices[idx].text = "Do NOT add Vim to the Start menu";
1935 }
1936}
1937
1938/*
1939 * Function to actually create the shortcuts
1940 *
1941 * Currently I am supplying no working directory to the shortcut. This
1942 * means that the initial working dir will be:
1943 * - the location of the shortcut if no file is supplied
1944 * - the location of the file being edited if a file is supplied (ie via
1945 * drag and drop onto the shortcut).
1946 */
1947 void
1948install_shortcut_gvim(int idx)
1949{
1950 /* Create shortcut(s) on the desktop */
1951 if (choices[idx].arg)
1952 {
1953 (void)build_shortcut(icon_names[0], "gvim.exe",
1954 "", "desktop", WORKDIR);
1955 need_uninstall_entry = 1;
1956 }
1957}
1958
1959 void
1960install_shortcut_evim(int idx)
1961{
1962 if (choices[idx].arg)
1963 {
1964 (void)build_shortcut(icon_names[1], "gvim.exe",
1965 "-y", "desktop", WORKDIR);
1966 need_uninstall_entry = 1;
1967 }
1968}
1969
1970 void
1971install_shortcut_gview(int idx)
1972{
1973 if (choices[idx].arg)
1974 {
1975 (void)build_shortcut(icon_names[2], "gvim.exe",
1976 "-R", "desktop", WORKDIR);
1977 need_uninstall_entry = 1;
1978 }
1979}
1980
1981 void
1982toggle_shortcut_choice(int idx)
1983{
1984 char *arg;
1985
1986 if (choices[idx].installfunc == install_shortcut_gvim)
1987 arg = "gVim";
1988 else if (choices[idx].installfunc == install_shortcut_evim)
1989 arg = "gVim Easy";
1990 else
1991 arg = "gVim Read-only";
1992 if (choices[idx].arg)
1993 {
1994 choices[idx].arg = 0;
1995 alloc_text(idx, "Do NOT create a desktop icon for %s", arg);
1996 }
1997 else
1998 {
1999 choices[idx].arg = 1;
2000 alloc_text(idx, "Create a desktop icon for %s", arg);
2001 }
2002}
Bram Moolenaar071d4272004-06-13 20:20:40 +00002003
2004 static void
2005init_startmenu_choice(void)
2006{
Bram Moolenaar071d4272004-06-13 20:20:40 +00002007 /* Start menu */
2008 choices[choice_count].changefunc = toggle_startmenu_choice;
2009 choices[choice_count].installfunc = NULL;
2010 choices[choice_count].active = 1;
2011 toggle_startmenu_choice(choice_count); /* set the text */
2012 ++choice_count;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002013}
2014
2015/*
2016 * Add the choice for the desktop shortcuts.
2017 */
2018 static void
2019init_shortcut_choices(void)
2020{
Bram Moolenaar071d4272004-06-13 20:20:40 +00002021 /* Shortcut to gvim */
2022 choices[choice_count].text = NULL;
2023 choices[choice_count].arg = 0;
2024 choices[choice_count].active = has_gvim;
2025 choices[choice_count].changefunc = toggle_shortcut_choice;
2026 choices[choice_count].installfunc = install_shortcut_gvim;
2027 toggle_shortcut_choice(choice_count);
2028 ++choice_count;
2029
2030 /* Shortcut to evim */
2031 choices[choice_count].text = NULL;
2032 choices[choice_count].arg = 0;
2033 choices[choice_count].active = has_gvim;
2034 choices[choice_count].changefunc = toggle_shortcut_choice;
2035 choices[choice_count].installfunc = install_shortcut_evim;
2036 toggle_shortcut_choice(choice_count);
2037 ++choice_count;
2038
2039 /* Shortcut to gview */
2040 choices[choice_count].text = NULL;
2041 choices[choice_count].arg = 0;
2042 choices[choice_count].active = has_gvim;
2043 choices[choice_count].changefunc = toggle_shortcut_choice;
2044 choices[choice_count].installfunc = install_shortcut_gview;
2045 toggle_shortcut_choice(choice_count);
2046 ++choice_count;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002047}
2048
Bram Moolenaar071d4272004-06-13 20:20:40 +00002049/*
2050 * Attempt to register OLE for Vim.
2051 */
2052 static void
2053install_OLE_register(void)
2054{
2055 char register_command_string[BUFSIZE + 30];
2056
2057 printf("\n--- Attempting to register Vim with OLE ---\n");
2058 printf("(There is no message whether this works or not.)\n");
2059
Bram Moolenaar071d4272004-06-13 20:20:40 +00002060 sprintf(register_command_string, "\"%s\\gvim.exe\" -silent -register", installdir);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002061 system(register_command_string);
2062}
Bram Moolenaar071d4272004-06-13 20:20:40 +00002063
2064/*
2065 * Remove the last part of directory "path[]" to get its parent, and put the
2066 * result in "to[]".
2067 */
2068 static void
2069dir_remove_last(const char *path, char to[BUFSIZE])
2070{
2071 char c;
2072 long last_char_to_copy;
2073 long path_length = strlen(path);
2074
2075 /* skip the last character just in case it is a '\\' */
2076 last_char_to_copy = path_length - 2;
2077 c = path[last_char_to_copy];
2078
2079 while (c != '\\')
2080 {
2081 last_char_to_copy--;
2082 c = path[last_char_to_copy];
2083 }
2084
2085 strncpy(to, path, (size_t)last_char_to_copy);
2086 to[last_char_to_copy] = NUL;
2087}
2088
2089 static void
2090set_directories_text(int idx)
2091{
Bram Moolenaar25a494c2018-11-16 19:39:50 +01002092 int vimfiles_dir_choice = choices[idx].arg;
2093
Bram Moolenaar071d4272004-06-13 20:20:40 +00002094 if (vimfiles_dir_choice == (int)vimfiles_dir_none)
2095 alloc_text(idx, "Do NOT create plugin directories%s", "");
2096 else
2097 alloc_text(idx, "Create plugin directories: %s",
2098 vimfiles_dir_choices[vimfiles_dir_choice]);
2099}
2100
2101/*
Bram Moolenaar25a494c2018-11-16 19:39:50 +01002102 * To get the "real" home directory:
2103 * - get value of $HOME
2104 * - if not found, get value of $HOMEDRIVE$HOMEPATH
2105 * - if not found, get value of $USERPROFILE
2106 *
2107 * This code is based on init_homedir() in misc1.c, keep in sync!
2108 */
2109static char *homedir = NULL;
2110
2111 void
2112init_homedir(void)
2113{
2114 char *var;
2115 char buf[MAX_PATH];
2116
2117 if (homedir != NULL)
2118 {
2119 free(homedir);
2120 homedir = NULL;
2121 }
2122
2123 var = getenv("HOME");
2124
2125 /*
2126 * Typically, $HOME is not defined on Windows, unless the user has
2127 * specifically defined it for Vim's sake. However, on Windows NT
2128 * platforms, $HOMEDRIVE and $HOMEPATH are automatically defined for
2129 * each user. Try constructing $HOME from these.
2130 */
2131 if (var == NULL || *var == NUL)
2132 {
2133 char *homedrive, *homepath;
2134
2135 homedrive = getenv("HOMEDRIVE");
2136 homepath = getenv("HOMEPATH");
2137 if (homepath == NULL || *homepath == NUL)
2138 homepath = "\\";
2139 if (homedrive != NULL
2140 && strlen(homedrive) + strlen(homepath) < MAX_PATH)
2141 {
2142 sprintf(buf, "%s%s", homedrive, homepath);
2143 if (buf[0] != NUL)
2144 var = buf;
2145 }
2146 }
2147
2148 if (var == NULL)
2149 var = getenv("USERPROFILE");
2150
2151 /*
2152 * Weird but true: $HOME may contain an indirect reference to another
2153 * variable, esp. "%USERPROFILE%". Happens when $USERPROFILE isn't set
2154 * when $HOME is being set.
2155 */
2156 if (var != NULL && *var == '%')
2157 {
2158 char *p;
2159 char *exp;
2160
2161 p = strchr(var + 1, '%');
2162 if (p != NULL)
2163 {
2164 strncpy(buf, var + 1, p - (var + 1));
2165 buf[p - (var + 1)] = NUL;
2166 exp = getenv(buf);
2167 if (exp != NULL && *exp != NUL
2168 && strlen(exp) + strlen(p) < MAX_PATH)
2169 {
2170 _snprintf(buf, MAX_PATH, "%s%s", exp, p + 1);
2171 buf[MAX_PATH - 1] = NUL;
2172 var = buf;
2173 }
2174 }
2175 }
2176
2177 if (var != NULL && *var == NUL) // empty is same as not set
2178 var = NULL;
2179
2180 if (var == NULL)
2181 homedir = NULL;
2182 else
2183 homedir = _strdup(var);
2184}
2185
2186/*
Bram Moolenaar071d4272004-06-13 20:20:40 +00002187 * Change the directory that the vim plugin directories will be created in:
2188 * $HOME, $VIM or nowhere.
2189 */
2190 static void
2191change_directories_choice(int idx)
2192{
2193 int choice_count = TABLE_SIZE(vimfiles_dir_choices);
2194
2195 /* Don't offer the $HOME choice if $HOME isn't set. */
Bram Moolenaar25a494c2018-11-16 19:39:50 +01002196 if (homedir == NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002197 --choice_count;
Bram Moolenaar25a494c2018-11-16 19:39:50 +01002198 choices[idx].arg = get_choice(vimfiles_dir_choices, choice_count);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002199 set_directories_text(idx);
2200}
2201
2202/*
2203 * Create the plugin directories...
2204 */
2205/*ARGSUSED*/
2206 static void
2207install_vimfilesdir(int idx)
2208{
2209 int i;
Bram Moolenaar25a494c2018-11-16 19:39:50 +01002210 int vimfiles_dir_choice = choices[idx].arg;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002211 char *p;
2212 char vimdir_path[BUFSIZE];
2213 char vimfiles_path[BUFSIZE];
2214 char tmp_dirname[BUFSIZE];
2215
2216 /* switch on the location that the user wants the plugin directories
2217 * built in */
2218 switch (vimfiles_dir_choice)
2219 {
2220 case vimfiles_dir_vim:
2221 {
2222 /* Go to the %VIM% directory - check env first, then go one dir
2223 * below installdir if there is no %VIM% environment variable.
2224 * The accuracy of $VIM is checked in inspect_system(), so we
2225 * can be sure it is ok to use here. */
2226 p = getenv("VIM");
2227 if (p == NULL) /* No $VIM in path */
2228 dir_remove_last(installdir, vimdir_path);
2229 else
2230 strcpy(vimdir_path, p);
2231 break;
2232 }
2233 case vimfiles_dir_home:
2234 {
Bram Moolenaar25a494c2018-11-16 19:39:50 +01002235 // Find the $HOME directory. Its existence was already checked.
2236 p = homedir;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002237 if (p == NULL)
2238 {
2239 printf("Internal error: $HOME is NULL\n");
2240 p = "c:\\";
2241 }
2242 strcpy(vimdir_path, p);
2243 break;
2244 }
2245 case vimfiles_dir_none:
2246 {
Bram Moolenaar25a494c2018-11-16 19:39:50 +01002247 // Do not create vim plugin directory.
Bram Moolenaar071d4272004-06-13 20:20:40 +00002248 return;
2249 }
2250 }
2251
2252 /* Now, just create the directory. If it already exists, it will fail
2253 * silently. */
2254 sprintf(vimfiles_path, "%s\\vimfiles", vimdir_path);
2255 vim_mkdir(vimfiles_path, 0755);
2256
2257 printf("Creating the following directories in \"%s\":\n", vimfiles_path);
2258 for (i = 0; i < TABLE_SIZE(vimfiles_subdirs); i++)
2259 {
2260 sprintf(tmp_dirname, "%s\\%s", vimfiles_path, vimfiles_subdirs[i]);
2261 printf(" %s", vimfiles_subdirs[i]);
2262 vim_mkdir(tmp_dirname, 0755);
2263 }
2264 printf("\n");
2265}
2266
2267/*
2268 * Add the creation of runtime files to the setup sequence.
2269 */
2270 static void
2271init_directories_choice(void)
2272{
2273 struct stat st;
2274 char tmp_dirname[BUFSIZE];
2275 char *p;
Bram Moolenaar25a494c2018-11-16 19:39:50 +01002276 int vimfiles_dir_choice;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002277
2278 choices[choice_count].text = alloc(150);
2279 choices[choice_count].changefunc = change_directories_choice;
2280 choices[choice_count].installfunc = install_vimfilesdir;
2281 choices[choice_count].active = 1;
2282
Bram Moolenaar25a494c2018-11-16 19:39:50 +01002283 // Check if the "compiler" directory already exists. That's a good
2284 // indication that the plugin directories were already created.
Bram Moolenaar071d4272004-06-13 20:20:40 +00002285 if (getenv("HOME") != NULL)
2286 {
2287 vimfiles_dir_choice = (int)vimfiles_dir_home;
2288 sprintf(tmp_dirname, "%s\\vimfiles\\compiler", getenv("HOME"));
2289 if (stat(tmp_dirname, &st) == 0)
2290 vimfiles_dir_choice = (int)vimfiles_dir_none;
2291 }
2292 else
2293 {
2294 vimfiles_dir_choice = (int)vimfiles_dir_vim;
2295 p = getenv("VIM");
Bram Moolenaar25a494c2018-11-16 19:39:50 +01002296 if (p == NULL) // No $VIM in path, use the install dir.
Bram Moolenaar071d4272004-06-13 20:20:40 +00002297 dir_remove_last(installdir, tmp_dirname);
2298 else
2299 strcpy(tmp_dirname, p);
2300 strcat(tmp_dirname, "\\vimfiles\\compiler");
2301 if (stat(tmp_dirname, &st) == 0)
2302 vimfiles_dir_choice = (int)vimfiles_dir_none;
2303 }
2304
Bram Moolenaar25a494c2018-11-16 19:39:50 +01002305 choices[choice_count].arg = vimfiles_dir_choice;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002306 set_directories_text(choice_count);
2307 ++choice_count;
2308}
2309
2310/*
2311 * Setup the choices and the default values.
2312 */
2313 static void
2314setup_choices(void)
2315{
2316 /* install the batch files */
2317 init_bat_choices();
2318
2319 /* (over) write _vimrc file */
2320 init_vimrc_choices();
2321
2322 /* Whether to add Vim to the popup menu */
2323 init_popup_choice();
2324
2325 /* Whether to add Vim to the "Open With..." menu */
2326 init_openwith_choice();
2327
2328 /* Whether to add Vim to the Start Menu. */
2329 init_startmenu_choice();
2330
2331 /* Whether to add shortcuts to the Desktop. */
2332 init_shortcut_choices();
2333
2334 /* Whether to create the runtime directories. */
2335 init_directories_choice();
2336}
2337
2338 static void
2339print_cmd_line_help(void)
2340{
2341 printf("Vim installer non-interactive command line arguments:\n");
2342 printf("\n");
2343 printf("-create-batfiles [vim gvim evim view gview vimdiff gvimdiff]\n");
2344 printf(" Create .bat files for Vim variants in the Windows directory.\n");
2345 printf("-create-vimrc\n");
2346 printf(" Create a default _vimrc file if one does not already exist.\n");
Bram Moolenaarc3fdf7f2017-10-28 18:36:48 +02002347 printf("-vimrc-remap [no|win]\n");
2348 printf(" Remap keys when creating a default _vimrc file.\n");
2349 printf("-vimrc-behave [unix|mswin|default]\n");
2350 printf(" Set mouse behavior when creating a default _vimrc file.\n");
Bram Moolenaar6cdb2c92018-10-13 17:25:27 +02002351 printf("-vimrc-compat [vi|vim|defaults|all]\n");
2352 printf(" Set Vi compatibility when creating a default _vimrc file.\n");
Bram Moolenaar071d4272004-06-13 20:20:40 +00002353 printf("-install-popup\n");
2354 printf(" Install the Edit-with-Vim context menu entry\n");
2355 printf("-install-openwith\n");
2356 printf(" Add Vim to the \"Open With...\" context menu list\n");
Bram Moolenaar071d4272004-06-13 20:20:40 +00002357 printf("-add-start-menu");
2358 printf(" Add Vim to the start menu\n");
2359 printf("-install-icons");
2360 printf(" Create icons for gVim executables on the desktop\n");
Bram Moolenaar071d4272004-06-13 20:20:40 +00002361 printf("-create-directories [vim|home]\n");
2362 printf(" Create runtime directories to drop plugins into; in the $VIM\n");
2363 printf(" or $HOME directory\n");
Bram Moolenaar071d4272004-06-13 20:20:40 +00002364 printf("-register-OLE");
Bram Moolenaarce0842a2005-07-18 21:58:11 +00002365 printf(" Ignored\n");
Bram Moolenaar071d4272004-06-13 20:20:40 +00002366 printf("\n");
2367}
2368
2369/*
2370 * Setup installation choices based on command line switches
2371 */
2372 static void
2373command_line_setup_choices(int argc, char **argv)
2374{
2375 int i, j;
2376
2377 for (i = 1; i < argc; i++)
2378 {
2379 if (strcmp(argv[i], "-create-batfiles") == 0)
2380 {
2381 if (i + 1 == argc)
2382 continue;
2383 while (argv[i + 1][0] != '-' && i < argc)
2384 {
2385 i++;
2386 for (j = 1; j < TARGET_COUNT; ++j)
2387 if ((targets[j].exenamearg[0] == 'g' ? has_gvim : has_vim)
2388 && strcmp(argv[i], targets[j].name) == 0)
2389 {
2390 init_bat_choice(j);
2391 break;
2392 }
2393 if (j == TARGET_COUNT)
2394 printf("%s is not a valid choice for -create-batfiles\n",
2395 argv[i]);
2396
2397 if (i + 1 == argc)
2398 break;
2399 }
2400 }
2401 else if (strcmp(argv[i], "-create-vimrc") == 0)
2402 {
2403 /* Setup default vimrc choices. If there is already a _vimrc file,
2404 * it will NOT be overwritten.
2405 */
2406 init_vimrc_choices();
2407 }
Bram Moolenaarc3fdf7f2017-10-28 18:36:48 +02002408 else if (strcmp(argv[i], "-vimrc-remap") == 0)
2409 {
2410 if (i + 1 == argc)
2411 break;
2412 i++;
2413 if (strcmp(argv[i], "no") == 0)
2414 remap_choice = remap_no;
2415 else if (strcmp(argv[i], "win") == 0)
2416 remap_choice = remap_win;
2417 }
2418 else if (strcmp(argv[i], "-vimrc-behave") == 0)
2419 {
2420 if (i + 1 == argc)
2421 break;
2422 i++;
2423 if (strcmp(argv[i], "unix") == 0)
2424 mouse_choice = mouse_xterm;
2425 else if (strcmp(argv[i], "mswin") == 0)
2426 mouse_choice = mouse_mswin;
2427 else if (strcmp(argv[i], "default") == 0)
2428 mouse_choice = mouse_default;
2429 }
Bram Moolenaar6cdb2c92018-10-13 17:25:27 +02002430 else if (strcmp(argv[i], "-vimrc-compat") == 0)
2431 {
2432 if (i + 1 == argc)
2433 break;
2434 i++;
2435 if (strcmp(argv[i], "vi") == 0)
2436 compat_choice = compat_vi;
2437 else if (strcmp(argv[i], "vim") == 0)
2438 compat_choice = compat_vim;
2439 else if (strcmp(argv[i], "defaults") == 0)
2440 compat_choice = compat_some_enhancements;
2441 else if (strcmp(argv[i], "all") == 0)
2442 compat_choice = compat_all_enhancements;
2443 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00002444 else if (strcmp(argv[i], "-install-popup") == 0)
2445 {
2446 init_popup_choice();
2447 }
2448 else if (strcmp(argv[i], "-install-openwith") == 0)
2449 {
2450 init_openwith_choice();
2451 }
2452 else if (strcmp(argv[i], "-add-start-menu") == 0)
2453 {
2454 init_startmenu_choice();
2455 }
2456 else if (strcmp(argv[i], "-install-icons") == 0)
2457 {
2458 init_shortcut_choices();
2459 }
2460 else if (strcmp(argv[i], "-create-directories") == 0)
2461 {
Bram Moolenaar25a494c2018-11-16 19:39:50 +01002462 int vimfiles_dir_choice;
2463
Bram Moolenaar071d4272004-06-13 20:20:40 +00002464 init_directories_choice();
2465 if (argv[i + 1][0] != '-')
2466 {
2467 i++;
2468 if (strcmp(argv[i], "vim") == 0)
2469 vimfiles_dir_choice = (int)vimfiles_dir_vim;
2470 else if (strcmp(argv[i], "home") == 0)
2471 {
Bram Moolenaar25a494c2018-11-16 19:39:50 +01002472 if (homedir == NULL) // No $HOME in environment
2473 vimfiles_dir_choice = (int)vimfiles_dir_none;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002474 else
2475 vimfiles_dir_choice = (int)vimfiles_dir_home;
2476 }
2477 else
2478 {
2479 printf("Unknown argument for -create-directories: %s\n",
2480 argv[i]);
2481 print_cmd_line_help();
2482 }
2483 }
2484 else /* No choice specified, default to vim directory */
2485 vimfiles_dir_choice = (int)vimfiles_dir_vim;
Bram Moolenaar25a494c2018-11-16 19:39:50 +01002486 choices[choice_count - 1].arg = vimfiles_dir_choice;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002487 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00002488 else if (strcmp(argv[i], "-register-OLE") == 0)
2489 {
2490 /* This is always done when gvim is found */
2491 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00002492 else /* Unknown switch */
2493 {
2494 printf("Got unknown argument argv[%d] = %s\n", i, argv[i]);
2495 print_cmd_line_help();
2496 }
2497 }
2498}
2499
2500
2501/*
2502 * Show a few screens full of helpful information.
2503 */
2504 static void
2505show_help(void)
2506{
2507 static char *(items[]) =
2508 {
2509"Installing .bat files\n"
2510"---------------------\n"
2511"The vim.bat file is written in one of the directories in $PATH.\n"
2512"This makes it possible to start Vim from the command line.\n"
2513"If vim.exe can be found in $PATH, the choice for vim.bat will not be\n"
2514"present. It is assumed you will use the existing vim.exe.\n"
2515"If vim.bat can already be found in $PATH this is probably for an old\n"
2516"version of Vim (but this is not checked!). You can overwrite it.\n"
2517"If no vim.bat already exists, you can select one of the directories in\n"
2518"$PATH for creating the batch file, or disable creating a vim.bat file.\n"
2519"\n"
2520"If you choose not to create the vim.bat file, Vim can still be executed\n"
2521"in other ways, but not from the command line.\n"
2522"\n"
2523"The same applies to choices for gvim, evim, (g)view, and (g)vimdiff.\n"
2524"The first item can be used to change the path for all of them.\n"
2525,
2526"Creating a _vimrc file\n"
2527"----------------------\n"
2528"The _vimrc file is used to set options for how Vim behaves.\n"
2529"The install program can create a _vimrc file with a few basic choices.\n"
2530"You can edit this file later to tune your preferences.\n"
2531"If you already have a _vimrc or .vimrc file it can be overwritten.\n"
2532"Don't do that if you have made changes to it.\n"
2533,
2534"Vim features\n"
2535"------------\n"
2536"(this choice is only available when creating a _vimrc file)\n"
2537"1. Vim can run in Vi-compatible mode. Many nice Vim features are then\n"
2538" disabled. In the not-Vi-compatible mode Vim is still mostly Vi\n"
2539" compatible, but adds nice features like multi-level undo. Only\n"
2540" choose Vi-compatible if you really need full Vi compatibility.\n"
2541"2. Running Vim with some enhancements is useful when you want some of\n"
2542" the nice Vim features, but have a slow computer and want to keep it\n"
2543" really fast.\n"
2544"3. Syntax highlighting shows many files in color. Not only does this look\n"
2545" nice, it also makes it easier to spot errors and you can work faster.\n"
2546" The other features include editing compressed files.\n"
2547,
2548"Windows key mapping\n"
2549"-------------------\n"
2550"(this choice is only available when creating a _vimrc file)\n"
2551"Under MS-Windows the CTRL-C key copies text to the clipboard and CTRL-V\n"
2552"pastes text from the clipboard. There are a few more keys like these.\n"
2553"Unfortunately, in Vim these keys normally have another meaning.\n"
2554"1. Choose to have the keys like they normally are in Vim (useful if you\n"
2555" also use Vim on other systems).\n"
2556"2. Choose to have the keys work like they are used on MS-Windows (useful\n"
2557" if you mostly work on MS-Windows).\n"
2558,
2559"Mouse use\n"
2560"---------\n"
2561"(this choice is only available when creating a _vimrc file)\n"
2562"The right mouse button can be used in two ways:\n"
2563"1. The Unix way is to extend an existing selection. The popup menu is\n"
2564" not available.\n"
2565"2. The MS-Windows way is to show a popup menu, which allows you to\n"
2566" copy/paste text, undo/redo, etc. Extending the selection can still be\n"
2567" done by keeping SHIFT pressed while using the left mouse button\n"
2568,
2569"Edit-with-Vim context menu entry\n"
2570"--------------------------------\n"
2571"(this choice is only available when gvim.exe and gvimext.dll are present)\n"
2572"You can associate different file types with Vim, so that you can (double)\n"
2573"click on a file to edit it with Vim. This means you have to individually\n"
2574"select each file type.\n"
2575"An alternative is the option offered here: Install an \"Edit with Vim\"\n"
2576"entry in the popup menu for the right mouse button. This means you can\n"
2577"edit any file with Vim.\n"
2578,
2579"\"Open With...\" context menu entry\n"
2580"--------------------------------\n"
2581"(this choice is only available when gvim.exe is present)\n"
2582"This option adds Vim to the \"Open With...\" entry in the popup menu for\n"
2583"the right mouse button. This also makes it possible to edit HTML files\n"
2584"directly from Internet Explorer.\n"
2585,
2586"Add Vim to the Start menu\n"
2587"-------------------------\n"
2588"In Windows 95 and later, Vim can be added to the Start menu. This will\n"
2589"create a submenu with an entry for vim, gvim, evim, vimdiff, etc..\n"
2590,
2591"Icons on the desktop\n"
2592"--------------------\n"
2593"(these choices are only available when installing gvim)\n"
2594"In Windows 95 and later, shortcuts (icons) can be created on the Desktop.\n"
2595,
2596"Create plugin directories\n"
2597"-------------------------\n"
2598"Plugin directories allow extending Vim by dropping a file into a directory.\n"
2599"This choice allows creating them in $HOME (if you have a home directory) or\n"
2600"$VIM (used for everybody on the system).\n"
2601,
2602NULL
2603 };
2604 int i;
2605 int c;
2606
2607 rewind(stdin);
2608 printf("\n");
2609 for (i = 0; items[i] != NULL; ++i)
2610 {
Bram Moolenaarc3fdf7f2017-10-28 18:36:48 +02002611 puts(items[i]);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002612 printf("Hit Enter to continue, b (back) or q (quit help): ");
2613 c = getchar();
2614 rewind(stdin);
2615 if (c == 'b' || c == 'B')
2616 {
2617 if (i == 0)
2618 --i;
2619 else
2620 i -= 2;
2621 }
2622 if (c == 'q' || c == 'Q')
2623 break;
2624 printf("\n");
2625 }
2626}
2627
2628/*
2629 * Install the choices.
2630 */
2631 static void
2632install(void)
2633{
2634 int i;
2635
2636 /* Install the selected choices. */
2637 for (i = 0; i < choice_count; ++i)
2638 if (choices[i].installfunc != NULL && choices[i].active)
2639 (choices[i].installfunc)(i);
2640
2641 /* Add some entries to the registry, if needed. */
2642 if (install_popup
2643 || install_openwith
2644 || (need_uninstall_entry && interactive)
2645 || !interactive)
2646 install_registry();
2647
Bram Moolenaar071d4272004-06-13 20:20:40 +00002648 /* Register gvim with OLE. */
2649 if (has_gvim)
2650 install_OLE_register();
Bram Moolenaar071d4272004-06-13 20:20:40 +00002651}
2652
2653/*
2654 * request_choice
2655 */
2656 static void
2657request_choice(void)
2658{
2659 int i;
2660
2661 printf("\n\nInstall will do for you:\n");
2662 for (i = 0; i < choice_count; ++i)
2663 if (choices[i].active)
2664 printf("%2d %s\n", i + 1, choices[i].text);
2665 printf("To change an item, enter its number\n\n");
2666 printf("Enter item number, h (help), d (do it) or q (quit): ");
2667}
2668
2669 int
2670main(int argc, char **argv)
2671{
2672 int i;
2673 char buf[BUFSIZE];
2674
2675 /*
2676 * Run interactively if there are no command line arguments.
2677 */
2678 if (argc > 1)
2679 interactive = 0;
2680 else
2681 interactive = 1;
2682
2683 /* Initialize this program. */
2684 do_inits(argv);
Bram Moolenaar25a494c2018-11-16 19:39:50 +01002685 init_homedir();
Bram Moolenaar071d4272004-06-13 20:20:40 +00002686
Bram Moolenaar071d4272004-06-13 20:20:40 +00002687 if (argc > 1 && strcmp(argv[1], "-uninstall-check") == 0)
2688 {
2689 /* Only check for already installed Vims. Used by NSIS installer. */
Bram Moolenaar442b4222010-05-24 21:34:22 +02002690 i = uninstall_check(1);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002691
2692 /* Find the value of $VIM, because NSIS isn't able to do this by
2693 * itself. */
2694 get_vim_env();
2695
2696 /* When nothing found exit quietly. If something found wait for
Bram Moolenaarb230bd52010-05-25 21:02:00 +02002697 * a little while, so that the user can read the messages. */
Bram Moolenaar6cdb2c92018-10-13 17:25:27 +02002698 if (i && _isatty(1))
Bram Moolenaarab8205e2010-07-07 15:14:03 +02002699 sleep(3);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002700 exit(0);
2701 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00002702
2703 printf("This program sets up the installation of Vim "
2704 VIM_VERSION_MEDIUM "\n\n");
2705
2706 /* Check if the user unpacked the archives properly. */
2707 check_unpack();
2708
Bram Moolenaar071d4272004-06-13 20:20:40 +00002709 /* Check for already installed Vims. */
2710 if (interactive)
Bram Moolenaar442b4222010-05-24 21:34:22 +02002711 uninstall_check(0);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002712
2713 /* Find out information about the system. */
2714 inspect_system();
2715
2716 if (interactive)
2717 {
2718 /* Setup all the choices. */
2719 setup_choices();
2720
2721 /* Let the user change choices and finally install (or quit). */
2722 for (;;)
2723 {
2724 request_choice();
2725 rewind(stdin);
2726 if (scanf("%99s", buf) == 1)
2727 {
2728 if (isdigit(buf[0]))
2729 {
2730 /* Change a choice. */
2731 i = atoi(buf);
2732 if (i > 0 && i <= choice_count && choices[i - 1].active)
2733 (choices[i - 1].changefunc)(i - 1);
2734 else
2735 printf("\nIllegal choice\n");
2736 }
2737 else if (buf[0] == 'h' || buf[0] == 'H')
2738 {
2739 /* Help */
2740 show_help();
2741 }
2742 else if (buf[0] == 'd' || buf[0] == 'D')
2743 {
2744 /* Install! */
2745 install();
2746 printf("\nThat finishes the installation. Happy Vimming!\n");
2747 break;
2748 }
2749 else if (buf[0] == 'q' || buf[0] == 'Q')
2750 {
2751 /* Quit */
2752 printf("\nExiting without anything done\n");
2753 break;
2754 }
2755 else
2756 printf("\nIllegal choice\n");
2757 }
2758 }
2759 printf("\n");
Bram Moolenaar442b4222010-05-24 21:34:22 +02002760 myexit(0);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002761 }
2762 else
2763 {
2764 /*
2765 * Run non-interactive - setup according to the command line switches
2766 */
2767 command_line_setup_choices(argc, argv);
2768 install();
Bram Moolenaar442b4222010-05-24 21:34:22 +02002769
2770 /* Avoid that the user has to hit Enter, just wait a little bit to
2771 * allow reading the messages. */
Bram Moolenaarab8205e2010-07-07 15:14:03 +02002772 sleep(2);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002773 }
2774
Bram Moolenaar071d4272004-06-13 20:20:40 +00002775 return 0;
2776}