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