blob: ca74758e0ffcd97c43413399f4f8a80c4851b027 [file] [log] [blame]
Bram Moolenaaredf3f972016-08-29 22:49:24 +02001/* vi:set ts=8 sts=4 sw=4 noet:
Bram Moolenaar071d4272004-06-13 20:20:40 +00002 *
3 * VIM - Vi IMproved by Bram Moolenaar
4 *
5 * Do ":help uganda" in Vim to read copying and usage conditions.
6 * Do ":help credits" in Vim to see a list of people who contributed.
7 * See README.txt for an overview of the Vim source code.
8 */
9
10/*
11 * dosinst.c: Install program for Vim on MS-DOS and MS-Windows
12 *
13 * Compile with Make_mvc.mak, Make_bc3.mak, Make_bc5.mak or Make_djg.mak.
14 */
15
16/*
17 * Include common code for dosinst.c and uninstal.c.
18 */
19#define DOSINST
20#include "dosinst.h"
Bram Moolenaar6cdb2c92018-10-13 17:25:27 +020021#include <io.h>
Bram Moolenaar071d4272004-06-13 20:20:40 +000022
Bram Moolenaar6199d432017-10-14 19:05:44 +020023#define GVIMEXT64_PATH "GvimExt64\\gvimext.dll"
24#define GVIMEXT32_PATH "GvimExt32\\gvimext.dll"
25
Bram Moolenaar071d4272004-06-13 20:20:40 +000026/* Macro to do an error check I was typing over and over */
Bram Moolenaar6f470022018-04-10 18:47:20 +020027#define CHECK_REG_ERROR(code) \
28 do { \
29 if (code != ERROR_SUCCESS) \
30 { \
31 printf("%ld error number: %ld\n", (long)__LINE__, (long)code); \
32 return 1; \
33 } \
34 } while (0)
Bram Moolenaar071d4272004-06-13 20:20:40 +000035
36int has_vim = 0; /* installable vim.exe exists */
37int has_gvim = 0; /* installable gvim.exe exists */
38
39char oldvimrc[BUFSIZE]; /* name of existing vimrc file */
40char vimrc[BUFSIZE]; /* name of vimrc file to create */
41
42char *default_bat_dir = NULL; /* when not NULL, use this as the default
43 directory to write .bat files in */
44char *default_vim_dir = NULL; /* when not NULL, use this as the default
45 install dir for NSIS */
Bram Moolenaar071d4272004-06-13 20:20:40 +000046
47/*
48 * Structure used for each choice the user can make.
49 */
50struct choice
51{
52 int active; /* non-zero when choice is active */
53 char *text; /* text displayed for this choice */
54 void (*changefunc)(int idx); /* function to change this choice */
55 int arg; /* argument for function */
56 void (*installfunc)(int idx); /* function to install this choice */
57};
58
59struct choice choices[30]; /* choices the user can make */
60int choice_count = 0; /* number of choices available */
61
62#define TABLE_SIZE(s) (int)(sizeof(s) / sizeof(*s))
63
64enum
65{
66 compat_vi = 1,
Bram Moolenaar6cdb2c92018-10-13 17:25:27 +020067 compat_vim,
Bram Moolenaar071d4272004-06-13 20:20:40 +000068 compat_some_enhancements,
69 compat_all_enhancements
70};
71char *(compat_choices[]) =
72{
73 "\nChoose the default way to run Vim:",
74 "Vi compatible",
Bram Moolenaar6cdb2c92018-10-13 17:25:27 +020075 "Vim default",
Bram Moolenaarfff2bee2010-05-15 13:56:02 +020076 "with some Vim enhancements",
Bram Moolenaar071d4272004-06-13 20:20:40 +000077 "with syntax highlighting and other features switched on",
78};
79int compat_choice = (int)compat_all_enhancements;
80char *compat_text = "- run Vim %s";
81
82enum
83{
84 remap_no = 1,
85 remap_win
86};
87char *(remap_choices[]) =
88{
89 "\nChoose:",
90 "Do not remap keys for Windows behavior",
Bram Moolenaar6199d432017-10-14 19:05:44 +020091 "Remap a few keys for Windows behavior (CTRL-V, CTRL-C, CTRL-F, etc)",
Bram Moolenaar071d4272004-06-13 20:20:40 +000092};
Bram Moolenaarc3fdf7f2017-10-28 18:36:48 +020093int remap_choice = (int)remap_no;
Bram Moolenaar071d4272004-06-13 20:20:40 +000094char *remap_text = "- %s";
95
96enum
97{
98 mouse_xterm = 1,
Bram Moolenaarb9fce6c2017-10-28 18:50:01 +020099 mouse_mswin,
Bram Moolenaarc3fdf7f2017-10-28 18:36:48 +0200100 mouse_default
Bram Moolenaar071d4272004-06-13 20:20:40 +0000101};
102char *(mouse_choices[]) =
103{
104 "\nChoose the way how Vim uses the mouse:",
105 "right button extends selection (the Unix way)",
Bram Moolenaarc3fdf7f2017-10-28 18:36:48 +0200106 "right button has a popup menu, left button starts select mode (the Windows way)",
107 "right button has a popup menu, left button starts visual mode",
Bram Moolenaar071d4272004-06-13 20:20:40 +0000108};
Bram Moolenaarc3fdf7f2017-10-28 18:36:48 +0200109int mouse_choice = (int)mouse_default;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000110char *mouse_text = "- The mouse %s";
111
112enum
113{
114 vimfiles_dir_none = 1,
115 vimfiles_dir_vim,
116 vimfiles_dir_home
117};
Bram Moolenaar25a494c2018-11-16 19:39:50 +0100118static char *(vimfiles_dir_choices[]) =
Bram Moolenaar071d4272004-06-13 20:20:40 +0000119{
120 "\nCreate plugin directories:",
121 "No",
122 "In the VIM directory",
123 "In your HOME directory",
124};
Bram Moolenaar071d4272004-06-13 20:20:40 +0000125
126/* non-zero when selected to install the popup menu entry. */
127static int install_popup = 0;
128
129/* non-zero when selected to install the "Open with" entry. */
130static int install_openwith = 0;
131
132/* non-zero when need to add an uninstall entry in the registry */
133static int need_uninstall_entry = 0;
134
135/*
136 * Definitions of the directory name (under $VIM) of the vimfiles directory
137 * and its subdirectories:
138 */
139static char *(vimfiles_subdirs[]) =
140{
141 "colors",
142 "compiler",
143 "doc",
144 "ftdetect",
145 "ftplugin",
146 "indent",
147 "keymap",
148 "plugin",
149 "syntax",
150};
151
152/*
Bram Moolenaar071d4272004-06-13 20:20:40 +0000153 * Obtain a choice from a table.
154 * First entry is a question, others are choices.
155 */
156 static int
157get_choice(char **table, int entries)
158{
159 int answer;
160 int idx;
161 char dummy[100];
162
163 do
164 {
165 for (idx = 0; idx < entries; ++idx)
166 {
167 if (idx)
168 printf("%2d ", idx);
Bram Moolenaarc3fdf7f2017-10-28 18:36:48 +0200169 puts(table[idx]);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000170 }
171 printf("Choice: ");
172 if (scanf("%d", &answer) != 1)
173 {
174 scanf("%99s", dummy);
175 answer = 0;
176 }
177 }
178 while (answer < 1 || answer >= entries);
179
180 return answer;
181}
182
183/*
184 * Check if the user unpacked the archives properly.
185 * Sets "runtimeidx".
186 */
187 static void
188check_unpack(void)
189{
190 char buf[BUFSIZE];
191 FILE *fd;
192 struct stat st;
193
194 /* check for presence of the correct version number in installdir[] */
195 runtimeidx = strlen(installdir) - strlen(VIM_VERSION_NODOT);
196 if (runtimeidx <= 0
197 || stricmp(installdir + runtimeidx, VIM_VERSION_NODOT) != 0
198 || (installdir[runtimeidx - 1] != '/'
199 && installdir[runtimeidx - 1] != '\\'))
200 {
201 printf("ERROR: Install program not in directory \"%s\"\n",
202 VIM_VERSION_NODOT);
203 printf("This program can only work when it is located in its original directory\n");
204 myexit(1);
205 }
206
207 /* check if filetype.vim is present, which means the runtime archive has
208 * been unpacked */
209 sprintf(buf, "%s\\filetype.vim", installdir);
210 if (stat(buf, &st) < 0)
211 {
212 printf("ERROR: Cannot find filetype.vim in \"%s\"\n", installdir);
213 printf("It looks like you did not unpack the runtime archive.\n");
214 printf("You must unpack the runtime archive \"vim%srt.zip\" before installing.\n",
215 VIM_VERSION_NODOT + 3);
216 myexit(1);
217 }
218
219 /* Check if vim.exe or gvim.exe is in the current directory. */
220 if ((fd = fopen("gvim.exe", "r")) != NULL)
221 {
222 fclose(fd);
223 has_gvim = 1;
224 }
225 if ((fd = fopen("vim.exe", "r")) != NULL)
226 {
227 fclose(fd);
228 has_vim = 1;
229 }
230 if (!has_gvim && !has_vim)
231 {
232 printf("ERROR: Cannot find any Vim executables in \"%s\"\n\n",
233 installdir);
234 myexit(1);
235 }
236}
237
238/*
239 * Compare paths "p[plen]" to "q[qlen]". Return 0 if they match.
240 * Ignores case and differences between '/' and '\'.
241 * "plen" and "qlen" can be negative, strlen() is used then.
242 */
243 static int
244pathcmp(char *p, int plen, char *q, int qlen)
245{
246 int i;
247
248 if (plen < 0)
249 plen = strlen(p);
250 if (qlen < 0)
251 qlen = strlen(q);
252 for (i = 0; ; ++i)
253 {
254 /* End of "p": check if "q" also ends or just has a slash. */
255 if (i == plen)
256 {
257 if (i == qlen) /* match */
258 return 0;
259 if (i == qlen - 1 && (q[i] == '\\' || q[i] == '/'))
260 return 0; /* match with trailing slash */
261 return 1; /* no match */
262 }
263
264 /* End of "q": check if "p" also ends or just has a slash. */
265 if (i == qlen)
266 {
267 if (i == plen) /* match */
268 return 0;
269 if (i == plen - 1 && (p[i] == '\\' || p[i] == '/'))
270 return 0; /* match with trailing slash */
271 return 1; /* no match */
272 }
273
274 if (!(mytoupper(p[i]) == mytoupper(q[i])
275 || ((p[i] == '/' || p[i] == '\\')
276 && (q[i] == '/' || q[i] == '\\'))))
277 return 1; /* no match */
278 }
279 /*NOTREACHED*/
280}
281
282/*
283 * If the executable "**destination" is in the install directory, find another
284 * one in $PATH.
285 * On input "**destination" is the path of an executable in allocated memory
286 * (or NULL).
287 * "*destination" is set to NULL or the location of the file.
288 */
289 static void
290findoldfile(char **destination)
291{
292 char *bp = *destination;
293 size_t indir_l = strlen(installdir);
Bram Moolenaarb7633612019-02-10 21:48:25 +0100294 char *cp;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000295 char *tmpname;
296 char *farname;
297
298 /*
299 * No action needed if exe not found or not in this directory.
300 */
Bram Moolenaarb7633612019-02-10 21:48:25 +0100301 if (bp == NULL || strnicmp(bp, installdir, indir_l) != 0)
302 return;
303 cp = bp + indir_l;
304 if (strchr("/\\", *cp++) == NULL
Bram Moolenaar071d4272004-06-13 20:20:40 +0000305 || strchr(cp, '\\') != NULL
306 || strchr(cp, '/') != NULL)
307 return;
308
309 tmpname = alloc((int)strlen(cp) + 1);
310 strcpy(tmpname, cp);
311 tmpname[strlen(tmpname) - 1] = 'x'; /* .exe -> .exx */
312
313 if (access(tmpname, 0) == 0)
314 {
315 printf("\nERROR: %s and %s clash. Remove or rename %s.\n",
316 tmpname, cp, tmpname);
317 myexit(1);
318 }
319
320 if (rename(cp, tmpname) != 0)
321 {
322 printf("\nERROR: failed to rename %s to %s: %s\n",
323 cp, tmpname, strerror(0));
324 myexit(1);
325 }
326
327 farname = searchpath_save(cp);
328
329 if (rename(tmpname, cp) != 0)
330 {
331 printf("\nERROR: failed to rename %s back to %s: %s\n",
332 tmpname, cp, strerror(0));
333 myexit(1);
334 }
335
336 free(*destination);
337 free(tmpname);
338 *destination = farname;
339}
340
341/*
342 * Check if there is a vim.[exe|bat|, gvim.[exe|bat|, etc. in the path.
343 * When "check_bat_only" is TRUE, only find "default_bat_dir".
344 */
345 static void
346find_bat_exe(int check_bat_only)
347{
348 int i;
349
Bram Moolenaar42bbef42006-03-25 22:02:07 +0000350 /* avoid looking in the "installdir" by chdir to system root */
351 mch_chdir(sysdrive);
352 mch_chdir("\\");
Bram Moolenaar071d4272004-06-13 20:20:40 +0000353
354 for (i = 1; i < TARGET_COUNT; ++i)
355 {
356 targets[i].oldbat = searchpath_save(targets[i].batname);
357 if (!check_bat_only)
358 targets[i].oldexe = searchpath_save(targets[i].exename);
359
360 if (default_bat_dir == NULL && targets[i].oldbat != NULL)
361 {
362 default_bat_dir = alloc(strlen(targets[i].oldbat) + 1);
363 strcpy(default_bat_dir, targets[i].oldbat);
364 remove_tail(default_bat_dir);
365 }
366 if (check_bat_only && targets[i].oldbat != NULL)
Bram Moolenaar42bbef42006-03-25 22:02:07 +0000367 {
Bram Moolenaar071d4272004-06-13 20:20:40 +0000368 free(targets[i].oldbat);
Bram Moolenaar42bbef42006-03-25 22:02:07 +0000369 targets[i].oldbat = NULL;
370 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000371 }
372
373 mch_chdir(installdir);
374}
375
Bram Moolenaar071d4272004-06-13 20:20:40 +0000376/*
377 * Get the value of $VIMRUNTIME or $VIM and write it in $TEMP/vimini.ini, so
378 * that NSIS can read it.
379 * When not set, use the directory of a previously installed Vim.
380 */
381 static void
382get_vim_env(void)
383{
384 char *vim;
385 char buf[BUFSIZE];
386 FILE *fd;
387 char fname[BUFSIZE];
388
389 /* First get $VIMRUNTIME. If it's set, remove the tail. */
390 vim = getenv("VIMRUNTIME");
Bram Moolenaare4963c52019-02-22 19:41:08 +0100391 if (vim != NULL && *vim != 0 && strlen(vim) < sizeof(buf))
Bram Moolenaar071d4272004-06-13 20:20:40 +0000392 {
393 strcpy(buf, vim);
394 remove_tail(buf);
395 vim = buf;
396 }
397 else
398 {
399 vim = getenv("VIM");
400 if (vim == NULL || *vim == 0)
401 {
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. */
Bram Moolenaare4963c52019-02-22 19:41:08 +0100414 GetTempPath(sizeof(fname) - 12, fname);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000415 add_pathsep(fname);
416 strcat(fname, "vimini.ini");
417
418 fd = fopen(fname, "w");
419 if (fd != NULL)
420 {
421 /* Make it look like an .ini file, so that NSIS can read it with a
422 * ReadINIStr command. */
423 fprintf(fd, "[vimini]\n");
424 fprintf(fd, "dir=\"%s\"\n", vim);
425 fclose(fd);
426 }
427 else
428 {
429 printf("Failed to open %s\n", fname);
Bram Moolenaarab8205e2010-07-07 15:14:03 +0200430 sleep(2);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000431 }
432}
433
Bram Moolenaarb230bd52010-05-25 21:02:00 +0200434static int num_windows;
435
436/*
437 * Callback used for EnumWindows():
438 * Count the window if the title looks like it is for the uninstaller.
439 */
440/*ARGSUSED*/
441 static BOOL CALLBACK
442window_cb(HWND hwnd, LPARAM lparam)
443{
444 char title[256];
445
446 title[0] = 0;
447 GetWindowText(hwnd, title, 256);
Bram Moolenaaraf610b82018-12-21 16:22:50 +0100448 if (strstr(title, "Vim ") != NULL && strstr(title, " Uninstall") != NULL)
Bram Moolenaarb230bd52010-05-25 21:02:00 +0200449 ++num_windows;
450 return TRUE;
451}
452
Bram Moolenaar071d4272004-06-13 20:20:40 +0000453/*
Bram Moolenaaraf610b82018-12-21 16:22:50 +0100454 * Run the uninstaller silently.
455 */
456 static int
457run_silent_uninstall(char *uninst_exe)
458{
Bram Moolenaare4963c52019-02-22 19:41:08 +0100459 char vimrt_dir[BUFSIZE];
Bram Moolenaaraf610b82018-12-21 16:22:50 +0100460 char temp_uninst[BUFSIZE];
461 char temp_dir[MAX_PATH];
462 char buf[BUFSIZE * 2 + 10];
463 int i;
464 DWORD tick;
465
466 strcpy(vimrt_dir, uninst_exe);
467 remove_tail(vimrt_dir);
468
469 if (!GetTempPath(sizeof(temp_dir), temp_dir))
470 return FAIL;
471
472 /* Copy the uninstaller to a temporary exe. */
473 tick = GetTickCount();
474 for (i = 0; ; i++)
475 {
476 sprintf(temp_uninst, "%s\\vimun%04X.exe", temp_dir,
Bram Moolenaar44a7db42019-01-11 20:47:31 +0100477 (unsigned int)((i + tick) & 0xFFFF));
Bram Moolenaaraf610b82018-12-21 16:22:50 +0100478 if (CopyFile(uninst_exe, temp_uninst, TRUE))
479 break;
480 if (GetLastError() != ERROR_FILE_EXISTS)
481 return FAIL;
482 if (i == 65535)
483 return FAIL;
484 }
485
486 /* Run the copied uninstaller silently. */
487 if (strchr(temp_uninst, ' ') != NULL)
488 sprintf(buf, "\"%s\" /S _?=%s", temp_uninst, vimrt_dir);
489 else
490 sprintf(buf, "%s /S _?=%s", temp_uninst, vimrt_dir);
491 run_command(buf);
492
493 DeleteFile(temp_uninst);
494 return OK;
495}
496
497/*
Bram Moolenaar071d4272004-06-13 20:20:40 +0000498 * Check for already installed Vims.
499 * Return non-zero when found one.
500 */
501 static int
Bram Moolenaar442b4222010-05-24 21:34:22 +0200502uninstall_check(int skip_question)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000503{
504 HKEY key_handle;
505 HKEY uninstall_key_handle;
506 char *uninstall_key = "software\\Microsoft\\Windows\\CurrentVersion\\Uninstall";
507 char subkey_name_buff[BUFSIZE];
Bram Moolenaarbbd854d2019-02-18 22:19:33 +0100508 char temp_string_buffer[BUFSIZE-2];
Bram Moolenaare4963c52019-02-22 19:41:08 +0100509 DWORD local_bufsize;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000510 FILETIME temp_pfiletime;
511 DWORD key_index;
512 char input;
513 long code;
514 DWORD value_type;
515 DWORD orig_num_keys;
516 DWORD new_num_keys;
Bram Moolenaaraf610b82018-12-21 16:22:50 +0100517 DWORD allow_silent;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000518 int foundone = 0;
519
Bram Moolenaar760d14a2010-07-31 22:03:44 +0200520 code = RegOpenKeyEx(HKEY_LOCAL_MACHINE, uninstall_key, 0,
521 KEY_WOW64_64KEY | KEY_READ, &key_handle);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000522 CHECK_REG_ERROR(code);
523
Bram Moolenaare4963c52019-02-22 19:41:08 +0100524 key_index = 0;
525 while (TRUE)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000526 {
Bram Moolenaare4963c52019-02-22 19:41:08 +0100527 local_bufsize = sizeof(subkey_name_buff);
528 if (RegEnumKeyEx(key_handle, key_index, subkey_name_buff, &local_bufsize,
529 NULL, NULL, NULL, &temp_pfiletime) == ERROR_NO_MORE_ITEMS)
530 break;
531
Bram Moolenaar071d4272004-06-13 20:20:40 +0000532 if (strncmp("Vim", subkey_name_buff, 3) == 0)
533 {
534 /* Open the key named Vim* */
Bram Moolenaar760d14a2010-07-31 22:03:44 +0200535 code = RegOpenKeyEx(key_handle, subkey_name_buff, 0,
536 KEY_WOW64_64KEY | KEY_READ, &uninstall_key_handle);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000537 CHECK_REG_ERROR(code);
538
539 /* get the DisplayName out of it to show the user */
Bram Moolenaare4963c52019-02-22 19:41:08 +0100540 local_bufsize = sizeof(temp_string_buffer);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000541 code = RegQueryValueEx(uninstall_key_handle, "displayname", 0,
542 &value_type, (LPBYTE)temp_string_buffer,
543 &local_bufsize);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000544 CHECK_REG_ERROR(code);
545
Bram Moolenaaraf610b82018-12-21 16:22:50 +0100546 allow_silent = 0;
547 if (skip_question)
548 {
549 DWORD varsize = sizeof(DWORD);
550
551 RegQueryValueEx(uninstall_key_handle, "AllowSilent", 0,
552 &value_type, (LPBYTE)&allow_silent,
553 &varsize);
554 }
555
Bram Moolenaar071d4272004-06-13 20:20:40 +0000556 foundone = 1;
557 printf("\n*********************************************************\n");
558 printf("Vim Install found what looks like an existing Vim version.\n");
559 printf("The name of the entry is:\n");
560 printf("\n \"%s\"\n\n", temp_string_buffer);
561
562 printf("Installing the new version will disable part of the existing version.\n");
563 printf("(The batch files used in a console and the \"Edit with Vim\" entry in\n");
564 printf("the popup menu will use the new version)\n");
565
Bram Moolenaar442b4222010-05-24 21:34:22 +0200566 if (skip_question)
567 printf("\nRunning uninstall program for \"%s\"\n", temp_string_buffer);
568 else
569 printf("\nDo you want to uninstall \"%s\" now?\n(y)es/(n)o) ", temp_string_buffer);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000570 fflush(stdout);
571
572 /* get the UninstallString */
Bram Moolenaare4963c52019-02-22 19:41:08 +0100573 local_bufsize = sizeof(temp_string_buffer);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000574 code = RegQueryValueEx(uninstall_key_handle, "uninstallstring", 0,
575 &value_type, (LPBYTE)temp_string_buffer, &local_bufsize);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000576 CHECK_REG_ERROR(code);
577
578 /* Remember the directory, it is used as the default for NSIS. */
579 default_vim_dir = alloc(strlen(temp_string_buffer) + 1);
580 strcpy(default_vim_dir, temp_string_buffer);
581 remove_tail(default_vim_dir);
582 remove_tail(default_vim_dir);
583
584 input = 'n';
585 do
586 {
587 if (input != 'n')
588 printf("%c is an invalid reply. Please enter either 'y' or 'n'\n", input);
589
Bram Moolenaar442b4222010-05-24 21:34:22 +0200590 if (skip_question)
591 input = 'y';
592 else
593 {
594 rewind(stdin);
595 scanf("%c", &input);
596 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000597 switch (input)
598 {
599 case 'y':
600 case 'Y':
601 /* save the number of uninstall keys so we can know if
602 * it changed */
603 RegQueryInfoKey(key_handle, NULL, NULL, NULL,
604 &orig_num_keys, NULL, NULL, NULL,
605 NULL, NULL, NULL, NULL);
606
Bram Moolenaar442b4222010-05-24 21:34:22 +0200607 /* Find existing .bat files before deleting them. */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000608 find_bat_exe(TRUE);
609
Bram Moolenaaraf610b82018-12-21 16:22:50 +0100610 if (allow_silent)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000611 {
Bram Moolenaaraf610b82018-12-21 16:22:50 +0100612 if (run_silent_uninstall(temp_string_buffer)
613 == FAIL)
614 allow_silent = 0; /* Retry with non silent. */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000615 }
Bram Moolenaaraf610b82018-12-21 16:22:50 +0100616 if (!allow_silent)
Bram Moolenaarb230bd52010-05-25 21:02:00 +0200617 {
Bram Moolenaaraf610b82018-12-21 16:22:50 +0100618 /* Execute the uninstall program. Put it in double
619 * quotes if there is an embedded space. */
Bram Moolenaarb230bd52010-05-25 21:02:00 +0200620 {
Bram Moolenaaraf610b82018-12-21 16:22:50 +0100621 char buf[BUFSIZE];
622
623 if (strchr(temp_string_buffer, ' ') != NULL)
624 sprintf(buf, "\"%s\"", temp_string_buffer);
625 else
626 strcpy(buf, temp_string_buffer);
627 run_command(buf);
628 }
629
630 /* Count the number of windows with a title that match
631 * the installer, so that we can check when it's done.
632 * The uninstaller copies itself, executes the copy
633 * and exits, thus we can't wait for the process to
634 * finish. */
635 sleep(1); /* wait for uninstaller to start up */
636 num_windows = 0;
637 EnumWindows(window_cb, 0);
638 if (num_windows == 0)
639 {
640 /* Did not find the uninstaller, ask user to press
641 * Enter when done. Just in case. */
642 printf("Press Enter when the uninstaller is finished\n");
643 rewind(stdin);
644 (void)getchar();
645 }
646 else
647 {
648 printf("Waiting for the uninstaller to finish (press CTRL-C to abort).");
649 do
650 {
651 printf(".");
652 fflush(stdout);
653 sleep(1); /* wait for the uninstaller to finish */
654 num_windows = 0;
655 EnumWindows(window_cb, 0);
656 } while (num_windows > 0);
657 }
Bram Moolenaarb230bd52010-05-25 21:02:00 +0200658 }
659 printf("\nDone!\n");
Bram Moolenaar071d4272004-06-13 20:20:40 +0000660
Bram Moolenaarfff2bee2010-05-15 13:56:02 +0200661 /* Check if an uninstall reg key was deleted.
Bram Moolenaar071d4272004-06-13 20:20:40 +0000662 * if it was, we want to decrement key_index.
663 * if we don't do this, we will skip the key
664 * immediately after any key that we delete. */
665 RegQueryInfoKey(key_handle, NULL, NULL, NULL,
666 &new_num_keys, NULL, NULL, NULL,
667 NULL, NULL, NULL, NULL);
668 if (new_num_keys < orig_num_keys)
669 key_index--;
670
671 input = 'y';
672 break;
673
674 case 'n':
675 case 'N':
676 /* Do not uninstall */
677 input = 'n';
678 break;
679
680 default: /* just drop through and redo the loop */
681 break;
682 }
683
684 } while (input != 'n' && input != 'y');
685
686 RegCloseKey(uninstall_key_handle);
687 }
Bram Moolenaare4963c52019-02-22 19:41:08 +0100688
689 key_index++;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000690 }
691 RegCloseKey(key_handle);
692
693 return foundone;
694}
Bram Moolenaar071d4272004-06-13 20:20:40 +0000695
696/*
697 * Find out information about the system.
698 */
699 static void
700inspect_system(void)
701{
702 char *p;
703 char buf[BUFSIZE];
704 FILE *fd;
705 int i;
706 int foundone;
707
708 /* This may take a little while, let the user know what we're doing. */
709 printf("Inspecting system...\n");
710
711 /*
712 * If $VIM is set, check that it's pointing to our directory.
713 */
714 p = getenv("VIM");
715 if (p != NULL && pathcmp(p, -1, installdir, runtimeidx - 1) != 0)
716 {
717 printf("------------------------------------------------------\n");
718 printf("$VIM is set to \"%s\".\n", p);
719 printf("This is different from where this version of Vim is:\n");
720 strcpy(buf, installdir);
721 *(buf + runtimeidx - 1) = NUL;
722 printf("\"%s\"\n", buf);
723 printf("You must adjust or remove the setting of $VIM,\n");
724 if (interactive)
725 {
726 printf("to be able to use this install program.\n");
727 myexit(1);
728 }
729 printf("otherwise Vim WILL NOT WORK properly!\n");
730 printf("------------------------------------------------------\n");
731 }
732
733 /*
734 * If $VIMRUNTIME is set, check that it's pointing to our runtime directory.
735 */
736 p = getenv("VIMRUNTIME");
737 if (p != NULL && pathcmp(p, -1, installdir, -1) != 0)
738 {
739 printf("------------------------------------------------------\n");
740 printf("$VIMRUNTIME is set to \"%s\".\n", p);
741 printf("This is different from where this version of Vim is:\n");
742 printf("\"%s\"\n", installdir);
743 printf("You must adjust or remove the setting of $VIMRUNTIME,\n");
744 if (interactive)
745 {
746 printf("to be able to use this install program.\n");
747 myexit(1);
748 }
749 printf("otherwise Vim WILL NOT WORK properly!\n");
750 printf("------------------------------------------------------\n");
751 }
752
753 /*
754 * Check if there is a vim.[exe|bat|, gvim.[exe|bat|, etc. in the path.
755 */
756 find_bat_exe(FALSE);
757
758 /*
759 * A .exe in the install directory may be found anyway on Windows 2000.
760 * Check for this situation and find another executable if necessary.
761 * w.briscoe@ponl.com 2001-01-20
762 */
763 foundone = 0;
764 for (i = 1; i < TARGET_COUNT; ++i)
765 {
766 findoldfile(&(targets[i].oldexe));
767 if (targets[i].oldexe != NULL)
768 foundone = 1;
769 }
770
771 if (foundone)
772 {
773 printf("Warning: Found Vim executable(s) in your $PATH:\n");
774 for (i = 1; i < TARGET_COUNT; ++i)
775 if (targets[i].oldexe != NULL)
776 printf("%s\n", targets[i].oldexe);
777 printf("It will be used instead of the version you are installing.\n");
778 printf("Please delete or rename it, or adjust your $PATH setting.\n");
779 }
780
781 /*
782 * Check if there is an existing ../_vimrc or ../.vimrc file.
783 */
784 strcpy(oldvimrc, installdir);
785 strcpy(oldvimrc + runtimeidx, "_vimrc");
786 if ((fd = fopen(oldvimrc, "r")) == NULL)
787 {
788 strcpy(oldvimrc + runtimeidx, "vimrc~1"); /* short version of .vimrc */
789 if ((fd = fopen(oldvimrc, "r")) == NULL)
790 {
791 strcpy(oldvimrc + runtimeidx, ".vimrc");
792 fd = fopen(oldvimrc, "r");
793 }
794 }
795 if (fd != NULL)
796 fclose(fd);
797 else
798 *oldvimrc = NUL;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000799}
800
801/*
802 * Add a dummy choice to avoid that the numbering changes depending on items
803 * in the environment. The user may type a number he remembered without
804 * looking.
805 */
806 static void
807add_dummy_choice(void)
808{
809 choices[choice_count].installfunc = NULL;
810 choices[choice_count].active = 0;
811 choices[choice_count].changefunc = NULL;
Bram Moolenaar25a494c2018-11-16 19:39:50 +0100812 choices[choice_count].text = NULL;
813 choices[choice_count].arg = 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000814 ++choice_count;
815}
816
817/***********************************************
818 * stuff for creating the batch files.
819 */
820
821/*
822 * Install the vim.bat, gvim.bat, etc. files.
823 */
824 static void
825install_bat_choice(int idx)
826{
827 char *batpath = targets[choices[idx].arg].batpath;
828 char *oldname = targets[choices[idx].arg].oldbat;
829 char *exename = targets[choices[idx].arg].exenamearg;
830 char *vimarg = targets[choices[idx].arg].exearg;
831 FILE *fd;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000832
833 if (*batpath != NUL)
834 {
835 fd = fopen(batpath, "w");
836 if (fd == NULL)
837 printf("\nERROR: Cannot open \"%s\" for writing.\n", batpath);
838 else
839 {
840 need_uninstall_entry = 1;
841
842 fprintf(fd, "@echo off\n");
Bram Moolenaar97b2ad32006-03-18 21:40:56 +0000843 fprintf(fd, "rem -- Run Vim --\n");
844 fprintf(fd, "\n");
Bram Moolenaare609ad52016-03-28 23:05:48 +0200845 fprintf(fd, "setlocal\n");
Bram Moolenaar071d4272004-06-13 20:20:40 +0000846
Bram Moolenaar97b2ad32006-03-18 21:40:56 +0000847 /* Don't use double quotes for the "set" argument, also when it
Bram Moolenaar071d4272004-06-13 20:20:40 +0000848 * contains a space. The quotes would be included in the value
Bram Moolenaar97b2ad32006-03-18 21:40:56 +0000849 * for MSDOS and NT.
850 * The order of preference is:
851 * 1. $VIMRUNTIME/vim.exe (user preference)
Bram Moolenaarabab0b02019-03-30 18:47:01 +0100852 * 2. $VIM/vim81/vim.exe (hard coded version)
Bram Moolenaar97b2ad32006-03-18 21:40:56 +0000853 * 3. installdir/vim.exe (hard coded install directory)
854 */
855 fprintf(fd, "set VIM_EXE_DIR=%s\n", installdir);
856 fprintf(fd, "if exist \"%%VIM%%\\%s\\%s\" set VIM_EXE_DIR=%%VIM%%\\%s\n",
857 VIM_VERSION_NODOT, exename, VIM_VERSION_NODOT);
858 fprintf(fd, "if exist \"%%VIMRUNTIME%%\\%s\" set VIM_EXE_DIR=%%VIMRUNTIME%%\n", exename);
859 fprintf(fd, "\n");
Bram Moolenaar071d4272004-06-13 20:20:40 +0000860
861 /* Give an error message when the executable could not be found. */
Bram Moolenaar97b2ad32006-03-18 21:40:56 +0000862 fprintf(fd, "if exist \"%%VIM_EXE_DIR%%\\%s\" goto havevim\n",
863 exename);
864 fprintf(fd, "echo \"%%VIM_EXE_DIR%%\\%s\" not found\n", exename);
865 fprintf(fd, "goto eof\n");
866 fprintf(fd, "\n");
Bram Moolenaar071d4272004-06-13 20:20:40 +0000867 fprintf(fd, ":havevim\n");
868
869 fprintf(fd, "rem collect the arguments in VIMARGS for Win95\n");
870 fprintf(fd, "set VIMARGS=\n");
871 if (*exename == 'g')
872 fprintf(fd, "set VIMNOFORK=\n");
873 fprintf(fd, ":loopstart\n");
874 fprintf(fd, "if .%%1==. goto loopend\n");
875 if (*exename == 'g')
876 {
Bram Moolenaare609ad52016-03-28 23:05:48 +0200877 fprintf(fd, "if NOT .%%1==.--nofork goto noforklongarg\n");
878 fprintf(fd, "set VIMNOFORK=1\n");
879 fprintf(fd, ":noforklongarg\n");
Bram Moolenaar071d4272004-06-13 20:20:40 +0000880 fprintf(fd, "if NOT .%%1==.-f goto noforkarg\n");
881 fprintf(fd, "set VIMNOFORK=1\n");
882 fprintf(fd, ":noforkarg\n");
883 }
884 fprintf(fd, "set VIMARGS=%%VIMARGS%% %%1\n");
885 fprintf(fd, "shift\n");
Bram Moolenaar97b2ad32006-03-18 21:40:56 +0000886 fprintf(fd, "goto loopstart\n");
Bram Moolenaar071d4272004-06-13 20:20:40 +0000887 fprintf(fd, ":loopend\n");
Bram Moolenaar97b2ad32006-03-18 21:40:56 +0000888 fprintf(fd, "\n");
Bram Moolenaar071d4272004-06-13 20:20:40 +0000889
Bram Moolenaar97b2ad32006-03-18 21:40:56 +0000890 fprintf(fd, "if .%%OS%%==.Windows_NT goto ntaction\n");
891 fprintf(fd, "\n");
Bram Moolenaar071d4272004-06-13 20:20:40 +0000892
893 /* For gvim.exe use "start" to avoid that the console window stays
894 * open. */
895 if (*exename == 'g')
896 {
897 fprintf(fd, "if .%%VIMNOFORK%%==.1 goto nofork\n");
898 fprintf(fd, "start ");
899 }
900
Bram Moolenaar97b2ad32006-03-18 21:40:56 +0000901 /* Always use quotes, $VIM or $VIMRUNTIME might have a space. */
902 fprintf(fd, "\"%%VIM_EXE_DIR%%\\%s\" %s %%VIMARGS%%\n",
903 exename, vimarg);
904 fprintf(fd, "goto eof\n");
905 fprintf(fd, "\n");
Bram Moolenaar071d4272004-06-13 20:20:40 +0000906
907 if (*exename == 'g')
908 {
909 fprintf(fd, ":nofork\n");
910 fprintf(fd, "start /w ");
Bram Moolenaar97b2ad32006-03-18 21:40:56 +0000911 /* Always use quotes, $VIM or $VIMRUNTIME might have a space. */
912 fprintf(fd, "\"%%VIM_EXE_DIR%%\\%s\" %s %%VIMARGS%%\n",
913 exename, vimarg);
914 fprintf(fd, "goto eof\n");
915 fprintf(fd, "\n");
Bram Moolenaar071d4272004-06-13 20:20:40 +0000916 }
917
918 fprintf(fd, ":ntaction\n");
919 fprintf(fd, "rem for WinNT we can use %%*\n");
920
921 /* For gvim.exe use "start /b" to avoid that the console window
922 * stays open. */
923 if (*exename == 'g')
924 {
925 fprintf(fd, "if .%%VIMNOFORK%%==.1 goto noforknt\n");
926 fprintf(fd, "start \"dummy\" /b ");
927 }
928
Bram Moolenaar97b2ad32006-03-18 21:40:56 +0000929 /* Always use quotes, $VIM or $VIMRUNTIME might have a space. */
930 fprintf(fd, "\"%%VIM_EXE_DIR%%\\%s\" %s %%*\n", exename, vimarg);
931 fprintf(fd, "goto eof\n");
932 fprintf(fd, "\n");
Bram Moolenaar071d4272004-06-13 20:20:40 +0000933
934 if (*exename == 'g')
935 {
936 fprintf(fd, ":noforknt\n");
937 fprintf(fd, "start \"dummy\" /b /wait ");
Bram Moolenaar97b2ad32006-03-18 21:40:56 +0000938 /* Always use quotes, $VIM or $VIMRUNTIME might have a space. */
939 fprintf(fd, "\"%%VIM_EXE_DIR%%\\%s\" %s %%*\n",
940 exename, vimarg);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000941 }
942
943 fprintf(fd, "\n:eof\n");
944 fprintf(fd, "set VIMARGS=\n");
945 if (*exename == 'g')
946 fprintf(fd, "set VIMNOFORK=\n");
947
948 fclose(fd);
949 printf("%s has been %s\n", batpath,
950 oldname == NULL ? "created" : "overwritten");
951 }
952 }
953}
954
955/*
956 * Make the text string for choice "idx".
957 * The format "fmt" is must have one %s item, which "arg" is used for.
958 */
959 static void
960alloc_text(int idx, char *fmt, char *arg)
961{
962 if (choices[idx].text != NULL)
963 free(choices[idx].text);
964
965 choices[idx].text = alloc((int)(strlen(fmt) + strlen(arg)) - 1);
966 sprintf(choices[idx].text, fmt, arg);
967}
968
969/*
970 * Toggle the "Overwrite .../vim.bat" to "Don't overwrite".
971 */
972 static void
973toggle_bat_choice(int idx)
974{
975 char *batname = targets[choices[idx].arg].batpath;
976 char *oldname = targets[choices[idx].arg].oldbat;
977
978 if (*batname == NUL)
979 {
980 alloc_text(idx, " Overwrite %s", oldname);
981 strcpy(batname, oldname);
982 }
983 else
984 {
985 alloc_text(idx, " Do NOT overwrite %s", oldname);
986 *batname = NUL;
987 }
988}
989
990/*
991 * Do some work for a batch file entry: Append the batch file name to the path
992 * and set the text for the choice.
993 */
994 static void
995set_bat_text(int idx, char *batpath, char *name)
996{
997 strcat(batpath, name);
998
999 alloc_text(idx, " Create %s", batpath);
1000}
1001
1002/*
1003 * Select a directory to write the batch file line.
1004 */
1005 static void
1006change_bat_choice(int idx)
1007{
1008 char *path;
1009 char *batpath;
1010 char *name;
1011 int n;
1012 char *s;
1013 char *p;
1014 int count;
1015 char **names = NULL;
1016 int i;
1017 int target = choices[idx].arg;
1018
1019 name = targets[target].batname;
1020 batpath = targets[target].batpath;
1021
1022 path = getenv("PATH");
1023 if (path == NULL)
1024 {
1025 printf("\nERROR: The variable $PATH is not set\n");
1026 return;
1027 }
1028
1029 /*
1030 * first round: count number of names in path;
1031 * second round: save names to names[].
1032 */
1033 for (;;)
1034 {
1035 count = 1;
1036 for (p = path; *p; )
1037 {
1038 s = strchr(p, ';');
1039 if (s == NULL)
1040 s = p + strlen(p);
1041 if (names != NULL)
1042 {
1043 names[count] = alloc((int)(s - p) + 1);
1044 strncpy(names[count], p, s - p);
1045 names[count][s - p] = NUL;
1046 }
1047 ++count;
1048 p = s;
1049 if (*p != NUL)
1050 ++p;
1051 }
1052 if (names != NULL)
1053 break;
1054 names = alloc((int)(count + 1) * sizeof(char *));
1055 }
1056 names[0] = alloc(50);
1057 sprintf(names[0], "Select directory to create %s in:", name);
1058 names[count] = alloc(50);
1059 if (choices[idx].arg == 0)
1060 sprintf(names[count], "Do not create any .bat file.");
1061 else
1062 sprintf(names[count], "Do not create a %s file.", name);
1063 n = get_choice(names, count + 1);
1064
1065 if (n == count)
1066 {
1067 /* Selected last item, don't create bat file. */
1068 *batpath = NUL;
1069 if (choices[idx].arg != 0)
1070 alloc_text(idx, " Do NOT create %s", name);
1071 }
1072 else
1073 {
1074 /* Selected one of the paths. For the first item only keep the path,
1075 * for the others append the batch file name. */
1076 strcpy(batpath, names[n]);
1077 add_pathsep(batpath);
1078 if (choices[idx].arg != 0)
1079 set_bat_text(idx, batpath, name);
1080 }
1081
1082 for (i = 0; i <= count; ++i)
1083 free(names[i]);
1084 free(names);
1085}
1086
1087char *bat_text_yes = "Install .bat files to use Vim at the command line:";
1088char *bat_text_no = "do NOT install .bat files to use Vim at the command line";
1089
1090 static void
1091change_main_bat_choice(int idx)
1092{
1093 int i;
1094
1095 /* let the user select a default directory or NONE */
1096 change_bat_choice(idx);
1097
1098 if (targets[0].batpath[0] != NUL)
1099 choices[idx].text = bat_text_yes;
1100 else
1101 choices[idx].text = bat_text_no;
1102
1103 /* update the individual batch file selections */
1104 for (i = 1; i < TARGET_COUNT; ++i)
1105 {
1106 /* Only make it active when the first item has a path and the vim.exe
1107 * or gvim.exe exists (there is a changefunc then). */
1108 if (targets[0].batpath[0] != NUL
1109 && choices[idx + i].changefunc != NULL)
1110 {
1111 choices[idx + i].active = 1;
1112 if (choices[idx + i].changefunc == change_bat_choice
1113 && targets[i].batpath[0] != NUL)
1114 {
1115 strcpy(targets[i].batpath, targets[0].batpath);
1116 set_bat_text(idx + i, targets[i].batpath, targets[i].batname);
1117 }
1118 }
1119 else
1120 choices[idx + i].active = 0;
1121 }
1122}
1123
1124/*
1125 * Initialize a choice for creating a batch file.
1126 */
1127 static void
1128init_bat_choice(int target)
1129{
1130 char *batpath = targets[target].batpath;
1131 char *oldbat = targets[target].oldbat;
1132 char *p;
1133 int i;
1134
1135 choices[choice_count].arg = target;
1136 choices[choice_count].installfunc = install_bat_choice;
1137 choices[choice_count].active = 1;
1138 choices[choice_count].text = NULL; /* will be set below */
1139 if (oldbat != NULL)
1140 {
1141 /* A [g]vim.bat exists: Only choice is to overwrite it or not. */
1142 choices[choice_count].changefunc = toggle_bat_choice;
1143 *batpath = NUL;
1144 toggle_bat_choice(choice_count);
1145 }
1146 else
1147 {
1148 if (default_bat_dir != NULL)
1149 /* Prefer using the same path as an existing .bat file. */
1150 strcpy(batpath, default_bat_dir);
1151 else
1152 {
1153 /* No [g]vim.bat exists: Write it to a directory in $PATH. Use
1154 * $WINDIR by default, if it's empty the first item in $PATH. */
1155 p = getenv("WINDIR");
1156 if (p != NULL && *p != NUL)
1157 strcpy(batpath, p);
1158 else
1159 {
1160 p = getenv("PATH");
1161 if (p == NULL || *p == NUL) /* "cannot happen" */
1162 strcpy(batpath, "C:/Windows");
1163 else
1164 {
1165 i = 0;
1166 while (*p != NUL && *p != ';')
1167 batpath[i++] = *p++;
1168 batpath[i] = NUL;
1169 }
1170 }
1171 }
1172 add_pathsep(batpath);
1173 set_bat_text(choice_count, batpath, targets[target].batname);
1174
1175 choices[choice_count].changefunc = change_bat_choice;
1176 }
1177 ++choice_count;
1178}
1179
1180/*
1181 * Set up the choices for installing .bat files.
1182 * For these items "arg" is the index in targets[].
1183 */
1184 static void
1185init_bat_choices(void)
1186{
1187 int i;
1188
1189 /* The first item is used to switch installing batch files on/off and
1190 * setting the default path. */
1191 choices[choice_count].text = bat_text_yes;
1192 choices[choice_count].changefunc = change_main_bat_choice;
1193 choices[choice_count].installfunc = NULL;
1194 choices[choice_count].active = 1;
1195 choices[choice_count].arg = 0;
1196 ++choice_count;
1197
1198 /* Add items for each batch file target. Only used when not disabled by
1199 * the first item. When a .exe exists, don't offer to create a .bat. */
1200 for (i = 1; i < TARGET_COUNT; ++i)
1201 if (targets[i].oldexe == NULL
1202 && (targets[i].exenamearg[0] == 'g' ? has_gvim : has_vim))
1203 init_bat_choice(i);
1204 else
1205 add_dummy_choice();
1206}
1207
1208/*
1209 * Install the vimrc file.
1210 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001211 static void
1212install_vimrc(int idx)
1213{
1214 FILE *fd, *tfd;
1215 char *fname;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001216
1217 /* If an old vimrc file exists, overwrite it.
1218 * Otherwise create a new one. */
1219 if (*oldvimrc != NUL)
1220 fname = oldvimrc;
1221 else
1222 fname = vimrc;
1223
1224 fd = fopen(fname, "w");
1225 if (fd == NULL)
1226 {
1227 printf("\nERROR: Cannot open \"%s\" for writing.\n", fname);
1228 return;
1229 }
1230 switch (compat_choice)
1231 {
1232 case compat_vi:
Bram Moolenaar6cdb2c92018-10-13 17:25:27 +02001233 fprintf(fd, "\" Vi compatible\n");
Bram Moolenaar071d4272004-06-13 20:20:40 +00001234 fprintf(fd, "set compatible\n");
1235 break;
Bram Moolenaar6cdb2c92018-10-13 17:25:27 +02001236 case compat_vim:
1237 fprintf(fd, "\" Vim's default behavior\n");
1238 fprintf(fd, "if &compatible\n");
1239 fprintf(fd, " set nocompatible\n");
1240 fprintf(fd, "endif\n");
1241 break;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001242 case compat_some_enhancements:
Bram Moolenaar6cdb2c92018-10-13 17:25:27 +02001243 fprintf(fd, "\" Vim with some enhancements\n");
Bram Moolenaarc73e4472016-07-29 18:33:38 +02001244 fprintf(fd, "source $VIMRUNTIME/defaults.vim\n");
Bram Moolenaar071d4272004-06-13 20:20:40 +00001245 break;
1246 case compat_all_enhancements:
Bram Moolenaar6cdb2c92018-10-13 17:25:27 +02001247 fprintf(fd, "\" Vim with all enhancements\n");
Bram Moolenaar071d4272004-06-13 20:20:40 +00001248 fprintf(fd, "source $VIMRUNTIME/vimrc_example.vim\n");
1249 break;
1250 }
1251 switch (remap_choice)
1252 {
1253 case remap_no:
1254 break;
1255 case remap_win:
Bram Moolenaar6cdb2c92018-10-13 17:25:27 +02001256 fprintf(fd, "\n");
1257 fprintf(fd, "\" Remap a few keys for Windows behavior\n");
Bram Moolenaar071d4272004-06-13 20:20:40 +00001258 fprintf(fd, "source $VIMRUNTIME/mswin.vim\n");
1259 break;
1260 }
1261 switch (mouse_choice)
1262 {
1263 case mouse_xterm:
Bram Moolenaar6cdb2c92018-10-13 17:25:27 +02001264 fprintf(fd, "\n");
1265 fprintf(fd, "\" Mouse behavior (the Unix way)\n");
Bram Moolenaar071d4272004-06-13 20:20:40 +00001266 fprintf(fd, "behave xterm\n");
1267 break;
1268 case mouse_mswin:
Bram Moolenaar6cdb2c92018-10-13 17:25:27 +02001269 fprintf(fd, "\n");
1270 fprintf(fd, "\" Mouse behavior (the Windows way)\n");
Bram Moolenaar071d4272004-06-13 20:20:40 +00001271 fprintf(fd, "behave mswin\n");
1272 break;
Bram Moolenaarc3fdf7f2017-10-28 18:36:48 +02001273 case mouse_default:
1274 break;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001275 }
1276 if ((tfd = fopen("diff.exe", "r")) != NULL)
1277 {
1278 /* Use the diff.exe that comes with the self-extracting gvim.exe. */
1279 fclose(tfd);
1280 fprintf(fd, "\n");
Bram Moolenaar6cdb2c92018-10-13 17:25:27 +02001281 fprintf(fd, "\" Use the internal diff if available.\n");
1282 fprintf(fd, "\" Otherwise use the special 'diffexpr' for Windows.\n");
1283 fprintf(fd, "if &diffopt !~# 'internal'\n");
1284 fprintf(fd, " set diffexpr=MyDiff()\n");
1285 fprintf(fd, "endif\n");
Bram Moolenaar071d4272004-06-13 20:20:40 +00001286 fprintf(fd, "function MyDiff()\n");
1287 fprintf(fd, " let opt = '-a --binary '\n");
1288 fprintf(fd, " if &diffopt =~ 'icase' | let opt = opt . '-i ' | endif\n");
1289 fprintf(fd, " if &diffopt =~ 'iwhite' | let opt = opt . '-b ' | endif\n");
Bram Moolenaar12365ce2018-05-13 14:45:25 +02001290 /* Use quotes only when needed, they may cause trouble.
1291 * Always escape "!". */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001292 fprintf(fd, " let arg1 = v:fname_in\n");
1293 fprintf(fd, " if arg1 =~ ' ' | let arg1 = '\"' . arg1 . '\"' | endif\n");
Bram Moolenaar12365ce2018-05-13 14:45:25 +02001294 fprintf(fd, " let arg1 = substitute(arg1, '!', '\\!', 'g')\n");
Bram Moolenaar071d4272004-06-13 20:20:40 +00001295 fprintf(fd, " let arg2 = v:fname_new\n");
1296 fprintf(fd, " if arg2 =~ ' ' | let arg2 = '\"' . arg2 . '\"' | endif\n");
Bram Moolenaar12365ce2018-05-13 14:45:25 +02001297 fprintf(fd, " let arg2 = substitute(arg2, '!', '\\!', 'g')\n");
Bram Moolenaar071d4272004-06-13 20:20:40 +00001298 fprintf(fd, " let arg3 = v:fname_out\n");
1299 fprintf(fd, " if arg3 =~ ' ' | let arg3 = '\"' . arg3 . '\"' | endif\n");
Bram Moolenaar12365ce2018-05-13 14:45:25 +02001300 fprintf(fd, " let arg3 = substitute(arg3, '!', '\\!', 'g')\n");
Bram Moolenaar33aec762006-01-22 23:30:12 +00001301
1302 /* If the path has a space: When using cmd.exe (Win NT/2000/XP) put
Bram Moolenaarc62a6442013-11-21 18:13:37 +01001303 * quotes around the diff command and rely on the default value of
Bram Moolenaar792f0e32018-02-27 17:27:13 +01001304 * shellxquote to solve the quoting problem for the whole command.
1305 *
Bram Moolenaar33aec762006-01-22 23:30:12 +00001306 * Otherwise put a double quote just before the space and at the
1307 * end of the command. Putting quotes around the whole thing
1308 * doesn't work on Win 95/98/ME. This is mostly guessed! */
Bram Moolenaar33aec762006-01-22 23:30:12 +00001309 fprintf(fd, " if $VIMRUNTIME =~ ' '\n");
1310 fprintf(fd, " if &sh =~ '\\<cmd'\n");
Bram Moolenaarc62a6442013-11-21 18:13:37 +01001311 fprintf(fd, " if empty(&shellxquote)\n");
1312 fprintf(fd, " let l:shxq_sav = ''\n");
1313 fprintf(fd, " set shellxquote&\n");
1314 fprintf(fd, " endif\n");
1315 fprintf(fd, " let cmd = '\"' . $VIMRUNTIME . '\\diff\"'\n");
Bram Moolenaar33aec762006-01-22 23:30:12 +00001316 fprintf(fd, " else\n");
1317 fprintf(fd, " let cmd = substitute($VIMRUNTIME, ' ', '\" ', '') . '\\diff\"'\n");
1318 fprintf(fd, " endif\n");
1319 fprintf(fd, " else\n");
1320 fprintf(fd, " let cmd = $VIMRUNTIME . '\\diff'\n");
1321 fprintf(fd, " endif\n");
Bram Moolenaar12365ce2018-05-13 14:45:25 +02001322 fprintf(fd, " let cmd = substitute(cmd, '!', '\\!', 'g')\n");
Bram Moolenaarc62a6442013-11-21 18:13:37 +01001323 fprintf(fd, " silent execute '!' . cmd . ' ' . opt . arg1 . ' ' . arg2 . ' > ' . arg3\n");
1324 fprintf(fd, " if exists('l:shxq_sav')\n");
1325 fprintf(fd, " let &shellxquote=l:shxq_sav\n");
1326 fprintf(fd, " endif\n");
Bram Moolenaar071d4272004-06-13 20:20:40 +00001327 fprintf(fd, "endfunction\n");
1328 fprintf(fd, "\n");
1329 }
1330 fclose(fd);
1331 printf("%s has been written\n", fname);
1332}
1333
1334 static void
1335change_vimrc_choice(int idx)
1336{
1337 if (choices[idx].installfunc != NULL)
1338 {
1339 /* Switch to NOT change or create a vimrc file. */
1340 if (*oldvimrc != NUL)
1341 alloc_text(idx, "Do NOT change startup file %s", oldvimrc);
1342 else
1343 alloc_text(idx, "Do NOT create startup file %s", vimrc);
1344 choices[idx].installfunc = NULL;
1345 choices[idx + 1].active = 0;
1346 choices[idx + 2].active = 0;
1347 choices[idx + 3].active = 0;
1348 }
1349 else
1350 {
1351 /* Switch to change or create a vimrc file. */
1352 if (*oldvimrc != NUL)
1353 alloc_text(idx, "Overwrite startup file %s with:", oldvimrc);
1354 else
1355 alloc_text(idx, "Create startup file %s with:", vimrc);
1356 choices[idx].installfunc = install_vimrc;
1357 choices[idx + 1].active = 1;
1358 choices[idx + 2].active = 1;
1359 choices[idx + 3].active = 1;
1360 }
1361}
1362
1363/*
1364 * Change the choice how to run Vim.
1365 */
1366 static void
1367change_run_choice(int idx)
1368{
1369 compat_choice = get_choice(compat_choices, TABLE_SIZE(compat_choices));
1370 alloc_text(idx, compat_text, compat_choices[compat_choice]);
1371}
1372
1373/*
1374 * Change the choice if keys are to be remapped.
1375 */
1376 static void
1377change_remap_choice(int idx)
1378{
1379 remap_choice = get_choice(remap_choices, TABLE_SIZE(remap_choices));
1380 alloc_text(idx, remap_text, remap_choices[remap_choice]);
1381}
1382
1383/*
1384 * Change the choice how to select text.
1385 */
1386 static void
1387change_mouse_choice(int idx)
1388{
1389 mouse_choice = get_choice(mouse_choices, TABLE_SIZE(mouse_choices));
1390 alloc_text(idx, mouse_text, mouse_choices[mouse_choice]);
1391}
1392
1393 static void
1394init_vimrc_choices(void)
1395{
1396 /* set path for a new _vimrc file (also when not used) */
1397 strcpy(vimrc, installdir);
1398 strcpy(vimrc + runtimeidx, "_vimrc");
1399
1400 /* Set opposite value and then toggle it by calling change_vimrc_choice() */
1401 if (*oldvimrc == NUL)
1402 choices[choice_count].installfunc = NULL;
1403 else
1404 choices[choice_count].installfunc = install_vimrc;
1405 choices[choice_count].text = NULL;
1406 change_vimrc_choice(choice_count);
1407 choices[choice_count].changefunc = change_vimrc_choice;
1408 choices[choice_count].active = 1;
1409 ++choice_count;
1410
1411 /* default way to run Vim */
1412 alloc_text(choice_count, compat_text, compat_choices[compat_choice]);
1413 choices[choice_count].changefunc = change_run_choice;
1414 choices[choice_count].installfunc = NULL;
1415 choices[choice_count].active = (*oldvimrc == NUL);
1416 ++choice_count;
1417
1418 /* Whether to remap keys */
1419 alloc_text(choice_count, remap_text , remap_choices[remap_choice]);
1420 choices[choice_count].changefunc = change_remap_choice;
Bram Moolenaar945ec092016-06-08 21:17:43 +02001421 choices[choice_count].installfunc = NULL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001422 choices[choice_count].active = (*oldvimrc == NUL);
1423 ++choice_count;
1424
1425 /* default way to use the mouse */
1426 alloc_text(choice_count, mouse_text, mouse_choices[mouse_choice]);
1427 choices[choice_count].changefunc = change_mouse_choice;
Bram Moolenaar945ec092016-06-08 21:17:43 +02001428 choices[choice_count].installfunc = NULL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001429 choices[choice_count].active = (*oldvimrc == NUL);
1430 ++choice_count;
1431}
1432
Bram Moolenaarccd9ccf2010-07-07 13:19:55 +02001433 static LONG
1434reg_create_key(
1435 HKEY root,
1436 const char *subkey,
Bram Moolenaar6199d432017-10-14 19:05:44 +02001437 PHKEY phKey,
1438 DWORD flag)
Bram Moolenaarccd9ccf2010-07-07 13:19:55 +02001439{
1440 DWORD disp;
1441
1442 *phKey = NULL;
1443 return RegCreateKeyEx(
Bram Moolenaarcc448b32010-07-14 16:52:17 +02001444 root, subkey,
1445 0, NULL, REG_OPTION_NON_VOLATILE,
Bram Moolenaar6199d432017-10-14 19:05:44 +02001446 flag | KEY_WRITE,
Bram Moolenaarcc448b32010-07-14 16:52:17 +02001447 NULL, phKey, &disp);
Bram Moolenaarccd9ccf2010-07-07 13:19:55 +02001448}
1449
1450 static LONG
1451reg_set_string_value(
1452 HKEY hKey,
1453 const char *value_name,
1454 const char *data)
1455{
1456 return RegSetValueEx(hKey, value_name, 0, REG_SZ,
1457 (LPBYTE)data, (DWORD)(1 + strlen(data)));
1458}
1459
1460 static LONG
1461reg_create_key_and_value(
1462 HKEY hRootKey,
1463 const char *subkey,
1464 const char *value_name,
Bram Moolenaar6199d432017-10-14 19:05:44 +02001465 const char *data,
1466 DWORD flag)
Bram Moolenaarccd9ccf2010-07-07 13:19:55 +02001467{
1468 HKEY hKey;
Bram Moolenaar6199d432017-10-14 19:05:44 +02001469 LONG lRet = reg_create_key(hRootKey, subkey, &hKey, flag);
Bram Moolenaarccd9ccf2010-07-07 13:19:55 +02001470
1471 if (ERROR_SUCCESS == lRet)
1472 {
Bram Moolenaarcc448b32010-07-14 16:52:17 +02001473 lRet = reg_set_string_value(hKey, value_name, data);
1474 RegCloseKey(hKey);
Bram Moolenaarccd9ccf2010-07-07 13:19:55 +02001475 }
1476 return lRet;
1477}
1478
1479 static LONG
1480register_inproc_server(
1481 HKEY hRootKey,
1482 const char *clsid,
1483 const char *extname,
1484 const char *module,
Bram Moolenaar6199d432017-10-14 19:05:44 +02001485 const char *threading_model,
1486 DWORD flag)
Bram Moolenaarccd9ccf2010-07-07 13:19:55 +02001487{
1488 CHAR subkey[BUFSIZE];
1489 LONG lRet;
1490
1491 sprintf(subkey, "CLSID\\%s", clsid);
Bram Moolenaar6199d432017-10-14 19:05:44 +02001492 lRet = reg_create_key_and_value(hRootKey, subkey, NULL, extname, flag);
Bram Moolenaarccd9ccf2010-07-07 13:19:55 +02001493 if (ERROR_SUCCESS == lRet)
1494 {
Bram Moolenaarcc448b32010-07-14 16:52:17 +02001495 sprintf(subkey, "CLSID\\%s\\InProcServer32", clsid);
Bram Moolenaar6199d432017-10-14 19:05:44 +02001496 lRet = reg_create_key_and_value(hRootKey, subkey, NULL, module, flag);
Bram Moolenaarcc448b32010-07-14 16:52:17 +02001497 if (ERROR_SUCCESS == lRet)
1498 {
1499 lRet = reg_create_key_and_value(hRootKey, subkey,
Bram Moolenaar6199d432017-10-14 19:05:44 +02001500 "ThreadingModel", threading_model, flag);
Bram Moolenaarcc448b32010-07-14 16:52:17 +02001501 }
Bram Moolenaarccd9ccf2010-07-07 13:19:55 +02001502 }
1503 return lRet;
1504}
1505
1506 static LONG
1507register_shellex(
1508 HKEY hRootKey,
1509 const char *clsid,
1510 const char *name,
Bram Moolenaar6199d432017-10-14 19:05:44 +02001511 const char *exe_path,
1512 DWORD flag)
Bram Moolenaarccd9ccf2010-07-07 13:19:55 +02001513{
1514 LONG lRet = reg_create_key_and_value(
Bram Moolenaarcc448b32010-07-14 16:52:17 +02001515 hRootKey,
1516 "*\\shellex\\ContextMenuHandlers\\gvim",
1517 NULL,
Bram Moolenaar6199d432017-10-14 19:05:44 +02001518 clsid,
1519 flag);
Bram Moolenaarccd9ccf2010-07-07 13:19:55 +02001520
1521 if (ERROR_SUCCESS == lRet)
1522 {
Bram Moolenaarcc448b32010-07-14 16:52:17 +02001523 lRet = reg_create_key_and_value(
1524 HKEY_LOCAL_MACHINE,
1525 "Software\\Microsoft\\Windows\\CurrentVersion\\Shell Extensions\\Approved",
1526 clsid,
Bram Moolenaar6199d432017-10-14 19:05:44 +02001527 name,
1528 flag);
Bram Moolenaarccd9ccf2010-07-07 13:19:55 +02001529
Bram Moolenaarcc448b32010-07-14 16:52:17 +02001530 if (ERROR_SUCCESS == lRet)
1531 {
1532 lRet = reg_create_key_and_value(
1533 HKEY_LOCAL_MACHINE,
1534 "Software\\Vim\\Gvim",
1535 "path",
Bram Moolenaar6199d432017-10-14 19:05:44 +02001536 exe_path,
1537 flag);
Bram Moolenaarcc448b32010-07-14 16:52:17 +02001538 }
Bram Moolenaarccd9ccf2010-07-07 13:19:55 +02001539 }
1540 return lRet;
1541}
1542
1543 static LONG
1544register_openwith(
1545 HKEY hRootKey,
Bram Moolenaar6199d432017-10-14 19:05:44 +02001546 const char *exe_path,
1547 DWORD flag)
Bram Moolenaarccd9ccf2010-07-07 13:19:55 +02001548{
Bram Moolenaar78050042010-07-31 20:53:54 +02001549 char exe_cmd[BUFSIZE];
1550 LONG lRet;
1551
Bram Moolenaarbbdcb482010-08-02 20:45:27 +02001552 sprintf(exe_cmd, "\"%s\" \"%%1\"", exe_path);
Bram Moolenaar78050042010-07-31 20:53:54 +02001553 lRet = reg_create_key_and_value(
Bram Moolenaarcc448b32010-07-14 16:52:17 +02001554 hRootKey,
1555 "Applications\\gvim.exe\\shell\\edit\\command",
1556 NULL,
Bram Moolenaar6199d432017-10-14 19:05:44 +02001557 exe_cmd,
1558 flag);
Bram Moolenaarccd9ccf2010-07-07 13:19:55 +02001559
1560 if (ERROR_SUCCESS == lRet)
1561 {
Bram Moolenaarcc448b32010-07-14 16:52:17 +02001562 int i;
1563 static const char *openwith[] = {
1564 ".htm\\OpenWithList\\gvim.exe",
1565 ".vim\\OpenWithList\\gvim.exe",
1566 "*\\OpenWithList\\gvim.exe",
1567 };
Bram Moolenaarccd9ccf2010-07-07 13:19:55 +02001568
Bram Moolenaarcc448b32010-07-14 16:52:17 +02001569 for (i = 0; ERROR_SUCCESS == lRet
Bram Moolenaarccd9ccf2010-07-07 13:19:55 +02001570 && i < sizeof(openwith) / sizeof(openwith[0]); i++)
Bram Moolenaar6199d432017-10-14 19:05:44 +02001571 lRet = reg_create_key_and_value(hRootKey, openwith[i], NULL, "", flag);
Bram Moolenaarccd9ccf2010-07-07 13:19:55 +02001572 }
1573
1574 return lRet;
1575}
1576
1577 static LONG
1578register_uninstall(
1579 HKEY hRootKey,
1580 const char *appname,
1581 const char *display_name,
Bram Moolenaar6cdb2c92018-10-13 17:25:27 +02001582 const char *uninstall_string,
1583 const char *display_icon,
1584 const char *display_version,
1585 const char *publisher)
Bram Moolenaarccd9ccf2010-07-07 13:19:55 +02001586{
1587 LONG lRet = reg_create_key_and_value(hRootKey, appname,
Bram Moolenaar6199d432017-10-14 19:05:44 +02001588 "DisplayName", display_name, KEY_WOW64_64KEY);
Bram Moolenaarccd9ccf2010-07-07 13:19:55 +02001589
1590 if (ERROR_SUCCESS == lRet)
Bram Moolenaarcc448b32010-07-14 16:52:17 +02001591 lRet = reg_create_key_and_value(hRootKey, appname,
Bram Moolenaar6199d432017-10-14 19:05:44 +02001592 "UninstallString", uninstall_string, KEY_WOW64_64KEY);
Bram Moolenaar6cdb2c92018-10-13 17:25:27 +02001593 if (ERROR_SUCCESS == lRet)
1594 lRet = reg_create_key_and_value(hRootKey, appname,
1595 "DisplayIcon", display_icon, KEY_WOW64_64KEY);
1596 if (ERROR_SUCCESS == lRet)
1597 lRet = reg_create_key_and_value(hRootKey, appname,
1598 "DisplayVersion", display_version, KEY_WOW64_64KEY);
1599 if (ERROR_SUCCESS == lRet)
1600 lRet = reg_create_key_and_value(hRootKey, appname,
1601 "Publisher", publisher, KEY_WOW64_64KEY);
Bram Moolenaarccd9ccf2010-07-07 13:19:55 +02001602 return lRet;
1603}
Bram Moolenaarccd9ccf2010-07-07 13:19:55 +02001604
Bram Moolenaar071d4272004-06-13 20:20:40 +00001605/*
1606 * Add some entries to the registry:
1607 * - to add "Edit with Vim" to the context * menu
1608 * - to add Vim to the "Open with..." list
1609 * - to uninstall Vim
1610 */
1611/*ARGSUSED*/
Bram Moolenaarab8205e2010-07-07 15:14:03 +02001612 static int
Bram Moolenaar071d4272004-06-13 20:20:40 +00001613install_registry(void)
1614{
Bram Moolenaarcc448b32010-07-14 16:52:17 +02001615 LONG lRet = ERROR_SUCCESS;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001616 const char *vim_ext_ThreadingModel = "Apartment";
1617 const char *vim_ext_name = "Vim Shell Extension";
1618 const char *vim_ext_clsid = "{51EEE242-AD87-11d3-9C1E-0090278BBD99}";
Bram Moolenaarbbd854d2019-02-18 22:19:33 +01001619 char vim_exe_path[MAX_PATH];
Bram Moolenaarcc448b32010-07-14 16:52:17 +02001620 char display_name[BUFSIZE];
1621 char uninstall_string[BUFSIZE];
Bram Moolenaar6cdb2c92018-10-13 17:25:27 +02001622 char icon_string[BUFSIZE];
Bram Moolenaar6199d432017-10-14 19:05:44 +02001623 int i;
1624 int loop_count = is_64bit_os() ? 2 : 1;
1625 DWORD flag;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001626
Bram Moolenaarccd9ccf2010-07-07 13:19:55 +02001627 sprintf(vim_exe_path, "%s\\gvim.exe", installdir);
1628
1629 if (install_popup)
1630 {
Bram Moolenaarcc448b32010-07-14 16:52:17 +02001631 char bufg[BUFSIZE];
Bram Moolenaarccd9ccf2010-07-07 13:19:55 +02001632
Bram Moolenaarcc448b32010-07-14 16:52:17 +02001633 printf("Creating \"Edit with Vim\" popup menu entry\n");
Bram Moolenaarccd9ccf2010-07-07 13:19:55 +02001634
Bram Moolenaar6199d432017-10-14 19:05:44 +02001635 for (i = 0; i < loop_count; i++)
1636 {
1637 if (i == 0)
1638 {
1639 sprintf(bufg, "%s\\" GVIMEXT32_PATH, installdir);
1640 flag = KEY_WOW64_32KEY;
1641 }
1642 else
1643 {
1644 sprintf(bufg, "%s\\" GVIMEXT64_PATH, installdir);
1645 flag = KEY_WOW64_64KEY;
1646 }
1647
1648 lRet = register_inproc_server(
1649 HKEY_CLASSES_ROOT, vim_ext_clsid, vim_ext_name,
1650 bufg, vim_ext_ThreadingModel, flag);
1651 if (ERROR_SUCCESS != lRet)
1652 return FAIL;
1653 lRet = register_shellex(
1654 HKEY_CLASSES_ROOT, vim_ext_clsid, vim_ext_name,
1655 vim_exe_path, flag);
1656 if (ERROR_SUCCESS != lRet)
1657 return FAIL;
1658 }
Bram Moolenaarccd9ccf2010-07-07 13:19:55 +02001659 }
1660
1661 if (install_openwith)
1662 {
Bram Moolenaarcc448b32010-07-14 16:52:17 +02001663 printf("Creating \"Open with ...\" list entry\n");
Bram Moolenaarccd9ccf2010-07-07 13:19:55 +02001664
Bram Moolenaar6199d432017-10-14 19:05:44 +02001665 for (i = 0; i < loop_count; i++)
1666 {
1667 if (i == 0)
1668 flag = KEY_WOW64_32KEY;
1669 else
1670 flag = KEY_WOW64_64KEY;
1671
1672 lRet = register_openwith(HKEY_CLASSES_ROOT, vim_exe_path, flag);
1673 if (ERROR_SUCCESS != lRet)
1674 return FAIL;
1675 }
Bram Moolenaarccd9ccf2010-07-07 13:19:55 +02001676 }
1677
1678 printf("Creating an uninstall entry\n");
Bram Moolenaaraf610b82018-12-21 16:22:50 +01001679 sprintf(display_name, "Vim " VIM_VERSION_SHORT
Bram Moolenaar577fadf2019-04-04 20:32:24 +02001680#ifdef _M_ARM64
1681 " (arm64)"
1682#elif _M_X64
Bram Moolenaaraf610b82018-12-21 16:22:50 +01001683 " (x64)"
1684#endif
1685 );
Bram Moolenaarccd9ccf2010-07-07 13:19:55 +02001686
1687 /* For the NSIS installer use the generated uninstaller. */
1688 if (interactive)
Bram Moolenaar16d79a32010-07-18 22:33:56 +02001689 sprintf(uninstall_string, "%s\\uninstal.exe", installdir);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001690 else
Bram Moolenaar16d79a32010-07-18 22:33:56 +02001691 sprintf(uninstall_string, "%s\\uninstall-gui.exe", installdir);
Bram Moolenaarccd9ccf2010-07-07 13:19:55 +02001692
Bram Moolenaar6cdb2c92018-10-13 17:25:27 +02001693 sprintf(icon_string, "%s\\gvim.exe,0", installdir);
1694
Bram Moolenaarccd9ccf2010-07-07 13:19:55 +02001695 lRet = register_uninstall(
Bram Moolenaarcc448b32010-07-14 16:52:17 +02001696 HKEY_LOCAL_MACHINE,
1697 "Software\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\Vim " VIM_VERSION_SHORT,
1698 display_name,
Bram Moolenaar6cdb2c92018-10-13 17:25:27 +02001699 uninstall_string,
1700 icon_string,
1701 VIM_VERSION_SHORT,
1702 "Bram Moolenaar et al.");
Bram Moolenaarab8205e2010-07-07 15:14:03 +02001703 if (ERROR_SUCCESS != lRet)
1704 return FAIL;
Bram Moolenaarccd9ccf2010-07-07 13:19:55 +02001705
Bram Moolenaarab8205e2010-07-07 15:14:03 +02001706 return OK;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001707}
1708
1709 static void
1710change_popup_choice(int idx)
1711{
1712 if (install_popup == 0)
1713 {
1714 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";
1715 install_popup = 1;
1716 }
1717 else
1718 {
1719 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";
1720 install_popup = 0;
1721 }
1722}
1723
1724/*
1725 * Only add the choice for the popup menu entry when gvim.exe was found and
1726 * both gvimext.dll and regedit.exe exist.
1727 */
1728 static void
1729init_popup_choice(void)
1730{
1731 struct stat st;
1732
1733 if (has_gvim
Bram Moolenaar6199d432017-10-14 19:05:44 +02001734 && (stat(GVIMEXT32_PATH, &st) >= 0
1735 || stat(GVIMEXT64_PATH, &st) >= 0))
Bram Moolenaar071d4272004-06-13 20:20:40 +00001736 {
1737 choices[choice_count].changefunc = change_popup_choice;
1738 choices[choice_count].installfunc = NULL;
1739 choices[choice_count].active = 1;
1740 change_popup_choice(choice_count); /* set the text */
1741 ++choice_count;
1742 }
1743 else
1744 add_dummy_choice();
1745}
1746
1747 static void
1748change_openwith_choice(int idx)
1749{
1750 if (install_openwith == 0)
1751 {
1752 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";
1753 install_openwith = 1;
1754 }
1755 else
1756 {
1757 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";
1758 install_openwith = 0;
1759 }
1760}
1761
1762/*
1763 * Only add the choice for the open-with menu entry when gvim.exe was found
Bram Moolenaar84a05ac2013-05-06 04:24:17 +02001764 * and regedit.exe exist.
Bram Moolenaar071d4272004-06-13 20:20:40 +00001765 */
1766 static void
1767init_openwith_choice(void)
1768{
Bram Moolenaar6199d432017-10-14 19:05:44 +02001769 if (has_gvim)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001770 {
1771 choices[choice_count].changefunc = change_openwith_choice;
1772 choices[choice_count].installfunc = NULL;
1773 choices[choice_count].active = 1;
1774 change_openwith_choice(choice_count); /* set the text */
1775 ++choice_count;
1776 }
1777 else
1778 add_dummy_choice();
1779}
1780
Bram Moolenaar071d4272004-06-13 20:20:40 +00001781/* create_shortcut
1782 *
1783 * Create a shell link.
1784 *
1785 * returns 0 on failure, non-zero on successful completion.
1786 *
1787 * NOTE: Currently untested with mingw.
1788 */
1789 int
1790create_shortcut(
1791 const char *shortcut_name,
1792 const char *iconfile_path,
1793 int iconindex,
1794 const char *shortcut_target,
1795 const char *shortcut_args,
1796 const char *workingdir
1797 )
1798{
1799 IShellLink *shelllink_ptr;
1800 HRESULT hres;
1801 IPersistFile *persistfile_ptr;
1802
1803 /* Initialize COM library */
1804 hres = CoInitialize(NULL);
1805 if (!SUCCEEDED(hres))
1806 {
1807 printf("Error: Could not open the COM library. Not creating shortcut.\n");
1808 return FAIL;
1809 }
1810
1811 /* Instantiate a COM object for the ShellLink, store a pointer to it
1812 * in shelllink_ptr. */
1813 hres = CoCreateInstance(&CLSID_ShellLink,
1814 NULL,
1815 CLSCTX_INPROC_SERVER,
1816 &IID_IShellLink,
1817 (void **) &shelllink_ptr);
1818
1819 if (SUCCEEDED(hres)) /* If the instantiation was successful... */
1820 {
1821 /* ...Then build a PersistFile interface for the ShellLink so we can
1822 * save it as a file after we build it. */
1823 hres = shelllink_ptr->lpVtbl->QueryInterface(shelllink_ptr,
1824 &IID_IPersistFile, (void **) &persistfile_ptr);
1825
1826 if (SUCCEEDED(hres))
1827 {
1828 wchar_t wsz[BUFSIZE];
1829
1830 /* translate the (possibly) multibyte shortcut filename to windows
1831 * Unicode so it can be used as a file name.
1832 */
Bram Moolenaare4963c52019-02-22 19:41:08 +01001833 MultiByteToWideChar(CP_ACP, 0, shortcut_name, -1, wsz, sizeof(wsz)/sizeof(wsz[0]));
Bram Moolenaar071d4272004-06-13 20:20:40 +00001834
1835 /* set the attributes */
1836 shelllink_ptr->lpVtbl->SetPath(shelllink_ptr, shortcut_target);
1837 shelllink_ptr->lpVtbl->SetWorkingDirectory(shelllink_ptr,
1838 workingdir);
1839 shelllink_ptr->lpVtbl->SetIconLocation(shelllink_ptr,
1840 iconfile_path, iconindex);
1841 shelllink_ptr->lpVtbl->SetArguments(shelllink_ptr, shortcut_args);
1842
1843 /* save the shortcut to a file and return the PersistFile object*/
1844 persistfile_ptr->lpVtbl->Save(persistfile_ptr, wsz, 1);
1845 persistfile_ptr->lpVtbl->Release(persistfile_ptr);
1846 }
1847 else
1848 {
1849 printf("QueryInterface Error\n");
1850 return FAIL;
1851 }
1852
1853 /* Return the ShellLink object */
1854 shelllink_ptr->lpVtbl->Release(shelllink_ptr);
1855 }
1856 else
1857 {
1858 printf("CoCreateInstance Error - hres = %08x\n", (int)hres);
1859 return FAIL;
1860 }
1861
1862 return OK;
1863}
1864
1865/*
1866 * Build a path to where we will put a specified link.
1867 *
1868 * Return 0 on error, non-zero on success
1869 */
1870 int
1871build_link_name(
1872 char *link_path,
1873 const char *link_name,
1874 const char *shell_folder_name)
1875{
Bram Moolenaarbbd854d2019-02-18 22:19:33 +01001876 char shell_folder_path[MAX_PATH];
Bram Moolenaar071d4272004-06-13 20:20:40 +00001877
1878 if (get_shell_folder_path(shell_folder_path, shell_folder_name) == FAIL)
1879 {
1880 printf("An error occurred while attempting to find the path to %s.\n",
1881 shell_folder_name);
1882 return FAIL;
1883 }
1884
1885 /* Make sure the directory exists (create Start Menu\Programs\Vim).
1886 * Ignore errors if it already exists. */
1887 vim_mkdir(shell_folder_path, 0755);
1888
1889 /* build the path to the shortcut and the path to gvim.exe */
1890 sprintf(link_path, "%s\\%s.lnk", shell_folder_path, link_name);
1891
1892 return OK;
1893}
1894
1895 static int
1896build_shortcut(
1897 const char *name, /* Name of the shortcut */
1898 const char *exename, /* Name of the executable (e.g., vim.exe) */
1899 const char *args,
1900 const char *shell_folder,
1901 const char *workingdir)
1902{
1903 char executable_path[BUFSIZE];
1904 char link_name[BUFSIZE];
1905
1906 sprintf(executable_path, "%s\\%s", installdir, exename);
1907
1908 if (build_link_name(link_name, name, shell_folder) == FAIL)
1909 {
1910 printf("An error has occurred. A shortcut to %s will not be created %s.\n",
1911 name,
1912 *shell_folder == 'd' ? "on the desktop" : "in the Start menu");
1913 return FAIL;
1914 }
1915
1916 /* Create the shortcut: */
1917 return create_shortcut(link_name, executable_path, 0,
1918 executable_path, args, workingdir);
1919}
1920
1921/*
1922 * We used to use "homedir" as the working directory, but that is a bad choice
Bram Moolenaar03e228a2013-11-07 04:49:27 +01001923 * on multi-user systems. However, not specifying a directory results in the
1924 * current directory to be c:\Windows\system32 on Windows 7. Use environment
1925 * variables instead.
Bram Moolenaar071d4272004-06-13 20:20:40 +00001926 */
Bram Moolenaar03e228a2013-11-07 04:49:27 +01001927#define WORKDIR "%HOMEDRIVE%%HOMEPATH%"
Bram Moolenaar071d4272004-06-13 20:20:40 +00001928
1929/*
1930 * Create shortcut(s) in the Start Menu\Programs\Vim folder.
1931 */
1932 static void
1933install_start_menu(int idx)
1934{
1935 need_uninstall_entry = 1;
1936 printf("Creating start menu\n");
1937 if (has_vim)
1938 {
1939 if (build_shortcut("Vim", "vim.exe", "",
1940 VIM_STARTMENU, WORKDIR) == FAIL)
1941 return;
1942 if (build_shortcut("Vim Read-only", "vim.exe", "-R",
1943 VIM_STARTMENU, WORKDIR) == FAIL)
1944 return;
1945 if (build_shortcut("Vim Diff", "vim.exe", "-d",
1946 VIM_STARTMENU, WORKDIR) == FAIL)
1947 return;
1948 }
1949 if (has_gvim)
1950 {
1951 if (build_shortcut("gVim", "gvim.exe", "",
1952 VIM_STARTMENU, WORKDIR) == FAIL)
1953 return;
1954 if (build_shortcut("gVim Easy", "gvim.exe", "-y",
1955 VIM_STARTMENU, WORKDIR) == FAIL)
1956 return;
1957 if (build_shortcut("gVim Read-only", "gvim.exe", "-R",
1958 VIM_STARTMENU, WORKDIR) == FAIL)
1959 return;
1960 if (build_shortcut("gVim Diff", "gvim.exe", "-d",
1961 VIM_STARTMENU, WORKDIR) == FAIL)
1962 return;
1963 }
1964 if (build_shortcut("Uninstall",
1965 interactive ? "uninstal.exe" : "uninstall-gui.exe", "",
1966 VIM_STARTMENU, installdir) == FAIL)
1967 return;
1968 /* For Windows NT the working dir of the vimtutor.bat must be right,
1969 * otherwise gvim.exe won't be found and using gvimbat doesn't work. */
1970 if (build_shortcut("Vim tutor", "vimtutor.bat", "",
1971 VIM_STARTMENU, installdir) == FAIL)
1972 return;
1973 if (build_shortcut("Help", has_gvim ? "gvim.exe" : "vim.exe", "-c h",
1974 VIM_STARTMENU, WORKDIR) == FAIL)
1975 return;
1976 {
1977 char shell_folder_path[BUFSIZE];
1978
1979 /* Creating the URL shortcut works a bit differently... */
1980 if (get_shell_folder_path(shell_folder_path, VIM_STARTMENU) == FAIL)
1981 {
1982 printf("Finding the path of the Start menu failed\n");
1983 return ;
1984 }
1985 add_pathsep(shell_folder_path);
1986 strcat(shell_folder_path, "Vim Online.url");
1987 if (!WritePrivateProfileString("InternetShortcut", "URL",
Bram Moolenaarbd87eb32018-06-26 23:18:45 +02001988 "https://www.vim.org/", shell_folder_path))
Bram Moolenaar071d4272004-06-13 20:20:40 +00001989 {
1990 printf("Creating the Vim online URL failed\n");
1991 return;
1992 }
1993 }
1994}
1995
1996 static void
1997toggle_startmenu_choice(int idx)
1998{
1999 if (choices[idx].installfunc == NULL)
2000 {
2001 choices[idx].installfunc = install_start_menu;
2002 choices[idx].text = "Add Vim to the Start menu";
2003 }
2004 else
2005 {
2006 choices[idx].installfunc = NULL;
2007 choices[idx].text = "Do NOT add Vim to the Start menu";
2008 }
2009}
2010
2011/*
2012 * Function to actually create the shortcuts
2013 *
2014 * Currently I am supplying no working directory to the shortcut. This
2015 * means that the initial working dir will be:
2016 * - the location of the shortcut if no file is supplied
2017 * - the location of the file being edited if a file is supplied (ie via
2018 * drag and drop onto the shortcut).
2019 */
2020 void
2021install_shortcut_gvim(int idx)
2022{
2023 /* Create shortcut(s) on the desktop */
2024 if (choices[idx].arg)
2025 {
2026 (void)build_shortcut(icon_names[0], "gvim.exe",
2027 "", "desktop", WORKDIR);
2028 need_uninstall_entry = 1;
2029 }
2030}
2031
2032 void
2033install_shortcut_evim(int idx)
2034{
2035 if (choices[idx].arg)
2036 {
2037 (void)build_shortcut(icon_names[1], "gvim.exe",
2038 "-y", "desktop", WORKDIR);
2039 need_uninstall_entry = 1;
2040 }
2041}
2042
2043 void
2044install_shortcut_gview(int idx)
2045{
2046 if (choices[idx].arg)
2047 {
2048 (void)build_shortcut(icon_names[2], "gvim.exe",
2049 "-R", "desktop", WORKDIR);
2050 need_uninstall_entry = 1;
2051 }
2052}
2053
2054 void
2055toggle_shortcut_choice(int idx)
2056{
2057 char *arg;
2058
2059 if (choices[idx].installfunc == install_shortcut_gvim)
2060 arg = "gVim";
2061 else if (choices[idx].installfunc == install_shortcut_evim)
2062 arg = "gVim Easy";
2063 else
2064 arg = "gVim Read-only";
2065 if (choices[idx].arg)
2066 {
2067 choices[idx].arg = 0;
2068 alloc_text(idx, "Do NOT create a desktop icon for %s", arg);
2069 }
2070 else
2071 {
2072 choices[idx].arg = 1;
2073 alloc_text(idx, "Create a desktop icon for %s", arg);
2074 }
2075}
Bram Moolenaar071d4272004-06-13 20:20:40 +00002076
2077 static void
2078init_startmenu_choice(void)
2079{
Bram Moolenaar071d4272004-06-13 20:20:40 +00002080 /* Start menu */
2081 choices[choice_count].changefunc = toggle_startmenu_choice;
2082 choices[choice_count].installfunc = NULL;
2083 choices[choice_count].active = 1;
2084 toggle_startmenu_choice(choice_count); /* set the text */
2085 ++choice_count;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002086}
2087
2088/*
2089 * Add the choice for the desktop shortcuts.
2090 */
2091 static void
2092init_shortcut_choices(void)
2093{
Bram Moolenaar071d4272004-06-13 20:20:40 +00002094 /* Shortcut to gvim */
2095 choices[choice_count].text = NULL;
2096 choices[choice_count].arg = 0;
2097 choices[choice_count].active = has_gvim;
2098 choices[choice_count].changefunc = toggle_shortcut_choice;
2099 choices[choice_count].installfunc = install_shortcut_gvim;
2100 toggle_shortcut_choice(choice_count);
2101 ++choice_count;
2102
2103 /* Shortcut to evim */
2104 choices[choice_count].text = NULL;
2105 choices[choice_count].arg = 0;
2106 choices[choice_count].active = has_gvim;
2107 choices[choice_count].changefunc = toggle_shortcut_choice;
2108 choices[choice_count].installfunc = install_shortcut_evim;
2109 toggle_shortcut_choice(choice_count);
2110 ++choice_count;
2111
2112 /* Shortcut to gview */
2113 choices[choice_count].text = NULL;
2114 choices[choice_count].arg = 0;
2115 choices[choice_count].active = has_gvim;
2116 choices[choice_count].changefunc = toggle_shortcut_choice;
2117 choices[choice_count].installfunc = install_shortcut_gview;
2118 toggle_shortcut_choice(choice_count);
2119 ++choice_count;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002120}
2121
Bram Moolenaar071d4272004-06-13 20:20:40 +00002122/*
2123 * Attempt to register OLE for Vim.
2124 */
2125 static void
2126install_OLE_register(void)
2127{
2128 char register_command_string[BUFSIZE + 30];
2129
2130 printf("\n--- Attempting to register Vim with OLE ---\n");
2131 printf("(There is no message whether this works or not.)\n");
2132
Bram Moolenaar071d4272004-06-13 20:20:40 +00002133 sprintf(register_command_string, "\"%s\\gvim.exe\" -silent -register", installdir);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002134 system(register_command_string);
2135}
Bram Moolenaar071d4272004-06-13 20:20:40 +00002136
2137/*
2138 * Remove the last part of directory "path[]" to get its parent, and put the
2139 * result in "to[]".
2140 */
2141 static void
Bram Moolenaare4963c52019-02-22 19:41:08 +01002142dir_remove_last(const char *path, char to[MAX_PATH])
Bram Moolenaar071d4272004-06-13 20:20:40 +00002143{
2144 char c;
2145 long last_char_to_copy;
2146 long path_length = strlen(path);
2147
2148 /* skip the last character just in case it is a '\\' */
2149 last_char_to_copy = path_length - 2;
2150 c = path[last_char_to_copy];
2151
2152 while (c != '\\')
2153 {
2154 last_char_to_copy--;
2155 c = path[last_char_to_copy];
2156 }
2157
2158 strncpy(to, path, (size_t)last_char_to_copy);
2159 to[last_char_to_copy] = NUL;
2160}
2161
2162 static void
2163set_directories_text(int idx)
2164{
Bram Moolenaar25a494c2018-11-16 19:39:50 +01002165 int vimfiles_dir_choice = choices[idx].arg;
2166
Bram Moolenaar071d4272004-06-13 20:20:40 +00002167 if (vimfiles_dir_choice == (int)vimfiles_dir_none)
2168 alloc_text(idx, "Do NOT create plugin directories%s", "");
2169 else
2170 alloc_text(idx, "Create plugin directories: %s",
2171 vimfiles_dir_choices[vimfiles_dir_choice]);
2172}
2173
2174/*
Bram Moolenaar25a494c2018-11-16 19:39:50 +01002175 * To get the "real" home directory:
2176 * - get value of $HOME
2177 * - if not found, get value of $HOMEDRIVE$HOMEPATH
2178 * - if not found, get value of $USERPROFILE
2179 *
2180 * This code is based on init_homedir() in misc1.c, keep in sync!
2181 */
2182static char *homedir = NULL;
2183
2184 void
2185init_homedir(void)
2186{
2187 char *var;
2188 char buf[MAX_PATH];
2189
2190 if (homedir != NULL)
2191 {
2192 free(homedir);
2193 homedir = NULL;
2194 }
2195
2196 var = getenv("HOME");
2197
2198 /*
2199 * Typically, $HOME is not defined on Windows, unless the user has
2200 * specifically defined it for Vim's sake. However, on Windows NT
2201 * platforms, $HOMEDRIVE and $HOMEPATH are automatically defined for
2202 * each user. Try constructing $HOME from these.
2203 */
2204 if (var == NULL || *var == NUL)
2205 {
2206 char *homedrive, *homepath;
2207
2208 homedrive = getenv("HOMEDRIVE");
2209 homepath = getenv("HOMEPATH");
2210 if (homepath == NULL || *homepath == NUL)
2211 homepath = "\\";
2212 if (homedrive != NULL
Bram Moolenaare4963c52019-02-22 19:41:08 +01002213 && strlen(homedrive) + strlen(homepath) < sizeof(buf))
Bram Moolenaar25a494c2018-11-16 19:39:50 +01002214 {
2215 sprintf(buf, "%s%s", homedrive, homepath);
2216 if (buf[0] != NUL)
2217 var = buf;
2218 }
2219 }
2220
2221 if (var == NULL)
2222 var = getenv("USERPROFILE");
2223
2224 /*
2225 * Weird but true: $HOME may contain an indirect reference to another
2226 * variable, esp. "%USERPROFILE%". Happens when $USERPROFILE isn't set
2227 * when $HOME is being set.
2228 */
2229 if (var != NULL && *var == '%')
2230 {
2231 char *p;
2232 char *exp;
2233
2234 p = strchr(var + 1, '%');
2235 if (p != NULL)
2236 {
2237 strncpy(buf, var + 1, p - (var + 1));
2238 buf[p - (var + 1)] = NUL;
2239 exp = getenv(buf);
2240 if (exp != NULL && *exp != NUL
Bram Moolenaare4963c52019-02-22 19:41:08 +01002241 && strlen(exp) + strlen(p) < sizeof(buf))
Bram Moolenaar25a494c2018-11-16 19:39:50 +01002242 {
Bram Moolenaare4963c52019-02-22 19:41:08 +01002243 sprintf(buf, "%s%s", exp, p + 1);
Bram Moolenaar25a494c2018-11-16 19:39:50 +01002244 var = buf;
2245 }
2246 }
2247 }
2248
2249 if (var != NULL && *var == NUL) // empty is same as not set
2250 var = NULL;
2251
2252 if (var == NULL)
2253 homedir = NULL;
2254 else
2255 homedir = _strdup(var);
2256}
2257
2258/*
Bram Moolenaar071d4272004-06-13 20:20:40 +00002259 * Change the directory that the vim plugin directories will be created in:
2260 * $HOME, $VIM or nowhere.
2261 */
2262 static void
2263change_directories_choice(int idx)
2264{
2265 int choice_count = TABLE_SIZE(vimfiles_dir_choices);
2266
2267 /* Don't offer the $HOME choice if $HOME isn't set. */
Bram Moolenaar25a494c2018-11-16 19:39:50 +01002268 if (homedir == NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002269 --choice_count;
Bram Moolenaar25a494c2018-11-16 19:39:50 +01002270 choices[idx].arg = get_choice(vimfiles_dir_choices, choice_count);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002271 set_directories_text(idx);
2272}
2273
2274/*
2275 * Create the plugin directories...
2276 */
2277/*ARGSUSED*/
2278 static void
2279install_vimfilesdir(int idx)
2280{
2281 int i;
Bram Moolenaar25a494c2018-11-16 19:39:50 +01002282 int vimfiles_dir_choice = choices[idx].arg;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002283 char *p;
Bram Moolenaarbbd854d2019-02-18 22:19:33 +01002284 char vimdir_path[MAX_PATH];
2285 char vimfiles_path[MAX_PATH + 9];
Bram Moolenaar071d4272004-06-13 20:20:40 +00002286 char tmp_dirname[BUFSIZE];
2287
2288 /* switch on the location that the user wants the plugin directories
2289 * built in */
2290 switch (vimfiles_dir_choice)
2291 {
2292 case vimfiles_dir_vim:
2293 {
2294 /* Go to the %VIM% directory - check env first, then go one dir
2295 * below installdir if there is no %VIM% environment variable.
2296 * The accuracy of $VIM is checked in inspect_system(), so we
2297 * can be sure it is ok to use here. */
2298 p = getenv("VIM");
2299 if (p == NULL) /* No $VIM in path */
2300 dir_remove_last(installdir, vimdir_path);
2301 else
2302 strcpy(vimdir_path, p);
2303 break;
2304 }
2305 case vimfiles_dir_home:
2306 {
Bram Moolenaar25a494c2018-11-16 19:39:50 +01002307 // Find the $HOME directory. Its existence was already checked.
2308 p = homedir;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002309 if (p == NULL)
2310 {
2311 printf("Internal error: $HOME is NULL\n");
2312 p = "c:\\";
2313 }
2314 strcpy(vimdir_path, p);
2315 break;
2316 }
2317 case vimfiles_dir_none:
2318 {
Bram Moolenaar25a494c2018-11-16 19:39:50 +01002319 // Do not create vim plugin directory.
Bram Moolenaar071d4272004-06-13 20:20:40 +00002320 return;
2321 }
2322 }
2323
2324 /* Now, just create the directory. If it already exists, it will fail
2325 * silently. */
2326 sprintf(vimfiles_path, "%s\\vimfiles", vimdir_path);
2327 vim_mkdir(vimfiles_path, 0755);
2328
2329 printf("Creating the following directories in \"%s\":\n", vimfiles_path);
2330 for (i = 0; i < TABLE_SIZE(vimfiles_subdirs); i++)
2331 {
2332 sprintf(tmp_dirname, "%s\\%s", vimfiles_path, vimfiles_subdirs[i]);
2333 printf(" %s", vimfiles_subdirs[i]);
2334 vim_mkdir(tmp_dirname, 0755);
2335 }
2336 printf("\n");
2337}
2338
2339/*
2340 * Add the creation of runtime files to the setup sequence.
2341 */
2342 static void
2343init_directories_choice(void)
2344{
2345 struct stat st;
2346 char tmp_dirname[BUFSIZE];
2347 char *p;
Bram Moolenaar25a494c2018-11-16 19:39:50 +01002348 int vimfiles_dir_choice;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002349
2350 choices[choice_count].text = alloc(150);
2351 choices[choice_count].changefunc = change_directories_choice;
2352 choices[choice_count].installfunc = install_vimfilesdir;
2353 choices[choice_count].active = 1;
2354
Bram Moolenaar25a494c2018-11-16 19:39:50 +01002355 // Check if the "compiler" directory already exists. That's a good
2356 // indication that the plugin directories were already created.
Bram Moolenaare4963c52019-02-22 19:41:08 +01002357 p = getenv("HOME");
2358 if (p != NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002359 {
2360 vimfiles_dir_choice = (int)vimfiles_dir_home;
Bram Moolenaare4963c52019-02-22 19:41:08 +01002361 sprintf(tmp_dirname, "%s\\vimfiles\\compiler", p);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002362 if (stat(tmp_dirname, &st) == 0)
2363 vimfiles_dir_choice = (int)vimfiles_dir_none;
2364 }
2365 else
2366 {
2367 vimfiles_dir_choice = (int)vimfiles_dir_vim;
2368 p = getenv("VIM");
Bram Moolenaar25a494c2018-11-16 19:39:50 +01002369 if (p == NULL) // No $VIM in path, use the install dir.
Bram Moolenaar071d4272004-06-13 20:20:40 +00002370 dir_remove_last(installdir, tmp_dirname);
2371 else
2372 strcpy(tmp_dirname, p);
2373 strcat(tmp_dirname, "\\vimfiles\\compiler");
2374 if (stat(tmp_dirname, &st) == 0)
2375 vimfiles_dir_choice = (int)vimfiles_dir_none;
2376 }
2377
Bram Moolenaar25a494c2018-11-16 19:39:50 +01002378 choices[choice_count].arg = vimfiles_dir_choice;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002379 set_directories_text(choice_count);
2380 ++choice_count;
2381}
2382
2383/*
2384 * Setup the choices and the default values.
2385 */
2386 static void
2387setup_choices(void)
2388{
2389 /* install the batch files */
2390 init_bat_choices();
2391
2392 /* (over) write _vimrc file */
2393 init_vimrc_choices();
2394
2395 /* Whether to add Vim to the popup menu */
2396 init_popup_choice();
2397
2398 /* Whether to add Vim to the "Open With..." menu */
2399 init_openwith_choice();
2400
2401 /* Whether to add Vim to the Start Menu. */
2402 init_startmenu_choice();
2403
2404 /* Whether to add shortcuts to the Desktop. */
2405 init_shortcut_choices();
2406
2407 /* Whether to create the runtime directories. */
2408 init_directories_choice();
2409}
2410
2411 static void
2412print_cmd_line_help(void)
2413{
2414 printf("Vim installer non-interactive command line arguments:\n");
2415 printf("\n");
2416 printf("-create-batfiles [vim gvim evim view gview vimdiff gvimdiff]\n");
2417 printf(" Create .bat files for Vim variants in the Windows directory.\n");
2418 printf("-create-vimrc\n");
2419 printf(" Create a default _vimrc file if one does not already exist.\n");
Bram Moolenaarc3fdf7f2017-10-28 18:36:48 +02002420 printf("-vimrc-remap [no|win]\n");
2421 printf(" Remap keys when creating a default _vimrc file.\n");
2422 printf("-vimrc-behave [unix|mswin|default]\n");
2423 printf(" Set mouse behavior when creating a default _vimrc file.\n");
Bram Moolenaar6cdb2c92018-10-13 17:25:27 +02002424 printf("-vimrc-compat [vi|vim|defaults|all]\n");
2425 printf(" Set Vi compatibility when creating a default _vimrc file.\n");
Bram Moolenaar071d4272004-06-13 20:20:40 +00002426 printf("-install-popup\n");
2427 printf(" Install the Edit-with-Vim context menu entry\n");
2428 printf("-install-openwith\n");
2429 printf(" Add Vim to the \"Open With...\" context menu list\n");
Bram Moolenaar071d4272004-06-13 20:20:40 +00002430 printf("-add-start-menu");
2431 printf(" Add Vim to the start menu\n");
2432 printf("-install-icons");
2433 printf(" Create icons for gVim executables on the desktop\n");
Bram Moolenaar071d4272004-06-13 20:20:40 +00002434 printf("-create-directories [vim|home]\n");
2435 printf(" Create runtime directories to drop plugins into; in the $VIM\n");
2436 printf(" or $HOME directory\n");
Bram Moolenaar071d4272004-06-13 20:20:40 +00002437 printf("-register-OLE");
Bram Moolenaarce0842a2005-07-18 21:58:11 +00002438 printf(" Ignored\n");
Bram Moolenaar071d4272004-06-13 20:20:40 +00002439 printf("\n");
2440}
2441
2442/*
2443 * Setup installation choices based on command line switches
2444 */
2445 static void
2446command_line_setup_choices(int argc, char **argv)
2447{
2448 int i, j;
2449
2450 for (i = 1; i < argc; i++)
2451 {
2452 if (strcmp(argv[i], "-create-batfiles") == 0)
2453 {
2454 if (i + 1 == argc)
2455 continue;
2456 while (argv[i + 1][0] != '-' && i < argc)
2457 {
2458 i++;
2459 for (j = 1; j < TARGET_COUNT; ++j)
2460 if ((targets[j].exenamearg[0] == 'g' ? has_gvim : has_vim)
2461 && strcmp(argv[i], targets[j].name) == 0)
2462 {
2463 init_bat_choice(j);
2464 break;
2465 }
2466 if (j == TARGET_COUNT)
2467 printf("%s is not a valid choice for -create-batfiles\n",
2468 argv[i]);
2469
2470 if (i + 1 == argc)
2471 break;
2472 }
2473 }
2474 else if (strcmp(argv[i], "-create-vimrc") == 0)
2475 {
2476 /* Setup default vimrc choices. If there is already a _vimrc file,
2477 * it will NOT be overwritten.
2478 */
2479 init_vimrc_choices();
2480 }
Bram Moolenaarc3fdf7f2017-10-28 18:36:48 +02002481 else if (strcmp(argv[i], "-vimrc-remap") == 0)
2482 {
2483 if (i + 1 == argc)
2484 break;
2485 i++;
2486 if (strcmp(argv[i], "no") == 0)
2487 remap_choice = remap_no;
2488 else if (strcmp(argv[i], "win") == 0)
2489 remap_choice = remap_win;
2490 }
2491 else if (strcmp(argv[i], "-vimrc-behave") == 0)
2492 {
2493 if (i + 1 == argc)
2494 break;
2495 i++;
2496 if (strcmp(argv[i], "unix") == 0)
2497 mouse_choice = mouse_xterm;
2498 else if (strcmp(argv[i], "mswin") == 0)
2499 mouse_choice = mouse_mswin;
2500 else if (strcmp(argv[i], "default") == 0)
2501 mouse_choice = mouse_default;
2502 }
Bram Moolenaar6cdb2c92018-10-13 17:25:27 +02002503 else if (strcmp(argv[i], "-vimrc-compat") == 0)
2504 {
2505 if (i + 1 == argc)
2506 break;
2507 i++;
2508 if (strcmp(argv[i], "vi") == 0)
2509 compat_choice = compat_vi;
2510 else if (strcmp(argv[i], "vim") == 0)
2511 compat_choice = compat_vim;
2512 else if (strcmp(argv[i], "defaults") == 0)
2513 compat_choice = compat_some_enhancements;
2514 else if (strcmp(argv[i], "all") == 0)
2515 compat_choice = compat_all_enhancements;
2516 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00002517 else if (strcmp(argv[i], "-install-popup") == 0)
2518 {
2519 init_popup_choice();
2520 }
2521 else if (strcmp(argv[i], "-install-openwith") == 0)
2522 {
2523 init_openwith_choice();
2524 }
2525 else if (strcmp(argv[i], "-add-start-menu") == 0)
2526 {
2527 init_startmenu_choice();
2528 }
2529 else if (strcmp(argv[i], "-install-icons") == 0)
2530 {
2531 init_shortcut_choices();
2532 }
2533 else if (strcmp(argv[i], "-create-directories") == 0)
2534 {
Bram Moolenaar142a9752018-12-14 19:54:39 +01002535 int vimfiles_dir_choice = (int)vimfiles_dir_none;
Bram Moolenaar25a494c2018-11-16 19:39:50 +01002536
Bram Moolenaar071d4272004-06-13 20:20:40 +00002537 init_directories_choice();
2538 if (argv[i + 1][0] != '-')
2539 {
2540 i++;
2541 if (strcmp(argv[i], "vim") == 0)
2542 vimfiles_dir_choice = (int)vimfiles_dir_vim;
2543 else if (strcmp(argv[i], "home") == 0)
2544 {
Bram Moolenaar25a494c2018-11-16 19:39:50 +01002545 if (homedir == NULL) // No $HOME in environment
2546 vimfiles_dir_choice = (int)vimfiles_dir_none;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002547 else
2548 vimfiles_dir_choice = (int)vimfiles_dir_home;
2549 }
2550 else
2551 {
2552 printf("Unknown argument for -create-directories: %s\n",
2553 argv[i]);
2554 print_cmd_line_help();
2555 }
2556 }
2557 else /* No choice specified, default to vim directory */
2558 vimfiles_dir_choice = (int)vimfiles_dir_vim;
Bram Moolenaar25a494c2018-11-16 19:39:50 +01002559 choices[choice_count - 1].arg = vimfiles_dir_choice;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002560 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00002561 else if (strcmp(argv[i], "-register-OLE") == 0)
2562 {
2563 /* This is always done when gvim is found */
2564 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00002565 else /* Unknown switch */
2566 {
2567 printf("Got unknown argument argv[%d] = %s\n", i, argv[i]);
2568 print_cmd_line_help();
2569 }
2570 }
2571}
2572
2573
2574/*
2575 * Show a few screens full of helpful information.
2576 */
2577 static void
2578show_help(void)
2579{
2580 static char *(items[]) =
2581 {
2582"Installing .bat files\n"
2583"---------------------\n"
2584"The vim.bat file is written in one of the directories in $PATH.\n"
2585"This makes it possible to start Vim from the command line.\n"
2586"If vim.exe can be found in $PATH, the choice for vim.bat will not be\n"
2587"present. It is assumed you will use the existing vim.exe.\n"
2588"If vim.bat can already be found in $PATH this is probably for an old\n"
2589"version of Vim (but this is not checked!). You can overwrite it.\n"
2590"If no vim.bat already exists, you can select one of the directories in\n"
2591"$PATH for creating the batch file, or disable creating a vim.bat file.\n"
2592"\n"
2593"If you choose not to create the vim.bat file, Vim can still be executed\n"
2594"in other ways, but not from the command line.\n"
2595"\n"
2596"The same applies to choices for gvim, evim, (g)view, and (g)vimdiff.\n"
2597"The first item can be used to change the path for all of them.\n"
2598,
2599"Creating a _vimrc file\n"
2600"----------------------\n"
2601"The _vimrc file is used to set options for how Vim behaves.\n"
2602"The install program can create a _vimrc file with a few basic choices.\n"
2603"You can edit this file later to tune your preferences.\n"
2604"If you already have a _vimrc or .vimrc file it can be overwritten.\n"
2605"Don't do that if you have made changes to it.\n"
2606,
2607"Vim features\n"
2608"------------\n"
2609"(this choice is only available when creating a _vimrc file)\n"
2610"1. Vim can run in Vi-compatible mode. Many nice Vim features are then\n"
Bram Moolenaar2b849492018-11-21 13:58:35 +01002611" disabled. Only choose Vi-compatible if you really need full Vi\n"
2612" compatibility.\n"
2613"2. Vim runs in not-Vi-compatible mode. Vim is still mostly Vi compatible,\n"
2614" but adds nice features like multi-level undo.\n"
2615"3. Running Vim with some enhancements is useful when you want some of\n"
Bram Moolenaar071d4272004-06-13 20:20:40 +00002616" the nice Vim features, but have a slow computer and want to keep it\n"
2617" really fast.\n"
Bram Moolenaar2b849492018-11-21 13:58:35 +01002618"4. Syntax highlighting shows many files in color. Not only does this look\n"
Bram Moolenaar071d4272004-06-13 20:20:40 +00002619" nice, it also makes it easier to spot errors and you can work faster.\n"
2620" The other features include editing compressed files.\n"
2621,
2622"Windows key mapping\n"
2623"-------------------\n"
2624"(this choice is only available when creating a _vimrc file)\n"
2625"Under MS-Windows the CTRL-C key copies text to the clipboard and CTRL-V\n"
2626"pastes text from the clipboard. There are a few more keys like these.\n"
2627"Unfortunately, in Vim these keys normally have another meaning.\n"
2628"1. Choose to have the keys like they normally are in Vim (useful if you\n"
2629" also use Vim on other systems).\n"
2630"2. Choose to have the keys work like they are used on MS-Windows (useful\n"
2631" if you mostly work on MS-Windows).\n"
2632,
2633"Mouse use\n"
2634"---------\n"
2635"(this choice is only available when creating a _vimrc file)\n"
2636"The right mouse button can be used in two ways:\n"
2637"1. The Unix way is to extend an existing selection. The popup menu is\n"
2638" not available.\n"
2639"2. The MS-Windows way is to show a popup menu, which allows you to\n"
2640" copy/paste text, undo/redo, etc. Extending the selection can still be\n"
2641" done by keeping SHIFT pressed while using the left mouse button\n"
2642,
2643"Edit-with-Vim context menu entry\n"
2644"--------------------------------\n"
2645"(this choice is only available when gvim.exe and gvimext.dll are present)\n"
2646"You can associate different file types with Vim, so that you can (double)\n"
2647"click on a file to edit it with Vim. This means you have to individually\n"
2648"select each file type.\n"
2649"An alternative is the option offered here: Install an \"Edit with Vim\"\n"
2650"entry in the popup menu for the right mouse button. This means you can\n"
2651"edit any file with Vim.\n"
2652,
2653"\"Open With...\" context menu entry\n"
2654"--------------------------------\n"
2655"(this choice is only available when gvim.exe is present)\n"
2656"This option adds Vim to the \"Open With...\" entry in the popup menu for\n"
2657"the right mouse button. This also makes it possible to edit HTML files\n"
2658"directly from Internet Explorer.\n"
2659,
2660"Add Vim to the Start menu\n"
2661"-------------------------\n"
2662"In Windows 95 and later, Vim can be added to the Start menu. This will\n"
2663"create a submenu with an entry for vim, gvim, evim, vimdiff, etc..\n"
2664,
2665"Icons on the desktop\n"
2666"--------------------\n"
2667"(these choices are only available when installing gvim)\n"
2668"In Windows 95 and later, shortcuts (icons) can be created on the Desktop.\n"
2669,
2670"Create plugin directories\n"
2671"-------------------------\n"
2672"Plugin directories allow extending Vim by dropping a file into a directory.\n"
2673"This choice allows creating them in $HOME (if you have a home directory) or\n"
2674"$VIM (used for everybody on the system).\n"
2675,
2676NULL
2677 };
2678 int i;
2679 int c;
2680
2681 rewind(stdin);
2682 printf("\n");
2683 for (i = 0; items[i] != NULL; ++i)
2684 {
Bram Moolenaarc3fdf7f2017-10-28 18:36:48 +02002685 puts(items[i]);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002686 printf("Hit Enter to continue, b (back) or q (quit help): ");
2687 c = getchar();
2688 rewind(stdin);
2689 if (c == 'b' || c == 'B')
2690 {
2691 if (i == 0)
2692 --i;
2693 else
2694 i -= 2;
2695 }
2696 if (c == 'q' || c == 'Q')
2697 break;
2698 printf("\n");
2699 }
2700}
2701
2702/*
2703 * Install the choices.
2704 */
2705 static void
2706install(void)
2707{
2708 int i;
2709
2710 /* Install the selected choices. */
2711 for (i = 0; i < choice_count; ++i)
2712 if (choices[i].installfunc != NULL && choices[i].active)
2713 (choices[i].installfunc)(i);
2714
2715 /* Add some entries to the registry, if needed. */
2716 if (install_popup
2717 || install_openwith
2718 || (need_uninstall_entry && interactive)
2719 || !interactive)
2720 install_registry();
2721
Bram Moolenaar071d4272004-06-13 20:20:40 +00002722 /* Register gvim with OLE. */
2723 if (has_gvim)
2724 install_OLE_register();
Bram Moolenaar071d4272004-06-13 20:20:40 +00002725}
2726
2727/*
2728 * request_choice
2729 */
2730 static void
2731request_choice(void)
2732{
2733 int i;
2734
2735 printf("\n\nInstall will do for you:\n");
2736 for (i = 0; i < choice_count; ++i)
2737 if (choices[i].active)
2738 printf("%2d %s\n", i + 1, choices[i].text);
2739 printf("To change an item, enter its number\n\n");
2740 printf("Enter item number, h (help), d (do it) or q (quit): ");
2741}
2742
2743 int
2744main(int argc, char **argv)
2745{
2746 int i;
2747 char buf[BUFSIZE];
2748
2749 /*
2750 * Run interactively if there are no command line arguments.
2751 */
2752 if (argc > 1)
2753 interactive = 0;
2754 else
2755 interactive = 1;
2756
2757 /* Initialize this program. */
2758 do_inits(argv);
Bram Moolenaar25a494c2018-11-16 19:39:50 +01002759 init_homedir();
Bram Moolenaar071d4272004-06-13 20:20:40 +00002760
Bram Moolenaar071d4272004-06-13 20:20:40 +00002761 if (argc > 1 && strcmp(argv[1], "-uninstall-check") == 0)
2762 {
2763 /* Only check for already installed Vims. Used by NSIS installer. */
Bram Moolenaar442b4222010-05-24 21:34:22 +02002764 i = uninstall_check(1);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002765
2766 /* Find the value of $VIM, because NSIS isn't able to do this by
2767 * itself. */
2768 get_vim_env();
2769
2770 /* When nothing found exit quietly. If something found wait for
Bram Moolenaarb230bd52010-05-25 21:02:00 +02002771 * a little while, so that the user can read the messages. */
Bram Moolenaar6cdb2c92018-10-13 17:25:27 +02002772 if (i && _isatty(1))
Bram Moolenaarab8205e2010-07-07 15:14:03 +02002773 sleep(3);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002774 exit(0);
2775 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00002776
2777 printf("This program sets up the installation of Vim "
2778 VIM_VERSION_MEDIUM "\n\n");
2779
2780 /* Check if the user unpacked the archives properly. */
2781 check_unpack();
2782
Bram Moolenaar071d4272004-06-13 20:20:40 +00002783 /* Check for already installed Vims. */
2784 if (interactive)
Bram Moolenaar442b4222010-05-24 21:34:22 +02002785 uninstall_check(0);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002786
2787 /* Find out information about the system. */
2788 inspect_system();
2789
2790 if (interactive)
2791 {
2792 /* Setup all the choices. */
2793 setup_choices();
2794
2795 /* Let the user change choices and finally install (or quit). */
2796 for (;;)
2797 {
2798 request_choice();
2799 rewind(stdin);
2800 if (scanf("%99s", buf) == 1)
2801 {
2802 if (isdigit(buf[0]))
2803 {
2804 /* Change a choice. */
2805 i = atoi(buf);
2806 if (i > 0 && i <= choice_count && choices[i - 1].active)
2807 (choices[i - 1].changefunc)(i - 1);
2808 else
2809 printf("\nIllegal choice\n");
2810 }
2811 else if (buf[0] == 'h' || buf[0] == 'H')
2812 {
2813 /* Help */
2814 show_help();
2815 }
2816 else if (buf[0] == 'd' || buf[0] == 'D')
2817 {
2818 /* Install! */
2819 install();
2820 printf("\nThat finishes the installation. Happy Vimming!\n");
2821 break;
2822 }
2823 else if (buf[0] == 'q' || buf[0] == 'Q')
2824 {
2825 /* Quit */
2826 printf("\nExiting without anything done\n");
2827 break;
2828 }
2829 else
2830 printf("\nIllegal choice\n");
2831 }
2832 }
2833 printf("\n");
Bram Moolenaar442b4222010-05-24 21:34:22 +02002834 myexit(0);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002835 }
2836 else
2837 {
2838 /*
2839 * Run non-interactive - setup according to the command line switches
2840 */
2841 command_line_setup_choices(argc, argv);
2842 install();
Bram Moolenaar442b4222010-05-24 21:34:22 +02002843
2844 /* Avoid that the user has to hit Enter, just wait a little bit to
2845 * allow reading the messages. */
Bram Moolenaarab8205e2010-07-07 15:14:03 +02002846 sleep(2);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002847 }
2848
Bram Moolenaar071d4272004-06-13 20:20:40 +00002849 return 0;
2850}