blob: b8c7ef82bac1bd0ad640fdb21f958189b0eac8a2 [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};
118static char *(vimfiles_dir_choices[]) =
119{
120 "\nCreate plugin directories:",
121 "No",
122 "In the VIM directory",
123 "In your HOME directory",
124};
125static int vimfiles_dir_choice;
126
127/* non-zero when selected to install the popup menu entry. */
128static int install_popup = 0;
129
130/* non-zero when selected to install the "Open with" entry. */
131static int install_openwith = 0;
132
133/* non-zero when need to add an uninstall entry in the registry */
134static int need_uninstall_entry = 0;
135
136/*
137 * Definitions of the directory name (under $VIM) of the vimfiles directory
138 * and its subdirectories:
139 */
140static char *(vimfiles_subdirs[]) =
141{
142 "colors",
143 "compiler",
144 "doc",
145 "ftdetect",
146 "ftplugin",
147 "indent",
148 "keymap",
149 "plugin",
150 "syntax",
151};
152
153/*
Bram Moolenaar071d4272004-06-13 20:20:40 +0000154 * Obtain a choice from a table.
155 * First entry is a question, others are choices.
156 */
157 static int
158get_choice(char **table, int entries)
159{
160 int answer;
161 int idx;
162 char dummy[100];
163
164 do
165 {
166 for (idx = 0; idx < entries; ++idx)
167 {
168 if (idx)
169 printf("%2d ", idx);
Bram Moolenaarc3fdf7f2017-10-28 18:36:48 +0200170 puts(table[idx]);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000171 }
172 printf("Choice: ");
173 if (scanf("%d", &answer) != 1)
174 {
175 scanf("%99s", dummy);
176 answer = 0;
177 }
178 }
179 while (answer < 1 || answer >= entries);
180
181 return answer;
182}
183
184/*
185 * Check if the user unpacked the archives properly.
186 * Sets "runtimeidx".
187 */
188 static void
189check_unpack(void)
190{
191 char buf[BUFSIZE];
192 FILE *fd;
193 struct stat st;
194
195 /* check for presence of the correct version number in installdir[] */
196 runtimeidx = strlen(installdir) - strlen(VIM_VERSION_NODOT);
197 if (runtimeidx <= 0
198 || stricmp(installdir + runtimeidx, VIM_VERSION_NODOT) != 0
199 || (installdir[runtimeidx - 1] != '/'
200 && installdir[runtimeidx - 1] != '\\'))
201 {
202 printf("ERROR: Install program not in directory \"%s\"\n",
203 VIM_VERSION_NODOT);
204 printf("This program can only work when it is located in its original directory\n");
205 myexit(1);
206 }
207
208 /* check if filetype.vim is present, which means the runtime archive has
209 * been unpacked */
210 sprintf(buf, "%s\\filetype.vim", installdir);
211 if (stat(buf, &st) < 0)
212 {
213 printf("ERROR: Cannot find filetype.vim in \"%s\"\n", installdir);
214 printf("It looks like you did not unpack the runtime archive.\n");
215 printf("You must unpack the runtime archive \"vim%srt.zip\" before installing.\n",
216 VIM_VERSION_NODOT + 3);
217 myexit(1);
218 }
219
220 /* Check if vim.exe or gvim.exe is in the current directory. */
221 if ((fd = fopen("gvim.exe", "r")) != NULL)
222 {
223 fclose(fd);
224 has_gvim = 1;
225 }
226 if ((fd = fopen("vim.exe", "r")) != NULL)
227 {
228 fclose(fd);
229 has_vim = 1;
230 }
231 if (!has_gvim && !has_vim)
232 {
233 printf("ERROR: Cannot find any Vim executables in \"%s\"\n\n",
234 installdir);
235 myexit(1);
236 }
237}
238
239/*
240 * Compare paths "p[plen]" to "q[qlen]". Return 0 if they match.
241 * Ignores case and differences between '/' and '\'.
242 * "plen" and "qlen" can be negative, strlen() is used then.
243 */
244 static int
245pathcmp(char *p, int plen, char *q, int qlen)
246{
247 int i;
248
249 if (plen < 0)
250 plen = strlen(p);
251 if (qlen < 0)
252 qlen = strlen(q);
253 for (i = 0; ; ++i)
254 {
255 /* End of "p": check if "q" also ends or just has a slash. */
256 if (i == plen)
257 {
258 if (i == qlen) /* match */
259 return 0;
260 if (i == qlen - 1 && (q[i] == '\\' || q[i] == '/'))
261 return 0; /* match with trailing slash */
262 return 1; /* no match */
263 }
264
265 /* End of "q": check if "p" also ends or just has a slash. */
266 if (i == qlen)
267 {
268 if (i == plen) /* match */
269 return 0;
270 if (i == plen - 1 && (p[i] == '\\' || p[i] == '/'))
271 return 0; /* match with trailing slash */
272 return 1; /* no match */
273 }
274
275 if (!(mytoupper(p[i]) == mytoupper(q[i])
276 || ((p[i] == '/' || p[i] == '\\')
277 && (q[i] == '/' || q[i] == '\\'))))
278 return 1; /* no match */
279 }
280 /*NOTREACHED*/
281}
282
283/*
284 * If the executable "**destination" is in the install directory, find another
285 * one in $PATH.
286 * On input "**destination" is the path of an executable in allocated memory
287 * (or NULL).
288 * "*destination" is set to NULL or the location of the file.
289 */
290 static void
291findoldfile(char **destination)
292{
293 char *bp = *destination;
294 size_t indir_l = strlen(installdir);
295 char *cp = bp + indir_l;
296 char *tmpname;
297 char *farname;
298
299 /*
300 * No action needed if exe not found or not in this directory.
301 */
302 if (bp == NULL
303 || strnicmp(bp, installdir, indir_l) != 0
304 || strchr("/\\", *cp++) == NULL
305 || strchr(cp, '\\') != NULL
306 || strchr(cp, '/') != NULL)
307 return;
308
309 tmpname = alloc((int)strlen(cp) + 1);
310 strcpy(tmpname, cp);
311 tmpname[strlen(tmpname) - 1] = 'x'; /* .exe -> .exx */
312
313 if (access(tmpname, 0) == 0)
314 {
315 printf("\nERROR: %s and %s clash. Remove or rename %s.\n",
316 tmpname, cp, tmpname);
317 myexit(1);
318 }
319
320 if (rename(cp, tmpname) != 0)
321 {
322 printf("\nERROR: failed to rename %s to %s: %s\n",
323 cp, tmpname, strerror(0));
324 myexit(1);
325 }
326
327 farname = searchpath_save(cp);
328
329 if (rename(tmpname, cp) != 0)
330 {
331 printf("\nERROR: failed to rename %s back to %s: %s\n",
332 tmpname, cp, strerror(0));
333 myexit(1);
334 }
335
336 free(*destination);
337 free(tmpname);
338 *destination = farname;
339}
340
341/*
342 * Check if there is a vim.[exe|bat|, gvim.[exe|bat|, etc. in the path.
343 * When "check_bat_only" is TRUE, only find "default_bat_dir".
344 */
345 static void
346find_bat_exe(int check_bat_only)
347{
348 int i;
349
Bram Moolenaar42bbef42006-03-25 22:02:07 +0000350 /* avoid looking in the "installdir" by chdir to system root */
351 mch_chdir(sysdrive);
352 mch_chdir("\\");
Bram Moolenaar071d4272004-06-13 20:20:40 +0000353
354 for (i = 1; i < TARGET_COUNT; ++i)
355 {
356 targets[i].oldbat = searchpath_save(targets[i].batname);
357 if (!check_bat_only)
358 targets[i].oldexe = searchpath_save(targets[i].exename);
359
360 if (default_bat_dir == NULL && targets[i].oldbat != NULL)
361 {
362 default_bat_dir = alloc(strlen(targets[i].oldbat) + 1);
363 strcpy(default_bat_dir, targets[i].oldbat);
364 remove_tail(default_bat_dir);
365 }
366 if (check_bat_only && targets[i].oldbat != NULL)
Bram Moolenaar42bbef42006-03-25 22:02:07 +0000367 {
Bram Moolenaar071d4272004-06-13 20:20:40 +0000368 free(targets[i].oldbat);
Bram Moolenaar42bbef42006-03-25 22:02:07 +0000369 targets[i].oldbat = NULL;
370 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000371 }
372
373 mch_chdir(installdir);
374}
375
Bram Moolenaar071d4272004-06-13 20:20:40 +0000376/*
377 * Get the value of $VIMRUNTIME or $VIM and write it in $TEMP/vimini.ini, so
378 * that NSIS can read it.
379 * When not set, use the directory of a previously installed Vim.
380 */
381 static void
382get_vim_env(void)
383{
384 char *vim;
385 char buf[BUFSIZE];
386 FILE *fd;
387 char fname[BUFSIZE];
388
389 /* First get $VIMRUNTIME. If it's set, remove the tail. */
390 vim = getenv("VIMRUNTIME");
Bram Moolenaar181ace22013-02-13 14:36:44 +0100391 if (vim != NULL && *vim != 0 && strlen(vim) < BUFSIZE)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000392 {
393 strcpy(buf, vim);
394 remove_tail(buf);
395 vim = buf;
396 }
397 else
398 {
399 vim = getenv("VIM");
400 if (vim == NULL || *vim == 0)
401 {
402 /* Use the directory from an old uninstall entry. */
403 if (default_vim_dir != NULL)
404 vim = default_vim_dir;
405 else
406 /* Let NSIS know there is no default, it should use
Bram Moolenaarb8017e72007-05-10 18:59:07 +0000407 * $PROGRAMFILES. */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000408 vim = "";
409 }
410 }
411
412 /* NSIS also uses GetTempPath(), thus we should get the same directory
413 * name as where NSIS will look for vimini.ini. */
414 GetTempPath(BUFSIZE, fname);
415 add_pathsep(fname);
416 strcat(fname, "vimini.ini");
417
418 fd = fopen(fname, "w");
419 if (fd != NULL)
420 {
421 /* Make it look like an .ini file, so that NSIS can read it with a
422 * ReadINIStr command. */
423 fprintf(fd, "[vimini]\n");
424 fprintf(fd, "dir=\"%s\"\n", vim);
425 fclose(fd);
426 }
427 else
428 {
429 printf("Failed to open %s\n", fname);
Bram Moolenaarab8205e2010-07-07 15:14:03 +0200430 sleep(2);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000431 }
432}
433
Bram Moolenaarb230bd52010-05-25 21:02:00 +0200434static int num_windows;
435
436/*
437 * Callback used for EnumWindows():
438 * Count the window if the title looks like it is for the uninstaller.
439 */
440/*ARGSUSED*/
441 static BOOL CALLBACK
442window_cb(HWND hwnd, LPARAM lparam)
443{
444 char title[256];
445
446 title[0] = 0;
447 GetWindowText(hwnd, title, 256);
448 if (strstr(title, "Vim ") != NULL && strstr(title, "Uninstall:") != NULL)
449 ++num_windows;
450 return TRUE;
451}
452
Bram Moolenaar071d4272004-06-13 20:20:40 +0000453/*
454 * Check for already installed Vims.
455 * Return non-zero when found one.
456 */
457 static int
Bram Moolenaar442b4222010-05-24 21:34:22 +0200458uninstall_check(int skip_question)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000459{
460 HKEY key_handle;
461 HKEY uninstall_key_handle;
462 char *uninstall_key = "software\\Microsoft\\Windows\\CurrentVersion\\Uninstall";
463 char subkey_name_buff[BUFSIZE];
464 char temp_string_buffer[BUFSIZE];
465 DWORD local_bufsize = BUFSIZE;
466 FILETIME temp_pfiletime;
467 DWORD key_index;
468 char input;
469 long code;
470 DWORD value_type;
471 DWORD orig_num_keys;
472 DWORD new_num_keys;
473 int foundone = 0;
474
Bram Moolenaar760d14a2010-07-31 22:03:44 +0200475 code = RegOpenKeyEx(HKEY_LOCAL_MACHINE, uninstall_key, 0,
476 KEY_WOW64_64KEY | KEY_READ, &key_handle);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000477 CHECK_REG_ERROR(code);
478
479 for (key_index = 0;
480 RegEnumKeyEx(key_handle, key_index, subkey_name_buff, &local_bufsize,
481 NULL, NULL, NULL, &temp_pfiletime) != ERROR_NO_MORE_ITEMS;
482 key_index++)
483 {
484 local_bufsize = BUFSIZE;
485 if (strncmp("Vim", subkey_name_buff, 3) == 0)
486 {
487 /* Open the key named Vim* */
Bram Moolenaar760d14a2010-07-31 22:03:44 +0200488 code = RegOpenKeyEx(key_handle, subkey_name_buff, 0,
489 KEY_WOW64_64KEY | KEY_READ, &uninstall_key_handle);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000490 CHECK_REG_ERROR(code);
491
492 /* get the DisplayName out of it to show the user */
493 code = RegQueryValueEx(uninstall_key_handle, "displayname", 0,
494 &value_type, (LPBYTE)temp_string_buffer,
495 &local_bufsize);
496 local_bufsize = BUFSIZE;
497 CHECK_REG_ERROR(code);
498
499 foundone = 1;
500 printf("\n*********************************************************\n");
501 printf("Vim Install found what looks like an existing Vim version.\n");
502 printf("The name of the entry is:\n");
503 printf("\n \"%s\"\n\n", temp_string_buffer);
504
505 printf("Installing the new version will disable part of the existing version.\n");
506 printf("(The batch files used in a console and the \"Edit with Vim\" entry in\n");
507 printf("the popup menu will use the new version)\n");
508
Bram Moolenaar442b4222010-05-24 21:34:22 +0200509 if (skip_question)
510 printf("\nRunning uninstall program for \"%s\"\n", temp_string_buffer);
511 else
512 printf("\nDo you want to uninstall \"%s\" now?\n(y)es/(n)o) ", temp_string_buffer);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000513 fflush(stdout);
514
515 /* get the UninstallString */
516 code = RegQueryValueEx(uninstall_key_handle, "uninstallstring", 0,
517 &value_type, (LPBYTE)temp_string_buffer, &local_bufsize);
518 local_bufsize = BUFSIZE;
519 CHECK_REG_ERROR(code);
520
521 /* Remember the directory, it is used as the default for NSIS. */
522 default_vim_dir = alloc(strlen(temp_string_buffer) + 1);
523 strcpy(default_vim_dir, temp_string_buffer);
524 remove_tail(default_vim_dir);
525 remove_tail(default_vim_dir);
526
527 input = 'n';
528 do
529 {
530 if (input != 'n')
531 printf("%c is an invalid reply. Please enter either 'y' or 'n'\n", input);
532
Bram Moolenaar442b4222010-05-24 21:34:22 +0200533 if (skip_question)
534 input = 'y';
535 else
536 {
537 rewind(stdin);
538 scanf("%c", &input);
539 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000540 switch (input)
541 {
542 case 'y':
543 case 'Y':
544 /* save the number of uninstall keys so we can know if
545 * it changed */
546 RegQueryInfoKey(key_handle, NULL, NULL, NULL,
547 &orig_num_keys, NULL, NULL, NULL,
548 NULL, NULL, NULL, NULL);
549
Bram Moolenaar442b4222010-05-24 21:34:22 +0200550 /* Find existing .bat files before deleting them. */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000551 find_bat_exe(TRUE);
552
553 /* Execute the uninstall program. Put it in double
554 * quotes if there is an embedded space. */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000555 {
556 char buf[BUFSIZE];
557
Bram Moolenaarb230bd52010-05-25 21:02:00 +0200558 if (strchr(temp_string_buffer, ' ') != NULL)
559 sprintf(buf, "\"%s\"", temp_string_buffer);
560 else
561 strcpy(buf, temp_string_buffer);
562 run_command(buf);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000563 }
Bram Moolenaarb230bd52010-05-25 21:02:00 +0200564
565 /* Count the number of windows with a title that match
566 * the installer, so that we can check when it's done.
567 * The uninstaller copies itself, executes the copy
568 * and exits, thus we can't wait for the process to
569 * finish. */
Bram Moolenaarab8205e2010-07-07 15:14:03 +0200570 sleep(1); /* wait for uninstaller to start up */
Bram Moolenaarb230bd52010-05-25 21:02:00 +0200571 num_windows = 0;
572 EnumWindows(window_cb, 0);
Bram Moolenaarb230bd52010-05-25 21:02:00 +0200573 if (num_windows == 0)
574 {
575 /* Did not find the uninstaller, ask user to press
576 * Enter when done. Just in case. */
577 printf("Press Enter when the uninstaller is finished\n");
578 rewind(stdin);
579 (void)getchar();
580 }
581 else
582 {
583 printf("Waiting for the uninstaller to finish (press CTRL-C to abort).");
584 do
585 {
586 printf(".");
587 fflush(stdout);
Bram Moolenaar6cdb2c92018-10-13 17:25:27 +0200588 sleep(1); /* wait for the uninstaller to finish */
Bram Moolenaarb230bd52010-05-25 21:02:00 +0200589 num_windows = 0;
590 EnumWindows(window_cb, 0);
Bram Moolenaarb230bd52010-05-25 21:02:00 +0200591 } while (num_windows > 0);
592 }
593 printf("\nDone!\n");
Bram Moolenaar071d4272004-06-13 20:20:40 +0000594
Bram Moolenaarfff2bee2010-05-15 13:56:02 +0200595 /* Check if an uninstall reg key was deleted.
Bram Moolenaar071d4272004-06-13 20:20:40 +0000596 * if it was, we want to decrement key_index.
597 * if we don't do this, we will skip the key
598 * immediately after any key that we delete. */
599 RegQueryInfoKey(key_handle, NULL, NULL, NULL,
600 &new_num_keys, NULL, NULL, NULL,
601 NULL, NULL, NULL, NULL);
602 if (new_num_keys < orig_num_keys)
603 key_index--;
604
605 input = 'y';
606 break;
607
608 case 'n':
609 case 'N':
610 /* Do not uninstall */
611 input = 'n';
612 break;
613
614 default: /* just drop through and redo the loop */
615 break;
616 }
617
618 } while (input != 'n' && input != 'y');
619
620 RegCloseKey(uninstall_key_handle);
621 }
622 }
623 RegCloseKey(key_handle);
624
625 return foundone;
626}
Bram Moolenaar071d4272004-06-13 20:20:40 +0000627
628/*
629 * Find out information about the system.
630 */
631 static void
632inspect_system(void)
633{
634 char *p;
635 char buf[BUFSIZE];
636 FILE *fd;
637 int i;
638 int foundone;
639
640 /* This may take a little while, let the user know what we're doing. */
641 printf("Inspecting system...\n");
642
643 /*
644 * If $VIM is set, check that it's pointing to our directory.
645 */
646 p = getenv("VIM");
647 if (p != NULL && pathcmp(p, -1, installdir, runtimeidx - 1) != 0)
648 {
649 printf("------------------------------------------------------\n");
650 printf("$VIM is set to \"%s\".\n", p);
651 printf("This is different from where this version of Vim is:\n");
652 strcpy(buf, installdir);
653 *(buf + runtimeidx - 1) = NUL;
654 printf("\"%s\"\n", buf);
655 printf("You must adjust or remove the setting of $VIM,\n");
656 if (interactive)
657 {
658 printf("to be able to use this install program.\n");
659 myexit(1);
660 }
661 printf("otherwise Vim WILL NOT WORK properly!\n");
662 printf("------------------------------------------------------\n");
663 }
664
665 /*
666 * If $VIMRUNTIME is set, check that it's pointing to our runtime directory.
667 */
668 p = getenv("VIMRUNTIME");
669 if (p != NULL && pathcmp(p, -1, installdir, -1) != 0)
670 {
671 printf("------------------------------------------------------\n");
672 printf("$VIMRUNTIME is set to \"%s\".\n", p);
673 printf("This is different from where this version of Vim is:\n");
674 printf("\"%s\"\n", installdir);
675 printf("You must adjust or remove the setting of $VIMRUNTIME,\n");
676 if (interactive)
677 {
678 printf("to be able to use this install program.\n");
679 myexit(1);
680 }
681 printf("otherwise Vim WILL NOT WORK properly!\n");
682 printf("------------------------------------------------------\n");
683 }
684
685 /*
686 * Check if there is a vim.[exe|bat|, gvim.[exe|bat|, etc. in the path.
687 */
688 find_bat_exe(FALSE);
689
690 /*
691 * A .exe in the install directory may be found anyway on Windows 2000.
692 * Check for this situation and find another executable if necessary.
693 * w.briscoe@ponl.com 2001-01-20
694 */
695 foundone = 0;
696 for (i = 1; i < TARGET_COUNT; ++i)
697 {
698 findoldfile(&(targets[i].oldexe));
699 if (targets[i].oldexe != NULL)
700 foundone = 1;
701 }
702
703 if (foundone)
704 {
705 printf("Warning: Found Vim executable(s) in your $PATH:\n");
706 for (i = 1; i < TARGET_COUNT; ++i)
707 if (targets[i].oldexe != NULL)
708 printf("%s\n", targets[i].oldexe);
709 printf("It will be used instead of the version you are installing.\n");
710 printf("Please delete or rename it, or adjust your $PATH setting.\n");
711 }
712
713 /*
714 * Check if there is an existing ../_vimrc or ../.vimrc file.
715 */
716 strcpy(oldvimrc, installdir);
717 strcpy(oldvimrc + runtimeidx, "_vimrc");
718 if ((fd = fopen(oldvimrc, "r")) == NULL)
719 {
720 strcpy(oldvimrc + runtimeidx, "vimrc~1"); /* short version of .vimrc */
721 if ((fd = fopen(oldvimrc, "r")) == NULL)
722 {
723 strcpy(oldvimrc + runtimeidx, ".vimrc");
724 fd = fopen(oldvimrc, "r");
725 }
726 }
727 if (fd != NULL)
728 fclose(fd);
729 else
730 *oldvimrc = NUL;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000731}
732
733/*
734 * Add a dummy choice to avoid that the numbering changes depending on items
735 * in the environment. The user may type a number he remembered without
736 * looking.
737 */
738 static void
739add_dummy_choice(void)
740{
741 choices[choice_count].installfunc = NULL;
742 choices[choice_count].active = 0;
743 choices[choice_count].changefunc = NULL;
744 choices[choice_count].installfunc = NULL;
745 ++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{
2092 if (vimfiles_dir_choice == (int)vimfiles_dir_none)
2093 alloc_text(idx, "Do NOT create plugin directories%s", "");
2094 else
2095 alloc_text(idx, "Create plugin directories: %s",
2096 vimfiles_dir_choices[vimfiles_dir_choice]);
2097}
2098
2099/*
2100 * Change the directory that the vim plugin directories will be created in:
2101 * $HOME, $VIM or nowhere.
2102 */
2103 static void
2104change_directories_choice(int idx)
2105{
2106 int choice_count = TABLE_SIZE(vimfiles_dir_choices);
2107
2108 /* Don't offer the $HOME choice if $HOME isn't set. */
2109 if (getenv("HOME") == NULL)
2110 --choice_count;
2111 vimfiles_dir_choice = get_choice(vimfiles_dir_choices, choice_count);
2112 set_directories_text(idx);
2113}
2114
2115/*
2116 * Create the plugin directories...
2117 */
2118/*ARGSUSED*/
2119 static void
2120install_vimfilesdir(int idx)
2121{
2122 int i;
2123 char *p;
2124 char vimdir_path[BUFSIZE];
2125 char vimfiles_path[BUFSIZE];
2126 char tmp_dirname[BUFSIZE];
2127
2128 /* switch on the location that the user wants the plugin directories
2129 * built in */
2130 switch (vimfiles_dir_choice)
2131 {
2132 case vimfiles_dir_vim:
2133 {
2134 /* Go to the %VIM% directory - check env first, then go one dir
2135 * below installdir if there is no %VIM% environment variable.
2136 * The accuracy of $VIM is checked in inspect_system(), so we
2137 * can be sure it is ok to use here. */
2138 p = getenv("VIM");
2139 if (p == NULL) /* No $VIM in path */
2140 dir_remove_last(installdir, vimdir_path);
2141 else
2142 strcpy(vimdir_path, p);
2143 break;
2144 }
2145 case vimfiles_dir_home:
2146 {
2147 /* Find the $HOME directory. Its existence was already checked. */
2148 p = getenv("HOME");
2149 if (p == NULL)
2150 {
2151 printf("Internal error: $HOME is NULL\n");
2152 p = "c:\\";
2153 }
2154 strcpy(vimdir_path, p);
2155 break;
2156 }
2157 case vimfiles_dir_none:
2158 {
2159 /* Do not create vim plugin directory */
2160 return;
2161 }
2162 }
2163
2164 /* Now, just create the directory. If it already exists, it will fail
2165 * silently. */
2166 sprintf(vimfiles_path, "%s\\vimfiles", vimdir_path);
2167 vim_mkdir(vimfiles_path, 0755);
2168
2169 printf("Creating the following directories in \"%s\":\n", vimfiles_path);
2170 for (i = 0; i < TABLE_SIZE(vimfiles_subdirs); i++)
2171 {
2172 sprintf(tmp_dirname, "%s\\%s", vimfiles_path, vimfiles_subdirs[i]);
2173 printf(" %s", vimfiles_subdirs[i]);
2174 vim_mkdir(tmp_dirname, 0755);
2175 }
2176 printf("\n");
2177}
2178
2179/*
2180 * Add the creation of runtime files to the setup sequence.
2181 */
2182 static void
2183init_directories_choice(void)
2184{
2185 struct stat st;
2186 char tmp_dirname[BUFSIZE];
2187 char *p;
2188
2189 choices[choice_count].text = alloc(150);
2190 choices[choice_count].changefunc = change_directories_choice;
2191 choices[choice_count].installfunc = install_vimfilesdir;
2192 choices[choice_count].active = 1;
2193
2194 /* Check if the "compiler" directory already exists. That's a good
2195 * indication that the plugin directories were already created. */
2196 if (getenv("HOME") != NULL)
2197 {
2198 vimfiles_dir_choice = (int)vimfiles_dir_home;
2199 sprintf(tmp_dirname, "%s\\vimfiles\\compiler", getenv("HOME"));
2200 if (stat(tmp_dirname, &st) == 0)
2201 vimfiles_dir_choice = (int)vimfiles_dir_none;
2202 }
2203 else
2204 {
2205 vimfiles_dir_choice = (int)vimfiles_dir_vim;
2206 p = getenv("VIM");
2207 if (p == NULL) /* No $VIM in path, use the install dir */
2208 dir_remove_last(installdir, tmp_dirname);
2209 else
2210 strcpy(tmp_dirname, p);
2211 strcat(tmp_dirname, "\\vimfiles\\compiler");
2212 if (stat(tmp_dirname, &st) == 0)
2213 vimfiles_dir_choice = (int)vimfiles_dir_none;
2214 }
2215
2216 set_directories_text(choice_count);
2217 ++choice_count;
2218}
2219
2220/*
2221 * Setup the choices and the default values.
2222 */
2223 static void
2224setup_choices(void)
2225{
2226 /* install the batch files */
2227 init_bat_choices();
2228
2229 /* (over) write _vimrc file */
2230 init_vimrc_choices();
2231
2232 /* Whether to add Vim to the popup menu */
2233 init_popup_choice();
2234
2235 /* Whether to add Vim to the "Open With..." menu */
2236 init_openwith_choice();
2237
2238 /* Whether to add Vim to the Start Menu. */
2239 init_startmenu_choice();
2240
2241 /* Whether to add shortcuts to the Desktop. */
2242 init_shortcut_choices();
2243
2244 /* Whether to create the runtime directories. */
2245 init_directories_choice();
2246}
2247
2248 static void
2249print_cmd_line_help(void)
2250{
2251 printf("Vim installer non-interactive command line arguments:\n");
2252 printf("\n");
2253 printf("-create-batfiles [vim gvim evim view gview vimdiff gvimdiff]\n");
2254 printf(" Create .bat files for Vim variants in the Windows directory.\n");
2255 printf("-create-vimrc\n");
2256 printf(" Create a default _vimrc file if one does not already exist.\n");
Bram Moolenaarc3fdf7f2017-10-28 18:36:48 +02002257 printf("-vimrc-remap [no|win]\n");
2258 printf(" Remap keys when creating a default _vimrc file.\n");
2259 printf("-vimrc-behave [unix|mswin|default]\n");
2260 printf(" Set mouse behavior when creating a default _vimrc file.\n");
Bram Moolenaar6cdb2c92018-10-13 17:25:27 +02002261 printf("-vimrc-compat [vi|vim|defaults|all]\n");
2262 printf(" Set Vi compatibility when creating a default _vimrc file.\n");
Bram Moolenaar071d4272004-06-13 20:20:40 +00002263 printf("-install-popup\n");
2264 printf(" Install the Edit-with-Vim context menu entry\n");
2265 printf("-install-openwith\n");
2266 printf(" Add Vim to the \"Open With...\" context menu list\n");
Bram Moolenaar071d4272004-06-13 20:20:40 +00002267 printf("-add-start-menu");
2268 printf(" Add Vim to the start menu\n");
2269 printf("-install-icons");
2270 printf(" Create icons for gVim executables on the desktop\n");
Bram Moolenaar071d4272004-06-13 20:20:40 +00002271 printf("-create-directories [vim|home]\n");
2272 printf(" Create runtime directories to drop plugins into; in the $VIM\n");
2273 printf(" or $HOME directory\n");
Bram Moolenaar071d4272004-06-13 20:20:40 +00002274 printf("-register-OLE");
Bram Moolenaarce0842a2005-07-18 21:58:11 +00002275 printf(" Ignored\n");
Bram Moolenaar071d4272004-06-13 20:20:40 +00002276 printf("\n");
2277}
2278
2279/*
2280 * Setup installation choices based on command line switches
2281 */
2282 static void
2283command_line_setup_choices(int argc, char **argv)
2284{
2285 int i, j;
2286
2287 for (i = 1; i < argc; i++)
2288 {
2289 if (strcmp(argv[i], "-create-batfiles") == 0)
2290 {
2291 if (i + 1 == argc)
2292 continue;
2293 while (argv[i + 1][0] != '-' && i < argc)
2294 {
2295 i++;
2296 for (j = 1; j < TARGET_COUNT; ++j)
2297 if ((targets[j].exenamearg[0] == 'g' ? has_gvim : has_vim)
2298 && strcmp(argv[i], targets[j].name) == 0)
2299 {
2300 init_bat_choice(j);
2301 break;
2302 }
2303 if (j == TARGET_COUNT)
2304 printf("%s is not a valid choice for -create-batfiles\n",
2305 argv[i]);
2306
2307 if (i + 1 == argc)
2308 break;
2309 }
2310 }
2311 else if (strcmp(argv[i], "-create-vimrc") == 0)
2312 {
2313 /* Setup default vimrc choices. If there is already a _vimrc file,
2314 * it will NOT be overwritten.
2315 */
2316 init_vimrc_choices();
2317 }
Bram Moolenaarc3fdf7f2017-10-28 18:36:48 +02002318 else if (strcmp(argv[i], "-vimrc-remap") == 0)
2319 {
2320 if (i + 1 == argc)
2321 break;
2322 i++;
2323 if (strcmp(argv[i], "no") == 0)
2324 remap_choice = remap_no;
2325 else if (strcmp(argv[i], "win") == 0)
2326 remap_choice = remap_win;
2327 }
2328 else if (strcmp(argv[i], "-vimrc-behave") == 0)
2329 {
2330 if (i + 1 == argc)
2331 break;
2332 i++;
2333 if (strcmp(argv[i], "unix") == 0)
2334 mouse_choice = mouse_xterm;
2335 else if (strcmp(argv[i], "mswin") == 0)
2336 mouse_choice = mouse_mswin;
2337 else if (strcmp(argv[i], "default") == 0)
2338 mouse_choice = mouse_default;
2339 }
Bram Moolenaar6cdb2c92018-10-13 17:25:27 +02002340 else if (strcmp(argv[i], "-vimrc-compat") == 0)
2341 {
2342 if (i + 1 == argc)
2343 break;
2344 i++;
2345 if (strcmp(argv[i], "vi") == 0)
2346 compat_choice = compat_vi;
2347 else if (strcmp(argv[i], "vim") == 0)
2348 compat_choice = compat_vim;
2349 else if (strcmp(argv[i], "defaults") == 0)
2350 compat_choice = compat_some_enhancements;
2351 else if (strcmp(argv[i], "all") == 0)
2352 compat_choice = compat_all_enhancements;
2353 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00002354 else if (strcmp(argv[i], "-install-popup") == 0)
2355 {
2356 init_popup_choice();
2357 }
2358 else if (strcmp(argv[i], "-install-openwith") == 0)
2359 {
2360 init_openwith_choice();
2361 }
2362 else if (strcmp(argv[i], "-add-start-menu") == 0)
2363 {
2364 init_startmenu_choice();
2365 }
2366 else if (strcmp(argv[i], "-install-icons") == 0)
2367 {
2368 init_shortcut_choices();
2369 }
2370 else if (strcmp(argv[i], "-create-directories") == 0)
2371 {
2372 init_directories_choice();
2373 if (argv[i + 1][0] != '-')
2374 {
2375 i++;
2376 if (strcmp(argv[i], "vim") == 0)
2377 vimfiles_dir_choice = (int)vimfiles_dir_vim;
2378 else if (strcmp(argv[i], "home") == 0)
2379 {
2380 if (getenv("HOME") == NULL) /* No $HOME in environment */
2381 vimfiles_dir_choice = (int)vimfiles_dir_vim;
2382 else
2383 vimfiles_dir_choice = (int)vimfiles_dir_home;
2384 }
2385 else
2386 {
2387 printf("Unknown argument for -create-directories: %s\n",
2388 argv[i]);
2389 print_cmd_line_help();
2390 }
2391 }
2392 else /* No choice specified, default to vim directory */
2393 vimfiles_dir_choice = (int)vimfiles_dir_vim;
2394 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00002395 else if (strcmp(argv[i], "-register-OLE") == 0)
2396 {
2397 /* This is always done when gvim is found */
2398 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00002399 else /* Unknown switch */
2400 {
2401 printf("Got unknown argument argv[%d] = %s\n", i, argv[i]);
2402 print_cmd_line_help();
2403 }
2404 }
2405}
2406
2407
2408/*
2409 * Show a few screens full of helpful information.
2410 */
2411 static void
2412show_help(void)
2413{
2414 static char *(items[]) =
2415 {
2416"Installing .bat files\n"
2417"---------------------\n"
2418"The vim.bat file is written in one of the directories in $PATH.\n"
2419"This makes it possible to start Vim from the command line.\n"
2420"If vim.exe can be found in $PATH, the choice for vim.bat will not be\n"
2421"present. It is assumed you will use the existing vim.exe.\n"
2422"If vim.bat can already be found in $PATH this is probably for an old\n"
2423"version of Vim (but this is not checked!). You can overwrite it.\n"
2424"If no vim.bat already exists, you can select one of the directories in\n"
2425"$PATH for creating the batch file, or disable creating a vim.bat file.\n"
2426"\n"
2427"If you choose not to create the vim.bat file, Vim can still be executed\n"
2428"in other ways, but not from the command line.\n"
2429"\n"
2430"The same applies to choices for gvim, evim, (g)view, and (g)vimdiff.\n"
2431"The first item can be used to change the path for all of them.\n"
2432,
2433"Creating a _vimrc file\n"
2434"----------------------\n"
2435"The _vimrc file is used to set options for how Vim behaves.\n"
2436"The install program can create a _vimrc file with a few basic choices.\n"
2437"You can edit this file later to tune your preferences.\n"
2438"If you already have a _vimrc or .vimrc file it can be overwritten.\n"
2439"Don't do that if you have made changes to it.\n"
2440,
2441"Vim features\n"
2442"------------\n"
2443"(this choice is only available when creating a _vimrc file)\n"
2444"1. Vim can run in Vi-compatible mode. Many nice Vim features are then\n"
2445" disabled. In the not-Vi-compatible mode Vim is still mostly Vi\n"
2446" compatible, but adds nice features like multi-level undo. Only\n"
2447" choose Vi-compatible if you really need full Vi compatibility.\n"
2448"2. Running Vim with some enhancements is useful when you want some of\n"
2449" the nice Vim features, but have a slow computer and want to keep it\n"
2450" really fast.\n"
2451"3. Syntax highlighting shows many files in color. Not only does this look\n"
2452" nice, it also makes it easier to spot errors and you can work faster.\n"
2453" The other features include editing compressed files.\n"
2454,
2455"Windows key mapping\n"
2456"-------------------\n"
2457"(this choice is only available when creating a _vimrc file)\n"
2458"Under MS-Windows the CTRL-C key copies text to the clipboard and CTRL-V\n"
2459"pastes text from the clipboard. There are a few more keys like these.\n"
2460"Unfortunately, in Vim these keys normally have another meaning.\n"
2461"1. Choose to have the keys like they normally are in Vim (useful if you\n"
2462" also use Vim on other systems).\n"
2463"2. Choose to have the keys work like they are used on MS-Windows (useful\n"
2464" if you mostly work on MS-Windows).\n"
2465,
2466"Mouse use\n"
2467"---------\n"
2468"(this choice is only available when creating a _vimrc file)\n"
2469"The right mouse button can be used in two ways:\n"
2470"1. The Unix way is to extend an existing selection. The popup menu is\n"
2471" not available.\n"
2472"2. The MS-Windows way is to show a popup menu, which allows you to\n"
2473" copy/paste text, undo/redo, etc. Extending the selection can still be\n"
2474" done by keeping SHIFT pressed while using the left mouse button\n"
2475,
2476"Edit-with-Vim context menu entry\n"
2477"--------------------------------\n"
2478"(this choice is only available when gvim.exe and gvimext.dll are present)\n"
2479"You can associate different file types with Vim, so that you can (double)\n"
2480"click on a file to edit it with Vim. This means you have to individually\n"
2481"select each file type.\n"
2482"An alternative is the option offered here: Install an \"Edit with Vim\"\n"
2483"entry in the popup menu for the right mouse button. This means you can\n"
2484"edit any file with Vim.\n"
2485,
2486"\"Open With...\" context menu entry\n"
2487"--------------------------------\n"
2488"(this choice is only available when gvim.exe is present)\n"
2489"This option adds Vim to the \"Open With...\" entry in the popup menu for\n"
2490"the right mouse button. This also makes it possible to edit HTML files\n"
2491"directly from Internet Explorer.\n"
2492,
2493"Add Vim to the Start menu\n"
2494"-------------------------\n"
2495"In Windows 95 and later, Vim can be added to the Start menu. This will\n"
2496"create a submenu with an entry for vim, gvim, evim, vimdiff, etc..\n"
2497,
2498"Icons on the desktop\n"
2499"--------------------\n"
2500"(these choices are only available when installing gvim)\n"
2501"In Windows 95 and later, shortcuts (icons) can be created on the Desktop.\n"
2502,
2503"Create plugin directories\n"
2504"-------------------------\n"
2505"Plugin directories allow extending Vim by dropping a file into a directory.\n"
2506"This choice allows creating them in $HOME (if you have a home directory) or\n"
2507"$VIM (used for everybody on the system).\n"
2508,
2509NULL
2510 };
2511 int i;
2512 int c;
2513
2514 rewind(stdin);
2515 printf("\n");
2516 for (i = 0; items[i] != NULL; ++i)
2517 {
Bram Moolenaarc3fdf7f2017-10-28 18:36:48 +02002518 puts(items[i]);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002519 printf("Hit Enter to continue, b (back) or q (quit help): ");
2520 c = getchar();
2521 rewind(stdin);
2522 if (c == 'b' || c == 'B')
2523 {
2524 if (i == 0)
2525 --i;
2526 else
2527 i -= 2;
2528 }
2529 if (c == 'q' || c == 'Q')
2530 break;
2531 printf("\n");
2532 }
2533}
2534
2535/*
2536 * Install the choices.
2537 */
2538 static void
2539install(void)
2540{
2541 int i;
2542
2543 /* Install the selected choices. */
2544 for (i = 0; i < choice_count; ++i)
2545 if (choices[i].installfunc != NULL && choices[i].active)
2546 (choices[i].installfunc)(i);
2547
2548 /* Add some entries to the registry, if needed. */
2549 if (install_popup
2550 || install_openwith
2551 || (need_uninstall_entry && interactive)
2552 || !interactive)
2553 install_registry();
2554
Bram Moolenaar071d4272004-06-13 20:20:40 +00002555 /* Register gvim with OLE. */
2556 if (has_gvim)
2557 install_OLE_register();
Bram Moolenaar071d4272004-06-13 20:20:40 +00002558}
2559
2560/*
2561 * request_choice
2562 */
2563 static void
2564request_choice(void)
2565{
2566 int i;
2567
2568 printf("\n\nInstall will do for you:\n");
2569 for (i = 0; i < choice_count; ++i)
2570 if (choices[i].active)
2571 printf("%2d %s\n", i + 1, choices[i].text);
2572 printf("To change an item, enter its number\n\n");
2573 printf("Enter item number, h (help), d (do it) or q (quit): ");
2574}
2575
2576 int
2577main(int argc, char **argv)
2578{
2579 int i;
2580 char buf[BUFSIZE];
2581
2582 /*
2583 * Run interactively if there are no command line arguments.
2584 */
2585 if (argc > 1)
2586 interactive = 0;
2587 else
2588 interactive = 1;
2589
2590 /* Initialize this program. */
2591 do_inits(argv);
2592
Bram Moolenaar071d4272004-06-13 20:20:40 +00002593 if (argc > 1 && strcmp(argv[1], "-uninstall-check") == 0)
2594 {
2595 /* Only check for already installed Vims. Used by NSIS installer. */
Bram Moolenaar442b4222010-05-24 21:34:22 +02002596 i = uninstall_check(1);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002597
2598 /* Find the value of $VIM, because NSIS isn't able to do this by
2599 * itself. */
2600 get_vim_env();
2601
2602 /* When nothing found exit quietly. If something found wait for
Bram Moolenaarb230bd52010-05-25 21:02:00 +02002603 * a little while, so that the user can read the messages. */
Bram Moolenaar6cdb2c92018-10-13 17:25:27 +02002604 if (i && _isatty(1))
Bram Moolenaarab8205e2010-07-07 15:14:03 +02002605 sleep(3);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002606 exit(0);
2607 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00002608
2609 printf("This program sets up the installation of Vim "
2610 VIM_VERSION_MEDIUM "\n\n");
2611
2612 /* Check if the user unpacked the archives properly. */
2613 check_unpack();
2614
Bram Moolenaar071d4272004-06-13 20:20:40 +00002615 /* Check for already installed Vims. */
2616 if (interactive)
Bram Moolenaar442b4222010-05-24 21:34:22 +02002617 uninstall_check(0);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002618
2619 /* Find out information about the system. */
2620 inspect_system();
2621
2622 if (interactive)
2623 {
2624 /* Setup all the choices. */
2625 setup_choices();
2626
2627 /* Let the user change choices and finally install (or quit). */
2628 for (;;)
2629 {
2630 request_choice();
2631 rewind(stdin);
2632 if (scanf("%99s", buf) == 1)
2633 {
2634 if (isdigit(buf[0]))
2635 {
2636 /* Change a choice. */
2637 i = atoi(buf);
2638 if (i > 0 && i <= choice_count && choices[i - 1].active)
2639 (choices[i - 1].changefunc)(i - 1);
2640 else
2641 printf("\nIllegal choice\n");
2642 }
2643 else if (buf[0] == 'h' || buf[0] == 'H')
2644 {
2645 /* Help */
2646 show_help();
2647 }
2648 else if (buf[0] == 'd' || buf[0] == 'D')
2649 {
2650 /* Install! */
2651 install();
2652 printf("\nThat finishes the installation. Happy Vimming!\n");
2653 break;
2654 }
2655 else if (buf[0] == 'q' || buf[0] == 'Q')
2656 {
2657 /* Quit */
2658 printf("\nExiting without anything done\n");
2659 break;
2660 }
2661 else
2662 printf("\nIllegal choice\n");
2663 }
2664 }
2665 printf("\n");
Bram Moolenaar442b4222010-05-24 21:34:22 +02002666 myexit(0);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002667 }
2668 else
2669 {
2670 /*
2671 * Run non-interactive - setup according to the command line switches
2672 */
2673 command_line_setup_choices(argc, argv);
2674 install();
Bram Moolenaar442b4222010-05-24 21:34:22 +02002675
2676 /* Avoid that the user has to hit Enter, just wait a little bit to
2677 * allow reading the messages. */
Bram Moolenaarab8205e2010-07-07 15:14:03 +02002678 sleep(2);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002679 }
2680
Bram Moolenaar071d4272004-06-13 20:20:40 +00002681 return 0;
2682}