blob: 6ce40439a0eb3b0999631f754e4505414401c52b [file] [log] [blame]
Bram Moolenaaredf3f972016-08-29 22:49:24 +02001/* vi:set ts=8 sts=4 sw=4 noet:
Bram Moolenaar071d4272004-06-13 20:20:40 +00002 *
3 * VIM - Vi IMproved by Bram Moolenaar
4 *
5 * Do ":help uganda" in Vim to read copying and usage conditions.
6 * Do ":help credits" in Vim to see a list of people who contributed.
7 * See README.txt for an overview of the Vim source code.
8 */
9
10/*
11 * dosinst.c: Install program for Vim on MS-DOS and MS-Windows
12 *
Bram Moolenaareae1b912019-05-09 15:12:55 +020013 * Compile with Make_mvc.mak, Make_cyg.mak or Make_ming.mak.
Bram Moolenaar071d4272004-06-13 20:20:40 +000014 */
15
16/*
Bram Moolenaar30e8e732019-09-27 13:08:36 +020017 * Include common code for dosinst.c and uninstall.c.
Bram Moolenaar071d4272004-06-13 20:20:40 +000018 */
19#define DOSINST
20#include "dosinst.h"
Bram Moolenaar6cdb2c92018-10-13 17:25:27 +020021#include <io.h>
Bram Moolenaar071d4272004-06-13 20:20:40 +000022
Bram Moolenaar6199d432017-10-14 19:05:44 +020023#define GVIMEXT64_PATH "GvimExt64\\gvimext.dll"
24#define GVIMEXT32_PATH "GvimExt32\\gvimext.dll"
25
Bram Moolenaar5d18efe2019-12-01 21:11:22 +010026// Macro to do an error check I was typing over and over
Bram Moolenaar6f470022018-04-10 18:47:20 +020027#define CHECK_REG_ERROR(code) \
28 do { \
29 if (code != ERROR_SUCCESS) \
30 { \
31 printf("%ld error number: %ld\n", (long)__LINE__, (long)code); \
32 return 1; \
33 } \
34 } while (0)
Bram Moolenaar071d4272004-06-13 20:20:40 +000035
Bram Moolenaar5d18efe2019-12-01 21:11:22 +010036int has_vim = 0; // installable vim.exe exists
37int has_gvim = 0; // installable gvim.exe exists
Bram Moolenaar071d4272004-06-13 20:20:40 +000038
Bram Moolenaar5d18efe2019-12-01 21:11:22 +010039char oldvimrc[BUFSIZE]; // name of existing vimrc file
40char vimrc[BUFSIZE]; // name of vimrc file to create
Bram Moolenaar071d4272004-06-13 20:20:40 +000041
Bram Moolenaar5d18efe2019-12-01 21:11:22 +010042char *default_bat_dir = NULL; // when not NULL, use this as the default
43 // directory to write .bat files in
44char *default_vim_dir = NULL; // when not NULL, use this as the default
45 // install dir for NSIS
Bram Moolenaar071d4272004-06-13 20:20:40 +000046
47/*
48 * Structure used for each choice the user can make.
49 */
50struct choice
51{
Bram Moolenaar5d18efe2019-12-01 21:11:22 +010052 int active; // non-zero when choice is active
53 char *text; // text displayed for this choice
54 void (*changefunc)(int idx); // function to change this choice
55 int arg; // argument for function
56 void (*installfunc)(int idx); // function to install this choice
Bram Moolenaar071d4272004-06-13 20:20:40 +000057};
58
Bram Moolenaar5d18efe2019-12-01 21:11:22 +010059struct choice choices[30]; // choices the user can make
60int choice_count = 0; // number of choices available
Bram Moolenaar071d4272004-06-13 20:20:40 +000061
62#define TABLE_SIZE(s) (int)(sizeof(s) / sizeof(*s))
63
64enum
65{
66 compat_vi = 1,
Bram Moolenaar6cdb2c92018-10-13 17:25:27 +020067 compat_vim,
Bram Moolenaar071d4272004-06-13 20:20:40 +000068 compat_some_enhancements,
69 compat_all_enhancements
70};
71char *(compat_choices[]) =
72{
73 "\nChoose the default way to run Vim:",
74 "Vi compatible",
Bram Moolenaar6cdb2c92018-10-13 17:25:27 +020075 "Vim default",
Bram Moolenaarfff2bee2010-05-15 13:56:02 +020076 "with some Vim enhancements",
Bram Moolenaar071d4272004-06-13 20:20:40 +000077 "with syntax highlighting and other features switched on",
78};
79int compat_choice = (int)compat_all_enhancements;
80char *compat_text = "- run Vim %s";
81
82enum
83{
84 remap_no = 1,
85 remap_win
86};
87char *(remap_choices[]) =
88{
89 "\nChoose:",
90 "Do not remap keys for Windows behavior",
Bram Moolenaar6199d432017-10-14 19:05:44 +020091 "Remap a few keys for Windows behavior (CTRL-V, CTRL-C, CTRL-F, etc)",
Bram Moolenaar071d4272004-06-13 20:20:40 +000092};
Bram Moolenaarc3fdf7f2017-10-28 18:36:48 +020093int remap_choice = (int)remap_no;
Bram Moolenaar071d4272004-06-13 20:20:40 +000094char *remap_text = "- %s";
95
96enum
97{
98 mouse_xterm = 1,
Bram Moolenaarb9fce6c2017-10-28 18:50:01 +020099 mouse_mswin,
Bram Moolenaarc3fdf7f2017-10-28 18:36:48 +0200100 mouse_default
Bram Moolenaar071d4272004-06-13 20:20:40 +0000101};
102char *(mouse_choices[]) =
103{
104 "\nChoose the way how Vim uses the mouse:",
105 "right button extends selection (the Unix way)",
Bram Moolenaarc3fdf7f2017-10-28 18:36:48 +0200106 "right button has a popup menu, left button starts select mode (the Windows way)",
107 "right button has a popup menu, left button starts visual mode",
Bram Moolenaar071d4272004-06-13 20:20:40 +0000108};
Bram Moolenaarc3fdf7f2017-10-28 18:36:48 +0200109int mouse_choice = (int)mouse_default;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000110char *mouse_text = "- The mouse %s";
111
112enum
113{
114 vimfiles_dir_none = 1,
115 vimfiles_dir_vim,
116 vimfiles_dir_home
117};
Bram Moolenaar25a494c2018-11-16 19:39:50 +0100118static char *(vimfiles_dir_choices[]) =
Bram Moolenaar071d4272004-06-13 20:20:40 +0000119{
120 "\nCreate plugin directories:",
121 "No",
122 "In the VIM directory",
123 "In your HOME directory",
124};
Bram Moolenaar071d4272004-06-13 20:20:40 +0000125
Bram Moolenaar5d18efe2019-12-01 21:11:22 +0100126// non-zero when selected to install the popup menu entry.
Bram Moolenaar071d4272004-06-13 20:20:40 +0000127static int install_popup = 0;
128
Bram Moolenaar5d18efe2019-12-01 21:11:22 +0100129// non-zero when selected to install the "Open with" entry.
Bram Moolenaar071d4272004-06-13 20:20:40 +0000130static int install_openwith = 0;
131
Bram Moolenaar5d18efe2019-12-01 21:11:22 +0100132// non-zero when need to add an uninstall entry in the registry
Bram Moolenaar071d4272004-06-13 20:20:40 +0000133static int need_uninstall_entry = 0;
134
135/*
136 * Definitions of the directory name (under $VIM) of the vimfiles directory
137 * and its subdirectories:
138 */
139static char *(vimfiles_subdirs[]) =
140{
141 "colors",
142 "compiler",
143 "doc",
144 "ftdetect",
145 "ftplugin",
146 "indent",
147 "keymap",
148 "plugin",
149 "syntax",
150};
151
152/*
Bram Moolenaar071d4272004-06-13 20:20:40 +0000153 * Obtain a choice from a table.
154 * First entry is a question, others are choices.
155 */
156 static int
157get_choice(char **table, int entries)
158{
159 int answer;
160 int idx;
161 char dummy[100];
162
163 do
164 {
165 for (idx = 0; idx < entries; ++idx)
166 {
167 if (idx)
168 printf("%2d ", idx);
Bram Moolenaarc3fdf7f2017-10-28 18:36:48 +0200169 puts(table[idx]);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000170 }
171 printf("Choice: ");
172 if (scanf("%d", &answer) != 1)
173 {
174 scanf("%99s", dummy);
175 answer = 0;
176 }
177 }
178 while (answer < 1 || answer >= entries);
179
180 return answer;
181}
182
183/*
184 * Check if the user unpacked the archives properly.
185 * Sets "runtimeidx".
186 */
187 static void
188check_unpack(void)
189{
190 char buf[BUFSIZE];
191 FILE *fd;
192 struct stat st;
193
Bram Moolenaar5d18efe2019-12-01 21:11:22 +0100194 // check for presence of the correct version number in installdir[]
Bram Moolenaar071d4272004-06-13 20:20:40 +0000195 runtimeidx = strlen(installdir) - strlen(VIM_VERSION_NODOT);
196 if (runtimeidx <= 0
197 || stricmp(installdir + runtimeidx, VIM_VERSION_NODOT) != 0
198 || (installdir[runtimeidx - 1] != '/'
199 && installdir[runtimeidx - 1] != '\\'))
200 {
201 printf("ERROR: Install program not in directory \"%s\"\n",
202 VIM_VERSION_NODOT);
203 printf("This program can only work when it is located in its original directory\n");
204 myexit(1);
205 }
206
Bram Moolenaar5d18efe2019-12-01 21:11:22 +0100207 // check if filetype.vim is present, which means the runtime archive has
208 // been unpacked
Bram Moolenaar071d4272004-06-13 20:20:40 +0000209 sprintf(buf, "%s\\filetype.vim", installdir);
210 if (stat(buf, &st) < 0)
211 {
212 printf("ERROR: Cannot find filetype.vim in \"%s\"\n", installdir);
213 printf("It looks like you did not unpack the runtime archive.\n");
214 printf("You must unpack the runtime archive \"vim%srt.zip\" before installing.\n",
215 VIM_VERSION_NODOT + 3);
216 myexit(1);
217 }
218
Bram Moolenaar5d18efe2019-12-01 21:11:22 +0100219 // Check if vim.exe or gvim.exe is in the current directory.
Bram Moolenaar071d4272004-06-13 20:20:40 +0000220 if ((fd = fopen("gvim.exe", "r")) != NULL)
221 {
222 fclose(fd);
223 has_gvim = 1;
224 }
225 if ((fd = fopen("vim.exe", "r")) != NULL)
226 {
227 fclose(fd);
228 has_vim = 1;
229 }
230 if (!has_gvim && !has_vim)
231 {
232 printf("ERROR: Cannot find any Vim executables in \"%s\"\n\n",
233 installdir);
234 myexit(1);
235 }
236}
237
238/*
239 * Compare paths "p[plen]" to "q[qlen]". Return 0 if they match.
240 * Ignores case and differences between '/' and '\'.
241 * "plen" and "qlen" can be negative, strlen() is used then.
242 */
243 static int
244pathcmp(char *p, int plen, char *q, int qlen)
245{
246 int i;
247
248 if (plen < 0)
249 plen = strlen(p);
250 if (qlen < 0)
251 qlen = strlen(q);
252 for (i = 0; ; ++i)
253 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +0100254 // End of "p": check if "q" also ends or just has a slash.
Bram Moolenaar071d4272004-06-13 20:20:40 +0000255 if (i == plen)
256 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +0100257 if (i == qlen) // match
Bram Moolenaar071d4272004-06-13 20:20:40 +0000258 return 0;
259 if (i == qlen - 1 && (q[i] == '\\' || q[i] == '/'))
Bram Moolenaar5d18efe2019-12-01 21:11:22 +0100260 return 0; // match with trailing slash
261 return 1; // no match
Bram Moolenaar071d4272004-06-13 20:20:40 +0000262 }
263
Bram Moolenaar5d18efe2019-12-01 21:11:22 +0100264 // End of "q": check if "p" also ends or just has a slash.
Bram Moolenaar071d4272004-06-13 20:20:40 +0000265 if (i == qlen)
266 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +0100267 if (i == plen) // match
Bram Moolenaar071d4272004-06-13 20:20:40 +0000268 return 0;
269 if (i == plen - 1 && (p[i] == '\\' || p[i] == '/'))
Bram Moolenaar5d18efe2019-12-01 21:11:22 +0100270 return 0; // match with trailing slash
271 return 1; // no match
Bram Moolenaar071d4272004-06-13 20:20:40 +0000272 }
273
274 if (!(mytoupper(p[i]) == mytoupper(q[i])
275 || ((p[i] == '/' || p[i] == '\\')
276 && (q[i] == '/' || q[i] == '\\'))))
Bram Moolenaar5d18efe2019-12-01 21:11:22 +0100277 return 1; // no match
Bram Moolenaar071d4272004-06-13 20:20:40 +0000278 }
Bram Moolenaar5d18efe2019-12-01 21:11:22 +0100279 //NOTREACHED
Bram Moolenaar071d4272004-06-13 20:20:40 +0000280}
281
282/*
283 * If the executable "**destination" is in the install directory, find another
284 * one in $PATH.
285 * On input "**destination" is the path of an executable in allocated memory
286 * (or NULL).
287 * "*destination" is set to NULL or the location of the file.
288 */
289 static void
290findoldfile(char **destination)
291{
292 char *bp = *destination;
293 size_t indir_l = strlen(installdir);
Bram Moolenaarb7633612019-02-10 21:48:25 +0100294 char *cp;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000295 char *tmpname;
296 char *farname;
297
298 /*
299 * No action needed if exe not found or not in this directory.
300 */
Bram Moolenaarb7633612019-02-10 21:48:25 +0100301 if (bp == NULL || strnicmp(bp, installdir, indir_l) != 0)
302 return;
303 cp = bp + indir_l;
304 if (strchr("/\\", *cp++) == NULL
Bram Moolenaar071d4272004-06-13 20:20:40 +0000305 || strchr(cp, '\\') != NULL
306 || strchr(cp, '/') != NULL)
307 return;
308
Bram Moolenaar51e14382019-05-25 20:21:28 +0200309 tmpname = alloc(strlen(cp) + 1);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000310 strcpy(tmpname, cp);
Bram Moolenaar5d18efe2019-12-01 21:11:22 +0100311 tmpname[strlen(tmpname) - 1] = 'x'; // .exe -> .exx
Bram Moolenaar071d4272004-06-13 20:20:40 +0000312
313 if (access(tmpname, 0) == 0)
314 {
315 printf("\nERROR: %s and %s clash. Remove or rename %s.\n",
316 tmpname, cp, tmpname);
317 myexit(1);
318 }
319
320 if (rename(cp, tmpname) != 0)
321 {
322 printf("\nERROR: failed to rename %s to %s: %s\n",
323 cp, tmpname, strerror(0));
324 myexit(1);
325 }
326
327 farname = searchpath_save(cp);
328
329 if (rename(tmpname, cp) != 0)
330 {
331 printf("\nERROR: failed to rename %s back to %s: %s\n",
332 tmpname, cp, strerror(0));
333 myexit(1);
334 }
335
336 free(*destination);
337 free(tmpname);
338 *destination = farname;
339}
340
341/*
342 * Check if there is a vim.[exe|bat|, gvim.[exe|bat|, etc. in the path.
343 * When "check_bat_only" is TRUE, only find "default_bat_dir".
344 */
345 static void
346find_bat_exe(int check_bat_only)
347{
348 int i;
349
Bram Moolenaar5d18efe2019-12-01 21:11:22 +0100350 // avoid looking in the "installdir" by chdir to system root
Bram Moolenaar42bbef42006-03-25 22:02:07 +0000351 mch_chdir(sysdrive);
352 mch_chdir("\\");
Bram Moolenaar071d4272004-06-13 20:20:40 +0000353
354 for (i = 1; i < TARGET_COUNT; ++i)
355 {
356 targets[i].oldbat = searchpath_save(targets[i].batname);
357 if (!check_bat_only)
358 targets[i].oldexe = searchpath_save(targets[i].exename);
359
360 if (default_bat_dir == NULL && targets[i].oldbat != NULL)
361 {
362 default_bat_dir = alloc(strlen(targets[i].oldbat) + 1);
363 strcpy(default_bat_dir, targets[i].oldbat);
364 remove_tail(default_bat_dir);
365 }
366 if (check_bat_only && targets[i].oldbat != NULL)
Bram Moolenaar42bbef42006-03-25 22:02:07 +0000367 {
Bram Moolenaar071d4272004-06-13 20:20:40 +0000368 free(targets[i].oldbat);
Bram Moolenaar42bbef42006-03-25 22:02:07 +0000369 targets[i].oldbat = NULL;
370 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000371 }
372
373 mch_chdir(installdir);
374}
375
Bram Moolenaar071d4272004-06-13 20:20:40 +0000376/*
377 * Get the value of $VIMRUNTIME or $VIM and write it in $TEMP/vimini.ini, so
378 * that NSIS can read it.
379 * When not set, use the directory of a previously installed Vim.
380 */
381 static void
382get_vim_env(void)
383{
384 char *vim;
385 char buf[BUFSIZE];
386 FILE *fd;
387 char fname[BUFSIZE];
388
Bram Moolenaar5d18efe2019-12-01 21:11:22 +0100389 // First get $VIMRUNTIME. If it's set, remove the tail.
Bram Moolenaar071d4272004-06-13 20:20:40 +0000390 vim = getenv("VIMRUNTIME");
Bram Moolenaare4963c52019-02-22 19:41:08 +0100391 if (vim != NULL && *vim != 0 && strlen(vim) < sizeof(buf))
Bram Moolenaar071d4272004-06-13 20:20:40 +0000392 {
393 strcpy(buf, vim);
394 remove_tail(buf);
395 vim = buf;
396 }
397 else
398 {
399 vim = getenv("VIM");
400 if (vim == NULL || *vim == 0)
401 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +0100402 // Use the directory from an old uninstall entry.
Bram Moolenaar071d4272004-06-13 20:20:40 +0000403 if (default_vim_dir != NULL)
404 vim = default_vim_dir;
405 else
Bram Moolenaar5d18efe2019-12-01 21:11:22 +0100406 // Let NSIS know there is no default, it should use
407 // $PROGRAMFILES.
Bram Moolenaar071d4272004-06-13 20:20:40 +0000408 vim = "";
409 }
410 }
411
Bram Moolenaar5d18efe2019-12-01 21:11:22 +0100412 // NSIS also uses GetTempPath(), thus we should get the same directory
413 // name as where NSIS will look for vimini.ini.
Bram Moolenaare4963c52019-02-22 19:41:08 +0100414 GetTempPath(sizeof(fname) - 12, fname);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000415 add_pathsep(fname);
416 strcat(fname, "vimini.ini");
417
418 fd = fopen(fname, "w");
419 if (fd != NULL)
420 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +0100421 // Make it look like an .ini file, so that NSIS can read it with a
422 // ReadINIStr command.
Bram Moolenaar071d4272004-06-13 20:20:40 +0000423 fprintf(fd, "[vimini]\n");
424 fprintf(fd, "dir=\"%s\"\n", vim);
425 fclose(fd);
426 }
427 else
428 {
429 printf("Failed to open %s\n", fname);
Bram Moolenaarab8205e2010-07-07 15:14:03 +0200430 sleep(2);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000431 }
432}
433
Bram Moolenaarb230bd52010-05-25 21:02:00 +0200434static int num_windows;
435
436/*
437 * Callback used for EnumWindows():
438 * Count the window if the title looks like it is for the uninstaller.
439 */
Bram Moolenaar5d18efe2019-12-01 21:11:22 +0100440//ARGSUSED
Bram Moolenaarb230bd52010-05-25 21:02:00 +0200441 static BOOL CALLBACK
442window_cb(HWND hwnd, LPARAM lparam)
443{
444 char title[256];
445
446 title[0] = 0;
447 GetWindowText(hwnd, title, 256);
Bram Moolenaaraf610b82018-12-21 16:22:50 +0100448 if (strstr(title, "Vim ") != NULL && strstr(title, " Uninstall") != NULL)
Bram Moolenaarb230bd52010-05-25 21:02:00 +0200449 ++num_windows;
450 return TRUE;
451}
452
Bram Moolenaar071d4272004-06-13 20:20:40 +0000453/*
Bram Moolenaaraf610b82018-12-21 16:22:50 +0100454 * Run the uninstaller silently.
455 */
456 static int
457run_silent_uninstall(char *uninst_exe)
458{
Bram Moolenaare4963c52019-02-22 19:41:08 +0100459 char vimrt_dir[BUFSIZE];
Bram Moolenaaraf610b82018-12-21 16:22:50 +0100460 char temp_uninst[BUFSIZE];
461 char temp_dir[MAX_PATH];
462 char buf[BUFSIZE * 2 + 10];
463 int i;
464 DWORD tick;
465
466 strcpy(vimrt_dir, uninst_exe);
467 remove_tail(vimrt_dir);
468
469 if (!GetTempPath(sizeof(temp_dir), temp_dir))
470 return FAIL;
471
Bram Moolenaar5d18efe2019-12-01 21:11:22 +0100472 // Copy the uninstaller to a temporary exe.
Bram Moolenaaraf610b82018-12-21 16:22:50 +0100473 tick = GetTickCount();
474 for (i = 0; ; i++)
475 {
476 sprintf(temp_uninst, "%s\\vimun%04X.exe", temp_dir,
Bram Moolenaar44a7db42019-01-11 20:47:31 +0100477 (unsigned int)((i + tick) & 0xFFFF));
Bram Moolenaaraf610b82018-12-21 16:22:50 +0100478 if (CopyFile(uninst_exe, temp_uninst, TRUE))
479 break;
480 if (GetLastError() != ERROR_FILE_EXISTS)
481 return FAIL;
482 if (i == 65535)
483 return FAIL;
484 }
485
Bram Moolenaar5d18efe2019-12-01 21:11:22 +0100486 // Run the copied uninstaller silently.
Bram Moolenaaraf610b82018-12-21 16:22:50 +0100487 if (strchr(temp_uninst, ' ') != NULL)
488 sprintf(buf, "\"%s\" /S _?=%s", temp_uninst, vimrt_dir);
489 else
490 sprintf(buf, "%s /S _?=%s", temp_uninst, vimrt_dir);
491 run_command(buf);
492
493 DeleteFile(temp_uninst);
494 return OK;
495}
496
497/*
Bram Moolenaar071d4272004-06-13 20:20:40 +0000498 * Check for already installed Vims.
499 * Return non-zero when found one.
500 */
501 static int
Bram Moolenaar442b4222010-05-24 21:34:22 +0200502uninstall_check(int skip_question)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000503{
504 HKEY key_handle;
505 HKEY uninstall_key_handle;
506 char *uninstall_key = "software\\Microsoft\\Windows\\CurrentVersion\\Uninstall";
507 char subkey_name_buff[BUFSIZE];
Bram Moolenaarbbd854d2019-02-18 22:19:33 +0100508 char temp_string_buffer[BUFSIZE-2];
Bram Moolenaare4963c52019-02-22 19:41:08 +0100509 DWORD local_bufsize;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000510 FILETIME temp_pfiletime;
511 DWORD key_index;
512 char input;
513 long code;
514 DWORD value_type;
515 DWORD orig_num_keys;
516 DWORD new_num_keys;
Bram Moolenaaraf610b82018-12-21 16:22:50 +0100517 DWORD allow_silent;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000518 int foundone = 0;
519
Bram Moolenaar760d14a2010-07-31 22:03:44 +0200520 code = RegOpenKeyEx(HKEY_LOCAL_MACHINE, uninstall_key, 0,
521 KEY_WOW64_64KEY | KEY_READ, &key_handle);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000522 CHECK_REG_ERROR(code);
523
Bram Moolenaare4963c52019-02-22 19:41:08 +0100524 key_index = 0;
525 while (TRUE)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000526 {
Bram Moolenaare4963c52019-02-22 19:41:08 +0100527 local_bufsize = sizeof(subkey_name_buff);
528 if (RegEnumKeyEx(key_handle, key_index, subkey_name_buff, &local_bufsize,
529 NULL, NULL, NULL, &temp_pfiletime) == ERROR_NO_MORE_ITEMS)
530 break;
531
Bram Moolenaar071d4272004-06-13 20:20:40 +0000532 if (strncmp("Vim", subkey_name_buff, 3) == 0)
533 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +0100534 // Open the key named Vim*
Bram Moolenaar760d14a2010-07-31 22:03:44 +0200535 code = RegOpenKeyEx(key_handle, subkey_name_buff, 0,
536 KEY_WOW64_64KEY | KEY_READ, &uninstall_key_handle);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000537 CHECK_REG_ERROR(code);
538
Bram Moolenaar5d18efe2019-12-01 21:11:22 +0100539 // get the DisplayName out of it to show the user
Bram Moolenaare4963c52019-02-22 19:41:08 +0100540 local_bufsize = sizeof(temp_string_buffer);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000541 code = RegQueryValueEx(uninstall_key_handle, "displayname", 0,
542 &value_type, (LPBYTE)temp_string_buffer,
543 &local_bufsize);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000544 CHECK_REG_ERROR(code);
545
Bram Moolenaaraf610b82018-12-21 16:22:50 +0100546 allow_silent = 0;
547 if (skip_question)
548 {
549 DWORD varsize = sizeof(DWORD);
550
551 RegQueryValueEx(uninstall_key_handle, "AllowSilent", 0,
552 &value_type, (LPBYTE)&allow_silent,
553 &varsize);
554 }
555
Bram Moolenaar071d4272004-06-13 20:20:40 +0000556 foundone = 1;
557 printf("\n*********************************************************\n");
558 printf("Vim Install found what looks like an existing Vim version.\n");
559 printf("The name of the entry is:\n");
560 printf("\n \"%s\"\n\n", temp_string_buffer);
561
562 printf("Installing the new version will disable part of the existing version.\n");
563 printf("(The batch files used in a console and the \"Edit with Vim\" entry in\n");
564 printf("the popup menu will use the new version)\n");
565
Bram Moolenaar442b4222010-05-24 21:34:22 +0200566 if (skip_question)
567 printf("\nRunning uninstall program for \"%s\"\n", temp_string_buffer);
568 else
569 printf("\nDo you want to uninstall \"%s\" now?\n(y)es/(n)o) ", temp_string_buffer);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000570 fflush(stdout);
571
Bram Moolenaar5d18efe2019-12-01 21:11:22 +0100572 // get the UninstallString
Bram Moolenaare4963c52019-02-22 19:41:08 +0100573 local_bufsize = sizeof(temp_string_buffer);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000574 code = RegQueryValueEx(uninstall_key_handle, "uninstallstring", 0,
575 &value_type, (LPBYTE)temp_string_buffer, &local_bufsize);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000576 CHECK_REG_ERROR(code);
577
Bram Moolenaar5d18efe2019-12-01 21:11:22 +0100578 // Remember the directory, it is used as the default for NSIS.
Bram Moolenaar071d4272004-06-13 20:20:40 +0000579 default_vim_dir = alloc(strlen(temp_string_buffer) + 1);
580 strcpy(default_vim_dir, temp_string_buffer);
581 remove_tail(default_vim_dir);
582 remove_tail(default_vim_dir);
583
584 input = 'n';
585 do
586 {
587 if (input != 'n')
588 printf("%c is an invalid reply. Please enter either 'y' or 'n'\n", input);
589
Bram Moolenaar442b4222010-05-24 21:34:22 +0200590 if (skip_question)
591 input = 'y';
592 else
593 {
594 rewind(stdin);
595 scanf("%c", &input);
596 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000597 switch (input)
598 {
599 case 'y':
600 case 'Y':
Bram Moolenaar5d18efe2019-12-01 21:11:22 +0100601 // save the number of uninstall keys so we can know if
602 // it changed
Bram Moolenaar071d4272004-06-13 20:20:40 +0000603 RegQueryInfoKey(key_handle, NULL, NULL, NULL,
604 &orig_num_keys, NULL, NULL, NULL,
605 NULL, NULL, NULL, NULL);
606
Bram Moolenaar5d18efe2019-12-01 21:11:22 +0100607 // Find existing .bat files before deleting them.
Bram Moolenaar071d4272004-06-13 20:20:40 +0000608 find_bat_exe(TRUE);
609
Bram Moolenaaraf610b82018-12-21 16:22:50 +0100610 if (allow_silent)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000611 {
Bram Moolenaaraf610b82018-12-21 16:22:50 +0100612 if (run_silent_uninstall(temp_string_buffer)
613 == FAIL)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +0100614 allow_silent = 0; // Retry with non silent.
Bram Moolenaar071d4272004-06-13 20:20:40 +0000615 }
Bram Moolenaaraf610b82018-12-21 16:22:50 +0100616 if (!allow_silent)
Bram Moolenaarb230bd52010-05-25 21:02:00 +0200617 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +0100618 // Execute the uninstall program. Put it in double
619 // quotes if there is an embedded space.
Bram Moolenaarb230bd52010-05-25 21:02:00 +0200620 {
Bram Moolenaaraf610b82018-12-21 16:22:50 +0100621 char buf[BUFSIZE];
622
623 if (strchr(temp_string_buffer, ' ') != NULL)
624 sprintf(buf, "\"%s\"", temp_string_buffer);
625 else
626 strcpy(buf, temp_string_buffer);
627 run_command(buf);
628 }
629
Bram Moolenaar5d18efe2019-12-01 21:11:22 +0100630 // Count the number of windows with a title that
631 // match the installer, so that we can check when
632 // it's done. The uninstaller copies itself,
633 // executes the copy and exits, thus we can't wait
634 // for the process to finish.
635 sleep(1); // wait for uninstaller to start up
Bram Moolenaaraf610b82018-12-21 16:22:50 +0100636 num_windows = 0;
637 EnumWindows(window_cb, 0);
638 if (num_windows == 0)
639 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +0100640 // Did not find the uninstaller, ask user to
641 // press Enter when done. Just in case.
Bram Moolenaaraf610b82018-12-21 16:22:50 +0100642 printf("Press Enter when the uninstaller is finished\n");
643 rewind(stdin);
644 (void)getchar();
645 }
646 else
647 {
648 printf("Waiting for the uninstaller to finish (press CTRL-C to abort).");
649 do
650 {
651 printf(".");
652 fflush(stdout);
Bram Moolenaar5d18efe2019-12-01 21:11:22 +0100653 sleep(1); // wait for the uninstaller to
654 // finish
Bram Moolenaaraf610b82018-12-21 16:22:50 +0100655 num_windows = 0;
656 EnumWindows(window_cb, 0);
657 } while (num_windows > 0);
658 }
Bram Moolenaarb230bd52010-05-25 21:02:00 +0200659 }
660 printf("\nDone!\n");
Bram Moolenaar071d4272004-06-13 20:20:40 +0000661
Bram Moolenaar5d18efe2019-12-01 21:11:22 +0100662 // Check if an uninstall reg key was deleted.
663 // if it was, we want to decrement key_index.
664 // if we don't do this, we will skip the key
665 // immediately after any key that we delete.
Bram Moolenaar071d4272004-06-13 20:20:40 +0000666 RegQueryInfoKey(key_handle, NULL, NULL, NULL,
667 &new_num_keys, NULL, NULL, NULL,
668 NULL, NULL, NULL, NULL);
669 if (new_num_keys < orig_num_keys)
670 key_index--;
671
672 input = 'y';
673 break;
674
675 case 'n':
676 case 'N':
Bram Moolenaar5d18efe2019-12-01 21:11:22 +0100677 // Do not uninstall
Bram Moolenaar071d4272004-06-13 20:20:40 +0000678 input = 'n';
679 break;
680
Bram Moolenaar5d18efe2019-12-01 21:11:22 +0100681 default: // just drop through and redo the loop
Bram Moolenaar071d4272004-06-13 20:20:40 +0000682 break;
683 }
684
685 } while (input != 'n' && input != 'y');
686
687 RegCloseKey(uninstall_key_handle);
688 }
Bram Moolenaare4963c52019-02-22 19:41:08 +0100689
690 key_index++;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000691 }
692 RegCloseKey(key_handle);
693
694 return foundone;
695}
Bram Moolenaar071d4272004-06-13 20:20:40 +0000696
697/*
698 * Find out information about the system.
699 */
700 static void
701inspect_system(void)
702{
703 char *p;
704 char buf[BUFSIZE];
705 FILE *fd;
706 int i;
707 int foundone;
708
Bram Moolenaar5d18efe2019-12-01 21:11:22 +0100709 // This may take a little while, let the user know what we're doing.
Bram Moolenaar071d4272004-06-13 20:20:40 +0000710 printf("Inspecting system...\n");
711
712 /*
713 * If $VIM is set, check that it's pointing to our directory.
714 */
715 p = getenv("VIM");
716 if (p != NULL && pathcmp(p, -1, installdir, runtimeidx - 1) != 0)
717 {
718 printf("------------------------------------------------------\n");
719 printf("$VIM is set to \"%s\".\n", p);
720 printf("This is different from where this version of Vim is:\n");
721 strcpy(buf, installdir);
722 *(buf + runtimeidx - 1) = NUL;
723 printf("\"%s\"\n", buf);
724 printf("You must adjust or remove the setting of $VIM,\n");
725 if (interactive)
726 {
727 printf("to be able to use this install program.\n");
728 myexit(1);
729 }
730 printf("otherwise Vim WILL NOT WORK properly!\n");
731 printf("------------------------------------------------------\n");
732 }
733
734 /*
735 * If $VIMRUNTIME is set, check that it's pointing to our runtime directory.
736 */
737 p = getenv("VIMRUNTIME");
738 if (p != NULL && pathcmp(p, -1, installdir, -1) != 0)
739 {
740 printf("------------------------------------------------------\n");
741 printf("$VIMRUNTIME is set to \"%s\".\n", p);
742 printf("This is different from where this version of Vim is:\n");
743 printf("\"%s\"\n", installdir);
744 printf("You must adjust or remove the setting of $VIMRUNTIME,\n");
745 if (interactive)
746 {
747 printf("to be able to use this install program.\n");
748 myexit(1);
749 }
750 printf("otherwise Vim WILL NOT WORK properly!\n");
751 printf("------------------------------------------------------\n");
752 }
753
754 /*
755 * Check if there is a vim.[exe|bat|, gvim.[exe|bat|, etc. in the path.
756 */
757 find_bat_exe(FALSE);
758
759 /*
760 * A .exe in the install directory may be found anyway on Windows 2000.
761 * Check for this situation and find another executable if necessary.
762 * w.briscoe@ponl.com 2001-01-20
763 */
764 foundone = 0;
765 for (i = 1; i < TARGET_COUNT; ++i)
766 {
767 findoldfile(&(targets[i].oldexe));
768 if (targets[i].oldexe != NULL)
769 foundone = 1;
770 }
771
772 if (foundone)
773 {
774 printf("Warning: Found Vim executable(s) in your $PATH:\n");
775 for (i = 1; i < TARGET_COUNT; ++i)
776 if (targets[i].oldexe != NULL)
777 printf("%s\n", targets[i].oldexe);
778 printf("It will be used instead of the version you are installing.\n");
779 printf("Please delete or rename it, or adjust your $PATH setting.\n");
780 }
781
782 /*
783 * Check if there is an existing ../_vimrc or ../.vimrc file.
784 */
785 strcpy(oldvimrc, installdir);
786 strcpy(oldvimrc + runtimeidx, "_vimrc");
787 if ((fd = fopen(oldvimrc, "r")) == NULL)
788 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +0100789 strcpy(oldvimrc + runtimeidx, "vimrc~1"); // short version of .vimrc
Bram Moolenaar071d4272004-06-13 20:20:40 +0000790 if ((fd = fopen(oldvimrc, "r")) == NULL)
791 {
792 strcpy(oldvimrc + runtimeidx, ".vimrc");
793 fd = fopen(oldvimrc, "r");
794 }
795 }
796 if (fd != NULL)
797 fclose(fd);
798 else
799 *oldvimrc = NUL;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000800}
801
802/*
803 * Add a dummy choice to avoid that the numbering changes depending on items
804 * in the environment. The user may type a number he remembered without
805 * looking.
806 */
807 static void
808add_dummy_choice(void)
809{
810 choices[choice_count].installfunc = NULL;
811 choices[choice_count].active = 0;
812 choices[choice_count].changefunc = NULL;
Bram Moolenaar25a494c2018-11-16 19:39:50 +0100813 choices[choice_count].text = NULL;
814 choices[choice_count].arg = 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000815 ++choice_count;
816}
817
Bram Moolenaar5d18efe2019-12-01 21:11:22 +0100818////////////////////////////////////////////////
819// stuff for creating the batch files.
Bram Moolenaar071d4272004-06-13 20:20:40 +0000820
821/*
822 * Install the vim.bat, gvim.bat, etc. files.
823 */
824 static void
825install_bat_choice(int idx)
826{
827 char *batpath = targets[choices[idx].arg].batpath;
828 char *oldname = targets[choices[idx].arg].oldbat;
829 char *exename = targets[choices[idx].arg].exenamearg;
830 char *vimarg = targets[choices[idx].arg].exearg;
831 FILE *fd;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000832
833 if (*batpath != NUL)
834 {
835 fd = fopen(batpath, "w");
836 if (fd == NULL)
837 printf("\nERROR: Cannot open \"%s\" for writing.\n", batpath);
838 else
839 {
840 need_uninstall_entry = 1;
841
842 fprintf(fd, "@echo off\n");
Bram Moolenaar97b2ad32006-03-18 21:40:56 +0000843 fprintf(fd, "rem -- Run Vim --\n");
Bram Moolenaar1fa8d2c2020-02-17 22:53:14 +0100844 fprintf(fd, VIMBAT_UNINSTKEY "\n");
Bram Moolenaar97b2ad32006-03-18 21:40:56 +0000845 fprintf(fd, "\n");
Bram Moolenaare609ad52016-03-28 23:05:48 +0200846 fprintf(fd, "setlocal\n");
Bram Moolenaar071d4272004-06-13 20:20:40 +0000847
Bram Moolenaar5d18efe2019-12-01 21:11:22 +0100848 /*
849 * Don't use double quotes for the "set" argument, also when it
Bram Moolenaar071d4272004-06-13 20:20:40 +0000850 * contains a space. The quotes would be included in the value
Bram Moolenaar97b2ad32006-03-18 21:40:56 +0000851 * for MSDOS and NT.
852 * The order of preference is:
853 * 1. $VIMRUNTIME/vim.exe (user preference)
Bram Moolenaarabab0b02019-03-30 18:47:01 +0100854 * 2. $VIM/vim81/vim.exe (hard coded version)
Bram Moolenaar97b2ad32006-03-18 21:40:56 +0000855 * 3. installdir/vim.exe (hard coded install directory)
856 */
857 fprintf(fd, "set VIM_EXE_DIR=%s\n", installdir);
858 fprintf(fd, "if exist \"%%VIM%%\\%s\\%s\" set VIM_EXE_DIR=%%VIM%%\\%s\n",
859 VIM_VERSION_NODOT, exename, VIM_VERSION_NODOT);
860 fprintf(fd, "if exist \"%%VIMRUNTIME%%\\%s\" set VIM_EXE_DIR=%%VIMRUNTIME%%\n", exename);
861 fprintf(fd, "\n");
Bram Moolenaar071d4272004-06-13 20:20:40 +0000862
Bram Moolenaar5d18efe2019-12-01 21:11:22 +0100863 // Give an error message when the executable could not be found.
Bram Moolenaar97b2ad32006-03-18 21:40:56 +0000864 fprintf(fd, "if exist \"%%VIM_EXE_DIR%%\\%s\" goto havevim\n",
865 exename);
866 fprintf(fd, "echo \"%%VIM_EXE_DIR%%\\%s\" not found\n", exename);
867 fprintf(fd, "goto eof\n");
868 fprintf(fd, "\n");
Bram Moolenaar071d4272004-06-13 20:20:40 +0000869 fprintf(fd, ":havevim\n");
870
871 fprintf(fd, "rem collect the arguments in VIMARGS for Win95\n");
872 fprintf(fd, "set VIMARGS=\n");
873 if (*exename == 'g')
874 fprintf(fd, "set VIMNOFORK=\n");
875 fprintf(fd, ":loopstart\n");
876 fprintf(fd, "if .%%1==. goto loopend\n");
877 if (*exename == 'g')
878 {
Bram Moolenaare609ad52016-03-28 23:05:48 +0200879 fprintf(fd, "if NOT .%%1==.--nofork goto noforklongarg\n");
880 fprintf(fd, "set VIMNOFORK=1\n");
881 fprintf(fd, ":noforklongarg\n");
Bram Moolenaar071d4272004-06-13 20:20:40 +0000882 fprintf(fd, "if NOT .%%1==.-f goto noforkarg\n");
883 fprintf(fd, "set VIMNOFORK=1\n");
884 fprintf(fd, ":noforkarg\n");
885 }
886 fprintf(fd, "set VIMARGS=%%VIMARGS%% %%1\n");
887 fprintf(fd, "shift\n");
Bram Moolenaar97b2ad32006-03-18 21:40:56 +0000888 fprintf(fd, "goto loopstart\n");
Bram Moolenaar071d4272004-06-13 20:20:40 +0000889 fprintf(fd, ":loopend\n");
Bram Moolenaar97b2ad32006-03-18 21:40:56 +0000890 fprintf(fd, "\n");
Bram Moolenaar071d4272004-06-13 20:20:40 +0000891
Bram Moolenaar97b2ad32006-03-18 21:40:56 +0000892 fprintf(fd, "if .%%OS%%==.Windows_NT goto ntaction\n");
893 fprintf(fd, "\n");
Bram Moolenaar071d4272004-06-13 20:20:40 +0000894
Bram Moolenaar5d18efe2019-12-01 21:11:22 +0100895 // For gvim.exe use "start" to avoid that the console window stays
896 // open.
Bram Moolenaar071d4272004-06-13 20:20:40 +0000897 if (*exename == 'g')
898 {
899 fprintf(fd, "if .%%VIMNOFORK%%==.1 goto nofork\n");
900 fprintf(fd, "start ");
901 }
902
Bram Moolenaar5d18efe2019-12-01 21:11:22 +0100903 // Always use quotes, $VIM or $VIMRUNTIME might have a space.
Bram Moolenaar97b2ad32006-03-18 21:40:56 +0000904 fprintf(fd, "\"%%VIM_EXE_DIR%%\\%s\" %s %%VIMARGS%%\n",
905 exename, vimarg);
906 fprintf(fd, "goto eof\n");
907 fprintf(fd, "\n");
Bram Moolenaar071d4272004-06-13 20:20:40 +0000908
909 if (*exename == 'g')
910 {
911 fprintf(fd, ":nofork\n");
912 fprintf(fd, "start /w ");
Bram Moolenaar5d18efe2019-12-01 21:11:22 +0100913 // Always use quotes, $VIM or $VIMRUNTIME might have a space.
Bram Moolenaar97b2ad32006-03-18 21:40:56 +0000914 fprintf(fd, "\"%%VIM_EXE_DIR%%\\%s\" %s %%VIMARGS%%\n",
915 exename, vimarg);
916 fprintf(fd, "goto eof\n");
917 fprintf(fd, "\n");
Bram Moolenaar071d4272004-06-13 20:20:40 +0000918 }
919
920 fprintf(fd, ":ntaction\n");
921 fprintf(fd, "rem for WinNT we can use %%*\n");
922
Bram Moolenaar5d18efe2019-12-01 21:11:22 +0100923 // For gvim.exe use "start /b" to avoid that the console window
924 // stays open.
Bram Moolenaar071d4272004-06-13 20:20:40 +0000925 if (*exename == 'g')
926 {
927 fprintf(fd, "if .%%VIMNOFORK%%==.1 goto noforknt\n");
928 fprintf(fd, "start \"dummy\" /b ");
929 }
930
Bram Moolenaar5d18efe2019-12-01 21:11:22 +0100931 // Always use quotes, $VIM or $VIMRUNTIME might have a space.
Bram Moolenaar97b2ad32006-03-18 21:40:56 +0000932 fprintf(fd, "\"%%VIM_EXE_DIR%%\\%s\" %s %%*\n", exename, vimarg);
933 fprintf(fd, "goto eof\n");
934 fprintf(fd, "\n");
Bram Moolenaar071d4272004-06-13 20:20:40 +0000935
936 if (*exename == 'g')
937 {
938 fprintf(fd, ":noforknt\n");
939 fprintf(fd, "start \"dummy\" /b /wait ");
Bram Moolenaar5d18efe2019-12-01 21:11:22 +0100940 // Always use quotes, $VIM or $VIMRUNTIME might have a space.
Bram Moolenaar97b2ad32006-03-18 21:40:56 +0000941 fprintf(fd, "\"%%VIM_EXE_DIR%%\\%s\" %s %%*\n",
942 exename, vimarg);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000943 }
944
945 fprintf(fd, "\n:eof\n");
946 fprintf(fd, "set VIMARGS=\n");
947 if (*exename == 'g')
948 fprintf(fd, "set VIMNOFORK=\n");
949
950 fclose(fd);
951 printf("%s has been %s\n", batpath,
952 oldname == NULL ? "created" : "overwritten");
953 }
954 }
955}
956
957/*
958 * Make the text string for choice "idx".
959 * The format "fmt" is must have one %s item, which "arg" is used for.
960 */
961 static void
962alloc_text(int idx, char *fmt, char *arg)
963{
964 if (choices[idx].text != NULL)
965 free(choices[idx].text);
966
Bram Moolenaar51e14382019-05-25 20:21:28 +0200967 choices[idx].text = alloc(strlen(fmt) + strlen(arg) - 1);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000968 sprintf(choices[idx].text, fmt, arg);
969}
970
971/*
972 * Toggle the "Overwrite .../vim.bat" to "Don't overwrite".
973 */
974 static void
975toggle_bat_choice(int idx)
976{
977 char *batname = targets[choices[idx].arg].batpath;
978 char *oldname = targets[choices[idx].arg].oldbat;
979
980 if (*batname == NUL)
981 {
982 alloc_text(idx, " Overwrite %s", oldname);
983 strcpy(batname, oldname);
984 }
985 else
986 {
987 alloc_text(idx, " Do NOT overwrite %s", oldname);
988 *batname = NUL;
989 }
990}
991
992/*
993 * Do some work for a batch file entry: Append the batch file name to the path
994 * and set the text for the choice.
995 */
996 static void
997set_bat_text(int idx, char *batpath, char *name)
998{
999 strcat(batpath, name);
1000
1001 alloc_text(idx, " Create %s", batpath);
1002}
1003
1004/*
1005 * Select a directory to write the batch file line.
1006 */
1007 static void
1008change_bat_choice(int idx)
1009{
1010 char *path;
1011 char *batpath;
1012 char *name;
1013 int n;
1014 char *s;
1015 char *p;
1016 int count;
1017 char **names = NULL;
1018 int i;
1019 int target = choices[idx].arg;
1020
1021 name = targets[target].batname;
1022 batpath = targets[target].batpath;
1023
1024 path = getenv("PATH");
1025 if (path == NULL)
1026 {
1027 printf("\nERROR: The variable $PATH is not set\n");
1028 return;
1029 }
1030
1031 /*
1032 * first round: count number of names in path;
1033 * second round: save names to names[].
1034 */
1035 for (;;)
1036 {
1037 count = 1;
1038 for (p = path; *p; )
1039 {
1040 s = strchr(p, ';');
1041 if (s == NULL)
1042 s = p + strlen(p);
1043 if (names != NULL)
1044 {
Bram Moolenaar51e14382019-05-25 20:21:28 +02001045 names[count] = alloc(s - p + 1);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001046 strncpy(names[count], p, s - p);
1047 names[count][s - p] = NUL;
1048 }
1049 ++count;
1050 p = s;
1051 if (*p != NUL)
1052 ++p;
1053 }
1054 if (names != NULL)
1055 break;
Bram Moolenaar51e14382019-05-25 20:21:28 +02001056 names = alloc((count + 1) * sizeof(char *));
Bram Moolenaar071d4272004-06-13 20:20:40 +00001057 }
1058 names[0] = alloc(50);
1059 sprintf(names[0], "Select directory to create %s in:", name);
1060 names[count] = alloc(50);
1061 if (choices[idx].arg == 0)
1062 sprintf(names[count], "Do not create any .bat file.");
1063 else
1064 sprintf(names[count], "Do not create a %s file.", name);
1065 n = get_choice(names, count + 1);
1066
1067 if (n == count)
1068 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01001069 // Selected last item, don't create bat file.
Bram Moolenaar071d4272004-06-13 20:20:40 +00001070 *batpath = NUL;
1071 if (choices[idx].arg != 0)
1072 alloc_text(idx, " Do NOT create %s", name);
1073 }
1074 else
1075 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01001076 // Selected one of the paths. For the first item only keep the path,
1077 // for the others append the batch file name.
Bram Moolenaar071d4272004-06-13 20:20:40 +00001078 strcpy(batpath, names[n]);
1079 add_pathsep(batpath);
1080 if (choices[idx].arg != 0)
1081 set_bat_text(idx, batpath, name);
1082 }
1083
1084 for (i = 0; i <= count; ++i)
1085 free(names[i]);
1086 free(names);
1087}
1088
1089char *bat_text_yes = "Install .bat files to use Vim at the command line:";
1090char *bat_text_no = "do NOT install .bat files to use Vim at the command line";
1091
1092 static void
1093change_main_bat_choice(int idx)
1094{
1095 int i;
1096
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01001097 // let the user select a default directory or NONE
Bram Moolenaar071d4272004-06-13 20:20:40 +00001098 change_bat_choice(idx);
1099
1100 if (targets[0].batpath[0] != NUL)
1101 choices[idx].text = bat_text_yes;
1102 else
1103 choices[idx].text = bat_text_no;
1104
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01001105 // update the individual batch file selections
Bram Moolenaar071d4272004-06-13 20:20:40 +00001106 for (i = 1; i < TARGET_COUNT; ++i)
1107 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01001108 // Only make it active when the first item has a path and the vim.exe
1109 // or gvim.exe exists (there is a changefunc then).
Bram Moolenaar071d4272004-06-13 20:20:40 +00001110 if (targets[0].batpath[0] != NUL
1111 && choices[idx + i].changefunc != NULL)
1112 {
1113 choices[idx + i].active = 1;
1114 if (choices[idx + i].changefunc == change_bat_choice
1115 && targets[i].batpath[0] != NUL)
1116 {
1117 strcpy(targets[i].batpath, targets[0].batpath);
1118 set_bat_text(idx + i, targets[i].batpath, targets[i].batname);
1119 }
1120 }
1121 else
1122 choices[idx + i].active = 0;
1123 }
1124}
1125
1126/*
1127 * Initialize a choice for creating a batch file.
1128 */
1129 static void
1130init_bat_choice(int target)
1131{
1132 char *batpath = targets[target].batpath;
1133 char *oldbat = targets[target].oldbat;
1134 char *p;
1135 int i;
1136
1137 choices[choice_count].arg = target;
1138 choices[choice_count].installfunc = install_bat_choice;
1139 choices[choice_count].active = 1;
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01001140 choices[choice_count].text = NULL; // will be set below
Bram Moolenaar071d4272004-06-13 20:20:40 +00001141 if (oldbat != NULL)
1142 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01001143 // A [g]vim.bat exists: Only choice is to overwrite it or not.
Bram Moolenaar071d4272004-06-13 20:20:40 +00001144 choices[choice_count].changefunc = toggle_bat_choice;
1145 *batpath = NUL;
1146 toggle_bat_choice(choice_count);
1147 }
1148 else
1149 {
1150 if (default_bat_dir != NULL)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01001151 // Prefer using the same path as an existing .bat file.
Bram Moolenaar071d4272004-06-13 20:20:40 +00001152 strcpy(batpath, default_bat_dir);
1153 else
1154 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01001155 // No [g]vim.bat exists: Write it to a directory in $PATH. Use
1156 // $WINDIR by default, if it's empty the first item in $PATH.
Bram Moolenaar071d4272004-06-13 20:20:40 +00001157 p = getenv("WINDIR");
1158 if (p != NULL && *p != NUL)
1159 strcpy(batpath, p);
1160 else
1161 {
1162 p = getenv("PATH");
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01001163 if (p == NULL || *p == NUL) // "cannot happen"
Bram Moolenaar071d4272004-06-13 20:20:40 +00001164 strcpy(batpath, "C:/Windows");
1165 else
1166 {
1167 i = 0;
1168 while (*p != NUL && *p != ';')
1169 batpath[i++] = *p++;
1170 batpath[i] = NUL;
1171 }
1172 }
1173 }
1174 add_pathsep(batpath);
1175 set_bat_text(choice_count, batpath, targets[target].batname);
1176
1177 choices[choice_count].changefunc = change_bat_choice;
1178 }
1179 ++choice_count;
1180}
1181
1182/*
1183 * Set up the choices for installing .bat files.
1184 * For these items "arg" is the index in targets[].
1185 */
1186 static void
1187init_bat_choices(void)
1188{
1189 int i;
1190
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01001191 // The first item is used to switch installing batch files on/off and
1192 // setting the default path.
Bram Moolenaar071d4272004-06-13 20:20:40 +00001193 choices[choice_count].text = bat_text_yes;
1194 choices[choice_count].changefunc = change_main_bat_choice;
1195 choices[choice_count].installfunc = NULL;
1196 choices[choice_count].active = 1;
1197 choices[choice_count].arg = 0;
1198 ++choice_count;
1199
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01001200 // Add items for each batch file target. Only used when not disabled by
1201 // the first item. When a .exe exists, don't offer to create a .bat.
Bram Moolenaar071d4272004-06-13 20:20:40 +00001202 for (i = 1; i < TARGET_COUNT; ++i)
1203 if (targets[i].oldexe == NULL
1204 && (targets[i].exenamearg[0] == 'g' ? has_gvim : has_vim))
1205 init_bat_choice(i);
1206 else
1207 add_dummy_choice();
1208}
1209
1210/*
1211 * Install the vimrc file.
1212 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001213 static void
1214install_vimrc(int idx)
1215{
1216 FILE *fd, *tfd;
1217 char *fname;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001218
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01001219 // If an old vimrc file exists, overwrite it.
1220 // Otherwise create a new one.
Bram Moolenaar071d4272004-06-13 20:20:40 +00001221 if (*oldvimrc != NUL)
1222 fname = oldvimrc;
1223 else
1224 fname = vimrc;
1225
1226 fd = fopen(fname, "w");
1227 if (fd == NULL)
1228 {
1229 printf("\nERROR: Cannot open \"%s\" for writing.\n", fname);
1230 return;
1231 }
1232 switch (compat_choice)
1233 {
1234 case compat_vi:
Bram Moolenaar6cdb2c92018-10-13 17:25:27 +02001235 fprintf(fd, "\" Vi compatible\n");
Bram Moolenaar071d4272004-06-13 20:20:40 +00001236 fprintf(fd, "set compatible\n");
1237 break;
Bram Moolenaar6cdb2c92018-10-13 17:25:27 +02001238 case compat_vim:
1239 fprintf(fd, "\" Vim's default behavior\n");
1240 fprintf(fd, "if &compatible\n");
1241 fprintf(fd, " set nocompatible\n");
1242 fprintf(fd, "endif\n");
1243 break;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001244 case compat_some_enhancements:
Bram Moolenaar6cdb2c92018-10-13 17:25:27 +02001245 fprintf(fd, "\" Vim with some enhancements\n");
Bram Moolenaarc73e4472016-07-29 18:33:38 +02001246 fprintf(fd, "source $VIMRUNTIME/defaults.vim\n");
Bram Moolenaar071d4272004-06-13 20:20:40 +00001247 break;
1248 case compat_all_enhancements:
Bram Moolenaar6cdb2c92018-10-13 17:25:27 +02001249 fprintf(fd, "\" Vim with all enhancements\n");
Bram Moolenaar071d4272004-06-13 20:20:40 +00001250 fprintf(fd, "source $VIMRUNTIME/vimrc_example.vim\n");
1251 break;
1252 }
1253 switch (remap_choice)
1254 {
1255 case remap_no:
1256 break;
1257 case remap_win:
Bram Moolenaar6cdb2c92018-10-13 17:25:27 +02001258 fprintf(fd, "\n");
1259 fprintf(fd, "\" Remap a few keys for Windows behavior\n");
Bram Moolenaar071d4272004-06-13 20:20:40 +00001260 fprintf(fd, "source $VIMRUNTIME/mswin.vim\n");
1261 break;
1262 }
1263 switch (mouse_choice)
1264 {
1265 case mouse_xterm:
Bram Moolenaar6cdb2c92018-10-13 17:25:27 +02001266 fprintf(fd, "\n");
1267 fprintf(fd, "\" Mouse behavior (the Unix way)\n");
Bram Moolenaar071d4272004-06-13 20:20:40 +00001268 fprintf(fd, "behave xterm\n");
1269 break;
1270 case mouse_mswin:
Bram Moolenaar6cdb2c92018-10-13 17:25:27 +02001271 fprintf(fd, "\n");
1272 fprintf(fd, "\" Mouse behavior (the Windows way)\n");
Bram Moolenaar071d4272004-06-13 20:20:40 +00001273 fprintf(fd, "behave mswin\n");
1274 break;
Bram Moolenaarc3fdf7f2017-10-28 18:36:48 +02001275 case mouse_default:
1276 break;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001277 }
1278 if ((tfd = fopen("diff.exe", "r")) != NULL)
1279 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01001280 // Use the diff.exe that comes with the self-extracting gvim.exe.
Bram Moolenaar071d4272004-06-13 20:20:40 +00001281 fclose(tfd);
1282 fprintf(fd, "\n");
Bram Moolenaar6cdb2c92018-10-13 17:25:27 +02001283 fprintf(fd, "\" Use the internal diff if available.\n");
1284 fprintf(fd, "\" Otherwise use the special 'diffexpr' for Windows.\n");
1285 fprintf(fd, "if &diffopt !~# 'internal'\n");
1286 fprintf(fd, " set diffexpr=MyDiff()\n");
1287 fprintf(fd, "endif\n");
Bram Moolenaar071d4272004-06-13 20:20:40 +00001288 fprintf(fd, "function MyDiff()\n");
1289 fprintf(fd, " let opt = '-a --binary '\n");
1290 fprintf(fd, " if &diffopt =~ 'icase' | let opt = opt . '-i ' | endif\n");
1291 fprintf(fd, " if &diffopt =~ 'iwhite' | let opt = opt . '-b ' | endif\n");
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01001292 // Use quotes only when needed, they may cause trouble.
1293 // Always escape "!".
Bram Moolenaar071d4272004-06-13 20:20:40 +00001294 fprintf(fd, " let arg1 = v:fname_in\n");
1295 fprintf(fd, " if arg1 =~ ' ' | let arg1 = '\"' . arg1 . '\"' | endif\n");
Bram Moolenaar12365ce2018-05-13 14:45:25 +02001296 fprintf(fd, " let arg1 = substitute(arg1, '!', '\\!', 'g')\n");
Bram Moolenaar071d4272004-06-13 20:20:40 +00001297 fprintf(fd, " let arg2 = v:fname_new\n");
1298 fprintf(fd, " if arg2 =~ ' ' | let arg2 = '\"' . arg2 . '\"' | endif\n");
Bram Moolenaar12365ce2018-05-13 14:45:25 +02001299 fprintf(fd, " let arg2 = substitute(arg2, '!', '\\!', 'g')\n");
Bram Moolenaar071d4272004-06-13 20:20:40 +00001300 fprintf(fd, " let arg3 = v:fname_out\n");
1301 fprintf(fd, " if arg3 =~ ' ' | let arg3 = '\"' . arg3 . '\"' | endif\n");
Bram Moolenaar12365ce2018-05-13 14:45:25 +02001302 fprintf(fd, " let arg3 = substitute(arg3, '!', '\\!', 'g')\n");
Bram Moolenaar33aec762006-01-22 23:30:12 +00001303
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01001304 // If the path has a space: When using cmd.exe (Win NT/2000/XP) put
1305 // quotes around the diff command and rely on the default value of
1306 // shellxquote to solve the quoting problem for the whole command.
1307 //
1308 // Otherwise put a double quote just before the space and at the
1309 // end of the command. Putting quotes around the whole thing
1310 // doesn't work on Win 95/98/ME. This is mostly guessed!
Bram Moolenaar33aec762006-01-22 23:30:12 +00001311 fprintf(fd, " if $VIMRUNTIME =~ ' '\n");
1312 fprintf(fd, " if &sh =~ '\\<cmd'\n");
Bram Moolenaarc62a6442013-11-21 18:13:37 +01001313 fprintf(fd, " if empty(&shellxquote)\n");
1314 fprintf(fd, " let l:shxq_sav = ''\n");
1315 fprintf(fd, " set shellxquote&\n");
1316 fprintf(fd, " endif\n");
1317 fprintf(fd, " let cmd = '\"' . $VIMRUNTIME . '\\diff\"'\n");
Bram Moolenaar33aec762006-01-22 23:30:12 +00001318 fprintf(fd, " else\n");
1319 fprintf(fd, " let cmd = substitute($VIMRUNTIME, ' ', '\" ', '') . '\\diff\"'\n");
1320 fprintf(fd, " endif\n");
1321 fprintf(fd, " else\n");
1322 fprintf(fd, " let cmd = $VIMRUNTIME . '\\diff'\n");
1323 fprintf(fd, " endif\n");
Bram Moolenaar12365ce2018-05-13 14:45:25 +02001324 fprintf(fd, " let cmd = substitute(cmd, '!', '\\!', 'g')\n");
Bram Moolenaarc62a6442013-11-21 18:13:37 +01001325 fprintf(fd, " silent execute '!' . cmd . ' ' . opt . arg1 . ' ' . arg2 . ' > ' . arg3\n");
1326 fprintf(fd, " if exists('l:shxq_sav')\n");
1327 fprintf(fd, " let &shellxquote=l:shxq_sav\n");
1328 fprintf(fd, " endif\n");
Bram Moolenaar071d4272004-06-13 20:20:40 +00001329 fprintf(fd, "endfunction\n");
1330 fprintf(fd, "\n");
1331 }
1332 fclose(fd);
1333 printf("%s has been written\n", fname);
1334}
1335
1336 static void
1337change_vimrc_choice(int idx)
1338{
1339 if (choices[idx].installfunc != NULL)
1340 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01001341 // Switch to NOT change or create a vimrc file.
Bram Moolenaar071d4272004-06-13 20:20:40 +00001342 if (*oldvimrc != NUL)
1343 alloc_text(idx, "Do NOT change startup file %s", oldvimrc);
1344 else
1345 alloc_text(idx, "Do NOT create startup file %s", vimrc);
1346 choices[idx].installfunc = NULL;
1347 choices[idx + 1].active = 0;
1348 choices[idx + 2].active = 0;
1349 choices[idx + 3].active = 0;
1350 }
1351 else
1352 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01001353 // Switch to change or create a vimrc file.
Bram Moolenaar071d4272004-06-13 20:20:40 +00001354 if (*oldvimrc != NUL)
1355 alloc_text(idx, "Overwrite startup file %s with:", oldvimrc);
1356 else
1357 alloc_text(idx, "Create startup file %s with:", vimrc);
1358 choices[idx].installfunc = install_vimrc;
1359 choices[idx + 1].active = 1;
1360 choices[idx + 2].active = 1;
1361 choices[idx + 3].active = 1;
1362 }
1363}
1364
1365/*
1366 * Change the choice how to run Vim.
1367 */
1368 static void
1369change_run_choice(int idx)
1370{
1371 compat_choice = get_choice(compat_choices, TABLE_SIZE(compat_choices));
1372 alloc_text(idx, compat_text, compat_choices[compat_choice]);
1373}
1374
1375/*
1376 * Change the choice if keys are to be remapped.
1377 */
1378 static void
1379change_remap_choice(int idx)
1380{
1381 remap_choice = get_choice(remap_choices, TABLE_SIZE(remap_choices));
1382 alloc_text(idx, remap_text, remap_choices[remap_choice]);
1383}
1384
1385/*
1386 * Change the choice how to select text.
1387 */
1388 static void
1389change_mouse_choice(int idx)
1390{
1391 mouse_choice = get_choice(mouse_choices, TABLE_SIZE(mouse_choices));
1392 alloc_text(idx, mouse_text, mouse_choices[mouse_choice]);
1393}
1394
1395 static void
1396init_vimrc_choices(void)
1397{
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01001398 // set path for a new _vimrc file (also when not used)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001399 strcpy(vimrc, installdir);
1400 strcpy(vimrc + runtimeidx, "_vimrc");
1401
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01001402 // Set opposite value and then toggle it by calling change_vimrc_choice()
Bram Moolenaar071d4272004-06-13 20:20:40 +00001403 if (*oldvimrc == NUL)
1404 choices[choice_count].installfunc = NULL;
1405 else
1406 choices[choice_count].installfunc = install_vimrc;
1407 choices[choice_count].text = NULL;
1408 change_vimrc_choice(choice_count);
1409 choices[choice_count].changefunc = change_vimrc_choice;
1410 choices[choice_count].active = 1;
1411 ++choice_count;
1412
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01001413 // default way to run Vim
Bram Moolenaar071d4272004-06-13 20:20:40 +00001414 alloc_text(choice_count, compat_text, compat_choices[compat_choice]);
1415 choices[choice_count].changefunc = change_run_choice;
1416 choices[choice_count].installfunc = NULL;
1417 choices[choice_count].active = (*oldvimrc == NUL);
1418 ++choice_count;
1419
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01001420 // Whether to remap keys
Bram Moolenaar071d4272004-06-13 20:20:40 +00001421 alloc_text(choice_count, remap_text , remap_choices[remap_choice]);
1422 choices[choice_count].changefunc = change_remap_choice;
Bram Moolenaar945ec092016-06-08 21:17:43 +02001423 choices[choice_count].installfunc = NULL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001424 choices[choice_count].active = (*oldvimrc == NUL);
1425 ++choice_count;
1426
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01001427 // default way to use the mouse
Bram Moolenaar071d4272004-06-13 20:20:40 +00001428 alloc_text(choice_count, mouse_text, mouse_choices[mouse_choice]);
1429 choices[choice_count].changefunc = change_mouse_choice;
Bram Moolenaar945ec092016-06-08 21:17:43 +02001430 choices[choice_count].installfunc = NULL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001431 choices[choice_count].active = (*oldvimrc == NUL);
1432 ++choice_count;
1433}
1434
Bram Moolenaarccd9ccf2010-07-07 13:19:55 +02001435 static LONG
1436reg_create_key(
1437 HKEY root,
1438 const char *subkey,
Bram Moolenaar6199d432017-10-14 19:05:44 +02001439 PHKEY phKey,
1440 DWORD flag)
Bram Moolenaarccd9ccf2010-07-07 13:19:55 +02001441{
1442 DWORD disp;
1443
1444 *phKey = NULL;
1445 return RegCreateKeyEx(
Bram Moolenaarcc448b32010-07-14 16:52:17 +02001446 root, subkey,
1447 0, NULL, REG_OPTION_NON_VOLATILE,
Bram Moolenaar6199d432017-10-14 19:05:44 +02001448 flag | KEY_WRITE,
Bram Moolenaarcc448b32010-07-14 16:52:17 +02001449 NULL, phKey, &disp);
Bram Moolenaarccd9ccf2010-07-07 13:19:55 +02001450}
1451
1452 static LONG
1453reg_set_string_value(
1454 HKEY hKey,
1455 const char *value_name,
1456 const char *data)
1457{
1458 return RegSetValueEx(hKey, value_name, 0, REG_SZ,
1459 (LPBYTE)data, (DWORD)(1 + strlen(data)));
1460}
1461
1462 static LONG
1463reg_create_key_and_value(
1464 HKEY hRootKey,
1465 const char *subkey,
1466 const char *value_name,
Bram Moolenaar6199d432017-10-14 19:05:44 +02001467 const char *data,
1468 DWORD flag)
Bram Moolenaarccd9ccf2010-07-07 13:19:55 +02001469{
1470 HKEY hKey;
Bram Moolenaar6199d432017-10-14 19:05:44 +02001471 LONG lRet = reg_create_key(hRootKey, subkey, &hKey, flag);
Bram Moolenaarccd9ccf2010-07-07 13:19:55 +02001472
1473 if (ERROR_SUCCESS == lRet)
1474 {
Bram Moolenaarcc448b32010-07-14 16:52:17 +02001475 lRet = reg_set_string_value(hKey, value_name, data);
1476 RegCloseKey(hKey);
Bram Moolenaarccd9ccf2010-07-07 13:19:55 +02001477 }
1478 return lRet;
1479}
1480
1481 static LONG
1482register_inproc_server(
1483 HKEY hRootKey,
1484 const char *clsid,
1485 const char *extname,
1486 const char *module,
Bram Moolenaar6199d432017-10-14 19:05:44 +02001487 const char *threading_model,
1488 DWORD flag)
Bram Moolenaarccd9ccf2010-07-07 13:19:55 +02001489{
1490 CHAR subkey[BUFSIZE];
1491 LONG lRet;
1492
1493 sprintf(subkey, "CLSID\\%s", clsid);
Bram Moolenaar6199d432017-10-14 19:05:44 +02001494 lRet = reg_create_key_and_value(hRootKey, subkey, NULL, extname, flag);
Bram Moolenaarccd9ccf2010-07-07 13:19:55 +02001495 if (ERROR_SUCCESS == lRet)
1496 {
Bram Moolenaarcc448b32010-07-14 16:52:17 +02001497 sprintf(subkey, "CLSID\\%s\\InProcServer32", clsid);
Bram Moolenaar6199d432017-10-14 19:05:44 +02001498 lRet = reg_create_key_and_value(hRootKey, subkey, NULL, module, flag);
Bram Moolenaarcc448b32010-07-14 16:52:17 +02001499 if (ERROR_SUCCESS == lRet)
1500 {
1501 lRet = reg_create_key_and_value(hRootKey, subkey,
Bram Moolenaar6199d432017-10-14 19:05:44 +02001502 "ThreadingModel", threading_model, flag);
Bram Moolenaarcc448b32010-07-14 16:52:17 +02001503 }
Bram Moolenaarccd9ccf2010-07-07 13:19:55 +02001504 }
1505 return lRet;
1506}
1507
1508 static LONG
1509register_shellex(
1510 HKEY hRootKey,
1511 const char *clsid,
1512 const char *name,
Bram Moolenaar6199d432017-10-14 19:05:44 +02001513 const char *exe_path,
1514 DWORD flag)
Bram Moolenaarccd9ccf2010-07-07 13:19:55 +02001515{
1516 LONG lRet = reg_create_key_and_value(
Bram Moolenaarcc448b32010-07-14 16:52:17 +02001517 hRootKey,
1518 "*\\shellex\\ContextMenuHandlers\\gvim",
1519 NULL,
Bram Moolenaar6199d432017-10-14 19:05:44 +02001520 clsid,
1521 flag);
Bram Moolenaarccd9ccf2010-07-07 13:19:55 +02001522
1523 if (ERROR_SUCCESS == lRet)
1524 {
Bram Moolenaarcc448b32010-07-14 16:52:17 +02001525 lRet = reg_create_key_and_value(
1526 HKEY_LOCAL_MACHINE,
1527 "Software\\Microsoft\\Windows\\CurrentVersion\\Shell Extensions\\Approved",
1528 clsid,
Bram Moolenaar6199d432017-10-14 19:05:44 +02001529 name,
1530 flag);
Bram Moolenaarccd9ccf2010-07-07 13:19:55 +02001531
Bram Moolenaarcc448b32010-07-14 16:52:17 +02001532 if (ERROR_SUCCESS == lRet)
1533 {
1534 lRet = reg_create_key_and_value(
1535 HKEY_LOCAL_MACHINE,
1536 "Software\\Vim\\Gvim",
1537 "path",
Bram Moolenaar6199d432017-10-14 19:05:44 +02001538 exe_path,
1539 flag);
Bram Moolenaarcc448b32010-07-14 16:52:17 +02001540 }
Bram Moolenaarccd9ccf2010-07-07 13:19:55 +02001541 }
1542 return lRet;
1543}
1544
1545 static LONG
1546register_openwith(
1547 HKEY hRootKey,
Bram Moolenaar6199d432017-10-14 19:05:44 +02001548 const char *exe_path,
1549 DWORD flag)
Bram Moolenaarccd9ccf2010-07-07 13:19:55 +02001550{
Bram Moolenaar78050042010-07-31 20:53:54 +02001551 char exe_cmd[BUFSIZE];
1552 LONG lRet;
1553
Bram Moolenaarbbdcb482010-08-02 20:45:27 +02001554 sprintf(exe_cmd, "\"%s\" \"%%1\"", exe_path);
Bram Moolenaar78050042010-07-31 20:53:54 +02001555 lRet = reg_create_key_and_value(
Bram Moolenaarcc448b32010-07-14 16:52:17 +02001556 hRootKey,
1557 "Applications\\gvim.exe\\shell\\edit\\command",
1558 NULL,
Bram Moolenaar6199d432017-10-14 19:05:44 +02001559 exe_cmd,
1560 flag);
Bram Moolenaarccd9ccf2010-07-07 13:19:55 +02001561
1562 if (ERROR_SUCCESS == lRet)
1563 {
Bram Moolenaarcc448b32010-07-14 16:52:17 +02001564 int i;
1565 static const char *openwith[] = {
1566 ".htm\\OpenWithList\\gvim.exe",
1567 ".vim\\OpenWithList\\gvim.exe",
1568 "*\\OpenWithList\\gvim.exe",
1569 };
Bram Moolenaarccd9ccf2010-07-07 13:19:55 +02001570
Bram Moolenaarcc448b32010-07-14 16:52:17 +02001571 for (i = 0; ERROR_SUCCESS == lRet
Bram Moolenaarccd9ccf2010-07-07 13:19:55 +02001572 && i < sizeof(openwith) / sizeof(openwith[0]); i++)
Bram Moolenaar6199d432017-10-14 19:05:44 +02001573 lRet = reg_create_key_and_value(hRootKey, openwith[i], NULL, "", flag);
Bram Moolenaarccd9ccf2010-07-07 13:19:55 +02001574 }
1575
1576 return lRet;
1577}
1578
1579 static LONG
1580register_uninstall(
1581 HKEY hRootKey,
1582 const char *appname,
1583 const char *display_name,
Bram Moolenaar6cdb2c92018-10-13 17:25:27 +02001584 const char *uninstall_string,
1585 const char *display_icon,
1586 const char *display_version,
1587 const char *publisher)
Bram Moolenaarccd9ccf2010-07-07 13:19:55 +02001588{
1589 LONG lRet = reg_create_key_and_value(hRootKey, appname,
Bram Moolenaar6199d432017-10-14 19:05:44 +02001590 "DisplayName", display_name, KEY_WOW64_64KEY);
Bram Moolenaarccd9ccf2010-07-07 13:19:55 +02001591
1592 if (ERROR_SUCCESS == lRet)
Bram Moolenaarcc448b32010-07-14 16:52:17 +02001593 lRet = reg_create_key_and_value(hRootKey, appname,
Bram Moolenaar6199d432017-10-14 19:05:44 +02001594 "UninstallString", uninstall_string, KEY_WOW64_64KEY);
Bram Moolenaar6cdb2c92018-10-13 17:25:27 +02001595 if (ERROR_SUCCESS == lRet)
1596 lRet = reg_create_key_and_value(hRootKey, appname,
1597 "DisplayIcon", display_icon, KEY_WOW64_64KEY);
1598 if (ERROR_SUCCESS == lRet)
1599 lRet = reg_create_key_and_value(hRootKey, appname,
1600 "DisplayVersion", display_version, KEY_WOW64_64KEY);
1601 if (ERROR_SUCCESS == lRet)
1602 lRet = reg_create_key_and_value(hRootKey, appname,
1603 "Publisher", publisher, KEY_WOW64_64KEY);
Bram Moolenaarccd9ccf2010-07-07 13:19:55 +02001604 return lRet;
1605}
Bram Moolenaarccd9ccf2010-07-07 13:19:55 +02001606
Bram Moolenaar071d4272004-06-13 20:20:40 +00001607/*
1608 * Add some entries to the registry:
1609 * - to add "Edit with Vim" to the context * menu
1610 * - to add Vim to the "Open with..." list
1611 * - to uninstall Vim
1612 */
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01001613//ARGSUSED
Bram Moolenaarab8205e2010-07-07 15:14:03 +02001614 static int
Bram Moolenaar071d4272004-06-13 20:20:40 +00001615install_registry(void)
1616{
Bram Moolenaarcc448b32010-07-14 16:52:17 +02001617 LONG lRet = ERROR_SUCCESS;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001618 const char *vim_ext_ThreadingModel = "Apartment";
1619 const char *vim_ext_name = "Vim Shell Extension";
1620 const char *vim_ext_clsid = "{51EEE242-AD87-11d3-9C1E-0090278BBD99}";
Bram Moolenaarbbd854d2019-02-18 22:19:33 +01001621 char vim_exe_path[MAX_PATH];
Bram Moolenaarcc448b32010-07-14 16:52:17 +02001622 char display_name[BUFSIZE];
1623 char uninstall_string[BUFSIZE];
Bram Moolenaar6cdb2c92018-10-13 17:25:27 +02001624 char icon_string[BUFSIZE];
Bram Moolenaar6199d432017-10-14 19:05:44 +02001625 int i;
1626 int loop_count = is_64bit_os() ? 2 : 1;
1627 DWORD flag;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001628
Bram Moolenaarccd9ccf2010-07-07 13:19:55 +02001629 sprintf(vim_exe_path, "%s\\gvim.exe", installdir);
1630
1631 if (install_popup)
1632 {
Bram Moolenaarcc448b32010-07-14 16:52:17 +02001633 char bufg[BUFSIZE];
Bram Moolenaarccd9ccf2010-07-07 13:19:55 +02001634
Bram Moolenaarcc448b32010-07-14 16:52:17 +02001635 printf("Creating \"Edit with Vim\" popup menu entry\n");
Bram Moolenaarccd9ccf2010-07-07 13:19:55 +02001636
Bram Moolenaar6199d432017-10-14 19:05:44 +02001637 for (i = 0; i < loop_count; i++)
1638 {
1639 if (i == 0)
1640 {
1641 sprintf(bufg, "%s\\" GVIMEXT32_PATH, installdir);
1642 flag = KEY_WOW64_32KEY;
1643 }
1644 else
1645 {
1646 sprintf(bufg, "%s\\" GVIMEXT64_PATH, installdir);
1647 flag = KEY_WOW64_64KEY;
1648 }
1649
1650 lRet = register_inproc_server(
1651 HKEY_CLASSES_ROOT, vim_ext_clsid, vim_ext_name,
1652 bufg, vim_ext_ThreadingModel, flag);
1653 if (ERROR_SUCCESS != lRet)
1654 return FAIL;
1655 lRet = register_shellex(
1656 HKEY_CLASSES_ROOT, vim_ext_clsid, vim_ext_name,
1657 vim_exe_path, flag);
1658 if (ERROR_SUCCESS != lRet)
1659 return FAIL;
1660 }
Bram Moolenaarccd9ccf2010-07-07 13:19:55 +02001661 }
1662
1663 if (install_openwith)
1664 {
Bram Moolenaarcc448b32010-07-14 16:52:17 +02001665 printf("Creating \"Open with ...\" list entry\n");
Bram Moolenaarccd9ccf2010-07-07 13:19:55 +02001666
Bram Moolenaar6199d432017-10-14 19:05:44 +02001667 for (i = 0; i < loop_count; i++)
1668 {
1669 if (i == 0)
1670 flag = KEY_WOW64_32KEY;
1671 else
1672 flag = KEY_WOW64_64KEY;
1673
1674 lRet = register_openwith(HKEY_CLASSES_ROOT, vim_exe_path, flag);
1675 if (ERROR_SUCCESS != lRet)
1676 return FAIL;
1677 }
Bram Moolenaarccd9ccf2010-07-07 13:19:55 +02001678 }
1679
1680 printf("Creating an uninstall entry\n");
Bram Moolenaaraf610b82018-12-21 16:22:50 +01001681 sprintf(display_name, "Vim " VIM_VERSION_SHORT
Bram Moolenaar577fadf2019-04-04 20:32:24 +02001682#ifdef _M_ARM64
1683 " (arm64)"
1684#elif _M_X64
Bram Moolenaaraf610b82018-12-21 16:22:50 +01001685 " (x64)"
1686#endif
1687 );
Bram Moolenaarccd9ccf2010-07-07 13:19:55 +02001688
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01001689 // For the NSIS installer use the generated uninstaller.
Bram Moolenaarccd9ccf2010-07-07 13:19:55 +02001690 if (interactive)
Bram Moolenaar30e8e732019-09-27 13:08:36 +02001691 sprintf(uninstall_string, "%s\\uninstall.exe", installdir);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001692 else
Bram Moolenaar16d79a32010-07-18 22:33:56 +02001693 sprintf(uninstall_string, "%s\\uninstall-gui.exe", installdir);
Bram Moolenaarccd9ccf2010-07-07 13:19:55 +02001694
Bram Moolenaar6cdb2c92018-10-13 17:25:27 +02001695 sprintf(icon_string, "%s\\gvim.exe,0", installdir);
1696
Bram Moolenaarccd9ccf2010-07-07 13:19:55 +02001697 lRet = register_uninstall(
Bram Moolenaarcc448b32010-07-14 16:52:17 +02001698 HKEY_LOCAL_MACHINE,
1699 "Software\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\Vim " VIM_VERSION_SHORT,
1700 display_name,
Bram Moolenaar6cdb2c92018-10-13 17:25:27 +02001701 uninstall_string,
1702 icon_string,
1703 VIM_VERSION_SHORT,
1704 "Bram Moolenaar et al.");
Bram Moolenaarab8205e2010-07-07 15:14:03 +02001705 if (ERROR_SUCCESS != lRet)
1706 return FAIL;
Bram Moolenaarccd9ccf2010-07-07 13:19:55 +02001707
Bram Moolenaarab8205e2010-07-07 15:14:03 +02001708 return OK;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001709}
1710
1711 static void
1712change_popup_choice(int idx)
1713{
1714 if (install_popup == 0)
1715 {
1716 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";
1717 install_popup = 1;
1718 }
1719 else
1720 {
1721 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";
1722 install_popup = 0;
1723 }
1724}
1725
1726/*
1727 * Only add the choice for the popup menu entry when gvim.exe was found and
1728 * both gvimext.dll and regedit.exe exist.
1729 */
1730 static void
1731init_popup_choice(void)
1732{
1733 struct stat st;
1734
1735 if (has_gvim
Bram Moolenaar6199d432017-10-14 19:05:44 +02001736 && (stat(GVIMEXT32_PATH, &st) >= 0
1737 || stat(GVIMEXT64_PATH, &st) >= 0))
Bram Moolenaar071d4272004-06-13 20:20:40 +00001738 {
1739 choices[choice_count].changefunc = change_popup_choice;
1740 choices[choice_count].installfunc = NULL;
1741 choices[choice_count].active = 1;
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01001742 change_popup_choice(choice_count); // set the text
Bram Moolenaar071d4272004-06-13 20:20:40 +00001743 ++choice_count;
1744 }
1745 else
1746 add_dummy_choice();
1747}
1748
1749 static void
1750change_openwith_choice(int idx)
1751{
1752 if (install_openwith == 0)
1753 {
1754 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";
1755 install_openwith = 1;
1756 }
1757 else
1758 {
1759 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";
1760 install_openwith = 0;
1761 }
1762}
1763
1764/*
1765 * Only add the choice for the open-with menu entry when gvim.exe was found
Bram Moolenaar84a05ac2013-05-06 04:24:17 +02001766 * and regedit.exe exist.
Bram Moolenaar071d4272004-06-13 20:20:40 +00001767 */
1768 static void
1769init_openwith_choice(void)
1770{
Bram Moolenaar6199d432017-10-14 19:05:44 +02001771 if (has_gvim)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001772 {
1773 choices[choice_count].changefunc = change_openwith_choice;
1774 choices[choice_count].installfunc = NULL;
1775 choices[choice_count].active = 1;
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01001776 change_openwith_choice(choice_count); // set the text
Bram Moolenaar071d4272004-06-13 20:20:40 +00001777 ++choice_count;
1778 }
1779 else
1780 add_dummy_choice();
1781}
1782
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01001783/*
Bram Moolenaar071d4272004-06-13 20:20:40 +00001784 * Create a shell link.
1785 *
1786 * returns 0 on failure, non-zero on successful completion.
1787 *
1788 * NOTE: Currently untested with mingw.
1789 */
1790 int
1791create_shortcut(
1792 const char *shortcut_name,
1793 const char *iconfile_path,
1794 int iconindex,
1795 const char *shortcut_target,
1796 const char *shortcut_args,
1797 const char *workingdir
1798 )
1799{
1800 IShellLink *shelllink_ptr;
1801 HRESULT hres;
1802 IPersistFile *persistfile_ptr;
1803
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01001804 // Initialize COM library
Bram Moolenaar071d4272004-06-13 20:20:40 +00001805 hres = CoInitialize(NULL);
1806 if (!SUCCEEDED(hres))
1807 {
1808 printf("Error: Could not open the COM library. Not creating shortcut.\n");
1809 return FAIL;
1810 }
1811
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01001812 // Instantiate a COM object for the ShellLink, store a pointer to it
1813 // in shelllink_ptr.
Bram Moolenaar071d4272004-06-13 20:20:40 +00001814 hres = CoCreateInstance(&CLSID_ShellLink,
1815 NULL,
1816 CLSCTX_INPROC_SERVER,
1817 &IID_IShellLink,
1818 (void **) &shelllink_ptr);
1819
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01001820 if (SUCCEEDED(hres)) // If the instantiation was successful...
Bram Moolenaar071d4272004-06-13 20:20:40 +00001821 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01001822 // ...Then build a PersistFile interface for the ShellLink so we can
1823 // save it as a file after we build it.
Bram Moolenaar071d4272004-06-13 20:20:40 +00001824 hres = shelllink_ptr->lpVtbl->QueryInterface(shelllink_ptr,
1825 &IID_IPersistFile, (void **) &persistfile_ptr);
1826
1827 if (SUCCEEDED(hres))
1828 {
1829 wchar_t wsz[BUFSIZE];
1830
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01001831 // translate the (possibly) multibyte shortcut filename to windows
1832 // Unicode so it can be used as a file name.
Bram Moolenaare4963c52019-02-22 19:41:08 +01001833 MultiByteToWideChar(CP_ACP, 0, shortcut_name, -1, wsz, sizeof(wsz)/sizeof(wsz[0]));
Bram Moolenaar071d4272004-06-13 20:20:40 +00001834
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01001835 // set the attributes
Bram Moolenaar071d4272004-06-13 20:20:40 +00001836 shelllink_ptr->lpVtbl->SetPath(shelllink_ptr, shortcut_target);
1837 shelllink_ptr->lpVtbl->SetWorkingDirectory(shelllink_ptr,
1838 workingdir);
1839 shelllink_ptr->lpVtbl->SetIconLocation(shelllink_ptr,
1840 iconfile_path, iconindex);
1841 shelllink_ptr->lpVtbl->SetArguments(shelllink_ptr, shortcut_args);
1842
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01001843 // save the shortcut to a file and return the PersistFile object
Bram Moolenaar071d4272004-06-13 20:20:40 +00001844 persistfile_ptr->lpVtbl->Save(persistfile_ptr, wsz, 1);
1845 persistfile_ptr->lpVtbl->Release(persistfile_ptr);
1846 }
1847 else
1848 {
1849 printf("QueryInterface Error\n");
1850 return FAIL;
1851 }
1852
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01001853 // Return the ShellLink object
Bram Moolenaar071d4272004-06-13 20:20:40 +00001854 shelllink_ptr->lpVtbl->Release(shelllink_ptr);
1855 }
1856 else
1857 {
1858 printf("CoCreateInstance Error - hres = %08x\n", (int)hres);
1859 return FAIL;
1860 }
1861
1862 return OK;
1863}
1864
1865/*
1866 * Build a path to where we will put a specified link.
1867 *
1868 * Return 0 on error, non-zero on success
1869 */
1870 int
1871build_link_name(
1872 char *link_path,
1873 const char *link_name,
1874 const char *shell_folder_name)
1875{
Bram Moolenaarbbd854d2019-02-18 22:19:33 +01001876 char shell_folder_path[MAX_PATH];
Bram Moolenaar071d4272004-06-13 20:20:40 +00001877
1878 if (get_shell_folder_path(shell_folder_path, shell_folder_name) == FAIL)
1879 {
1880 printf("An error occurred while attempting to find the path to %s.\n",
1881 shell_folder_name);
1882 return FAIL;
1883 }
1884
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01001885 // Make sure the directory exists (create Start Menu\Programs\Vim).
1886 // Ignore errors if it already exists.
Bram Moolenaar071d4272004-06-13 20:20:40 +00001887 vim_mkdir(shell_folder_path, 0755);
1888
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01001889 // build the path to the shortcut and the path to gvim.exe
Bram Moolenaar071d4272004-06-13 20:20:40 +00001890 sprintf(link_path, "%s\\%s.lnk", shell_folder_path, link_name);
1891
1892 return OK;
1893}
1894
1895 static int
1896build_shortcut(
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01001897 const char *name, // Name of the shortcut
1898 const char *exename, // Name of the executable (e.g., vim.exe)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001899 const char *args,
1900 const char *shell_folder,
1901 const char *workingdir)
1902{
1903 char executable_path[BUFSIZE];
1904 char link_name[BUFSIZE];
1905
1906 sprintf(executable_path, "%s\\%s", installdir, exename);
1907
1908 if (build_link_name(link_name, name, shell_folder) == FAIL)
1909 {
1910 printf("An error has occurred. A shortcut to %s will not be created %s.\n",
1911 name,
1912 *shell_folder == 'd' ? "on the desktop" : "in the Start menu");
1913 return FAIL;
1914 }
1915
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01001916 // Create the shortcut:
Bram Moolenaar071d4272004-06-13 20:20:40 +00001917 return create_shortcut(link_name, executable_path, 0,
1918 executable_path, args, workingdir);
1919}
1920
1921/*
1922 * We used to use "homedir" as the working directory, but that is a bad choice
Bram Moolenaar03e228a2013-11-07 04:49:27 +01001923 * on multi-user systems. However, not specifying a directory results in the
1924 * current directory to be c:\Windows\system32 on Windows 7. Use environment
1925 * variables instead.
Bram Moolenaar071d4272004-06-13 20:20:40 +00001926 */
Bram Moolenaar03e228a2013-11-07 04:49:27 +01001927#define WORKDIR "%HOMEDRIVE%%HOMEPATH%"
Bram Moolenaar071d4272004-06-13 20:20:40 +00001928
1929/*
1930 * Create shortcut(s) in the Start Menu\Programs\Vim folder.
1931 */
1932 static void
1933install_start_menu(int idx)
1934{
1935 need_uninstall_entry = 1;
1936 printf("Creating start menu\n");
1937 if (has_vim)
1938 {
1939 if (build_shortcut("Vim", "vim.exe", "",
1940 VIM_STARTMENU, WORKDIR) == FAIL)
1941 return;
1942 if (build_shortcut("Vim Read-only", "vim.exe", "-R",
1943 VIM_STARTMENU, WORKDIR) == FAIL)
1944 return;
1945 if (build_shortcut("Vim Diff", "vim.exe", "-d",
1946 VIM_STARTMENU, WORKDIR) == FAIL)
1947 return;
1948 }
1949 if (has_gvim)
1950 {
1951 if (build_shortcut("gVim", "gvim.exe", "",
1952 VIM_STARTMENU, WORKDIR) == FAIL)
1953 return;
1954 if (build_shortcut("gVim Easy", "gvim.exe", "-y",
1955 VIM_STARTMENU, WORKDIR) == FAIL)
1956 return;
1957 if (build_shortcut("gVim Read-only", "gvim.exe", "-R",
1958 VIM_STARTMENU, WORKDIR) == FAIL)
1959 return;
1960 if (build_shortcut("gVim Diff", "gvim.exe", "-d",
1961 VIM_STARTMENU, WORKDIR) == FAIL)
1962 return;
1963 }
1964 if (build_shortcut("Uninstall",
Bram Moolenaar30e8e732019-09-27 13:08:36 +02001965 interactive ? "uninstall.exe" : "uninstall-gui.exe", "",
Bram Moolenaar071d4272004-06-13 20:20:40 +00001966 VIM_STARTMENU, installdir) == FAIL)
1967 return;
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01001968 // For Windows NT the working dir of the vimtutor.bat must be right,
1969 // otherwise gvim.exe won't be found and using gvimbat doesn't work.
Bram Moolenaar071d4272004-06-13 20:20:40 +00001970 if (build_shortcut("Vim tutor", "vimtutor.bat", "",
1971 VIM_STARTMENU, installdir) == FAIL)
1972 return;
1973 if (build_shortcut("Help", has_gvim ? "gvim.exe" : "vim.exe", "-c h",
1974 VIM_STARTMENU, WORKDIR) == FAIL)
1975 return;
1976 {
1977 char shell_folder_path[BUFSIZE];
1978
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01001979 // Creating the URL shortcut works a bit differently...
Bram Moolenaar071d4272004-06-13 20:20:40 +00001980 if (get_shell_folder_path(shell_folder_path, VIM_STARTMENU) == FAIL)
1981 {
1982 printf("Finding the path of the Start menu failed\n");
1983 return ;
1984 }
1985 add_pathsep(shell_folder_path);
1986 strcat(shell_folder_path, "Vim Online.url");
1987 if (!WritePrivateProfileString("InternetShortcut", "URL",
Bram Moolenaarbd87eb32018-06-26 23:18:45 +02001988 "https://www.vim.org/", shell_folder_path))
Bram Moolenaar071d4272004-06-13 20:20:40 +00001989 {
1990 printf("Creating the Vim online URL failed\n");
1991 return;
1992 }
1993 }
1994}
1995
1996 static void
1997toggle_startmenu_choice(int idx)
1998{
1999 if (choices[idx].installfunc == NULL)
2000 {
2001 choices[idx].installfunc = install_start_menu;
2002 choices[idx].text = "Add Vim to the Start menu";
2003 }
2004 else
2005 {
2006 choices[idx].installfunc = NULL;
2007 choices[idx].text = "Do NOT add Vim to the Start menu";
2008 }
2009}
2010
2011/*
2012 * Function to actually create the shortcuts
2013 *
2014 * Currently I am supplying no working directory to the shortcut. This
2015 * means that the initial working dir will be:
2016 * - the location of the shortcut if no file is supplied
2017 * - the location of the file being edited if a file is supplied (ie via
2018 * drag and drop onto the shortcut).
2019 */
2020 void
2021install_shortcut_gvim(int idx)
2022{
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002023 // Create shortcut(s) on the desktop
Bram Moolenaar071d4272004-06-13 20:20:40 +00002024 if (choices[idx].arg)
2025 {
2026 (void)build_shortcut(icon_names[0], "gvim.exe",
2027 "", "desktop", WORKDIR);
2028 need_uninstall_entry = 1;
2029 }
2030}
2031
2032 void
2033install_shortcut_evim(int idx)
2034{
2035 if (choices[idx].arg)
2036 {
2037 (void)build_shortcut(icon_names[1], "gvim.exe",
2038 "-y", "desktop", WORKDIR);
2039 need_uninstall_entry = 1;
2040 }
2041}
2042
2043 void
2044install_shortcut_gview(int idx)
2045{
2046 if (choices[idx].arg)
2047 {
2048 (void)build_shortcut(icon_names[2], "gvim.exe",
2049 "-R", "desktop", WORKDIR);
2050 need_uninstall_entry = 1;
2051 }
2052}
2053
2054 void
2055toggle_shortcut_choice(int idx)
2056{
2057 char *arg;
2058
2059 if (choices[idx].installfunc == install_shortcut_gvim)
2060 arg = "gVim";
2061 else if (choices[idx].installfunc == install_shortcut_evim)
2062 arg = "gVim Easy";
2063 else
2064 arg = "gVim Read-only";
2065 if (choices[idx].arg)
2066 {
2067 choices[idx].arg = 0;
2068 alloc_text(idx, "Do NOT create a desktop icon for %s", arg);
2069 }
2070 else
2071 {
2072 choices[idx].arg = 1;
2073 alloc_text(idx, "Create a desktop icon for %s", arg);
2074 }
2075}
Bram Moolenaar071d4272004-06-13 20:20:40 +00002076
2077 static void
2078init_startmenu_choice(void)
2079{
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002080 // Start menu
Bram Moolenaar071d4272004-06-13 20:20:40 +00002081 choices[choice_count].changefunc = toggle_startmenu_choice;
2082 choices[choice_count].installfunc = NULL;
2083 choices[choice_count].active = 1;
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002084 toggle_startmenu_choice(choice_count); // set the text
Bram Moolenaar071d4272004-06-13 20:20:40 +00002085 ++choice_count;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002086}
2087
2088/*
2089 * Add the choice for the desktop shortcuts.
2090 */
2091 static void
2092init_shortcut_choices(void)
2093{
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002094 // Shortcut to gvim
Bram Moolenaar071d4272004-06-13 20:20:40 +00002095 choices[choice_count].text = NULL;
2096 choices[choice_count].arg = 0;
2097 choices[choice_count].active = has_gvim;
2098 choices[choice_count].changefunc = toggle_shortcut_choice;
2099 choices[choice_count].installfunc = install_shortcut_gvim;
2100 toggle_shortcut_choice(choice_count);
2101 ++choice_count;
2102
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002103 // Shortcut to evim
Bram Moolenaar071d4272004-06-13 20:20:40 +00002104 choices[choice_count].text = NULL;
2105 choices[choice_count].arg = 0;
2106 choices[choice_count].active = has_gvim;
2107 choices[choice_count].changefunc = toggle_shortcut_choice;
2108 choices[choice_count].installfunc = install_shortcut_evim;
2109 toggle_shortcut_choice(choice_count);
2110 ++choice_count;
2111
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002112 // Shortcut to gview
Bram Moolenaar071d4272004-06-13 20:20:40 +00002113 choices[choice_count].text = NULL;
2114 choices[choice_count].arg = 0;
2115 choices[choice_count].active = has_gvim;
2116 choices[choice_count].changefunc = toggle_shortcut_choice;
2117 choices[choice_count].installfunc = install_shortcut_gview;
2118 toggle_shortcut_choice(choice_count);
2119 ++choice_count;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002120}
2121
Bram Moolenaar071d4272004-06-13 20:20:40 +00002122/*
2123 * Attempt to register OLE for Vim.
2124 */
2125 static void
2126install_OLE_register(void)
2127{
2128 char register_command_string[BUFSIZE + 30];
2129
2130 printf("\n--- Attempting to register Vim with OLE ---\n");
2131 printf("(There is no message whether this works or not.)\n");
2132
Bram Moolenaar071d4272004-06-13 20:20:40 +00002133 sprintf(register_command_string, "\"%s\\gvim.exe\" -silent -register", installdir);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002134 system(register_command_string);
2135}
Bram Moolenaar071d4272004-06-13 20:20:40 +00002136
2137/*
2138 * Remove the last part of directory "path[]" to get its parent, and put the
2139 * result in "to[]".
2140 */
2141 static void
Bram Moolenaare4963c52019-02-22 19:41:08 +01002142dir_remove_last(const char *path, char to[MAX_PATH])
Bram Moolenaar071d4272004-06-13 20:20:40 +00002143{
2144 char c;
2145 long last_char_to_copy;
2146 long path_length = strlen(path);
2147
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002148 // skip the last character just in case it is a '\\'
Bram Moolenaar071d4272004-06-13 20:20:40 +00002149 last_char_to_copy = path_length - 2;
2150 c = path[last_char_to_copy];
2151
2152 while (c != '\\')
2153 {
2154 last_char_to_copy--;
2155 c = path[last_char_to_copy];
2156 }
2157
2158 strncpy(to, path, (size_t)last_char_to_copy);
2159 to[last_char_to_copy] = NUL;
2160}
2161
2162 static void
2163set_directories_text(int idx)
2164{
Bram Moolenaar25a494c2018-11-16 19:39:50 +01002165 int vimfiles_dir_choice = choices[idx].arg;
2166
Bram Moolenaar071d4272004-06-13 20:20:40 +00002167 if (vimfiles_dir_choice == (int)vimfiles_dir_none)
2168 alloc_text(idx, "Do NOT create plugin directories%s", "");
2169 else
2170 alloc_text(idx, "Create plugin directories: %s",
2171 vimfiles_dir_choices[vimfiles_dir_choice]);
2172}
2173
2174/*
Bram Moolenaar25a494c2018-11-16 19:39:50 +01002175 * To get the "real" home directory:
2176 * - get value of $HOME
2177 * - if not found, get value of $HOMEDRIVE$HOMEPATH
2178 * - if not found, get value of $USERPROFILE
2179 *
2180 * This code is based on init_homedir() in misc1.c, keep in sync!
2181 */
2182static char *homedir = NULL;
2183
2184 void
2185init_homedir(void)
2186{
2187 char *var;
2188 char buf[MAX_PATH];
2189
2190 if (homedir != NULL)
2191 {
2192 free(homedir);
2193 homedir = NULL;
2194 }
2195
2196 var = getenv("HOME");
2197
2198 /*
2199 * Typically, $HOME is not defined on Windows, unless the user has
2200 * specifically defined it for Vim's sake. However, on Windows NT
2201 * platforms, $HOMEDRIVE and $HOMEPATH are automatically defined for
2202 * each user. Try constructing $HOME from these.
2203 */
2204 if (var == NULL || *var == NUL)
2205 {
2206 char *homedrive, *homepath;
2207
2208 homedrive = getenv("HOMEDRIVE");
2209 homepath = getenv("HOMEPATH");
2210 if (homepath == NULL || *homepath == NUL)
2211 homepath = "\\";
2212 if (homedrive != NULL
Bram Moolenaare4963c52019-02-22 19:41:08 +01002213 && strlen(homedrive) + strlen(homepath) < sizeof(buf))
Bram Moolenaar25a494c2018-11-16 19:39:50 +01002214 {
2215 sprintf(buf, "%s%s", homedrive, homepath);
2216 if (buf[0] != NUL)
2217 var = buf;
2218 }
2219 }
2220
2221 if (var == NULL)
2222 var = getenv("USERPROFILE");
2223
2224 /*
2225 * Weird but true: $HOME may contain an indirect reference to another
2226 * variable, esp. "%USERPROFILE%". Happens when $USERPROFILE isn't set
2227 * when $HOME is being set.
2228 */
2229 if (var != NULL && *var == '%')
2230 {
2231 char *p;
2232 char *exp;
2233
2234 p = strchr(var + 1, '%');
2235 if (p != NULL)
2236 {
2237 strncpy(buf, var + 1, p - (var + 1));
2238 buf[p - (var + 1)] = NUL;
2239 exp = getenv(buf);
2240 if (exp != NULL && *exp != NUL
Bram Moolenaare4963c52019-02-22 19:41:08 +01002241 && strlen(exp) + strlen(p) < sizeof(buf))
Bram Moolenaar25a494c2018-11-16 19:39:50 +01002242 {
Bram Moolenaare4963c52019-02-22 19:41:08 +01002243 sprintf(buf, "%s%s", exp, p + 1);
Bram Moolenaar25a494c2018-11-16 19:39:50 +01002244 var = buf;
2245 }
2246 }
2247 }
2248
2249 if (var != NULL && *var == NUL) // empty is same as not set
2250 var = NULL;
2251
2252 if (var == NULL)
2253 homedir = NULL;
2254 else
2255 homedir = _strdup(var);
2256}
2257
2258/*
Bram Moolenaar071d4272004-06-13 20:20:40 +00002259 * Change the directory that the vim plugin directories will be created in:
2260 * $HOME, $VIM or nowhere.
2261 */
2262 static void
2263change_directories_choice(int idx)
2264{
2265 int choice_count = TABLE_SIZE(vimfiles_dir_choices);
2266
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002267 // Don't offer the $HOME choice if $HOME isn't set.
Bram Moolenaar25a494c2018-11-16 19:39:50 +01002268 if (homedir == NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002269 --choice_count;
Bram Moolenaar25a494c2018-11-16 19:39:50 +01002270 choices[idx].arg = get_choice(vimfiles_dir_choices, choice_count);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002271 set_directories_text(idx);
2272}
2273
2274/*
2275 * Create the plugin directories...
2276 */
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002277//ARGSUSED
Bram Moolenaar071d4272004-06-13 20:20:40 +00002278 static void
2279install_vimfilesdir(int idx)
2280{
2281 int i;
Bram Moolenaar25a494c2018-11-16 19:39:50 +01002282 int vimfiles_dir_choice = choices[idx].arg;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002283 char *p;
Bram Moolenaarbbd854d2019-02-18 22:19:33 +01002284 char vimdir_path[MAX_PATH];
2285 char vimfiles_path[MAX_PATH + 9];
Bram Moolenaar071d4272004-06-13 20:20:40 +00002286 char tmp_dirname[BUFSIZE];
2287
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002288 // switch on the location that the user wants the plugin directories
2289 // built in
Bram Moolenaar071d4272004-06-13 20:20:40 +00002290 switch (vimfiles_dir_choice)
2291 {
2292 case vimfiles_dir_vim:
2293 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002294 // Go to the %VIM% directory - check env first, then go one dir
2295 // below installdir if there is no %VIM% environment variable.
2296 // The accuracy of $VIM is checked in inspect_system(), so we
2297 // can be sure it is ok to use here.
Bram Moolenaar071d4272004-06-13 20:20:40 +00002298 p = getenv("VIM");
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002299 if (p == NULL) // No $VIM in path
Bram Moolenaar071d4272004-06-13 20:20:40 +00002300 dir_remove_last(installdir, vimdir_path);
2301 else
2302 strcpy(vimdir_path, p);
2303 break;
2304 }
2305 case vimfiles_dir_home:
2306 {
Bram Moolenaar25a494c2018-11-16 19:39:50 +01002307 // Find the $HOME directory. Its existence was already checked.
2308 p = homedir;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002309 if (p == NULL)
2310 {
2311 printf("Internal error: $HOME is NULL\n");
2312 p = "c:\\";
2313 }
2314 strcpy(vimdir_path, p);
2315 break;
2316 }
2317 case vimfiles_dir_none:
2318 {
Bram Moolenaar25a494c2018-11-16 19:39:50 +01002319 // Do not create vim plugin directory.
Bram Moolenaar071d4272004-06-13 20:20:40 +00002320 return;
2321 }
2322 }
2323
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002324 // Now, just create the directory. If it already exists, it will fail
2325 // silently.
Bram Moolenaar071d4272004-06-13 20:20:40 +00002326 sprintf(vimfiles_path, "%s\\vimfiles", vimdir_path);
2327 vim_mkdir(vimfiles_path, 0755);
2328
2329 printf("Creating the following directories in \"%s\":\n", vimfiles_path);
2330 for (i = 0; i < TABLE_SIZE(vimfiles_subdirs); i++)
2331 {
2332 sprintf(tmp_dirname, "%s\\%s", vimfiles_path, vimfiles_subdirs[i]);
2333 printf(" %s", vimfiles_subdirs[i]);
2334 vim_mkdir(tmp_dirname, 0755);
2335 }
2336 printf("\n");
2337}
2338
2339/*
2340 * Add the creation of runtime files to the setup sequence.
2341 */
2342 static void
2343init_directories_choice(void)
2344{
2345 struct stat st;
2346 char tmp_dirname[BUFSIZE];
2347 char *p;
Bram Moolenaar25a494c2018-11-16 19:39:50 +01002348 int vimfiles_dir_choice;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002349
2350 choices[choice_count].text = alloc(150);
2351 choices[choice_count].changefunc = change_directories_choice;
2352 choices[choice_count].installfunc = install_vimfilesdir;
2353 choices[choice_count].active = 1;
2354
Bram Moolenaar25a494c2018-11-16 19:39:50 +01002355 // Check if the "compiler" directory already exists. That's a good
2356 // indication that the plugin directories were already created.
Bram Moolenaare4963c52019-02-22 19:41:08 +01002357 p = getenv("HOME");
2358 if (p != NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002359 {
2360 vimfiles_dir_choice = (int)vimfiles_dir_home;
Bram Moolenaare4963c52019-02-22 19:41:08 +01002361 sprintf(tmp_dirname, "%s\\vimfiles\\compiler", p);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002362 if (stat(tmp_dirname, &st) == 0)
2363 vimfiles_dir_choice = (int)vimfiles_dir_none;
2364 }
2365 else
2366 {
2367 vimfiles_dir_choice = (int)vimfiles_dir_vim;
2368 p = getenv("VIM");
Bram Moolenaar25a494c2018-11-16 19:39:50 +01002369 if (p == NULL) // No $VIM in path, use the install dir.
Bram Moolenaar071d4272004-06-13 20:20:40 +00002370 dir_remove_last(installdir, tmp_dirname);
2371 else
2372 strcpy(tmp_dirname, p);
2373 strcat(tmp_dirname, "\\vimfiles\\compiler");
2374 if (stat(tmp_dirname, &st) == 0)
2375 vimfiles_dir_choice = (int)vimfiles_dir_none;
2376 }
2377
Bram Moolenaar25a494c2018-11-16 19:39:50 +01002378 choices[choice_count].arg = vimfiles_dir_choice;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002379 set_directories_text(choice_count);
2380 ++choice_count;
2381}
2382
2383/*
2384 * Setup the choices and the default values.
2385 */
2386 static void
2387setup_choices(void)
2388{
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002389 // install the batch files
Bram Moolenaar071d4272004-06-13 20:20:40 +00002390 init_bat_choices();
2391
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002392 // (over) write _vimrc file
Bram Moolenaar071d4272004-06-13 20:20:40 +00002393 init_vimrc_choices();
2394
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002395 // Whether to add Vim to the popup menu
Bram Moolenaar071d4272004-06-13 20:20:40 +00002396 init_popup_choice();
2397
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002398 // Whether to add Vim to the "Open With..." menu
Bram Moolenaar071d4272004-06-13 20:20:40 +00002399 init_openwith_choice();
2400
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002401 // Whether to add Vim to the Start Menu.
Bram Moolenaar071d4272004-06-13 20:20:40 +00002402 init_startmenu_choice();
2403
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002404 // Whether to add shortcuts to the Desktop.
Bram Moolenaar071d4272004-06-13 20:20:40 +00002405 init_shortcut_choices();
2406
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002407 // Whether to create the runtime directories.
Bram Moolenaar071d4272004-06-13 20:20:40 +00002408 init_directories_choice();
2409}
2410
2411 static void
2412print_cmd_line_help(void)
2413{
2414 printf("Vim installer non-interactive command line arguments:\n");
2415 printf("\n");
2416 printf("-create-batfiles [vim gvim evim view gview vimdiff gvimdiff]\n");
2417 printf(" Create .bat files for Vim variants in the Windows directory.\n");
2418 printf("-create-vimrc\n");
2419 printf(" Create a default _vimrc file if one does not already exist.\n");
Bram Moolenaarc3fdf7f2017-10-28 18:36:48 +02002420 printf("-vimrc-remap [no|win]\n");
2421 printf(" Remap keys when creating a default _vimrc file.\n");
2422 printf("-vimrc-behave [unix|mswin|default]\n");
2423 printf(" Set mouse behavior when creating a default _vimrc file.\n");
Bram Moolenaar6cdb2c92018-10-13 17:25:27 +02002424 printf("-vimrc-compat [vi|vim|defaults|all]\n");
2425 printf(" Set Vi compatibility when creating a default _vimrc file.\n");
Bram Moolenaar071d4272004-06-13 20:20:40 +00002426 printf("-install-popup\n");
2427 printf(" Install the Edit-with-Vim context menu entry\n");
2428 printf("-install-openwith\n");
2429 printf(" Add Vim to the \"Open With...\" context menu list\n");
Bram Moolenaar071d4272004-06-13 20:20:40 +00002430 printf("-add-start-menu");
2431 printf(" Add Vim to the start menu\n");
2432 printf("-install-icons");
2433 printf(" Create icons for gVim executables on the desktop\n");
Bram Moolenaar071d4272004-06-13 20:20:40 +00002434 printf("-create-directories [vim|home]\n");
2435 printf(" Create runtime directories to drop plugins into; in the $VIM\n");
2436 printf(" or $HOME directory\n");
Bram Moolenaar071d4272004-06-13 20:20:40 +00002437 printf("-register-OLE");
Bram Moolenaarce0842a2005-07-18 21:58:11 +00002438 printf(" Ignored\n");
Bram Moolenaar071d4272004-06-13 20:20:40 +00002439 printf("\n");
2440}
2441
2442/*
2443 * Setup installation choices based on command line switches
2444 */
2445 static void
2446command_line_setup_choices(int argc, char **argv)
2447{
2448 int i, j;
2449
2450 for (i = 1; i < argc; i++)
2451 {
2452 if (strcmp(argv[i], "-create-batfiles") == 0)
2453 {
2454 if (i + 1 == argc)
2455 continue;
2456 while (argv[i + 1][0] != '-' && i < argc)
2457 {
2458 i++;
2459 for (j = 1; j < TARGET_COUNT; ++j)
2460 if ((targets[j].exenamearg[0] == 'g' ? has_gvim : has_vim)
2461 && strcmp(argv[i], targets[j].name) == 0)
2462 {
2463 init_bat_choice(j);
2464 break;
2465 }
2466 if (j == TARGET_COUNT)
2467 printf("%s is not a valid choice for -create-batfiles\n",
2468 argv[i]);
2469
2470 if (i + 1 == argc)
2471 break;
2472 }
2473 }
2474 else if (strcmp(argv[i], "-create-vimrc") == 0)
2475 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002476 // Setup default vimrc choices. If there is already a _vimrc file,
2477 // it will NOT be overwritten.
Bram Moolenaar071d4272004-06-13 20:20:40 +00002478 init_vimrc_choices();
2479 }
Bram Moolenaarc3fdf7f2017-10-28 18:36:48 +02002480 else if (strcmp(argv[i], "-vimrc-remap") == 0)
2481 {
2482 if (i + 1 == argc)
2483 break;
2484 i++;
2485 if (strcmp(argv[i], "no") == 0)
2486 remap_choice = remap_no;
2487 else if (strcmp(argv[i], "win") == 0)
2488 remap_choice = remap_win;
2489 }
2490 else if (strcmp(argv[i], "-vimrc-behave") == 0)
2491 {
2492 if (i + 1 == argc)
2493 break;
2494 i++;
2495 if (strcmp(argv[i], "unix") == 0)
2496 mouse_choice = mouse_xterm;
2497 else if (strcmp(argv[i], "mswin") == 0)
2498 mouse_choice = mouse_mswin;
2499 else if (strcmp(argv[i], "default") == 0)
2500 mouse_choice = mouse_default;
2501 }
Bram Moolenaar6cdb2c92018-10-13 17:25:27 +02002502 else if (strcmp(argv[i], "-vimrc-compat") == 0)
2503 {
2504 if (i + 1 == argc)
2505 break;
2506 i++;
2507 if (strcmp(argv[i], "vi") == 0)
2508 compat_choice = compat_vi;
2509 else if (strcmp(argv[i], "vim") == 0)
2510 compat_choice = compat_vim;
2511 else if (strcmp(argv[i], "defaults") == 0)
2512 compat_choice = compat_some_enhancements;
2513 else if (strcmp(argv[i], "all") == 0)
2514 compat_choice = compat_all_enhancements;
2515 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00002516 else if (strcmp(argv[i], "-install-popup") == 0)
2517 {
2518 init_popup_choice();
2519 }
2520 else if (strcmp(argv[i], "-install-openwith") == 0)
2521 {
2522 init_openwith_choice();
2523 }
2524 else if (strcmp(argv[i], "-add-start-menu") == 0)
2525 {
2526 init_startmenu_choice();
2527 }
2528 else if (strcmp(argv[i], "-install-icons") == 0)
2529 {
2530 init_shortcut_choices();
2531 }
2532 else if (strcmp(argv[i], "-create-directories") == 0)
2533 {
Bram Moolenaar142a9752018-12-14 19:54:39 +01002534 int vimfiles_dir_choice = (int)vimfiles_dir_none;
Bram Moolenaar25a494c2018-11-16 19:39:50 +01002535
Bram Moolenaar071d4272004-06-13 20:20:40 +00002536 init_directories_choice();
2537 if (argv[i + 1][0] != '-')
2538 {
2539 i++;
2540 if (strcmp(argv[i], "vim") == 0)
2541 vimfiles_dir_choice = (int)vimfiles_dir_vim;
2542 else if (strcmp(argv[i], "home") == 0)
2543 {
Bram Moolenaar25a494c2018-11-16 19:39:50 +01002544 if (homedir == NULL) // No $HOME in environment
2545 vimfiles_dir_choice = (int)vimfiles_dir_none;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002546 else
2547 vimfiles_dir_choice = (int)vimfiles_dir_home;
2548 }
2549 else
2550 {
2551 printf("Unknown argument for -create-directories: %s\n",
2552 argv[i]);
2553 print_cmd_line_help();
2554 }
2555 }
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002556 else // No choice specified, default to vim directory
Bram Moolenaar071d4272004-06-13 20:20:40 +00002557 vimfiles_dir_choice = (int)vimfiles_dir_vim;
Bram Moolenaar25a494c2018-11-16 19:39:50 +01002558 choices[choice_count - 1].arg = vimfiles_dir_choice;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002559 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00002560 else if (strcmp(argv[i], "-register-OLE") == 0)
2561 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002562 // This is always done when gvim is found
Bram Moolenaar071d4272004-06-13 20:20:40 +00002563 }
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002564 else // Unknown switch
Bram Moolenaar071d4272004-06-13 20:20:40 +00002565 {
2566 printf("Got unknown argument argv[%d] = %s\n", i, argv[i]);
2567 print_cmd_line_help();
2568 }
2569 }
2570}
2571
2572
2573/*
2574 * Show a few screens full of helpful information.
2575 */
2576 static void
2577show_help(void)
2578{
2579 static char *(items[]) =
2580 {
2581"Installing .bat files\n"
2582"---------------------\n"
2583"The vim.bat file is written in one of the directories in $PATH.\n"
2584"This makes it possible to start Vim from the command line.\n"
2585"If vim.exe can be found in $PATH, the choice for vim.bat will not be\n"
2586"present. It is assumed you will use the existing vim.exe.\n"
2587"If vim.bat can already be found in $PATH this is probably for an old\n"
2588"version of Vim (but this is not checked!). You can overwrite it.\n"
2589"If no vim.bat already exists, you can select one of the directories in\n"
2590"$PATH for creating the batch file, or disable creating a vim.bat file.\n"
2591"\n"
2592"If you choose not to create the vim.bat file, Vim can still be executed\n"
2593"in other ways, but not from the command line.\n"
2594"\n"
2595"The same applies to choices for gvim, evim, (g)view, and (g)vimdiff.\n"
2596"The first item can be used to change the path for all of them.\n"
2597,
2598"Creating a _vimrc file\n"
2599"----------------------\n"
2600"The _vimrc file is used to set options for how Vim behaves.\n"
2601"The install program can create a _vimrc file with a few basic choices.\n"
2602"You can edit this file later to tune your preferences.\n"
2603"If you already have a _vimrc or .vimrc file it can be overwritten.\n"
2604"Don't do that if you have made changes to it.\n"
2605,
2606"Vim features\n"
2607"------------\n"
2608"(this choice is only available when creating a _vimrc file)\n"
2609"1. Vim can run in Vi-compatible mode. Many nice Vim features are then\n"
Bram Moolenaar2b849492018-11-21 13:58:35 +01002610" disabled. Only choose Vi-compatible if you really need full Vi\n"
2611" compatibility.\n"
2612"2. Vim runs in not-Vi-compatible mode. Vim is still mostly Vi compatible,\n"
2613" but adds nice features like multi-level undo.\n"
2614"3. Running Vim with some enhancements is useful when you want some of\n"
Bram Moolenaar071d4272004-06-13 20:20:40 +00002615" the nice Vim features, but have a slow computer and want to keep it\n"
2616" really fast.\n"
Bram Moolenaar2b849492018-11-21 13:58:35 +01002617"4. Syntax highlighting shows many files in color. Not only does this look\n"
Bram Moolenaar071d4272004-06-13 20:20:40 +00002618" nice, it also makes it easier to spot errors and you can work faster.\n"
2619" The other features include editing compressed files.\n"
2620,
2621"Windows key mapping\n"
2622"-------------------\n"
2623"(this choice is only available when creating a _vimrc file)\n"
2624"Under MS-Windows the CTRL-C key copies text to the clipboard and CTRL-V\n"
2625"pastes text from the clipboard. There are a few more keys like these.\n"
2626"Unfortunately, in Vim these keys normally have another meaning.\n"
2627"1. Choose to have the keys like they normally are in Vim (useful if you\n"
2628" also use Vim on other systems).\n"
2629"2. Choose to have the keys work like they are used on MS-Windows (useful\n"
2630" if you mostly work on MS-Windows).\n"
2631,
2632"Mouse use\n"
2633"---------\n"
2634"(this choice is only available when creating a _vimrc file)\n"
2635"The right mouse button can be used in two ways:\n"
2636"1. The Unix way is to extend an existing selection. The popup menu is\n"
2637" not available.\n"
2638"2. The MS-Windows way is to show a popup menu, which allows you to\n"
2639" copy/paste text, undo/redo, etc. Extending the selection can still be\n"
2640" done by keeping SHIFT pressed while using the left mouse button\n"
2641,
2642"Edit-with-Vim context menu entry\n"
2643"--------------------------------\n"
2644"(this choice is only available when gvim.exe and gvimext.dll are present)\n"
2645"You can associate different file types with Vim, so that you can (double)\n"
2646"click on a file to edit it with Vim. This means you have to individually\n"
2647"select each file type.\n"
2648"An alternative is the option offered here: Install an \"Edit with Vim\"\n"
2649"entry in the popup menu for the right mouse button. This means you can\n"
2650"edit any file with Vim.\n"
2651,
2652"\"Open With...\" context menu entry\n"
2653"--------------------------------\n"
2654"(this choice is only available when gvim.exe is present)\n"
2655"This option adds Vim to the \"Open With...\" entry in the popup menu for\n"
2656"the right mouse button. This also makes it possible to edit HTML files\n"
2657"directly from Internet Explorer.\n"
2658,
2659"Add Vim to the Start menu\n"
2660"-------------------------\n"
2661"In Windows 95 and later, Vim can be added to the Start menu. This will\n"
2662"create a submenu with an entry for vim, gvim, evim, vimdiff, etc..\n"
2663,
2664"Icons on the desktop\n"
2665"--------------------\n"
2666"(these choices are only available when installing gvim)\n"
2667"In Windows 95 and later, shortcuts (icons) can be created on the Desktop.\n"
2668,
2669"Create plugin directories\n"
2670"-------------------------\n"
2671"Plugin directories allow extending Vim by dropping a file into a directory.\n"
2672"This choice allows creating them in $HOME (if you have a home directory) or\n"
2673"$VIM (used for everybody on the system).\n"
2674,
2675NULL
2676 };
2677 int i;
2678 int c;
2679
2680 rewind(stdin);
2681 printf("\n");
2682 for (i = 0; items[i] != NULL; ++i)
2683 {
Bram Moolenaarc3fdf7f2017-10-28 18:36:48 +02002684 puts(items[i]);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002685 printf("Hit Enter to continue, b (back) or q (quit help): ");
2686 c = getchar();
2687 rewind(stdin);
2688 if (c == 'b' || c == 'B')
2689 {
2690 if (i == 0)
2691 --i;
2692 else
2693 i -= 2;
2694 }
2695 if (c == 'q' || c == 'Q')
2696 break;
2697 printf("\n");
2698 }
2699}
2700
2701/*
2702 * Install the choices.
2703 */
2704 static void
2705install(void)
2706{
2707 int i;
2708
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002709 // Install the selected choices.
Bram Moolenaar071d4272004-06-13 20:20:40 +00002710 for (i = 0; i < choice_count; ++i)
2711 if (choices[i].installfunc != NULL && choices[i].active)
2712 (choices[i].installfunc)(i);
2713
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002714 // Add some entries to the registry, if needed.
Bram Moolenaar071d4272004-06-13 20:20:40 +00002715 if (install_popup
2716 || install_openwith
2717 || (need_uninstall_entry && interactive)
2718 || !interactive)
2719 install_registry();
2720
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002721 // Register gvim with OLE.
Bram Moolenaar071d4272004-06-13 20:20:40 +00002722 if (has_gvim)
2723 install_OLE_register();
Bram Moolenaar071d4272004-06-13 20:20:40 +00002724}
2725
2726/*
2727 * request_choice
2728 */
2729 static void
2730request_choice(void)
2731{
2732 int i;
2733
2734 printf("\n\nInstall will do for you:\n");
2735 for (i = 0; i < choice_count; ++i)
2736 if (choices[i].active)
2737 printf("%2d %s\n", i + 1, choices[i].text);
2738 printf("To change an item, enter its number\n\n");
2739 printf("Enter item number, h (help), d (do it) or q (quit): ");
2740}
2741
2742 int
2743main(int argc, char **argv)
2744{
2745 int i;
2746 char buf[BUFSIZE];
2747
2748 /*
2749 * Run interactively if there are no command line arguments.
2750 */
2751 if (argc > 1)
2752 interactive = 0;
2753 else
2754 interactive = 1;
2755
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002756 // Initialize this program.
Bram Moolenaar071d4272004-06-13 20:20:40 +00002757 do_inits(argv);
Bram Moolenaar25a494c2018-11-16 19:39:50 +01002758 init_homedir();
Bram Moolenaar071d4272004-06-13 20:20:40 +00002759
Bram Moolenaar071d4272004-06-13 20:20:40 +00002760 if (argc > 1 && strcmp(argv[1], "-uninstall-check") == 0)
2761 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002762 // Only check for already installed Vims. Used by NSIS installer.
Bram Moolenaar442b4222010-05-24 21:34:22 +02002763 i = uninstall_check(1);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002764
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002765 // Find the value of $VIM, because NSIS isn't able to do this by
2766 // itself.
Bram Moolenaar071d4272004-06-13 20:20:40 +00002767 get_vim_env();
2768
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002769 // When nothing found exit quietly. If something found wait for
2770 // a little while, so that the user can read the messages.
Bram Moolenaar6cdb2c92018-10-13 17:25:27 +02002771 if (i && _isatty(1))
Bram Moolenaarab8205e2010-07-07 15:14:03 +02002772 sleep(3);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002773 exit(0);
2774 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00002775
2776 printf("This program sets up the installation of Vim "
2777 VIM_VERSION_MEDIUM "\n\n");
2778
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002779 // Check if the user unpacked the archives properly.
Bram Moolenaar071d4272004-06-13 20:20:40 +00002780 check_unpack();
2781
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002782 // Check for already installed Vims.
Bram Moolenaar071d4272004-06-13 20:20:40 +00002783 if (interactive)
Bram Moolenaar442b4222010-05-24 21:34:22 +02002784 uninstall_check(0);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002785
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002786 // Find out information about the system.
Bram Moolenaar071d4272004-06-13 20:20:40 +00002787 inspect_system();
2788
2789 if (interactive)
2790 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002791 // Setup all the choices.
Bram Moolenaar071d4272004-06-13 20:20:40 +00002792 setup_choices();
2793
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002794 // Let the user change choices and finally install (or quit).
Bram Moolenaar071d4272004-06-13 20:20:40 +00002795 for (;;)
2796 {
2797 request_choice();
2798 rewind(stdin);
2799 if (scanf("%99s", buf) == 1)
2800 {
2801 if (isdigit(buf[0]))
2802 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002803 // Change a choice.
Bram Moolenaar071d4272004-06-13 20:20:40 +00002804 i = atoi(buf);
2805 if (i > 0 && i <= choice_count && choices[i - 1].active)
2806 (choices[i - 1].changefunc)(i - 1);
2807 else
2808 printf("\nIllegal choice\n");
2809 }
2810 else if (buf[0] == 'h' || buf[0] == 'H')
2811 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002812 // Help
Bram Moolenaar071d4272004-06-13 20:20:40 +00002813 show_help();
2814 }
2815 else if (buf[0] == 'd' || buf[0] == 'D')
2816 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002817 // Install!
Bram Moolenaar071d4272004-06-13 20:20:40 +00002818 install();
2819 printf("\nThat finishes the installation. Happy Vimming!\n");
2820 break;
2821 }
2822 else if (buf[0] == 'q' || buf[0] == 'Q')
2823 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002824 // Quit
Bram Moolenaar071d4272004-06-13 20:20:40 +00002825 printf("\nExiting without anything done\n");
2826 break;
2827 }
2828 else
2829 printf("\nIllegal choice\n");
2830 }
2831 }
2832 printf("\n");
Bram Moolenaar442b4222010-05-24 21:34:22 +02002833 myexit(0);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002834 }
2835 else
2836 {
2837 /*
2838 * Run non-interactive - setup according to the command line switches
2839 */
2840 command_line_setup_choices(argc, argv);
2841 install();
Bram Moolenaar442b4222010-05-24 21:34:22 +02002842
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002843 // Avoid that the user has to hit Enter, just wait a little bit to
2844 // allow reading the messages.
Bram Moolenaarab8205e2010-07-07 15:14:03 +02002845 sleep(2);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002846 }
2847
Bram Moolenaar071d4272004-06-13 20:20:40 +00002848 return 0;
2849}