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