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