blob: 2c05cf4c2c42af19e58819cf1f181f22bf2ef3f9 [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
1680#ifdef _WIN64
1681 " (x64)"
1682#endif
1683 );
Bram Moolenaarccd9ccf2010-07-07 13:19:55 +02001684
1685 /* For the NSIS installer use the generated uninstaller. */
1686 if (interactive)
Bram Moolenaar16d79a32010-07-18 22:33:56 +02001687 sprintf(uninstall_string, "%s\\uninstal.exe", installdir);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001688 else
Bram Moolenaar16d79a32010-07-18 22:33:56 +02001689 sprintf(uninstall_string, "%s\\uninstall-gui.exe", installdir);
Bram Moolenaarccd9ccf2010-07-07 13:19:55 +02001690
Bram Moolenaar6cdb2c92018-10-13 17:25:27 +02001691 sprintf(icon_string, "%s\\gvim.exe,0", installdir);
1692
Bram Moolenaarccd9ccf2010-07-07 13:19:55 +02001693 lRet = register_uninstall(
Bram Moolenaarcc448b32010-07-14 16:52:17 +02001694 HKEY_LOCAL_MACHINE,
1695 "Software\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\Vim " VIM_VERSION_SHORT,
1696 display_name,
Bram Moolenaar6cdb2c92018-10-13 17:25:27 +02001697 uninstall_string,
1698 icon_string,
1699 VIM_VERSION_SHORT,
1700 "Bram Moolenaar et al.");
Bram Moolenaarab8205e2010-07-07 15:14:03 +02001701 if (ERROR_SUCCESS != lRet)
1702 return FAIL;
Bram Moolenaarccd9ccf2010-07-07 13:19:55 +02001703
Bram Moolenaarab8205e2010-07-07 15:14:03 +02001704 return OK;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001705}
1706
1707 static void
1708change_popup_choice(int idx)
1709{
1710 if (install_popup == 0)
1711 {
1712 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";
1713 install_popup = 1;
1714 }
1715 else
1716 {
1717 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";
1718 install_popup = 0;
1719 }
1720}
1721
1722/*
1723 * Only add the choice for the popup menu entry when gvim.exe was found and
1724 * both gvimext.dll and regedit.exe exist.
1725 */
1726 static void
1727init_popup_choice(void)
1728{
1729 struct stat st;
1730
1731 if (has_gvim
Bram Moolenaar6199d432017-10-14 19:05:44 +02001732 && (stat(GVIMEXT32_PATH, &st) >= 0
1733 || stat(GVIMEXT64_PATH, &st) >= 0))
Bram Moolenaar071d4272004-06-13 20:20:40 +00001734 {
1735 choices[choice_count].changefunc = change_popup_choice;
1736 choices[choice_count].installfunc = NULL;
1737 choices[choice_count].active = 1;
1738 change_popup_choice(choice_count); /* set the text */
1739 ++choice_count;
1740 }
1741 else
1742 add_dummy_choice();
1743}
1744
1745 static void
1746change_openwith_choice(int idx)
1747{
1748 if (install_openwith == 0)
1749 {
1750 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";
1751 install_openwith = 1;
1752 }
1753 else
1754 {
1755 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";
1756 install_openwith = 0;
1757 }
1758}
1759
1760/*
1761 * Only add the choice for the open-with menu entry when gvim.exe was found
Bram Moolenaar84a05ac2013-05-06 04:24:17 +02001762 * and regedit.exe exist.
Bram Moolenaar071d4272004-06-13 20:20:40 +00001763 */
1764 static void
1765init_openwith_choice(void)
1766{
Bram Moolenaar6199d432017-10-14 19:05:44 +02001767 if (has_gvim)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001768 {
1769 choices[choice_count].changefunc = change_openwith_choice;
1770 choices[choice_count].installfunc = NULL;
1771 choices[choice_count].active = 1;
1772 change_openwith_choice(choice_count); /* set the text */
1773 ++choice_count;
1774 }
1775 else
1776 add_dummy_choice();
1777}
1778
Bram Moolenaar071d4272004-06-13 20:20:40 +00001779/* create_shortcut
1780 *
1781 * Create a shell link.
1782 *
1783 * returns 0 on failure, non-zero on successful completion.
1784 *
1785 * NOTE: Currently untested with mingw.
1786 */
1787 int
1788create_shortcut(
1789 const char *shortcut_name,
1790 const char *iconfile_path,
1791 int iconindex,
1792 const char *shortcut_target,
1793 const char *shortcut_args,
1794 const char *workingdir
1795 )
1796{
1797 IShellLink *shelllink_ptr;
1798 HRESULT hres;
1799 IPersistFile *persistfile_ptr;
1800
1801 /* Initialize COM library */
1802 hres = CoInitialize(NULL);
1803 if (!SUCCEEDED(hres))
1804 {
1805 printf("Error: Could not open the COM library. Not creating shortcut.\n");
1806 return FAIL;
1807 }
1808
1809 /* Instantiate a COM object for the ShellLink, store a pointer to it
1810 * in shelllink_ptr. */
1811 hres = CoCreateInstance(&CLSID_ShellLink,
1812 NULL,
1813 CLSCTX_INPROC_SERVER,
1814 &IID_IShellLink,
1815 (void **) &shelllink_ptr);
1816
1817 if (SUCCEEDED(hres)) /* If the instantiation was successful... */
1818 {
1819 /* ...Then build a PersistFile interface for the ShellLink so we can
1820 * save it as a file after we build it. */
1821 hres = shelllink_ptr->lpVtbl->QueryInterface(shelllink_ptr,
1822 &IID_IPersistFile, (void **) &persistfile_ptr);
1823
1824 if (SUCCEEDED(hres))
1825 {
1826 wchar_t wsz[BUFSIZE];
1827
1828 /* translate the (possibly) multibyte shortcut filename to windows
1829 * Unicode so it can be used as a file name.
1830 */
Bram Moolenaare4963c52019-02-22 19:41:08 +01001831 MultiByteToWideChar(CP_ACP, 0, shortcut_name, -1, wsz, sizeof(wsz)/sizeof(wsz[0]));
Bram Moolenaar071d4272004-06-13 20:20:40 +00001832
1833 /* set the attributes */
1834 shelllink_ptr->lpVtbl->SetPath(shelllink_ptr, shortcut_target);
1835 shelllink_ptr->lpVtbl->SetWorkingDirectory(shelllink_ptr,
1836 workingdir);
1837 shelllink_ptr->lpVtbl->SetIconLocation(shelllink_ptr,
1838 iconfile_path, iconindex);
1839 shelllink_ptr->lpVtbl->SetArguments(shelllink_ptr, shortcut_args);
1840
1841 /* save the shortcut to a file and return the PersistFile object*/
1842 persistfile_ptr->lpVtbl->Save(persistfile_ptr, wsz, 1);
1843 persistfile_ptr->lpVtbl->Release(persistfile_ptr);
1844 }
1845 else
1846 {
1847 printf("QueryInterface Error\n");
1848 return FAIL;
1849 }
1850
1851 /* Return the ShellLink object */
1852 shelllink_ptr->lpVtbl->Release(shelllink_ptr);
1853 }
1854 else
1855 {
1856 printf("CoCreateInstance Error - hres = %08x\n", (int)hres);
1857 return FAIL;
1858 }
1859
1860 return OK;
1861}
1862
1863/*
1864 * Build a path to where we will put a specified link.
1865 *
1866 * Return 0 on error, non-zero on success
1867 */
1868 int
1869build_link_name(
1870 char *link_path,
1871 const char *link_name,
1872 const char *shell_folder_name)
1873{
Bram Moolenaarbbd854d2019-02-18 22:19:33 +01001874 char shell_folder_path[MAX_PATH];
Bram Moolenaar071d4272004-06-13 20:20:40 +00001875
1876 if (get_shell_folder_path(shell_folder_path, shell_folder_name) == FAIL)
1877 {
1878 printf("An error occurred while attempting to find the path to %s.\n",
1879 shell_folder_name);
1880 return FAIL;
1881 }
1882
1883 /* Make sure the directory exists (create Start Menu\Programs\Vim).
1884 * Ignore errors if it already exists. */
1885 vim_mkdir(shell_folder_path, 0755);
1886
1887 /* build the path to the shortcut and the path to gvim.exe */
1888 sprintf(link_path, "%s\\%s.lnk", shell_folder_path, link_name);
1889
1890 return OK;
1891}
1892
1893 static int
1894build_shortcut(
1895 const char *name, /* Name of the shortcut */
1896 const char *exename, /* Name of the executable (e.g., vim.exe) */
1897 const char *args,
1898 const char *shell_folder,
1899 const char *workingdir)
1900{
1901 char executable_path[BUFSIZE];
1902 char link_name[BUFSIZE];
1903
1904 sprintf(executable_path, "%s\\%s", installdir, exename);
1905
1906 if (build_link_name(link_name, name, shell_folder) == FAIL)
1907 {
1908 printf("An error has occurred. A shortcut to %s will not be created %s.\n",
1909 name,
1910 *shell_folder == 'd' ? "on the desktop" : "in the Start menu");
1911 return FAIL;
1912 }
1913
1914 /* Create the shortcut: */
1915 return create_shortcut(link_name, executable_path, 0,
1916 executable_path, args, workingdir);
1917}
1918
1919/*
1920 * We used to use "homedir" as the working directory, but that is a bad choice
Bram Moolenaar03e228a2013-11-07 04:49:27 +01001921 * on multi-user systems. However, not specifying a directory results in the
1922 * current directory to be c:\Windows\system32 on Windows 7. Use environment
1923 * variables instead.
Bram Moolenaar071d4272004-06-13 20:20:40 +00001924 */
Bram Moolenaar03e228a2013-11-07 04:49:27 +01001925#define WORKDIR "%HOMEDRIVE%%HOMEPATH%"
Bram Moolenaar071d4272004-06-13 20:20:40 +00001926
1927/*
1928 * Create shortcut(s) in the Start Menu\Programs\Vim folder.
1929 */
1930 static void
1931install_start_menu(int idx)
1932{
1933 need_uninstall_entry = 1;
1934 printf("Creating start menu\n");
1935 if (has_vim)
1936 {
1937 if (build_shortcut("Vim", "vim.exe", "",
1938 VIM_STARTMENU, WORKDIR) == FAIL)
1939 return;
1940 if (build_shortcut("Vim Read-only", "vim.exe", "-R",
1941 VIM_STARTMENU, WORKDIR) == FAIL)
1942 return;
1943 if (build_shortcut("Vim Diff", "vim.exe", "-d",
1944 VIM_STARTMENU, WORKDIR) == FAIL)
1945 return;
1946 }
1947 if (has_gvim)
1948 {
1949 if (build_shortcut("gVim", "gvim.exe", "",
1950 VIM_STARTMENU, WORKDIR) == FAIL)
1951 return;
1952 if (build_shortcut("gVim Easy", "gvim.exe", "-y",
1953 VIM_STARTMENU, WORKDIR) == FAIL)
1954 return;
1955 if (build_shortcut("gVim Read-only", "gvim.exe", "-R",
1956 VIM_STARTMENU, WORKDIR) == FAIL)
1957 return;
1958 if (build_shortcut("gVim Diff", "gvim.exe", "-d",
1959 VIM_STARTMENU, WORKDIR) == FAIL)
1960 return;
1961 }
1962 if (build_shortcut("Uninstall",
1963 interactive ? "uninstal.exe" : "uninstall-gui.exe", "",
1964 VIM_STARTMENU, installdir) == FAIL)
1965 return;
1966 /* For Windows NT the working dir of the vimtutor.bat must be right,
1967 * otherwise gvim.exe won't be found and using gvimbat doesn't work. */
1968 if (build_shortcut("Vim tutor", "vimtutor.bat", "",
1969 VIM_STARTMENU, installdir) == FAIL)
1970 return;
1971 if (build_shortcut("Help", has_gvim ? "gvim.exe" : "vim.exe", "-c h",
1972 VIM_STARTMENU, WORKDIR) == FAIL)
1973 return;
1974 {
1975 char shell_folder_path[BUFSIZE];
1976
1977 /* Creating the URL shortcut works a bit differently... */
1978 if (get_shell_folder_path(shell_folder_path, VIM_STARTMENU) == FAIL)
1979 {
1980 printf("Finding the path of the Start menu failed\n");
1981 return ;
1982 }
1983 add_pathsep(shell_folder_path);
1984 strcat(shell_folder_path, "Vim Online.url");
1985 if (!WritePrivateProfileString("InternetShortcut", "URL",
Bram Moolenaarbd87eb32018-06-26 23:18:45 +02001986 "https://www.vim.org/", shell_folder_path))
Bram Moolenaar071d4272004-06-13 20:20:40 +00001987 {
1988 printf("Creating the Vim online URL failed\n");
1989 return;
1990 }
1991 }
1992}
1993
1994 static void
1995toggle_startmenu_choice(int idx)
1996{
1997 if (choices[idx].installfunc == NULL)
1998 {
1999 choices[idx].installfunc = install_start_menu;
2000 choices[idx].text = "Add Vim to the Start menu";
2001 }
2002 else
2003 {
2004 choices[idx].installfunc = NULL;
2005 choices[idx].text = "Do NOT add Vim to the Start menu";
2006 }
2007}
2008
2009/*
2010 * Function to actually create the shortcuts
2011 *
2012 * Currently I am supplying no working directory to the shortcut. This
2013 * means that the initial working dir will be:
2014 * - the location of the shortcut if no file is supplied
2015 * - the location of the file being edited if a file is supplied (ie via
2016 * drag and drop onto the shortcut).
2017 */
2018 void
2019install_shortcut_gvim(int idx)
2020{
2021 /* Create shortcut(s) on the desktop */
2022 if (choices[idx].arg)
2023 {
2024 (void)build_shortcut(icon_names[0], "gvim.exe",
2025 "", "desktop", WORKDIR);
2026 need_uninstall_entry = 1;
2027 }
2028}
2029
2030 void
2031install_shortcut_evim(int idx)
2032{
2033 if (choices[idx].arg)
2034 {
2035 (void)build_shortcut(icon_names[1], "gvim.exe",
2036 "-y", "desktop", WORKDIR);
2037 need_uninstall_entry = 1;
2038 }
2039}
2040
2041 void
2042install_shortcut_gview(int idx)
2043{
2044 if (choices[idx].arg)
2045 {
2046 (void)build_shortcut(icon_names[2], "gvim.exe",
2047 "-R", "desktop", WORKDIR);
2048 need_uninstall_entry = 1;
2049 }
2050}
2051
2052 void
2053toggle_shortcut_choice(int idx)
2054{
2055 char *arg;
2056
2057 if (choices[idx].installfunc == install_shortcut_gvim)
2058 arg = "gVim";
2059 else if (choices[idx].installfunc == install_shortcut_evim)
2060 arg = "gVim Easy";
2061 else
2062 arg = "gVim Read-only";
2063 if (choices[idx].arg)
2064 {
2065 choices[idx].arg = 0;
2066 alloc_text(idx, "Do NOT create a desktop icon for %s", arg);
2067 }
2068 else
2069 {
2070 choices[idx].arg = 1;
2071 alloc_text(idx, "Create a desktop icon for %s", arg);
2072 }
2073}
Bram Moolenaar071d4272004-06-13 20:20:40 +00002074
2075 static void
2076init_startmenu_choice(void)
2077{
Bram Moolenaar071d4272004-06-13 20:20:40 +00002078 /* Start menu */
2079 choices[choice_count].changefunc = toggle_startmenu_choice;
2080 choices[choice_count].installfunc = NULL;
2081 choices[choice_count].active = 1;
2082 toggle_startmenu_choice(choice_count); /* set the text */
2083 ++choice_count;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002084}
2085
2086/*
2087 * Add the choice for the desktop shortcuts.
2088 */
2089 static void
2090init_shortcut_choices(void)
2091{
Bram Moolenaar071d4272004-06-13 20:20:40 +00002092 /* Shortcut to gvim */
2093 choices[choice_count].text = NULL;
2094 choices[choice_count].arg = 0;
2095 choices[choice_count].active = has_gvim;
2096 choices[choice_count].changefunc = toggle_shortcut_choice;
2097 choices[choice_count].installfunc = install_shortcut_gvim;
2098 toggle_shortcut_choice(choice_count);
2099 ++choice_count;
2100
2101 /* Shortcut to evim */
2102 choices[choice_count].text = NULL;
2103 choices[choice_count].arg = 0;
2104 choices[choice_count].active = has_gvim;
2105 choices[choice_count].changefunc = toggle_shortcut_choice;
2106 choices[choice_count].installfunc = install_shortcut_evim;
2107 toggle_shortcut_choice(choice_count);
2108 ++choice_count;
2109
2110 /* Shortcut to gview */
2111 choices[choice_count].text = NULL;
2112 choices[choice_count].arg = 0;
2113 choices[choice_count].active = has_gvim;
2114 choices[choice_count].changefunc = toggle_shortcut_choice;
2115 choices[choice_count].installfunc = install_shortcut_gview;
2116 toggle_shortcut_choice(choice_count);
2117 ++choice_count;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002118}
2119
Bram Moolenaar071d4272004-06-13 20:20:40 +00002120/*
2121 * Attempt to register OLE for Vim.
2122 */
2123 static void
2124install_OLE_register(void)
2125{
2126 char register_command_string[BUFSIZE + 30];
2127
2128 printf("\n--- Attempting to register Vim with OLE ---\n");
2129 printf("(There is no message whether this works or not.)\n");
2130
Bram Moolenaar071d4272004-06-13 20:20:40 +00002131 sprintf(register_command_string, "\"%s\\gvim.exe\" -silent -register", installdir);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002132 system(register_command_string);
2133}
Bram Moolenaar071d4272004-06-13 20:20:40 +00002134
2135/*
2136 * Remove the last part of directory "path[]" to get its parent, and put the
2137 * result in "to[]".
2138 */
2139 static void
Bram Moolenaare4963c52019-02-22 19:41:08 +01002140dir_remove_last(const char *path, char to[MAX_PATH])
Bram Moolenaar071d4272004-06-13 20:20:40 +00002141{
2142 char c;
2143 long last_char_to_copy;
2144 long path_length = strlen(path);
2145
2146 /* skip the last character just in case it is a '\\' */
2147 last_char_to_copy = path_length - 2;
2148 c = path[last_char_to_copy];
2149
2150 while (c != '\\')
2151 {
2152 last_char_to_copy--;
2153 c = path[last_char_to_copy];
2154 }
2155
2156 strncpy(to, path, (size_t)last_char_to_copy);
2157 to[last_char_to_copy] = NUL;
2158}
2159
2160 static void
2161set_directories_text(int idx)
2162{
Bram Moolenaar25a494c2018-11-16 19:39:50 +01002163 int vimfiles_dir_choice = choices[idx].arg;
2164
Bram Moolenaar071d4272004-06-13 20:20:40 +00002165 if (vimfiles_dir_choice == (int)vimfiles_dir_none)
2166 alloc_text(idx, "Do NOT create plugin directories%s", "");
2167 else
2168 alloc_text(idx, "Create plugin directories: %s",
2169 vimfiles_dir_choices[vimfiles_dir_choice]);
2170}
2171
2172/*
Bram Moolenaar25a494c2018-11-16 19:39:50 +01002173 * To get the "real" home directory:
2174 * - get value of $HOME
2175 * - if not found, get value of $HOMEDRIVE$HOMEPATH
2176 * - if not found, get value of $USERPROFILE
2177 *
2178 * This code is based on init_homedir() in misc1.c, keep in sync!
2179 */
2180static char *homedir = NULL;
2181
2182 void
2183init_homedir(void)
2184{
2185 char *var;
2186 char buf[MAX_PATH];
2187
2188 if (homedir != NULL)
2189 {
2190 free(homedir);
2191 homedir = NULL;
2192 }
2193
2194 var = getenv("HOME");
2195
2196 /*
2197 * Typically, $HOME is not defined on Windows, unless the user has
2198 * specifically defined it for Vim's sake. However, on Windows NT
2199 * platforms, $HOMEDRIVE and $HOMEPATH are automatically defined for
2200 * each user. Try constructing $HOME from these.
2201 */
2202 if (var == NULL || *var == NUL)
2203 {
2204 char *homedrive, *homepath;
2205
2206 homedrive = getenv("HOMEDRIVE");
2207 homepath = getenv("HOMEPATH");
2208 if (homepath == NULL || *homepath == NUL)
2209 homepath = "\\";
2210 if (homedrive != NULL
Bram Moolenaare4963c52019-02-22 19:41:08 +01002211 && strlen(homedrive) + strlen(homepath) < sizeof(buf))
Bram Moolenaar25a494c2018-11-16 19:39:50 +01002212 {
2213 sprintf(buf, "%s%s", homedrive, homepath);
2214 if (buf[0] != NUL)
2215 var = buf;
2216 }
2217 }
2218
2219 if (var == NULL)
2220 var = getenv("USERPROFILE");
2221
2222 /*
2223 * Weird but true: $HOME may contain an indirect reference to another
2224 * variable, esp. "%USERPROFILE%". Happens when $USERPROFILE isn't set
2225 * when $HOME is being set.
2226 */
2227 if (var != NULL && *var == '%')
2228 {
2229 char *p;
2230 char *exp;
2231
2232 p = strchr(var + 1, '%');
2233 if (p != NULL)
2234 {
2235 strncpy(buf, var + 1, p - (var + 1));
2236 buf[p - (var + 1)] = NUL;
2237 exp = getenv(buf);
2238 if (exp != NULL && *exp != NUL
Bram Moolenaare4963c52019-02-22 19:41:08 +01002239 && strlen(exp) + strlen(p) < sizeof(buf))
Bram Moolenaar25a494c2018-11-16 19:39:50 +01002240 {
Bram Moolenaare4963c52019-02-22 19:41:08 +01002241 sprintf(buf, "%s%s", exp, p + 1);
Bram Moolenaar25a494c2018-11-16 19:39:50 +01002242 var = buf;
2243 }
2244 }
2245 }
2246
2247 if (var != NULL && *var == NUL) // empty is same as not set
2248 var = NULL;
2249
2250 if (var == NULL)
2251 homedir = NULL;
2252 else
2253 homedir = _strdup(var);
2254}
2255
2256/*
Bram Moolenaar071d4272004-06-13 20:20:40 +00002257 * Change the directory that the vim plugin directories will be created in:
2258 * $HOME, $VIM or nowhere.
2259 */
2260 static void
2261change_directories_choice(int idx)
2262{
2263 int choice_count = TABLE_SIZE(vimfiles_dir_choices);
2264
2265 /* Don't offer the $HOME choice if $HOME isn't set. */
Bram Moolenaar25a494c2018-11-16 19:39:50 +01002266 if (homedir == NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002267 --choice_count;
Bram Moolenaar25a494c2018-11-16 19:39:50 +01002268 choices[idx].arg = get_choice(vimfiles_dir_choices, choice_count);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002269 set_directories_text(idx);
2270}
2271
2272/*
2273 * Create the plugin directories...
2274 */
2275/*ARGSUSED*/
2276 static void
2277install_vimfilesdir(int idx)
2278{
2279 int i;
Bram Moolenaar25a494c2018-11-16 19:39:50 +01002280 int vimfiles_dir_choice = choices[idx].arg;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002281 char *p;
Bram Moolenaarbbd854d2019-02-18 22:19:33 +01002282 char vimdir_path[MAX_PATH];
2283 char vimfiles_path[MAX_PATH + 9];
Bram Moolenaar071d4272004-06-13 20:20:40 +00002284 char tmp_dirname[BUFSIZE];
2285
2286 /* switch on the location that the user wants the plugin directories
2287 * built in */
2288 switch (vimfiles_dir_choice)
2289 {
2290 case vimfiles_dir_vim:
2291 {
2292 /* Go to the %VIM% directory - check env first, then go one dir
2293 * below installdir if there is no %VIM% environment variable.
2294 * The accuracy of $VIM is checked in inspect_system(), so we
2295 * can be sure it is ok to use here. */
2296 p = getenv("VIM");
2297 if (p == NULL) /* No $VIM in path */
2298 dir_remove_last(installdir, vimdir_path);
2299 else
2300 strcpy(vimdir_path, p);
2301 break;
2302 }
2303 case vimfiles_dir_home:
2304 {
Bram Moolenaar25a494c2018-11-16 19:39:50 +01002305 // Find the $HOME directory. Its existence was already checked.
2306 p = homedir;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002307 if (p == NULL)
2308 {
2309 printf("Internal error: $HOME is NULL\n");
2310 p = "c:\\";
2311 }
2312 strcpy(vimdir_path, p);
2313 break;
2314 }
2315 case vimfiles_dir_none:
2316 {
Bram Moolenaar25a494c2018-11-16 19:39:50 +01002317 // Do not create vim plugin directory.
Bram Moolenaar071d4272004-06-13 20:20:40 +00002318 return;
2319 }
2320 }
2321
2322 /* Now, just create the directory. If it already exists, it will fail
2323 * silently. */
2324 sprintf(vimfiles_path, "%s\\vimfiles", vimdir_path);
2325 vim_mkdir(vimfiles_path, 0755);
2326
2327 printf("Creating the following directories in \"%s\":\n", vimfiles_path);
2328 for (i = 0; i < TABLE_SIZE(vimfiles_subdirs); i++)
2329 {
2330 sprintf(tmp_dirname, "%s\\%s", vimfiles_path, vimfiles_subdirs[i]);
2331 printf(" %s", vimfiles_subdirs[i]);
2332 vim_mkdir(tmp_dirname, 0755);
2333 }
2334 printf("\n");
2335}
2336
2337/*
2338 * Add the creation of runtime files to the setup sequence.
2339 */
2340 static void
2341init_directories_choice(void)
2342{
2343 struct stat st;
2344 char tmp_dirname[BUFSIZE];
2345 char *p;
Bram Moolenaar25a494c2018-11-16 19:39:50 +01002346 int vimfiles_dir_choice;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002347
2348 choices[choice_count].text = alloc(150);
2349 choices[choice_count].changefunc = change_directories_choice;
2350 choices[choice_count].installfunc = install_vimfilesdir;
2351 choices[choice_count].active = 1;
2352
Bram Moolenaar25a494c2018-11-16 19:39:50 +01002353 // Check if the "compiler" directory already exists. That's a good
2354 // indication that the plugin directories were already created.
Bram Moolenaare4963c52019-02-22 19:41:08 +01002355 p = getenv("HOME");
2356 if (p != NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002357 {
2358 vimfiles_dir_choice = (int)vimfiles_dir_home;
Bram Moolenaare4963c52019-02-22 19:41:08 +01002359 sprintf(tmp_dirname, "%s\\vimfiles\\compiler", p);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002360 if (stat(tmp_dirname, &st) == 0)
2361 vimfiles_dir_choice = (int)vimfiles_dir_none;
2362 }
2363 else
2364 {
2365 vimfiles_dir_choice = (int)vimfiles_dir_vim;
2366 p = getenv("VIM");
Bram Moolenaar25a494c2018-11-16 19:39:50 +01002367 if (p == NULL) // No $VIM in path, use the install dir.
Bram Moolenaar071d4272004-06-13 20:20:40 +00002368 dir_remove_last(installdir, tmp_dirname);
2369 else
2370 strcpy(tmp_dirname, p);
2371 strcat(tmp_dirname, "\\vimfiles\\compiler");
2372 if (stat(tmp_dirname, &st) == 0)
2373 vimfiles_dir_choice = (int)vimfiles_dir_none;
2374 }
2375
Bram Moolenaar25a494c2018-11-16 19:39:50 +01002376 choices[choice_count].arg = vimfiles_dir_choice;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002377 set_directories_text(choice_count);
2378 ++choice_count;
2379}
2380
2381/*
2382 * Setup the choices and the default values.
2383 */
2384 static void
2385setup_choices(void)
2386{
2387 /* install the batch files */
2388 init_bat_choices();
2389
2390 /* (over) write _vimrc file */
2391 init_vimrc_choices();
2392
2393 /* Whether to add Vim to the popup menu */
2394 init_popup_choice();
2395
2396 /* Whether to add Vim to the "Open With..." menu */
2397 init_openwith_choice();
2398
2399 /* Whether to add Vim to the Start Menu. */
2400 init_startmenu_choice();
2401
2402 /* Whether to add shortcuts to the Desktop. */
2403 init_shortcut_choices();
2404
2405 /* Whether to create the runtime directories. */
2406 init_directories_choice();
2407}
2408
2409 static void
2410print_cmd_line_help(void)
2411{
2412 printf("Vim installer non-interactive command line arguments:\n");
2413 printf("\n");
2414 printf("-create-batfiles [vim gvim evim view gview vimdiff gvimdiff]\n");
2415 printf(" Create .bat files for Vim variants in the Windows directory.\n");
2416 printf("-create-vimrc\n");
2417 printf(" Create a default _vimrc file if one does not already exist.\n");
Bram Moolenaarc3fdf7f2017-10-28 18:36:48 +02002418 printf("-vimrc-remap [no|win]\n");
2419 printf(" Remap keys when creating a default _vimrc file.\n");
2420 printf("-vimrc-behave [unix|mswin|default]\n");
2421 printf(" Set mouse behavior when creating a default _vimrc file.\n");
Bram Moolenaar6cdb2c92018-10-13 17:25:27 +02002422 printf("-vimrc-compat [vi|vim|defaults|all]\n");
2423 printf(" Set Vi compatibility when creating a default _vimrc file.\n");
Bram Moolenaar071d4272004-06-13 20:20:40 +00002424 printf("-install-popup\n");
2425 printf(" Install the Edit-with-Vim context menu entry\n");
2426 printf("-install-openwith\n");
2427 printf(" Add Vim to the \"Open With...\" context menu list\n");
Bram Moolenaar071d4272004-06-13 20:20:40 +00002428 printf("-add-start-menu");
2429 printf(" Add Vim to the start menu\n");
2430 printf("-install-icons");
2431 printf(" Create icons for gVim executables on the desktop\n");
Bram Moolenaar071d4272004-06-13 20:20:40 +00002432 printf("-create-directories [vim|home]\n");
2433 printf(" Create runtime directories to drop plugins into; in the $VIM\n");
2434 printf(" or $HOME directory\n");
Bram Moolenaar071d4272004-06-13 20:20:40 +00002435 printf("-register-OLE");
Bram Moolenaarce0842a2005-07-18 21:58:11 +00002436 printf(" Ignored\n");
Bram Moolenaar071d4272004-06-13 20:20:40 +00002437 printf("\n");
2438}
2439
2440/*
2441 * Setup installation choices based on command line switches
2442 */
2443 static void
2444command_line_setup_choices(int argc, char **argv)
2445{
2446 int i, j;
2447
2448 for (i = 1; i < argc; i++)
2449 {
2450 if (strcmp(argv[i], "-create-batfiles") == 0)
2451 {
2452 if (i + 1 == argc)
2453 continue;
2454 while (argv[i + 1][0] != '-' && i < argc)
2455 {
2456 i++;
2457 for (j = 1; j < TARGET_COUNT; ++j)
2458 if ((targets[j].exenamearg[0] == 'g' ? has_gvim : has_vim)
2459 && strcmp(argv[i], targets[j].name) == 0)
2460 {
2461 init_bat_choice(j);
2462 break;
2463 }
2464 if (j == TARGET_COUNT)
2465 printf("%s is not a valid choice for -create-batfiles\n",
2466 argv[i]);
2467
2468 if (i + 1 == argc)
2469 break;
2470 }
2471 }
2472 else if (strcmp(argv[i], "-create-vimrc") == 0)
2473 {
2474 /* Setup default vimrc choices. If there is already a _vimrc file,
2475 * it will NOT be overwritten.
2476 */
2477 init_vimrc_choices();
2478 }
Bram Moolenaarc3fdf7f2017-10-28 18:36:48 +02002479 else if (strcmp(argv[i], "-vimrc-remap") == 0)
2480 {
2481 if (i + 1 == argc)
2482 break;
2483 i++;
2484 if (strcmp(argv[i], "no") == 0)
2485 remap_choice = remap_no;
2486 else if (strcmp(argv[i], "win") == 0)
2487 remap_choice = remap_win;
2488 }
2489 else if (strcmp(argv[i], "-vimrc-behave") == 0)
2490 {
2491 if (i + 1 == argc)
2492 break;
2493 i++;
2494 if (strcmp(argv[i], "unix") == 0)
2495 mouse_choice = mouse_xterm;
2496 else if (strcmp(argv[i], "mswin") == 0)
2497 mouse_choice = mouse_mswin;
2498 else if (strcmp(argv[i], "default") == 0)
2499 mouse_choice = mouse_default;
2500 }
Bram Moolenaar6cdb2c92018-10-13 17:25:27 +02002501 else if (strcmp(argv[i], "-vimrc-compat") == 0)
2502 {
2503 if (i + 1 == argc)
2504 break;
2505 i++;
2506 if (strcmp(argv[i], "vi") == 0)
2507 compat_choice = compat_vi;
2508 else if (strcmp(argv[i], "vim") == 0)
2509 compat_choice = compat_vim;
2510 else if (strcmp(argv[i], "defaults") == 0)
2511 compat_choice = compat_some_enhancements;
2512 else if (strcmp(argv[i], "all") == 0)
2513 compat_choice = compat_all_enhancements;
2514 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00002515 else if (strcmp(argv[i], "-install-popup") == 0)
2516 {
2517 init_popup_choice();
2518 }
2519 else if (strcmp(argv[i], "-install-openwith") == 0)
2520 {
2521 init_openwith_choice();
2522 }
2523 else if (strcmp(argv[i], "-add-start-menu") == 0)
2524 {
2525 init_startmenu_choice();
2526 }
2527 else if (strcmp(argv[i], "-install-icons") == 0)
2528 {
2529 init_shortcut_choices();
2530 }
2531 else if (strcmp(argv[i], "-create-directories") == 0)
2532 {
Bram Moolenaar142a9752018-12-14 19:54:39 +01002533 int vimfiles_dir_choice = (int)vimfiles_dir_none;
Bram Moolenaar25a494c2018-11-16 19:39:50 +01002534
Bram Moolenaar071d4272004-06-13 20:20:40 +00002535 init_directories_choice();
2536 if (argv[i + 1][0] != '-')
2537 {
2538 i++;
2539 if (strcmp(argv[i], "vim") == 0)
2540 vimfiles_dir_choice = (int)vimfiles_dir_vim;
2541 else if (strcmp(argv[i], "home") == 0)
2542 {
Bram Moolenaar25a494c2018-11-16 19:39:50 +01002543 if (homedir == NULL) // No $HOME in environment
2544 vimfiles_dir_choice = (int)vimfiles_dir_none;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002545 else
2546 vimfiles_dir_choice = (int)vimfiles_dir_home;
2547 }
2548 else
2549 {
2550 printf("Unknown argument for -create-directories: %s\n",
2551 argv[i]);
2552 print_cmd_line_help();
2553 }
2554 }
2555 else /* No choice specified, default to vim directory */
2556 vimfiles_dir_choice = (int)vimfiles_dir_vim;
Bram Moolenaar25a494c2018-11-16 19:39:50 +01002557 choices[choice_count - 1].arg = vimfiles_dir_choice;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002558 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00002559 else if (strcmp(argv[i], "-register-OLE") == 0)
2560 {
2561 /* This is always done when gvim is found */
2562 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00002563 else /* Unknown switch */
2564 {
2565 printf("Got unknown argument argv[%d] = %s\n", i, argv[i]);
2566 print_cmd_line_help();
2567 }
2568 }
2569}
2570
2571
2572/*
2573 * Show a few screens full of helpful information.
2574 */
2575 static void
2576show_help(void)
2577{
2578 static char *(items[]) =
2579 {
2580"Installing .bat files\n"
2581"---------------------\n"
2582"The vim.bat file is written in one of the directories in $PATH.\n"
2583"This makes it possible to start Vim from the command line.\n"
2584"If vim.exe can be found in $PATH, the choice for vim.bat will not be\n"
2585"present. It is assumed you will use the existing vim.exe.\n"
2586"If vim.bat can already be found in $PATH this is probably for an old\n"
2587"version of Vim (but this is not checked!). You can overwrite it.\n"
2588"If no vim.bat already exists, you can select one of the directories in\n"
2589"$PATH for creating the batch file, or disable creating a vim.bat file.\n"
2590"\n"
2591"If you choose not to create the vim.bat file, Vim can still be executed\n"
2592"in other ways, but not from the command line.\n"
2593"\n"
2594"The same applies to choices for gvim, evim, (g)view, and (g)vimdiff.\n"
2595"The first item can be used to change the path for all of them.\n"
2596,
2597"Creating a _vimrc file\n"
2598"----------------------\n"
2599"The _vimrc file is used to set options for how Vim behaves.\n"
2600"The install program can create a _vimrc file with a few basic choices.\n"
2601"You can edit this file later to tune your preferences.\n"
2602"If you already have a _vimrc or .vimrc file it can be overwritten.\n"
2603"Don't do that if you have made changes to it.\n"
2604,
2605"Vim features\n"
2606"------------\n"
2607"(this choice is only available when creating a _vimrc file)\n"
2608"1. Vim can run in Vi-compatible mode. Many nice Vim features are then\n"
Bram Moolenaar2b849492018-11-21 13:58:35 +01002609" disabled. Only choose Vi-compatible if you really need full Vi\n"
2610" compatibility.\n"
2611"2. Vim runs in not-Vi-compatible mode. Vim is still mostly Vi compatible,\n"
2612" but adds nice features like multi-level undo.\n"
2613"3. Running Vim with some enhancements is useful when you want some of\n"
Bram Moolenaar071d4272004-06-13 20:20:40 +00002614" the nice Vim features, but have a slow computer and want to keep it\n"
2615" really fast.\n"
Bram Moolenaar2b849492018-11-21 13:58:35 +01002616"4. Syntax highlighting shows many files in color. Not only does this look\n"
Bram Moolenaar071d4272004-06-13 20:20:40 +00002617" nice, it also makes it easier to spot errors and you can work faster.\n"
2618" The other features include editing compressed files.\n"
2619,
2620"Windows key mapping\n"
2621"-------------------\n"
2622"(this choice is only available when creating a _vimrc file)\n"
2623"Under MS-Windows the CTRL-C key copies text to the clipboard and CTRL-V\n"
2624"pastes text from the clipboard. There are a few more keys like these.\n"
2625"Unfortunately, in Vim these keys normally have another meaning.\n"
2626"1. Choose to have the keys like they normally are in Vim (useful if you\n"
2627" also use Vim on other systems).\n"
2628"2. Choose to have the keys work like they are used on MS-Windows (useful\n"
2629" if you mostly work on MS-Windows).\n"
2630,
2631"Mouse use\n"
2632"---------\n"
2633"(this choice is only available when creating a _vimrc file)\n"
2634"The right mouse button can be used in two ways:\n"
2635"1. The Unix way is to extend an existing selection. The popup menu is\n"
2636" not available.\n"
2637"2. The MS-Windows way is to show a popup menu, which allows you to\n"
2638" copy/paste text, undo/redo, etc. Extending the selection can still be\n"
2639" done by keeping SHIFT pressed while using the left mouse button\n"
2640,
2641"Edit-with-Vim context menu entry\n"
2642"--------------------------------\n"
2643"(this choice is only available when gvim.exe and gvimext.dll are present)\n"
2644"You can associate different file types with Vim, so that you can (double)\n"
2645"click on a file to edit it with Vim. This means you have to individually\n"
2646"select each file type.\n"
2647"An alternative is the option offered here: Install an \"Edit with Vim\"\n"
2648"entry in the popup menu for the right mouse button. This means you can\n"
2649"edit any file with Vim.\n"
2650,
2651"\"Open With...\" context menu entry\n"
2652"--------------------------------\n"
2653"(this choice is only available when gvim.exe is present)\n"
2654"This option adds Vim to the \"Open With...\" entry in the popup menu for\n"
2655"the right mouse button. This also makes it possible to edit HTML files\n"
2656"directly from Internet Explorer.\n"
2657,
2658"Add Vim to the Start menu\n"
2659"-------------------------\n"
2660"In Windows 95 and later, Vim can be added to the Start menu. This will\n"
2661"create a submenu with an entry for vim, gvim, evim, vimdiff, etc..\n"
2662,
2663"Icons on the desktop\n"
2664"--------------------\n"
2665"(these choices are only available when installing gvim)\n"
2666"In Windows 95 and later, shortcuts (icons) can be created on the Desktop.\n"
2667,
2668"Create plugin directories\n"
2669"-------------------------\n"
2670"Plugin directories allow extending Vim by dropping a file into a directory.\n"
2671"This choice allows creating them in $HOME (if you have a home directory) or\n"
2672"$VIM (used for everybody on the system).\n"
2673,
2674NULL
2675 };
2676 int i;
2677 int c;
2678
2679 rewind(stdin);
2680 printf("\n");
2681 for (i = 0; items[i] != NULL; ++i)
2682 {
Bram Moolenaarc3fdf7f2017-10-28 18:36:48 +02002683 puts(items[i]);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002684 printf("Hit Enter to continue, b (back) or q (quit help): ");
2685 c = getchar();
2686 rewind(stdin);
2687 if (c == 'b' || c == 'B')
2688 {
2689 if (i == 0)
2690 --i;
2691 else
2692 i -= 2;
2693 }
2694 if (c == 'q' || c == 'Q')
2695 break;
2696 printf("\n");
2697 }
2698}
2699
2700/*
2701 * Install the choices.
2702 */
2703 static void
2704install(void)
2705{
2706 int i;
2707
2708 /* Install the selected choices. */
2709 for (i = 0; i < choice_count; ++i)
2710 if (choices[i].installfunc != NULL && choices[i].active)
2711 (choices[i].installfunc)(i);
2712
2713 /* Add some entries to the registry, if needed. */
2714 if (install_popup
2715 || install_openwith
2716 || (need_uninstall_entry && interactive)
2717 || !interactive)
2718 install_registry();
2719
Bram Moolenaar071d4272004-06-13 20:20:40 +00002720 /* Register gvim with OLE. */
2721 if (has_gvim)
2722 install_OLE_register();
Bram Moolenaar071d4272004-06-13 20:20:40 +00002723}
2724
2725/*
2726 * request_choice
2727 */
2728 static void
2729request_choice(void)
2730{
2731 int i;
2732
2733 printf("\n\nInstall will do for you:\n");
2734 for (i = 0; i < choice_count; ++i)
2735 if (choices[i].active)
2736 printf("%2d %s\n", i + 1, choices[i].text);
2737 printf("To change an item, enter its number\n\n");
2738 printf("Enter item number, h (help), d (do it) or q (quit): ");
2739}
2740
2741 int
2742main(int argc, char **argv)
2743{
2744 int i;
2745 char buf[BUFSIZE];
2746
2747 /*
2748 * Run interactively if there are no command line arguments.
2749 */
2750 if (argc > 1)
2751 interactive = 0;
2752 else
2753 interactive = 1;
2754
2755 /* Initialize this program. */
2756 do_inits(argv);
Bram Moolenaar25a494c2018-11-16 19:39:50 +01002757 init_homedir();
Bram Moolenaar071d4272004-06-13 20:20:40 +00002758
Bram Moolenaar071d4272004-06-13 20:20:40 +00002759 if (argc > 1 && strcmp(argv[1], "-uninstall-check") == 0)
2760 {
2761 /* Only check for already installed Vims. Used by NSIS installer. */
Bram Moolenaar442b4222010-05-24 21:34:22 +02002762 i = uninstall_check(1);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002763
2764 /* Find the value of $VIM, because NSIS isn't able to do this by
2765 * itself. */
2766 get_vim_env();
2767
2768 /* When nothing found exit quietly. If something found wait for
Bram Moolenaarb230bd52010-05-25 21:02:00 +02002769 * a little while, so that the user can read the messages. */
Bram Moolenaar6cdb2c92018-10-13 17:25:27 +02002770 if (i && _isatty(1))
Bram Moolenaarab8205e2010-07-07 15:14:03 +02002771 sleep(3);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002772 exit(0);
2773 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00002774
2775 printf("This program sets up the installation of Vim "
2776 VIM_VERSION_MEDIUM "\n\n");
2777
2778 /* Check if the user unpacked the archives properly. */
2779 check_unpack();
2780
Bram Moolenaar071d4272004-06-13 20:20:40 +00002781 /* Check for already installed Vims. */
2782 if (interactive)
Bram Moolenaar442b4222010-05-24 21:34:22 +02002783 uninstall_check(0);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002784
2785 /* Find out information about the system. */
2786 inspect_system();
2787
2788 if (interactive)
2789 {
2790 /* Setup all the choices. */
2791 setup_choices();
2792
2793 /* Let the user change choices and finally install (or quit). */
2794 for (;;)
2795 {
2796 request_choice();
2797 rewind(stdin);
2798 if (scanf("%99s", buf) == 1)
2799 {
2800 if (isdigit(buf[0]))
2801 {
2802 /* Change a choice. */
2803 i = atoi(buf);
2804 if (i > 0 && i <= choice_count && choices[i - 1].active)
2805 (choices[i - 1].changefunc)(i - 1);
2806 else
2807 printf("\nIllegal choice\n");
2808 }
2809 else if (buf[0] == 'h' || buf[0] == 'H')
2810 {
2811 /* Help */
2812 show_help();
2813 }
2814 else if (buf[0] == 'd' || buf[0] == 'D')
2815 {
2816 /* Install! */
2817 install();
2818 printf("\nThat finishes the installation. Happy Vimming!\n");
2819 break;
2820 }
2821 else if (buf[0] == 'q' || buf[0] == 'Q')
2822 {
2823 /* Quit */
2824 printf("\nExiting without anything done\n");
2825 break;
2826 }
2827 else
2828 printf("\nIllegal choice\n");
2829 }
2830 }
2831 printf("\n");
Bram Moolenaar442b4222010-05-24 21:34:22 +02002832 myexit(0);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002833 }
2834 else
2835 {
2836 /*
2837 * Run non-interactive - setup according to the command line switches
2838 */
2839 command_line_setup_choices(argc, argv);
2840 install();
Bram Moolenaar442b4222010-05-24 21:34:22 +02002841
2842 /* Avoid that the user has to hit Enter, just wait a little bit to
2843 * allow reading the messages. */
Bram Moolenaarab8205e2010-07-07 15:14:03 +02002844 sleep(2);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002845 }
2846
Bram Moolenaar071d4272004-06-13 20:20:40 +00002847 return 0;
2848}