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