blob: 2d2b95c10a5edcd9b0248d8e104d0b947f6195cf [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
K.Takataeeec2542021-06-02 13:28:16 +020062#define TABLE_SIZE(s) (int)ARRAYSIZE(s)
Bram Moolenaar071d4272004-06-13 20:20:40 +000063
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 Moolenaar0df54192020-03-23 22:17:11 +0100850 * contains a space. The quotes would be included in the value.
Bram Moolenaar97b2ad32006-03-18 21:40:56 +0000851 * The order of preference is:
852 * 1. $VIMRUNTIME/vim.exe (user preference)
Bram Moolenaarabab0b02019-03-30 18:47:01 +0100853 * 2. $VIM/vim81/vim.exe (hard coded version)
Bram Moolenaar97b2ad32006-03-18 21:40:56 +0000854 * 3. installdir/vim.exe (hard coded install directory)
855 */
856 fprintf(fd, "set VIM_EXE_DIR=%s\n", installdir);
857 fprintf(fd, "if exist \"%%VIM%%\\%s\\%s\" set VIM_EXE_DIR=%%VIM%%\\%s\n",
858 VIM_VERSION_NODOT, exename, VIM_VERSION_NODOT);
859 fprintf(fd, "if exist \"%%VIMRUNTIME%%\\%s\" set VIM_EXE_DIR=%%VIMRUNTIME%%\n", exename);
860 fprintf(fd, "\n");
Bram Moolenaar071d4272004-06-13 20:20:40 +0000861
Bram Moolenaar5d18efe2019-12-01 21:11:22 +0100862 // Give an error message when the executable could not be found.
Bram Moolenaar0df54192020-03-23 22:17:11 +0100863 fprintf(fd, "if not exist \"%%VIM_EXE_DIR%%\\%s\" (\n", exename);
864 fprintf(fd, " echo \"%%VIM_EXE_DIR%%\\%s\" not found\n", exename);
865 fprintf(fd, " goto :eof\n");
866 fprintf(fd, ")\n");
Bram Moolenaar97b2ad32006-03-18 21:40:56 +0000867 fprintf(fd, "\n");
Bram Moolenaar071d4272004-06-13 20:20:40 +0000868
Bram Moolenaar071d4272004-06-13 20:20:40 +0000869 if (*exename == 'g')
Bram Moolenaar0df54192020-03-23 22:17:11 +0100870 {
871 fprintf(fd, "rem check --nofork argument\n");
Bram Moolenaar071d4272004-06-13 20:20:40 +0000872 fprintf(fd, "set VIMNOFORK=\n");
Bram Moolenaar0df54192020-03-23 22:17:11 +0100873 fprintf(fd, ":loopstart\n");
874 fprintf(fd, "if .%%1==. goto loopend\n");
875 fprintf(fd, "if .%%1==.--nofork (\n");
876 fprintf(fd, " set VIMNOFORK=1\n");
877 fprintf(fd, ") else if .%%1==.-f (\n");
878 fprintf(fd, " set VIMNOFORK=1\n");
879 fprintf(fd, ")\n");
880 fprintf(fd, "shift\n");
881 fprintf(fd, "goto loopstart\n");
882 fprintf(fd, ":loopend\n");
Bram Moolenaar97b2ad32006-03-18 21:40:56 +0000883 fprintf(fd, "\n");
Bram Moolenaar071d4272004-06-13 20:20:40 +0000884 }
885
Bram Moolenaar071d4272004-06-13 20:20:40 +0000886 if (*exename == 'g')
887 {
Bram Moolenaar0df54192020-03-23 22:17:11 +0100888 // For gvim.exe use "start /b" to avoid that the console window
889 // stays open.
890 fprintf(fd, "if .%%VIMNOFORK%%==.1 (\n");
891 fprintf(fd, " start \"dummy\" /b /wait ");
892 // Always use quotes, $VIM or $VIMRUNTIME might have a space.
893 fprintf(fd, "\"%%VIM_EXE_DIR%%\\%s\" %s %%*\n",
894 exename, vimarg);
895 fprintf(fd, ") else (\n");
896 fprintf(fd, " start \"dummy\" /b ");
897 // Always use quotes, $VIM or $VIMRUNTIME might have a space.
898 fprintf(fd, "\"%%VIM_EXE_DIR%%\\%s\" %s %%*\n",
899 exename, vimarg);
900 fprintf(fd, ")\n");
Bram Moolenaar071d4272004-06-13 20:20:40 +0000901 }
Bram Moolenaar0df54192020-03-23 22:17:11 +0100902 else
Bram Moolenaar071d4272004-06-13 20:20:40 +0000903 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +0100904 // Always use quotes, $VIM or $VIMRUNTIME might have a space.
Bram Moolenaar97b2ad32006-03-18 21:40:56 +0000905 fprintf(fd, "\"%%VIM_EXE_DIR%%\\%s\" %s %%*\n",
906 exename, vimarg);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000907 }
908
Bram Moolenaar071d4272004-06-13 20:20:40 +0000909 fclose(fd);
910 printf("%s has been %s\n", batpath,
911 oldname == NULL ? "created" : "overwritten");
912 }
913 }
914}
915
916/*
917 * Make the text string for choice "idx".
918 * The format "fmt" is must have one %s item, which "arg" is used for.
919 */
920 static void
921alloc_text(int idx, char *fmt, char *arg)
922{
923 if (choices[idx].text != NULL)
924 free(choices[idx].text);
925
Bram Moolenaar51e14382019-05-25 20:21:28 +0200926 choices[idx].text = alloc(strlen(fmt) + strlen(arg) - 1);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000927 sprintf(choices[idx].text, fmt, arg);
928}
929
930/*
931 * Toggle the "Overwrite .../vim.bat" to "Don't overwrite".
932 */
933 static void
934toggle_bat_choice(int idx)
935{
936 char *batname = targets[choices[idx].arg].batpath;
937 char *oldname = targets[choices[idx].arg].oldbat;
938
939 if (*batname == NUL)
940 {
941 alloc_text(idx, " Overwrite %s", oldname);
942 strcpy(batname, oldname);
943 }
944 else
945 {
946 alloc_text(idx, " Do NOT overwrite %s", oldname);
947 *batname = NUL;
948 }
949}
950
951/*
952 * Do some work for a batch file entry: Append the batch file name to the path
953 * and set the text for the choice.
954 */
955 static void
956set_bat_text(int idx, char *batpath, char *name)
957{
958 strcat(batpath, name);
959
960 alloc_text(idx, " Create %s", batpath);
961}
962
963/*
964 * Select a directory to write the batch file line.
965 */
966 static void
967change_bat_choice(int idx)
968{
969 char *path;
970 char *batpath;
971 char *name;
972 int n;
973 char *s;
974 char *p;
975 int count;
976 char **names = NULL;
977 int i;
978 int target = choices[idx].arg;
979
980 name = targets[target].batname;
981 batpath = targets[target].batpath;
982
983 path = getenv("PATH");
984 if (path == NULL)
985 {
986 printf("\nERROR: The variable $PATH is not set\n");
987 return;
988 }
989
990 /*
991 * first round: count number of names in path;
992 * second round: save names to names[].
993 */
994 for (;;)
995 {
996 count = 1;
997 for (p = path; *p; )
998 {
999 s = strchr(p, ';');
1000 if (s == NULL)
1001 s = p + strlen(p);
1002 if (names != NULL)
1003 {
Bram Moolenaar51e14382019-05-25 20:21:28 +02001004 names[count] = alloc(s - p + 1);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001005 strncpy(names[count], p, s - p);
1006 names[count][s - p] = NUL;
1007 }
1008 ++count;
1009 p = s;
1010 if (*p != NUL)
1011 ++p;
1012 }
1013 if (names != NULL)
1014 break;
Bram Moolenaar51e14382019-05-25 20:21:28 +02001015 names = alloc((count + 1) * sizeof(char *));
Bram Moolenaar071d4272004-06-13 20:20:40 +00001016 }
1017 names[0] = alloc(50);
1018 sprintf(names[0], "Select directory to create %s in:", name);
1019 names[count] = alloc(50);
1020 if (choices[idx].arg == 0)
1021 sprintf(names[count], "Do not create any .bat file.");
1022 else
1023 sprintf(names[count], "Do not create a %s file.", name);
1024 n = get_choice(names, count + 1);
1025
1026 if (n == count)
1027 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01001028 // Selected last item, don't create bat file.
Bram Moolenaar071d4272004-06-13 20:20:40 +00001029 *batpath = NUL;
1030 if (choices[idx].arg != 0)
1031 alloc_text(idx, " Do NOT create %s", name);
1032 }
1033 else
1034 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01001035 // Selected one of the paths. For the first item only keep the path,
1036 // for the others append the batch file name.
Bram Moolenaar071d4272004-06-13 20:20:40 +00001037 strcpy(batpath, names[n]);
1038 add_pathsep(batpath);
1039 if (choices[idx].arg != 0)
1040 set_bat_text(idx, batpath, name);
1041 }
1042
1043 for (i = 0; i <= count; ++i)
1044 free(names[i]);
1045 free(names);
1046}
1047
1048char *bat_text_yes = "Install .bat files to use Vim at the command line:";
1049char *bat_text_no = "do NOT install .bat files to use Vim at the command line";
1050
1051 static void
1052change_main_bat_choice(int idx)
1053{
1054 int i;
1055
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01001056 // let the user select a default directory or NONE
Bram Moolenaar071d4272004-06-13 20:20:40 +00001057 change_bat_choice(idx);
1058
1059 if (targets[0].batpath[0] != NUL)
1060 choices[idx].text = bat_text_yes;
1061 else
1062 choices[idx].text = bat_text_no;
1063
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01001064 // update the individual batch file selections
Bram Moolenaar071d4272004-06-13 20:20:40 +00001065 for (i = 1; i < TARGET_COUNT; ++i)
1066 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01001067 // Only make it active when the first item has a path and the vim.exe
1068 // or gvim.exe exists (there is a changefunc then).
Bram Moolenaar071d4272004-06-13 20:20:40 +00001069 if (targets[0].batpath[0] != NUL
1070 && choices[idx + i].changefunc != NULL)
1071 {
1072 choices[idx + i].active = 1;
1073 if (choices[idx + i].changefunc == change_bat_choice
1074 && targets[i].batpath[0] != NUL)
1075 {
1076 strcpy(targets[i].batpath, targets[0].batpath);
1077 set_bat_text(idx + i, targets[i].batpath, targets[i].batname);
1078 }
1079 }
1080 else
1081 choices[idx + i].active = 0;
1082 }
1083}
1084
1085/*
1086 * Initialize a choice for creating a batch file.
1087 */
1088 static void
1089init_bat_choice(int target)
1090{
1091 char *batpath = targets[target].batpath;
1092 char *oldbat = targets[target].oldbat;
1093 char *p;
1094 int i;
1095
1096 choices[choice_count].arg = target;
1097 choices[choice_count].installfunc = install_bat_choice;
1098 choices[choice_count].active = 1;
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01001099 choices[choice_count].text = NULL; // will be set below
Bram Moolenaar071d4272004-06-13 20:20:40 +00001100 if (oldbat != NULL)
1101 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01001102 // A [g]vim.bat exists: Only choice is to overwrite it or not.
Bram Moolenaar071d4272004-06-13 20:20:40 +00001103 choices[choice_count].changefunc = toggle_bat_choice;
1104 *batpath = NUL;
1105 toggle_bat_choice(choice_count);
1106 }
1107 else
1108 {
1109 if (default_bat_dir != NULL)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01001110 // Prefer using the same path as an existing .bat file.
Bram Moolenaar071d4272004-06-13 20:20:40 +00001111 strcpy(batpath, default_bat_dir);
1112 else
1113 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01001114 // No [g]vim.bat exists: Write it to a directory in $PATH. Use
1115 // $WINDIR by default, if it's empty the first item in $PATH.
Bram Moolenaar071d4272004-06-13 20:20:40 +00001116 p = getenv("WINDIR");
1117 if (p != NULL && *p != NUL)
1118 strcpy(batpath, p);
1119 else
1120 {
1121 p = getenv("PATH");
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01001122 if (p == NULL || *p == NUL) // "cannot happen"
Bram Moolenaar071d4272004-06-13 20:20:40 +00001123 strcpy(batpath, "C:/Windows");
1124 else
1125 {
1126 i = 0;
1127 while (*p != NUL && *p != ';')
1128 batpath[i++] = *p++;
1129 batpath[i] = NUL;
1130 }
1131 }
1132 }
1133 add_pathsep(batpath);
1134 set_bat_text(choice_count, batpath, targets[target].batname);
1135
1136 choices[choice_count].changefunc = change_bat_choice;
1137 }
1138 ++choice_count;
1139}
1140
1141/*
1142 * Set up the choices for installing .bat files.
1143 * For these items "arg" is the index in targets[].
1144 */
1145 static void
1146init_bat_choices(void)
1147{
1148 int i;
1149
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01001150 // The first item is used to switch installing batch files on/off and
1151 // setting the default path.
Bram Moolenaar071d4272004-06-13 20:20:40 +00001152 choices[choice_count].text = bat_text_yes;
1153 choices[choice_count].changefunc = change_main_bat_choice;
1154 choices[choice_count].installfunc = NULL;
1155 choices[choice_count].active = 1;
1156 choices[choice_count].arg = 0;
1157 ++choice_count;
1158
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01001159 // Add items for each batch file target. Only used when not disabled by
1160 // the first item. When a .exe exists, don't offer to create a .bat.
Bram Moolenaar071d4272004-06-13 20:20:40 +00001161 for (i = 1; i < TARGET_COUNT; ++i)
1162 if (targets[i].oldexe == NULL
1163 && (targets[i].exenamearg[0] == 'g' ? has_gvim : has_vim))
1164 init_bat_choice(i);
1165 else
1166 add_dummy_choice();
1167}
1168
1169/*
1170 * Install the vimrc file.
1171 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001172 static void
1173install_vimrc(int idx)
1174{
1175 FILE *fd, *tfd;
1176 char *fname;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001177
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01001178 // If an old vimrc file exists, overwrite it.
1179 // Otherwise create a new one.
Bram Moolenaar071d4272004-06-13 20:20:40 +00001180 if (*oldvimrc != NUL)
1181 fname = oldvimrc;
1182 else
1183 fname = vimrc;
1184
1185 fd = fopen(fname, "w");
1186 if (fd == NULL)
1187 {
1188 printf("\nERROR: Cannot open \"%s\" for writing.\n", fname);
1189 return;
1190 }
1191 switch (compat_choice)
1192 {
1193 case compat_vi:
Bram Moolenaar6cdb2c92018-10-13 17:25:27 +02001194 fprintf(fd, "\" Vi compatible\n");
Bram Moolenaar071d4272004-06-13 20:20:40 +00001195 fprintf(fd, "set compatible\n");
1196 break;
Bram Moolenaar6cdb2c92018-10-13 17:25:27 +02001197 case compat_vim:
1198 fprintf(fd, "\" Vim's default behavior\n");
1199 fprintf(fd, "if &compatible\n");
1200 fprintf(fd, " set nocompatible\n");
1201 fprintf(fd, "endif\n");
1202 break;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001203 case compat_some_enhancements:
Bram Moolenaar6cdb2c92018-10-13 17:25:27 +02001204 fprintf(fd, "\" Vim with some enhancements\n");
Bram Moolenaarc73e4472016-07-29 18:33:38 +02001205 fprintf(fd, "source $VIMRUNTIME/defaults.vim\n");
Bram Moolenaar071d4272004-06-13 20:20:40 +00001206 break;
1207 case compat_all_enhancements:
Bram Moolenaar6cdb2c92018-10-13 17:25:27 +02001208 fprintf(fd, "\" Vim with all enhancements\n");
Bram Moolenaar071d4272004-06-13 20:20:40 +00001209 fprintf(fd, "source $VIMRUNTIME/vimrc_example.vim\n");
1210 break;
1211 }
1212 switch (remap_choice)
1213 {
1214 case remap_no:
1215 break;
1216 case remap_win:
Bram Moolenaar6cdb2c92018-10-13 17:25:27 +02001217 fprintf(fd, "\n");
1218 fprintf(fd, "\" Remap a few keys for Windows behavior\n");
Bram Moolenaar071d4272004-06-13 20:20:40 +00001219 fprintf(fd, "source $VIMRUNTIME/mswin.vim\n");
1220 break;
1221 }
1222 switch (mouse_choice)
1223 {
1224 case mouse_xterm:
Bram Moolenaar6cdb2c92018-10-13 17:25:27 +02001225 fprintf(fd, "\n");
1226 fprintf(fd, "\" Mouse behavior (the Unix way)\n");
Bram Moolenaar071d4272004-06-13 20:20:40 +00001227 fprintf(fd, "behave xterm\n");
1228 break;
1229 case mouse_mswin:
Bram Moolenaar6cdb2c92018-10-13 17:25:27 +02001230 fprintf(fd, "\n");
1231 fprintf(fd, "\" Mouse behavior (the Windows way)\n");
Bram Moolenaar071d4272004-06-13 20:20:40 +00001232 fprintf(fd, "behave mswin\n");
1233 break;
Bram Moolenaarc3fdf7f2017-10-28 18:36:48 +02001234 case mouse_default:
1235 break;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001236 }
1237 if ((tfd = fopen("diff.exe", "r")) != NULL)
1238 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01001239 // Use the diff.exe that comes with the self-extracting gvim.exe.
Bram Moolenaar071d4272004-06-13 20:20:40 +00001240 fclose(tfd);
1241 fprintf(fd, "\n");
Bram Moolenaar6cdb2c92018-10-13 17:25:27 +02001242 fprintf(fd, "\" Use the internal diff if available.\n");
1243 fprintf(fd, "\" Otherwise use the special 'diffexpr' for Windows.\n");
1244 fprintf(fd, "if &diffopt !~# 'internal'\n");
1245 fprintf(fd, " set diffexpr=MyDiff()\n");
1246 fprintf(fd, "endif\n");
Bram Moolenaar071d4272004-06-13 20:20:40 +00001247 fprintf(fd, "function MyDiff()\n");
1248 fprintf(fd, " let opt = '-a --binary '\n");
1249 fprintf(fd, " if &diffopt =~ 'icase' | let opt = opt . '-i ' | endif\n");
1250 fprintf(fd, " if &diffopt =~ 'iwhite' | let opt = opt . '-b ' | endif\n");
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01001251 // Use quotes only when needed, they may cause trouble.
1252 // Always escape "!".
Bram Moolenaar071d4272004-06-13 20:20:40 +00001253 fprintf(fd, " let arg1 = v:fname_in\n");
1254 fprintf(fd, " if arg1 =~ ' ' | let arg1 = '\"' . arg1 . '\"' | endif\n");
Bram Moolenaar12365ce2018-05-13 14:45:25 +02001255 fprintf(fd, " let arg1 = substitute(arg1, '!', '\\!', 'g')\n");
Bram Moolenaar071d4272004-06-13 20:20:40 +00001256 fprintf(fd, " let arg2 = v:fname_new\n");
1257 fprintf(fd, " if arg2 =~ ' ' | let arg2 = '\"' . arg2 . '\"' | endif\n");
Bram Moolenaar12365ce2018-05-13 14:45:25 +02001258 fprintf(fd, " let arg2 = substitute(arg2, '!', '\\!', 'g')\n");
Bram Moolenaar071d4272004-06-13 20:20:40 +00001259 fprintf(fd, " let arg3 = v:fname_out\n");
1260 fprintf(fd, " if arg3 =~ ' ' | let arg3 = '\"' . arg3 . '\"' | endif\n");
Bram Moolenaar12365ce2018-05-13 14:45:25 +02001261 fprintf(fd, " let arg3 = substitute(arg3, '!', '\\!', 'g')\n");
Bram Moolenaar33aec762006-01-22 23:30:12 +00001262
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01001263 // If the path has a space: When using cmd.exe (Win NT/2000/XP) put
1264 // quotes around the diff command and rely on the default value of
1265 // shellxquote to solve the quoting problem for the whole command.
1266 //
1267 // Otherwise put a double quote just before the space and at the
1268 // end of the command. Putting quotes around the whole thing
1269 // doesn't work on Win 95/98/ME. This is mostly guessed!
Bram Moolenaar33aec762006-01-22 23:30:12 +00001270 fprintf(fd, " if $VIMRUNTIME =~ ' '\n");
1271 fprintf(fd, " if &sh =~ '\\<cmd'\n");
Bram Moolenaarc62a6442013-11-21 18:13:37 +01001272 fprintf(fd, " if empty(&shellxquote)\n");
1273 fprintf(fd, " let l:shxq_sav = ''\n");
1274 fprintf(fd, " set shellxquote&\n");
1275 fprintf(fd, " endif\n");
1276 fprintf(fd, " let cmd = '\"' . $VIMRUNTIME . '\\diff\"'\n");
Bram Moolenaar33aec762006-01-22 23:30:12 +00001277 fprintf(fd, " else\n");
1278 fprintf(fd, " let cmd = substitute($VIMRUNTIME, ' ', '\" ', '') . '\\diff\"'\n");
1279 fprintf(fd, " endif\n");
1280 fprintf(fd, " else\n");
1281 fprintf(fd, " let cmd = $VIMRUNTIME . '\\diff'\n");
1282 fprintf(fd, " endif\n");
Bram Moolenaar12365ce2018-05-13 14:45:25 +02001283 fprintf(fd, " let cmd = substitute(cmd, '!', '\\!', 'g')\n");
Bram Moolenaarc62a6442013-11-21 18:13:37 +01001284 fprintf(fd, " silent execute '!' . cmd . ' ' . opt . arg1 . ' ' . arg2 . ' > ' . arg3\n");
1285 fprintf(fd, " if exists('l:shxq_sav')\n");
1286 fprintf(fd, " let &shellxquote=l:shxq_sav\n");
1287 fprintf(fd, " endif\n");
Bram Moolenaar071d4272004-06-13 20:20:40 +00001288 fprintf(fd, "endfunction\n");
1289 fprintf(fd, "\n");
1290 }
1291 fclose(fd);
1292 printf("%s has been written\n", fname);
1293}
1294
1295 static void
1296change_vimrc_choice(int idx)
1297{
1298 if (choices[idx].installfunc != NULL)
1299 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01001300 // Switch to NOT change or create a vimrc file.
Bram Moolenaar071d4272004-06-13 20:20:40 +00001301 if (*oldvimrc != NUL)
1302 alloc_text(idx, "Do NOT change startup file %s", oldvimrc);
1303 else
1304 alloc_text(idx, "Do NOT create startup file %s", vimrc);
1305 choices[idx].installfunc = NULL;
1306 choices[idx + 1].active = 0;
1307 choices[idx + 2].active = 0;
1308 choices[idx + 3].active = 0;
1309 }
1310 else
1311 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01001312 // Switch to change or create a vimrc file.
Bram Moolenaar071d4272004-06-13 20:20:40 +00001313 if (*oldvimrc != NUL)
1314 alloc_text(idx, "Overwrite startup file %s with:", oldvimrc);
1315 else
1316 alloc_text(idx, "Create startup file %s with:", vimrc);
1317 choices[idx].installfunc = install_vimrc;
1318 choices[idx + 1].active = 1;
1319 choices[idx + 2].active = 1;
1320 choices[idx + 3].active = 1;
1321 }
1322}
1323
1324/*
1325 * Change the choice how to run Vim.
1326 */
1327 static void
1328change_run_choice(int idx)
1329{
1330 compat_choice = get_choice(compat_choices, TABLE_SIZE(compat_choices));
1331 alloc_text(idx, compat_text, compat_choices[compat_choice]);
1332}
1333
1334/*
1335 * Change the choice if keys are to be remapped.
1336 */
1337 static void
1338change_remap_choice(int idx)
1339{
1340 remap_choice = get_choice(remap_choices, TABLE_SIZE(remap_choices));
1341 alloc_text(idx, remap_text, remap_choices[remap_choice]);
1342}
1343
1344/*
1345 * Change the choice how to select text.
1346 */
1347 static void
1348change_mouse_choice(int idx)
1349{
1350 mouse_choice = get_choice(mouse_choices, TABLE_SIZE(mouse_choices));
1351 alloc_text(idx, mouse_text, mouse_choices[mouse_choice]);
1352}
1353
1354 static void
1355init_vimrc_choices(void)
1356{
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01001357 // set path for a new _vimrc file (also when not used)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001358 strcpy(vimrc, installdir);
1359 strcpy(vimrc + runtimeidx, "_vimrc");
1360
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01001361 // Set opposite value and then toggle it by calling change_vimrc_choice()
Bram Moolenaar071d4272004-06-13 20:20:40 +00001362 if (*oldvimrc == NUL)
1363 choices[choice_count].installfunc = NULL;
1364 else
1365 choices[choice_count].installfunc = install_vimrc;
1366 choices[choice_count].text = NULL;
1367 change_vimrc_choice(choice_count);
1368 choices[choice_count].changefunc = change_vimrc_choice;
1369 choices[choice_count].active = 1;
1370 ++choice_count;
1371
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01001372 // default way to run Vim
Bram Moolenaar071d4272004-06-13 20:20:40 +00001373 alloc_text(choice_count, compat_text, compat_choices[compat_choice]);
1374 choices[choice_count].changefunc = change_run_choice;
1375 choices[choice_count].installfunc = NULL;
1376 choices[choice_count].active = (*oldvimrc == NUL);
1377 ++choice_count;
1378
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01001379 // Whether to remap keys
Bram Moolenaar071d4272004-06-13 20:20:40 +00001380 alloc_text(choice_count, remap_text , remap_choices[remap_choice]);
1381 choices[choice_count].changefunc = change_remap_choice;
Bram Moolenaar945ec092016-06-08 21:17:43 +02001382 choices[choice_count].installfunc = NULL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001383 choices[choice_count].active = (*oldvimrc == NUL);
1384 ++choice_count;
1385
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01001386 // default way to use the mouse
Bram Moolenaar071d4272004-06-13 20:20:40 +00001387 alloc_text(choice_count, mouse_text, mouse_choices[mouse_choice]);
1388 choices[choice_count].changefunc = change_mouse_choice;
Bram Moolenaar945ec092016-06-08 21:17:43 +02001389 choices[choice_count].installfunc = NULL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001390 choices[choice_count].active = (*oldvimrc == NUL);
1391 ++choice_count;
1392}
1393
Bram Moolenaarccd9ccf2010-07-07 13:19:55 +02001394 static LONG
1395reg_create_key(
1396 HKEY root,
1397 const char *subkey,
Bram Moolenaar6199d432017-10-14 19:05:44 +02001398 PHKEY phKey,
1399 DWORD flag)
Bram Moolenaarccd9ccf2010-07-07 13:19:55 +02001400{
1401 DWORD disp;
1402
1403 *phKey = NULL;
1404 return RegCreateKeyEx(
Bram Moolenaarcc448b32010-07-14 16:52:17 +02001405 root, subkey,
1406 0, NULL, REG_OPTION_NON_VOLATILE,
Bram Moolenaar6199d432017-10-14 19:05:44 +02001407 flag | KEY_WRITE,
Bram Moolenaarcc448b32010-07-14 16:52:17 +02001408 NULL, phKey, &disp);
Bram Moolenaarccd9ccf2010-07-07 13:19:55 +02001409}
1410
1411 static LONG
1412reg_set_string_value(
1413 HKEY hKey,
1414 const char *value_name,
1415 const char *data)
1416{
1417 return RegSetValueEx(hKey, value_name, 0, REG_SZ,
1418 (LPBYTE)data, (DWORD)(1 + strlen(data)));
1419}
1420
1421 static LONG
1422reg_create_key_and_value(
1423 HKEY hRootKey,
1424 const char *subkey,
1425 const char *value_name,
Bram Moolenaar6199d432017-10-14 19:05:44 +02001426 const char *data,
1427 DWORD flag)
Bram Moolenaarccd9ccf2010-07-07 13:19:55 +02001428{
1429 HKEY hKey;
Bram Moolenaar6199d432017-10-14 19:05:44 +02001430 LONG lRet = reg_create_key(hRootKey, subkey, &hKey, flag);
Bram Moolenaarccd9ccf2010-07-07 13:19:55 +02001431
1432 if (ERROR_SUCCESS == lRet)
1433 {
Bram Moolenaarcc448b32010-07-14 16:52:17 +02001434 lRet = reg_set_string_value(hKey, value_name, data);
1435 RegCloseKey(hKey);
Bram Moolenaarccd9ccf2010-07-07 13:19:55 +02001436 }
1437 return lRet;
1438}
1439
1440 static LONG
1441register_inproc_server(
1442 HKEY hRootKey,
1443 const char *clsid,
1444 const char *extname,
1445 const char *module,
Bram Moolenaar6199d432017-10-14 19:05:44 +02001446 const char *threading_model,
1447 DWORD flag)
Bram Moolenaarccd9ccf2010-07-07 13:19:55 +02001448{
1449 CHAR subkey[BUFSIZE];
1450 LONG lRet;
1451
1452 sprintf(subkey, "CLSID\\%s", clsid);
Bram Moolenaar6199d432017-10-14 19:05:44 +02001453 lRet = reg_create_key_and_value(hRootKey, subkey, NULL, extname, flag);
Bram Moolenaarccd9ccf2010-07-07 13:19:55 +02001454 if (ERROR_SUCCESS == lRet)
1455 {
Bram Moolenaarcc448b32010-07-14 16:52:17 +02001456 sprintf(subkey, "CLSID\\%s\\InProcServer32", clsid);
Bram Moolenaar6199d432017-10-14 19:05:44 +02001457 lRet = reg_create_key_and_value(hRootKey, subkey, NULL, module, flag);
Bram Moolenaarcc448b32010-07-14 16:52:17 +02001458 if (ERROR_SUCCESS == lRet)
1459 {
1460 lRet = reg_create_key_and_value(hRootKey, subkey,
Bram Moolenaar6199d432017-10-14 19:05:44 +02001461 "ThreadingModel", threading_model, flag);
Bram Moolenaarcc448b32010-07-14 16:52:17 +02001462 }
Bram Moolenaarccd9ccf2010-07-07 13:19:55 +02001463 }
1464 return lRet;
1465}
1466
1467 static LONG
1468register_shellex(
1469 HKEY hRootKey,
1470 const char *clsid,
1471 const char *name,
Bram Moolenaar6199d432017-10-14 19:05:44 +02001472 const char *exe_path,
1473 DWORD flag)
Bram Moolenaarccd9ccf2010-07-07 13:19:55 +02001474{
1475 LONG lRet = reg_create_key_and_value(
Bram Moolenaarcc448b32010-07-14 16:52:17 +02001476 hRootKey,
1477 "*\\shellex\\ContextMenuHandlers\\gvim",
1478 NULL,
Bram Moolenaar6199d432017-10-14 19:05:44 +02001479 clsid,
1480 flag);
Bram Moolenaarccd9ccf2010-07-07 13:19:55 +02001481
1482 if (ERROR_SUCCESS == lRet)
1483 {
Bram Moolenaarcc448b32010-07-14 16:52:17 +02001484 lRet = reg_create_key_and_value(
1485 HKEY_LOCAL_MACHINE,
1486 "Software\\Microsoft\\Windows\\CurrentVersion\\Shell Extensions\\Approved",
1487 clsid,
Bram Moolenaar6199d432017-10-14 19:05:44 +02001488 name,
1489 flag);
Bram Moolenaarccd9ccf2010-07-07 13:19:55 +02001490
Bram Moolenaarcc448b32010-07-14 16:52:17 +02001491 if (ERROR_SUCCESS == lRet)
1492 {
1493 lRet = reg_create_key_and_value(
1494 HKEY_LOCAL_MACHINE,
1495 "Software\\Vim\\Gvim",
1496 "path",
Bram Moolenaar6199d432017-10-14 19:05:44 +02001497 exe_path,
1498 flag);
Bram Moolenaarcc448b32010-07-14 16:52:17 +02001499 }
Bram Moolenaarccd9ccf2010-07-07 13:19:55 +02001500 }
1501 return lRet;
1502}
1503
1504 static LONG
1505register_openwith(
1506 HKEY hRootKey,
Bram Moolenaar6199d432017-10-14 19:05:44 +02001507 const char *exe_path,
1508 DWORD flag)
Bram Moolenaarccd9ccf2010-07-07 13:19:55 +02001509{
Bram Moolenaar78050042010-07-31 20:53:54 +02001510 char exe_cmd[BUFSIZE];
1511 LONG lRet;
1512
Bram Moolenaarbbdcb482010-08-02 20:45:27 +02001513 sprintf(exe_cmd, "\"%s\" \"%%1\"", exe_path);
Bram Moolenaar78050042010-07-31 20:53:54 +02001514 lRet = reg_create_key_and_value(
Bram Moolenaarcc448b32010-07-14 16:52:17 +02001515 hRootKey,
1516 "Applications\\gvim.exe\\shell\\edit\\command",
1517 NULL,
Bram Moolenaar6199d432017-10-14 19:05:44 +02001518 exe_cmd,
1519 flag);
Bram Moolenaarccd9ccf2010-07-07 13:19:55 +02001520
1521 if (ERROR_SUCCESS == lRet)
1522 {
Bram Moolenaarcc448b32010-07-14 16:52:17 +02001523 int i;
1524 static const char *openwith[] = {
1525 ".htm\\OpenWithList\\gvim.exe",
1526 ".vim\\OpenWithList\\gvim.exe",
1527 "*\\OpenWithList\\gvim.exe",
1528 };
Bram Moolenaarccd9ccf2010-07-07 13:19:55 +02001529
K.Takataeeec2542021-06-02 13:28:16 +02001530 for (i = 0; ERROR_SUCCESS == lRet && i < ARRAYSIZE(openwith); i++)
Bram Moolenaar6199d432017-10-14 19:05:44 +02001531 lRet = reg_create_key_and_value(hRootKey, openwith[i], NULL, "", flag);
Bram Moolenaarccd9ccf2010-07-07 13:19:55 +02001532 }
1533
1534 return lRet;
1535}
1536
1537 static LONG
1538register_uninstall(
1539 HKEY hRootKey,
1540 const char *appname,
1541 const char *display_name,
Bram Moolenaar6cdb2c92018-10-13 17:25:27 +02001542 const char *uninstall_string,
1543 const char *display_icon,
1544 const char *display_version,
1545 const char *publisher)
Bram Moolenaarccd9ccf2010-07-07 13:19:55 +02001546{
1547 LONG lRet = reg_create_key_and_value(hRootKey, appname,
Bram Moolenaar6199d432017-10-14 19:05:44 +02001548 "DisplayName", display_name, KEY_WOW64_64KEY);
Bram Moolenaarccd9ccf2010-07-07 13:19:55 +02001549
1550 if (ERROR_SUCCESS == lRet)
Bram Moolenaarcc448b32010-07-14 16:52:17 +02001551 lRet = reg_create_key_and_value(hRootKey, appname,
Bram Moolenaar6199d432017-10-14 19:05:44 +02001552 "UninstallString", uninstall_string, KEY_WOW64_64KEY);
Bram Moolenaar6cdb2c92018-10-13 17:25:27 +02001553 if (ERROR_SUCCESS == lRet)
1554 lRet = reg_create_key_and_value(hRootKey, appname,
1555 "DisplayIcon", display_icon, KEY_WOW64_64KEY);
1556 if (ERROR_SUCCESS == lRet)
1557 lRet = reg_create_key_and_value(hRootKey, appname,
1558 "DisplayVersion", display_version, KEY_WOW64_64KEY);
1559 if (ERROR_SUCCESS == lRet)
1560 lRet = reg_create_key_and_value(hRootKey, appname,
1561 "Publisher", publisher, KEY_WOW64_64KEY);
Bram Moolenaarccd9ccf2010-07-07 13:19:55 +02001562 return lRet;
1563}
Bram Moolenaarccd9ccf2010-07-07 13:19:55 +02001564
Bram Moolenaar071d4272004-06-13 20:20:40 +00001565/*
1566 * Add some entries to the registry:
1567 * - to add "Edit with Vim" to the context * menu
1568 * - to add Vim to the "Open with..." list
1569 * - to uninstall Vim
1570 */
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01001571//ARGSUSED
Bram Moolenaarab8205e2010-07-07 15:14:03 +02001572 static int
Bram Moolenaar071d4272004-06-13 20:20:40 +00001573install_registry(void)
1574{
Bram Moolenaarcc448b32010-07-14 16:52:17 +02001575 LONG lRet = ERROR_SUCCESS;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001576 const char *vim_ext_ThreadingModel = "Apartment";
1577 const char *vim_ext_name = "Vim Shell Extension";
1578 const char *vim_ext_clsid = "{51EEE242-AD87-11d3-9C1E-0090278BBD99}";
Bram Moolenaarbbd854d2019-02-18 22:19:33 +01001579 char vim_exe_path[MAX_PATH];
Bram Moolenaarcc448b32010-07-14 16:52:17 +02001580 char display_name[BUFSIZE];
1581 char uninstall_string[BUFSIZE];
Bram Moolenaar6cdb2c92018-10-13 17:25:27 +02001582 char icon_string[BUFSIZE];
Bram Moolenaar6199d432017-10-14 19:05:44 +02001583 int i;
1584 int loop_count = is_64bit_os() ? 2 : 1;
1585 DWORD flag;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001586
Bram Moolenaarccd9ccf2010-07-07 13:19:55 +02001587 sprintf(vim_exe_path, "%s\\gvim.exe", installdir);
1588
1589 if (install_popup)
1590 {
Bram Moolenaarcc448b32010-07-14 16:52:17 +02001591 char bufg[BUFSIZE];
Bram Moolenaarccd9ccf2010-07-07 13:19:55 +02001592
Bram Moolenaarcc448b32010-07-14 16:52:17 +02001593 printf("Creating \"Edit with Vim\" popup menu entry\n");
Bram Moolenaarccd9ccf2010-07-07 13:19:55 +02001594
Bram Moolenaar6199d432017-10-14 19:05:44 +02001595 for (i = 0; i < loop_count; i++)
1596 {
1597 if (i == 0)
1598 {
1599 sprintf(bufg, "%s\\" GVIMEXT32_PATH, installdir);
1600 flag = KEY_WOW64_32KEY;
1601 }
1602 else
1603 {
1604 sprintf(bufg, "%s\\" GVIMEXT64_PATH, installdir);
1605 flag = KEY_WOW64_64KEY;
1606 }
1607
1608 lRet = register_inproc_server(
1609 HKEY_CLASSES_ROOT, vim_ext_clsid, vim_ext_name,
1610 bufg, vim_ext_ThreadingModel, flag);
1611 if (ERROR_SUCCESS != lRet)
1612 return FAIL;
1613 lRet = register_shellex(
1614 HKEY_CLASSES_ROOT, vim_ext_clsid, vim_ext_name,
1615 vim_exe_path, flag);
1616 if (ERROR_SUCCESS != lRet)
1617 return FAIL;
1618 }
Bram Moolenaarccd9ccf2010-07-07 13:19:55 +02001619 }
1620
1621 if (install_openwith)
1622 {
Bram Moolenaarcc448b32010-07-14 16:52:17 +02001623 printf("Creating \"Open with ...\" list entry\n");
Bram Moolenaarccd9ccf2010-07-07 13:19:55 +02001624
Bram Moolenaar6199d432017-10-14 19:05:44 +02001625 for (i = 0; i < loop_count; i++)
1626 {
1627 if (i == 0)
1628 flag = KEY_WOW64_32KEY;
1629 else
1630 flag = KEY_WOW64_64KEY;
1631
1632 lRet = register_openwith(HKEY_CLASSES_ROOT, vim_exe_path, flag);
1633 if (ERROR_SUCCESS != lRet)
1634 return FAIL;
1635 }
Bram Moolenaarccd9ccf2010-07-07 13:19:55 +02001636 }
1637
1638 printf("Creating an uninstall entry\n");
Bram Moolenaaraf610b82018-12-21 16:22:50 +01001639 sprintf(display_name, "Vim " VIM_VERSION_SHORT
Bram Moolenaar577fadf2019-04-04 20:32:24 +02001640#ifdef _M_ARM64
1641 " (arm64)"
1642#elif _M_X64
Bram Moolenaaraf610b82018-12-21 16:22:50 +01001643 " (x64)"
1644#endif
1645 );
Bram Moolenaarccd9ccf2010-07-07 13:19:55 +02001646
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01001647 // For the NSIS installer use the generated uninstaller.
Bram Moolenaarccd9ccf2010-07-07 13:19:55 +02001648 if (interactive)
Bram Moolenaar30e8e732019-09-27 13:08:36 +02001649 sprintf(uninstall_string, "%s\\uninstall.exe", installdir);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001650 else
Bram Moolenaar16d79a32010-07-18 22:33:56 +02001651 sprintf(uninstall_string, "%s\\uninstall-gui.exe", installdir);
Bram Moolenaarccd9ccf2010-07-07 13:19:55 +02001652
Bram Moolenaar6cdb2c92018-10-13 17:25:27 +02001653 sprintf(icon_string, "%s\\gvim.exe,0", installdir);
1654
Bram Moolenaarccd9ccf2010-07-07 13:19:55 +02001655 lRet = register_uninstall(
Bram Moolenaarcc448b32010-07-14 16:52:17 +02001656 HKEY_LOCAL_MACHINE,
1657 "Software\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\Vim " VIM_VERSION_SHORT,
1658 display_name,
Bram Moolenaar6cdb2c92018-10-13 17:25:27 +02001659 uninstall_string,
1660 icon_string,
1661 VIM_VERSION_SHORT,
1662 "Bram Moolenaar et al.");
Bram Moolenaarab8205e2010-07-07 15:14:03 +02001663 if (ERROR_SUCCESS != lRet)
1664 return FAIL;
Bram Moolenaarccd9ccf2010-07-07 13:19:55 +02001665
Bram Moolenaarab8205e2010-07-07 15:14:03 +02001666 return OK;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001667}
1668
1669 static void
1670change_popup_choice(int idx)
1671{
1672 if (install_popup == 0)
1673 {
1674 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";
1675 install_popup = 1;
1676 }
1677 else
1678 {
1679 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";
1680 install_popup = 0;
1681 }
1682}
1683
1684/*
1685 * Only add the choice for the popup menu entry when gvim.exe was found and
1686 * both gvimext.dll and regedit.exe exist.
1687 */
1688 static void
1689init_popup_choice(void)
1690{
1691 struct stat st;
1692
1693 if (has_gvim
Bram Moolenaar6199d432017-10-14 19:05:44 +02001694 && (stat(GVIMEXT32_PATH, &st) >= 0
1695 || stat(GVIMEXT64_PATH, &st) >= 0))
Bram Moolenaar071d4272004-06-13 20:20:40 +00001696 {
1697 choices[choice_count].changefunc = change_popup_choice;
1698 choices[choice_count].installfunc = NULL;
1699 choices[choice_count].active = 1;
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01001700 change_popup_choice(choice_count); // set the text
Bram Moolenaar071d4272004-06-13 20:20:40 +00001701 ++choice_count;
1702 }
1703 else
1704 add_dummy_choice();
1705}
1706
1707 static void
1708change_openwith_choice(int idx)
1709{
1710 if (install_openwith == 0)
1711 {
1712 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";
1713 install_openwith = 1;
1714 }
1715 else
1716 {
1717 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";
1718 install_openwith = 0;
1719 }
1720}
1721
1722/*
1723 * Only add the choice for the open-with menu entry when gvim.exe was found
Bram Moolenaar84a05ac2013-05-06 04:24:17 +02001724 * and regedit.exe exist.
Bram Moolenaar071d4272004-06-13 20:20:40 +00001725 */
1726 static void
1727init_openwith_choice(void)
1728{
Bram Moolenaar6199d432017-10-14 19:05:44 +02001729 if (has_gvim)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001730 {
1731 choices[choice_count].changefunc = change_openwith_choice;
1732 choices[choice_count].installfunc = NULL;
1733 choices[choice_count].active = 1;
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01001734 change_openwith_choice(choice_count); // set the text
Bram Moolenaar071d4272004-06-13 20:20:40 +00001735 ++choice_count;
1736 }
1737 else
1738 add_dummy_choice();
1739}
1740
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01001741/*
Bram Moolenaar071d4272004-06-13 20:20:40 +00001742 * Create a shell link.
1743 *
1744 * returns 0 on failure, non-zero on successful completion.
1745 *
1746 * NOTE: Currently untested with mingw.
1747 */
1748 int
1749create_shortcut(
1750 const char *shortcut_name,
1751 const char *iconfile_path,
1752 int iconindex,
1753 const char *shortcut_target,
1754 const char *shortcut_args,
1755 const char *workingdir
1756 )
1757{
1758 IShellLink *shelllink_ptr;
1759 HRESULT hres;
1760 IPersistFile *persistfile_ptr;
1761
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01001762 // Initialize COM library
Bram Moolenaar071d4272004-06-13 20:20:40 +00001763 hres = CoInitialize(NULL);
1764 if (!SUCCEEDED(hres))
1765 {
1766 printf("Error: Could not open the COM library. Not creating shortcut.\n");
1767 return FAIL;
1768 }
1769
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01001770 // Instantiate a COM object for the ShellLink, store a pointer to it
1771 // in shelllink_ptr.
Bram Moolenaar071d4272004-06-13 20:20:40 +00001772 hres = CoCreateInstance(&CLSID_ShellLink,
1773 NULL,
1774 CLSCTX_INPROC_SERVER,
1775 &IID_IShellLink,
1776 (void **) &shelllink_ptr);
1777
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01001778 if (SUCCEEDED(hres)) // If the instantiation was successful...
Bram Moolenaar071d4272004-06-13 20:20:40 +00001779 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01001780 // ...Then build a PersistFile interface for the ShellLink so we can
1781 // save it as a file after we build it.
Bram Moolenaar071d4272004-06-13 20:20:40 +00001782 hres = shelllink_ptr->lpVtbl->QueryInterface(shelllink_ptr,
1783 &IID_IPersistFile, (void **) &persistfile_ptr);
1784
1785 if (SUCCEEDED(hres))
1786 {
1787 wchar_t wsz[BUFSIZE];
1788
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01001789 // translate the (possibly) multibyte shortcut filename to windows
1790 // Unicode so it can be used as a file name.
Bram Moolenaare4963c52019-02-22 19:41:08 +01001791 MultiByteToWideChar(CP_ACP, 0, shortcut_name, -1, wsz, sizeof(wsz)/sizeof(wsz[0]));
Bram Moolenaar071d4272004-06-13 20:20:40 +00001792
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01001793 // set the attributes
Bram Moolenaar071d4272004-06-13 20:20:40 +00001794 shelllink_ptr->lpVtbl->SetPath(shelllink_ptr, shortcut_target);
1795 shelllink_ptr->lpVtbl->SetWorkingDirectory(shelllink_ptr,
1796 workingdir);
1797 shelllink_ptr->lpVtbl->SetIconLocation(shelllink_ptr,
1798 iconfile_path, iconindex);
1799 shelllink_ptr->lpVtbl->SetArguments(shelllink_ptr, shortcut_args);
1800
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01001801 // save the shortcut to a file and return the PersistFile object
Bram Moolenaar071d4272004-06-13 20:20:40 +00001802 persistfile_ptr->lpVtbl->Save(persistfile_ptr, wsz, 1);
1803 persistfile_ptr->lpVtbl->Release(persistfile_ptr);
1804 }
1805 else
1806 {
1807 printf("QueryInterface Error\n");
1808 return FAIL;
1809 }
1810
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01001811 // Return the ShellLink object
Bram Moolenaar071d4272004-06-13 20:20:40 +00001812 shelllink_ptr->lpVtbl->Release(shelllink_ptr);
1813 }
1814 else
1815 {
1816 printf("CoCreateInstance Error - hres = %08x\n", (int)hres);
1817 return FAIL;
1818 }
1819
1820 return OK;
1821}
1822
1823/*
1824 * Build a path to where we will put a specified link.
1825 *
1826 * Return 0 on error, non-zero on success
1827 */
1828 int
1829build_link_name(
1830 char *link_path,
1831 const char *link_name,
1832 const char *shell_folder_name)
1833{
Bram Moolenaarbbd854d2019-02-18 22:19:33 +01001834 char shell_folder_path[MAX_PATH];
Bram Moolenaar071d4272004-06-13 20:20:40 +00001835
1836 if (get_shell_folder_path(shell_folder_path, shell_folder_name) == FAIL)
1837 {
1838 printf("An error occurred while attempting to find the path to %s.\n",
1839 shell_folder_name);
1840 return FAIL;
1841 }
1842
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01001843 // Make sure the directory exists (create Start Menu\Programs\Vim).
1844 // Ignore errors if it already exists.
Bram Moolenaar071d4272004-06-13 20:20:40 +00001845 vim_mkdir(shell_folder_path, 0755);
1846
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01001847 // build the path to the shortcut and the path to gvim.exe
Bram Moolenaar071d4272004-06-13 20:20:40 +00001848 sprintf(link_path, "%s\\%s.lnk", shell_folder_path, link_name);
1849
1850 return OK;
1851}
1852
1853 static int
1854build_shortcut(
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01001855 const char *name, // Name of the shortcut
1856 const char *exename, // Name of the executable (e.g., vim.exe)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001857 const char *args,
1858 const char *shell_folder,
1859 const char *workingdir)
1860{
1861 char executable_path[BUFSIZE];
1862 char link_name[BUFSIZE];
1863
1864 sprintf(executable_path, "%s\\%s", installdir, exename);
1865
1866 if (build_link_name(link_name, name, shell_folder) == FAIL)
1867 {
1868 printf("An error has occurred. A shortcut to %s will not be created %s.\n",
1869 name,
1870 *shell_folder == 'd' ? "on the desktop" : "in the Start menu");
1871 return FAIL;
1872 }
1873
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01001874 // Create the shortcut:
Bram Moolenaar071d4272004-06-13 20:20:40 +00001875 return create_shortcut(link_name, executable_path, 0,
1876 executable_path, args, workingdir);
1877}
1878
1879/*
1880 * We used to use "homedir" as the working directory, but that is a bad choice
Bram Moolenaar03e228a2013-11-07 04:49:27 +01001881 * on multi-user systems. However, not specifying a directory results in the
1882 * current directory to be c:\Windows\system32 on Windows 7. Use environment
1883 * variables instead.
Bram Moolenaar071d4272004-06-13 20:20:40 +00001884 */
Bram Moolenaar03e228a2013-11-07 04:49:27 +01001885#define WORKDIR "%HOMEDRIVE%%HOMEPATH%"
Bram Moolenaar071d4272004-06-13 20:20:40 +00001886
1887/*
1888 * Create shortcut(s) in the Start Menu\Programs\Vim folder.
1889 */
1890 static void
1891install_start_menu(int idx)
1892{
1893 need_uninstall_entry = 1;
1894 printf("Creating start menu\n");
1895 if (has_vim)
1896 {
1897 if (build_shortcut("Vim", "vim.exe", "",
1898 VIM_STARTMENU, WORKDIR) == FAIL)
1899 return;
1900 if (build_shortcut("Vim Read-only", "vim.exe", "-R",
1901 VIM_STARTMENU, WORKDIR) == FAIL)
1902 return;
1903 if (build_shortcut("Vim Diff", "vim.exe", "-d",
1904 VIM_STARTMENU, WORKDIR) == FAIL)
1905 return;
1906 }
1907 if (has_gvim)
1908 {
1909 if (build_shortcut("gVim", "gvim.exe", "",
1910 VIM_STARTMENU, WORKDIR) == FAIL)
1911 return;
1912 if (build_shortcut("gVim Easy", "gvim.exe", "-y",
1913 VIM_STARTMENU, WORKDIR) == FAIL)
1914 return;
1915 if (build_shortcut("gVim Read-only", "gvim.exe", "-R",
1916 VIM_STARTMENU, WORKDIR) == FAIL)
1917 return;
1918 if (build_shortcut("gVim Diff", "gvim.exe", "-d",
1919 VIM_STARTMENU, WORKDIR) == FAIL)
1920 return;
1921 }
1922 if (build_shortcut("Uninstall",
Bram Moolenaar30e8e732019-09-27 13:08:36 +02001923 interactive ? "uninstall.exe" : "uninstall-gui.exe", "",
Bram Moolenaar071d4272004-06-13 20:20:40 +00001924 VIM_STARTMENU, installdir) == FAIL)
1925 return;
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01001926 // For Windows NT the working dir of the vimtutor.bat must be right,
1927 // otherwise gvim.exe won't be found and using gvimbat doesn't work.
Bram Moolenaar071d4272004-06-13 20:20:40 +00001928 if (build_shortcut("Vim tutor", "vimtutor.bat", "",
1929 VIM_STARTMENU, installdir) == FAIL)
1930 return;
1931 if (build_shortcut("Help", has_gvim ? "gvim.exe" : "vim.exe", "-c h",
1932 VIM_STARTMENU, WORKDIR) == FAIL)
1933 return;
1934 {
1935 char shell_folder_path[BUFSIZE];
1936
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01001937 // Creating the URL shortcut works a bit differently...
Bram Moolenaar071d4272004-06-13 20:20:40 +00001938 if (get_shell_folder_path(shell_folder_path, VIM_STARTMENU) == FAIL)
1939 {
1940 printf("Finding the path of the Start menu failed\n");
1941 return ;
1942 }
1943 add_pathsep(shell_folder_path);
1944 strcat(shell_folder_path, "Vim Online.url");
1945 if (!WritePrivateProfileString("InternetShortcut", "URL",
Bram Moolenaarbd87eb32018-06-26 23:18:45 +02001946 "https://www.vim.org/", shell_folder_path))
Bram Moolenaar071d4272004-06-13 20:20:40 +00001947 {
1948 printf("Creating the Vim online URL failed\n");
1949 return;
1950 }
1951 }
1952}
1953
1954 static void
1955toggle_startmenu_choice(int idx)
1956{
1957 if (choices[idx].installfunc == NULL)
1958 {
1959 choices[idx].installfunc = install_start_menu;
1960 choices[idx].text = "Add Vim to the Start menu";
1961 }
1962 else
1963 {
1964 choices[idx].installfunc = NULL;
1965 choices[idx].text = "Do NOT add Vim to the Start menu";
1966 }
1967}
1968
1969/*
1970 * Function to actually create the shortcuts
1971 *
1972 * Currently I am supplying no working directory to the shortcut. This
1973 * means that the initial working dir will be:
1974 * - the location of the shortcut if no file is supplied
1975 * - the location of the file being edited if a file is supplied (ie via
1976 * drag and drop onto the shortcut).
1977 */
1978 void
1979install_shortcut_gvim(int idx)
1980{
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01001981 // Create shortcut(s) on the desktop
Bram Moolenaar071d4272004-06-13 20:20:40 +00001982 if (choices[idx].arg)
1983 {
1984 (void)build_shortcut(icon_names[0], "gvim.exe",
1985 "", "desktop", WORKDIR);
1986 need_uninstall_entry = 1;
1987 }
1988}
1989
1990 void
1991install_shortcut_evim(int idx)
1992{
1993 if (choices[idx].arg)
1994 {
1995 (void)build_shortcut(icon_names[1], "gvim.exe",
1996 "-y", "desktop", WORKDIR);
1997 need_uninstall_entry = 1;
1998 }
1999}
2000
2001 void
2002install_shortcut_gview(int idx)
2003{
2004 if (choices[idx].arg)
2005 {
2006 (void)build_shortcut(icon_names[2], "gvim.exe",
2007 "-R", "desktop", WORKDIR);
2008 need_uninstall_entry = 1;
2009 }
2010}
2011
2012 void
2013toggle_shortcut_choice(int idx)
2014{
2015 char *arg;
2016
2017 if (choices[idx].installfunc == install_shortcut_gvim)
2018 arg = "gVim";
2019 else if (choices[idx].installfunc == install_shortcut_evim)
2020 arg = "gVim Easy";
2021 else
2022 arg = "gVim Read-only";
2023 if (choices[idx].arg)
2024 {
2025 choices[idx].arg = 0;
2026 alloc_text(idx, "Do NOT create a desktop icon for %s", arg);
2027 }
2028 else
2029 {
2030 choices[idx].arg = 1;
2031 alloc_text(idx, "Create a desktop icon for %s", arg);
2032 }
2033}
Bram Moolenaar071d4272004-06-13 20:20:40 +00002034
2035 static void
2036init_startmenu_choice(void)
2037{
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002038 // Start menu
Bram Moolenaar071d4272004-06-13 20:20:40 +00002039 choices[choice_count].changefunc = toggle_startmenu_choice;
2040 choices[choice_count].installfunc = NULL;
2041 choices[choice_count].active = 1;
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002042 toggle_startmenu_choice(choice_count); // set the text
Bram Moolenaar071d4272004-06-13 20:20:40 +00002043 ++choice_count;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002044}
2045
2046/*
2047 * Add the choice for the desktop shortcuts.
2048 */
2049 static void
2050init_shortcut_choices(void)
2051{
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002052 // Shortcut to gvim
Bram Moolenaar071d4272004-06-13 20:20:40 +00002053 choices[choice_count].text = NULL;
2054 choices[choice_count].arg = 0;
2055 choices[choice_count].active = has_gvim;
2056 choices[choice_count].changefunc = toggle_shortcut_choice;
2057 choices[choice_count].installfunc = install_shortcut_gvim;
2058 toggle_shortcut_choice(choice_count);
2059 ++choice_count;
2060
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002061 // Shortcut to evim
Bram Moolenaar071d4272004-06-13 20:20:40 +00002062 choices[choice_count].text = NULL;
2063 choices[choice_count].arg = 0;
2064 choices[choice_count].active = has_gvim;
2065 choices[choice_count].changefunc = toggle_shortcut_choice;
2066 choices[choice_count].installfunc = install_shortcut_evim;
2067 toggle_shortcut_choice(choice_count);
2068 ++choice_count;
2069
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002070 // Shortcut to gview
Bram Moolenaar071d4272004-06-13 20:20:40 +00002071 choices[choice_count].text = NULL;
2072 choices[choice_count].arg = 0;
2073 choices[choice_count].active = has_gvim;
2074 choices[choice_count].changefunc = toggle_shortcut_choice;
2075 choices[choice_count].installfunc = install_shortcut_gview;
2076 toggle_shortcut_choice(choice_count);
2077 ++choice_count;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002078}
2079
Bram Moolenaar071d4272004-06-13 20:20:40 +00002080/*
2081 * Attempt to register OLE for Vim.
2082 */
2083 static void
2084install_OLE_register(void)
2085{
2086 char register_command_string[BUFSIZE + 30];
2087
2088 printf("\n--- Attempting to register Vim with OLE ---\n");
2089 printf("(There is no message whether this works or not.)\n");
2090
Bram Moolenaar071d4272004-06-13 20:20:40 +00002091 sprintf(register_command_string, "\"%s\\gvim.exe\" -silent -register", installdir);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002092 system(register_command_string);
2093}
Bram Moolenaar071d4272004-06-13 20:20:40 +00002094
2095/*
2096 * Remove the last part of directory "path[]" to get its parent, and put the
2097 * result in "to[]".
2098 */
2099 static void
Bram Moolenaare4963c52019-02-22 19:41:08 +01002100dir_remove_last(const char *path, char to[MAX_PATH])
Bram Moolenaar071d4272004-06-13 20:20:40 +00002101{
2102 char c;
2103 long last_char_to_copy;
2104 long path_length = strlen(path);
2105
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002106 // skip the last character just in case it is a '\\'
Bram Moolenaar071d4272004-06-13 20:20:40 +00002107 last_char_to_copy = path_length - 2;
2108 c = path[last_char_to_copy];
2109
2110 while (c != '\\')
2111 {
2112 last_char_to_copy--;
2113 c = path[last_char_to_copy];
2114 }
2115
2116 strncpy(to, path, (size_t)last_char_to_copy);
2117 to[last_char_to_copy] = NUL;
2118}
2119
2120 static void
2121set_directories_text(int idx)
2122{
Bram Moolenaar25a494c2018-11-16 19:39:50 +01002123 int vimfiles_dir_choice = choices[idx].arg;
2124
Bram Moolenaar071d4272004-06-13 20:20:40 +00002125 if (vimfiles_dir_choice == (int)vimfiles_dir_none)
2126 alloc_text(idx, "Do NOT create plugin directories%s", "");
2127 else
2128 alloc_text(idx, "Create plugin directories: %s",
2129 vimfiles_dir_choices[vimfiles_dir_choice]);
2130}
2131
2132/*
Bram Moolenaar25a494c2018-11-16 19:39:50 +01002133 * To get the "real" home directory:
2134 * - get value of $HOME
2135 * - if not found, get value of $HOMEDRIVE$HOMEPATH
2136 * - if not found, get value of $USERPROFILE
2137 *
2138 * This code is based on init_homedir() in misc1.c, keep in sync!
2139 */
2140static char *homedir = NULL;
2141
2142 void
2143init_homedir(void)
2144{
2145 char *var;
2146 char buf[MAX_PATH];
2147
2148 if (homedir != NULL)
2149 {
2150 free(homedir);
2151 homedir = NULL;
2152 }
2153
2154 var = getenv("HOME");
2155
2156 /*
2157 * Typically, $HOME is not defined on Windows, unless the user has
2158 * specifically defined it for Vim's sake. However, on Windows NT
2159 * platforms, $HOMEDRIVE and $HOMEPATH are automatically defined for
2160 * each user. Try constructing $HOME from these.
2161 */
2162 if (var == NULL || *var == NUL)
2163 {
2164 char *homedrive, *homepath;
2165
2166 homedrive = getenv("HOMEDRIVE");
2167 homepath = getenv("HOMEPATH");
2168 if (homepath == NULL || *homepath == NUL)
2169 homepath = "\\";
2170 if (homedrive != NULL
Bram Moolenaare4963c52019-02-22 19:41:08 +01002171 && strlen(homedrive) + strlen(homepath) < sizeof(buf))
Bram Moolenaar25a494c2018-11-16 19:39:50 +01002172 {
2173 sprintf(buf, "%s%s", homedrive, homepath);
2174 if (buf[0] != NUL)
2175 var = buf;
2176 }
2177 }
2178
2179 if (var == NULL)
2180 var = getenv("USERPROFILE");
2181
2182 /*
2183 * Weird but true: $HOME may contain an indirect reference to another
2184 * variable, esp. "%USERPROFILE%". Happens when $USERPROFILE isn't set
2185 * when $HOME is being set.
2186 */
2187 if (var != NULL && *var == '%')
2188 {
2189 char *p;
2190 char *exp;
2191
2192 p = strchr(var + 1, '%');
2193 if (p != NULL)
2194 {
2195 strncpy(buf, var + 1, p - (var + 1));
2196 buf[p - (var + 1)] = NUL;
2197 exp = getenv(buf);
2198 if (exp != NULL && *exp != NUL
Bram Moolenaare4963c52019-02-22 19:41:08 +01002199 && strlen(exp) + strlen(p) < sizeof(buf))
Bram Moolenaar25a494c2018-11-16 19:39:50 +01002200 {
Bram Moolenaare4963c52019-02-22 19:41:08 +01002201 sprintf(buf, "%s%s", exp, p + 1);
Bram Moolenaar25a494c2018-11-16 19:39:50 +01002202 var = buf;
2203 }
2204 }
2205 }
2206
2207 if (var != NULL && *var == NUL) // empty is same as not set
2208 var = NULL;
2209
2210 if (var == NULL)
2211 homedir = NULL;
2212 else
2213 homedir = _strdup(var);
2214}
2215
2216/*
Bram Moolenaar071d4272004-06-13 20:20:40 +00002217 * Change the directory that the vim plugin directories will be created in:
2218 * $HOME, $VIM or nowhere.
2219 */
2220 static void
2221change_directories_choice(int idx)
2222{
2223 int choice_count = TABLE_SIZE(vimfiles_dir_choices);
2224
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002225 // Don't offer the $HOME choice if $HOME isn't set.
Bram Moolenaar25a494c2018-11-16 19:39:50 +01002226 if (homedir == NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002227 --choice_count;
Bram Moolenaar25a494c2018-11-16 19:39:50 +01002228 choices[idx].arg = get_choice(vimfiles_dir_choices, choice_count);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002229 set_directories_text(idx);
2230}
2231
2232/*
2233 * Create the plugin directories...
2234 */
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002235//ARGSUSED
Bram Moolenaar071d4272004-06-13 20:20:40 +00002236 static void
2237install_vimfilesdir(int idx)
2238{
2239 int i;
Bram Moolenaar25a494c2018-11-16 19:39:50 +01002240 int vimfiles_dir_choice = choices[idx].arg;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002241 char *p;
Bram Moolenaarbbd854d2019-02-18 22:19:33 +01002242 char vimdir_path[MAX_PATH];
2243 char vimfiles_path[MAX_PATH + 9];
Bram Moolenaar071d4272004-06-13 20:20:40 +00002244 char tmp_dirname[BUFSIZE];
2245
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002246 // switch on the location that the user wants the plugin directories
2247 // built in
Bram Moolenaar071d4272004-06-13 20:20:40 +00002248 switch (vimfiles_dir_choice)
2249 {
2250 case vimfiles_dir_vim:
2251 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002252 // Go to the %VIM% directory - check env first, then go one dir
2253 // below installdir if there is no %VIM% environment variable.
2254 // The accuracy of $VIM is checked in inspect_system(), so we
2255 // can be sure it is ok to use here.
Bram Moolenaar071d4272004-06-13 20:20:40 +00002256 p = getenv("VIM");
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002257 if (p == NULL) // No $VIM in path
Bram Moolenaar071d4272004-06-13 20:20:40 +00002258 dir_remove_last(installdir, vimdir_path);
2259 else
2260 strcpy(vimdir_path, p);
2261 break;
2262 }
2263 case vimfiles_dir_home:
2264 {
Bram Moolenaar25a494c2018-11-16 19:39:50 +01002265 // Find the $HOME directory. Its existence was already checked.
2266 p = homedir;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002267 if (p == NULL)
2268 {
2269 printf("Internal error: $HOME is NULL\n");
2270 p = "c:\\";
2271 }
2272 strcpy(vimdir_path, p);
2273 break;
2274 }
2275 case vimfiles_dir_none:
2276 {
Bram Moolenaar25a494c2018-11-16 19:39:50 +01002277 // Do not create vim plugin directory.
Bram Moolenaar071d4272004-06-13 20:20:40 +00002278 return;
2279 }
2280 }
2281
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002282 // Now, just create the directory. If it already exists, it will fail
2283 // silently.
Bram Moolenaar071d4272004-06-13 20:20:40 +00002284 sprintf(vimfiles_path, "%s\\vimfiles", vimdir_path);
2285 vim_mkdir(vimfiles_path, 0755);
2286
2287 printf("Creating the following directories in \"%s\":\n", vimfiles_path);
2288 for (i = 0; i < TABLE_SIZE(vimfiles_subdirs); i++)
2289 {
2290 sprintf(tmp_dirname, "%s\\%s", vimfiles_path, vimfiles_subdirs[i]);
2291 printf(" %s", vimfiles_subdirs[i]);
2292 vim_mkdir(tmp_dirname, 0755);
2293 }
2294 printf("\n");
2295}
2296
2297/*
2298 * Add the creation of runtime files to the setup sequence.
2299 */
2300 static void
2301init_directories_choice(void)
2302{
2303 struct stat st;
2304 char tmp_dirname[BUFSIZE];
2305 char *p;
Bram Moolenaar25a494c2018-11-16 19:39:50 +01002306 int vimfiles_dir_choice;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002307
2308 choices[choice_count].text = alloc(150);
2309 choices[choice_count].changefunc = change_directories_choice;
2310 choices[choice_count].installfunc = install_vimfilesdir;
2311 choices[choice_count].active = 1;
2312
Bram Moolenaar25a494c2018-11-16 19:39:50 +01002313 // Check if the "compiler" directory already exists. That's a good
2314 // indication that the plugin directories were already created.
Bram Moolenaare4963c52019-02-22 19:41:08 +01002315 p = getenv("HOME");
2316 if (p != NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002317 {
2318 vimfiles_dir_choice = (int)vimfiles_dir_home;
Bram Moolenaare4963c52019-02-22 19:41:08 +01002319 sprintf(tmp_dirname, "%s\\vimfiles\\compiler", p);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002320 if (stat(tmp_dirname, &st) == 0)
2321 vimfiles_dir_choice = (int)vimfiles_dir_none;
2322 }
2323 else
2324 {
2325 vimfiles_dir_choice = (int)vimfiles_dir_vim;
2326 p = getenv("VIM");
Bram Moolenaar25a494c2018-11-16 19:39:50 +01002327 if (p == NULL) // No $VIM in path, use the install dir.
Bram Moolenaar071d4272004-06-13 20:20:40 +00002328 dir_remove_last(installdir, tmp_dirname);
2329 else
2330 strcpy(tmp_dirname, p);
2331 strcat(tmp_dirname, "\\vimfiles\\compiler");
2332 if (stat(tmp_dirname, &st) == 0)
2333 vimfiles_dir_choice = (int)vimfiles_dir_none;
2334 }
2335
Bram Moolenaar25a494c2018-11-16 19:39:50 +01002336 choices[choice_count].arg = vimfiles_dir_choice;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002337 set_directories_text(choice_count);
2338 ++choice_count;
2339}
2340
2341/*
2342 * Setup the choices and the default values.
2343 */
2344 static void
2345setup_choices(void)
2346{
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002347 // install the batch files
Bram Moolenaar071d4272004-06-13 20:20:40 +00002348 init_bat_choices();
2349
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002350 // (over) write _vimrc file
Bram Moolenaar071d4272004-06-13 20:20:40 +00002351 init_vimrc_choices();
2352
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002353 // Whether to add Vim to the popup menu
Bram Moolenaar071d4272004-06-13 20:20:40 +00002354 init_popup_choice();
2355
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002356 // Whether to add Vim to the "Open With..." menu
Bram Moolenaar071d4272004-06-13 20:20:40 +00002357 init_openwith_choice();
2358
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002359 // Whether to add Vim to the Start Menu.
Bram Moolenaar071d4272004-06-13 20:20:40 +00002360 init_startmenu_choice();
2361
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002362 // Whether to add shortcuts to the Desktop.
Bram Moolenaar071d4272004-06-13 20:20:40 +00002363 init_shortcut_choices();
2364
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002365 // Whether to create the runtime directories.
Bram Moolenaar071d4272004-06-13 20:20:40 +00002366 init_directories_choice();
2367}
2368
2369 static void
2370print_cmd_line_help(void)
2371{
2372 printf("Vim installer non-interactive command line arguments:\n");
2373 printf("\n");
2374 printf("-create-batfiles [vim gvim evim view gview vimdiff gvimdiff]\n");
2375 printf(" Create .bat files for Vim variants in the Windows directory.\n");
2376 printf("-create-vimrc\n");
2377 printf(" Create a default _vimrc file if one does not already exist.\n");
Bram Moolenaarc3fdf7f2017-10-28 18:36:48 +02002378 printf("-vimrc-remap [no|win]\n");
2379 printf(" Remap keys when creating a default _vimrc file.\n");
2380 printf("-vimrc-behave [unix|mswin|default]\n");
2381 printf(" Set mouse behavior when creating a default _vimrc file.\n");
Bram Moolenaar6cdb2c92018-10-13 17:25:27 +02002382 printf("-vimrc-compat [vi|vim|defaults|all]\n");
2383 printf(" Set Vi compatibility when creating a default _vimrc file.\n");
Bram Moolenaar071d4272004-06-13 20:20:40 +00002384 printf("-install-popup\n");
2385 printf(" Install the Edit-with-Vim context menu entry\n");
2386 printf("-install-openwith\n");
2387 printf(" Add Vim to the \"Open With...\" context menu list\n");
Bram Moolenaar071d4272004-06-13 20:20:40 +00002388 printf("-add-start-menu");
2389 printf(" Add Vim to the start menu\n");
2390 printf("-install-icons");
2391 printf(" Create icons for gVim executables on the desktop\n");
Bram Moolenaar071d4272004-06-13 20:20:40 +00002392 printf("-create-directories [vim|home]\n");
2393 printf(" Create runtime directories to drop plugins into; in the $VIM\n");
2394 printf(" or $HOME directory\n");
Bram Moolenaar071d4272004-06-13 20:20:40 +00002395 printf("-register-OLE");
Bram Moolenaarce0842a2005-07-18 21:58:11 +00002396 printf(" Ignored\n");
Bram Moolenaar071d4272004-06-13 20:20:40 +00002397 printf("\n");
2398}
2399
2400/*
2401 * Setup installation choices based on command line switches
2402 */
2403 static void
2404command_line_setup_choices(int argc, char **argv)
2405{
2406 int i, j;
2407
2408 for (i = 1; i < argc; i++)
2409 {
2410 if (strcmp(argv[i], "-create-batfiles") == 0)
2411 {
2412 if (i + 1 == argc)
2413 continue;
2414 while (argv[i + 1][0] != '-' && i < argc)
2415 {
2416 i++;
2417 for (j = 1; j < TARGET_COUNT; ++j)
2418 if ((targets[j].exenamearg[0] == 'g' ? has_gvim : has_vim)
2419 && strcmp(argv[i], targets[j].name) == 0)
2420 {
2421 init_bat_choice(j);
2422 break;
2423 }
2424 if (j == TARGET_COUNT)
2425 printf("%s is not a valid choice for -create-batfiles\n",
2426 argv[i]);
2427
2428 if (i + 1 == argc)
2429 break;
2430 }
2431 }
2432 else if (strcmp(argv[i], "-create-vimrc") == 0)
2433 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002434 // Setup default vimrc choices. If there is already a _vimrc file,
2435 // it will NOT be overwritten.
Bram Moolenaar071d4272004-06-13 20:20:40 +00002436 init_vimrc_choices();
2437 }
Bram Moolenaarc3fdf7f2017-10-28 18:36:48 +02002438 else if (strcmp(argv[i], "-vimrc-remap") == 0)
2439 {
2440 if (i + 1 == argc)
2441 break;
2442 i++;
2443 if (strcmp(argv[i], "no") == 0)
2444 remap_choice = remap_no;
2445 else if (strcmp(argv[i], "win") == 0)
2446 remap_choice = remap_win;
2447 }
2448 else if (strcmp(argv[i], "-vimrc-behave") == 0)
2449 {
2450 if (i + 1 == argc)
2451 break;
2452 i++;
2453 if (strcmp(argv[i], "unix") == 0)
2454 mouse_choice = mouse_xterm;
2455 else if (strcmp(argv[i], "mswin") == 0)
2456 mouse_choice = mouse_mswin;
2457 else if (strcmp(argv[i], "default") == 0)
2458 mouse_choice = mouse_default;
2459 }
Bram Moolenaar6cdb2c92018-10-13 17:25:27 +02002460 else if (strcmp(argv[i], "-vimrc-compat") == 0)
2461 {
2462 if (i + 1 == argc)
2463 break;
2464 i++;
2465 if (strcmp(argv[i], "vi") == 0)
2466 compat_choice = compat_vi;
2467 else if (strcmp(argv[i], "vim") == 0)
2468 compat_choice = compat_vim;
2469 else if (strcmp(argv[i], "defaults") == 0)
2470 compat_choice = compat_some_enhancements;
2471 else if (strcmp(argv[i], "all") == 0)
2472 compat_choice = compat_all_enhancements;
2473 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00002474 else if (strcmp(argv[i], "-install-popup") == 0)
2475 {
2476 init_popup_choice();
2477 }
2478 else if (strcmp(argv[i], "-install-openwith") == 0)
2479 {
2480 init_openwith_choice();
2481 }
2482 else if (strcmp(argv[i], "-add-start-menu") == 0)
2483 {
2484 init_startmenu_choice();
2485 }
2486 else if (strcmp(argv[i], "-install-icons") == 0)
2487 {
2488 init_shortcut_choices();
2489 }
2490 else if (strcmp(argv[i], "-create-directories") == 0)
2491 {
Bram Moolenaar142a9752018-12-14 19:54:39 +01002492 int vimfiles_dir_choice = (int)vimfiles_dir_none;
Bram Moolenaar25a494c2018-11-16 19:39:50 +01002493
Bram Moolenaar071d4272004-06-13 20:20:40 +00002494 init_directories_choice();
2495 if (argv[i + 1][0] != '-')
2496 {
2497 i++;
2498 if (strcmp(argv[i], "vim") == 0)
2499 vimfiles_dir_choice = (int)vimfiles_dir_vim;
2500 else if (strcmp(argv[i], "home") == 0)
2501 {
Bram Moolenaar25a494c2018-11-16 19:39:50 +01002502 if (homedir == NULL) // No $HOME in environment
2503 vimfiles_dir_choice = (int)vimfiles_dir_none;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002504 else
2505 vimfiles_dir_choice = (int)vimfiles_dir_home;
2506 }
2507 else
2508 {
2509 printf("Unknown argument for -create-directories: %s\n",
2510 argv[i]);
2511 print_cmd_line_help();
2512 }
2513 }
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002514 else // No choice specified, default to vim directory
Bram Moolenaar071d4272004-06-13 20:20:40 +00002515 vimfiles_dir_choice = (int)vimfiles_dir_vim;
Bram Moolenaar25a494c2018-11-16 19:39:50 +01002516 choices[choice_count - 1].arg = vimfiles_dir_choice;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002517 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00002518 else if (strcmp(argv[i], "-register-OLE") == 0)
2519 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002520 // This is always done when gvim is found
Bram Moolenaar071d4272004-06-13 20:20:40 +00002521 }
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002522 else // Unknown switch
Bram Moolenaar071d4272004-06-13 20:20:40 +00002523 {
2524 printf("Got unknown argument argv[%d] = %s\n", i, argv[i]);
2525 print_cmd_line_help();
2526 }
2527 }
2528}
2529
2530
2531/*
2532 * Show a few screens full of helpful information.
2533 */
2534 static void
2535show_help(void)
2536{
2537 static char *(items[]) =
2538 {
2539"Installing .bat files\n"
2540"---------------------\n"
2541"The vim.bat file is written in one of the directories in $PATH.\n"
2542"This makes it possible to start Vim from the command line.\n"
2543"If vim.exe can be found in $PATH, the choice for vim.bat will not be\n"
2544"present. It is assumed you will use the existing vim.exe.\n"
2545"If vim.bat can already be found in $PATH this is probably for an old\n"
2546"version of Vim (but this is not checked!). You can overwrite it.\n"
2547"If no vim.bat already exists, you can select one of the directories in\n"
2548"$PATH for creating the batch file, or disable creating a vim.bat file.\n"
2549"\n"
2550"If you choose not to create the vim.bat file, Vim can still be executed\n"
2551"in other ways, but not from the command line.\n"
2552"\n"
2553"The same applies to choices for gvim, evim, (g)view, and (g)vimdiff.\n"
2554"The first item can be used to change the path for all of them.\n"
2555,
2556"Creating a _vimrc file\n"
2557"----------------------\n"
2558"The _vimrc file is used to set options for how Vim behaves.\n"
2559"The install program can create a _vimrc file with a few basic choices.\n"
2560"You can edit this file later to tune your preferences.\n"
2561"If you already have a _vimrc or .vimrc file it can be overwritten.\n"
2562"Don't do that if you have made changes to it.\n"
2563,
2564"Vim features\n"
2565"------------\n"
2566"(this choice is only available when creating a _vimrc file)\n"
2567"1. Vim can run in Vi-compatible mode. Many nice Vim features are then\n"
Bram Moolenaar2b849492018-11-21 13:58:35 +01002568" disabled. Only choose Vi-compatible if you really need full Vi\n"
2569" compatibility.\n"
2570"2. Vim runs in not-Vi-compatible mode. Vim is still mostly Vi compatible,\n"
2571" but adds nice features like multi-level undo.\n"
2572"3. Running Vim with some enhancements is useful when you want some of\n"
Bram Moolenaar071d4272004-06-13 20:20:40 +00002573" the nice Vim features, but have a slow computer and want to keep it\n"
2574" really fast.\n"
Bram Moolenaar2b849492018-11-21 13:58:35 +01002575"4. Syntax highlighting shows many files in color. Not only does this look\n"
Bram Moolenaar071d4272004-06-13 20:20:40 +00002576" nice, it also makes it easier to spot errors and you can work faster.\n"
2577" The other features include editing compressed files.\n"
2578,
2579"Windows key mapping\n"
2580"-------------------\n"
2581"(this choice is only available when creating a _vimrc file)\n"
2582"Under MS-Windows the CTRL-C key copies text to the clipboard and CTRL-V\n"
2583"pastes text from the clipboard. There are a few more keys like these.\n"
2584"Unfortunately, in Vim these keys normally have another meaning.\n"
2585"1. Choose to have the keys like they normally are in Vim (useful if you\n"
2586" also use Vim on other systems).\n"
2587"2. Choose to have the keys work like they are used on MS-Windows (useful\n"
2588" if you mostly work on MS-Windows).\n"
2589,
2590"Mouse use\n"
2591"---------\n"
2592"(this choice is only available when creating a _vimrc file)\n"
2593"The right mouse button can be used in two ways:\n"
2594"1. The Unix way is to extend an existing selection. The popup menu is\n"
2595" not available.\n"
2596"2. The MS-Windows way is to show a popup menu, which allows you to\n"
2597" copy/paste text, undo/redo, etc. Extending the selection can still be\n"
2598" done by keeping SHIFT pressed while using the left mouse button\n"
2599,
2600"Edit-with-Vim context menu entry\n"
2601"--------------------------------\n"
2602"(this choice is only available when gvim.exe and gvimext.dll are present)\n"
2603"You can associate different file types with Vim, so that you can (double)\n"
2604"click on a file to edit it with Vim. This means you have to individually\n"
2605"select each file type.\n"
2606"An alternative is the option offered here: Install an \"Edit with Vim\"\n"
2607"entry in the popup menu for the right mouse button. This means you can\n"
2608"edit any file with Vim.\n"
2609,
2610"\"Open With...\" context menu entry\n"
2611"--------------------------------\n"
2612"(this choice is only available when gvim.exe is present)\n"
2613"This option adds Vim to the \"Open With...\" entry in the popup menu for\n"
2614"the right mouse button. This also makes it possible to edit HTML files\n"
2615"directly from Internet Explorer.\n"
2616,
2617"Add Vim to the Start menu\n"
2618"-------------------------\n"
2619"In Windows 95 and later, Vim can be added to the Start menu. This will\n"
2620"create a submenu with an entry for vim, gvim, evim, vimdiff, etc..\n"
2621,
2622"Icons on the desktop\n"
2623"--------------------\n"
2624"(these choices are only available when installing gvim)\n"
2625"In Windows 95 and later, shortcuts (icons) can be created on the Desktop.\n"
2626,
2627"Create plugin directories\n"
2628"-------------------------\n"
2629"Plugin directories allow extending Vim by dropping a file into a directory.\n"
2630"This choice allows creating them in $HOME (if you have a home directory) or\n"
2631"$VIM (used for everybody on the system).\n"
2632,
2633NULL
2634 };
2635 int i;
2636 int c;
2637
2638 rewind(stdin);
2639 printf("\n");
2640 for (i = 0; items[i] != NULL; ++i)
2641 {
Bram Moolenaarc3fdf7f2017-10-28 18:36:48 +02002642 puts(items[i]);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002643 printf("Hit Enter to continue, b (back) or q (quit help): ");
2644 c = getchar();
2645 rewind(stdin);
2646 if (c == 'b' || c == 'B')
2647 {
2648 if (i == 0)
2649 --i;
2650 else
2651 i -= 2;
2652 }
2653 if (c == 'q' || c == 'Q')
2654 break;
2655 printf("\n");
2656 }
2657}
2658
2659/*
2660 * Install the choices.
2661 */
2662 static void
2663install(void)
2664{
2665 int i;
2666
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002667 // Install the selected choices.
Bram Moolenaar071d4272004-06-13 20:20:40 +00002668 for (i = 0; i < choice_count; ++i)
2669 if (choices[i].installfunc != NULL && choices[i].active)
2670 (choices[i].installfunc)(i);
2671
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002672 // Add some entries to the registry, if needed.
Bram Moolenaar071d4272004-06-13 20:20:40 +00002673 if (install_popup
2674 || install_openwith
2675 || (need_uninstall_entry && interactive)
2676 || !interactive)
2677 install_registry();
2678
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002679 // Register gvim with OLE.
Bram Moolenaar071d4272004-06-13 20:20:40 +00002680 if (has_gvim)
2681 install_OLE_register();
Bram Moolenaar071d4272004-06-13 20:20:40 +00002682}
2683
2684/*
2685 * request_choice
2686 */
2687 static void
2688request_choice(void)
2689{
2690 int i;
2691
2692 printf("\n\nInstall will do for you:\n");
2693 for (i = 0; i < choice_count; ++i)
2694 if (choices[i].active)
2695 printf("%2d %s\n", i + 1, choices[i].text);
2696 printf("To change an item, enter its number\n\n");
2697 printf("Enter item number, h (help), d (do it) or q (quit): ");
2698}
2699
2700 int
2701main(int argc, char **argv)
2702{
2703 int i;
2704 char buf[BUFSIZE];
2705
2706 /*
2707 * Run interactively if there are no command line arguments.
2708 */
2709 if (argc > 1)
2710 interactive = 0;
2711 else
2712 interactive = 1;
2713
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002714 // Initialize this program.
Bram Moolenaar071d4272004-06-13 20:20:40 +00002715 do_inits(argv);
Bram Moolenaar25a494c2018-11-16 19:39:50 +01002716 init_homedir();
Bram Moolenaar071d4272004-06-13 20:20:40 +00002717
Bram Moolenaar071d4272004-06-13 20:20:40 +00002718 if (argc > 1 && strcmp(argv[1], "-uninstall-check") == 0)
2719 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002720 // Only check for already installed Vims. Used by NSIS installer.
Bram Moolenaar442b4222010-05-24 21:34:22 +02002721 i = uninstall_check(1);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002722
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002723 // Find the value of $VIM, because NSIS isn't able to do this by
2724 // itself.
Bram Moolenaar071d4272004-06-13 20:20:40 +00002725 get_vim_env();
2726
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002727 // When nothing found exit quietly. If something found wait for
2728 // a little while, so that the user can read the messages.
Bram Moolenaar6cdb2c92018-10-13 17:25:27 +02002729 if (i && _isatty(1))
Bram Moolenaarab8205e2010-07-07 15:14:03 +02002730 sleep(3);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002731 exit(0);
2732 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00002733
2734 printf("This program sets up the installation of Vim "
2735 VIM_VERSION_MEDIUM "\n\n");
2736
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002737 // Check if the user unpacked the archives properly.
Bram Moolenaar071d4272004-06-13 20:20:40 +00002738 check_unpack();
2739
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002740 // Check for already installed Vims.
Bram Moolenaar071d4272004-06-13 20:20:40 +00002741 if (interactive)
Bram Moolenaar442b4222010-05-24 21:34:22 +02002742 uninstall_check(0);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002743
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002744 // Find out information about the system.
Bram Moolenaar071d4272004-06-13 20:20:40 +00002745 inspect_system();
2746
2747 if (interactive)
2748 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002749 // Setup all the choices.
Bram Moolenaar071d4272004-06-13 20:20:40 +00002750 setup_choices();
2751
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002752 // Let the user change choices and finally install (or quit).
Bram Moolenaar071d4272004-06-13 20:20:40 +00002753 for (;;)
2754 {
2755 request_choice();
2756 rewind(stdin);
2757 if (scanf("%99s", buf) == 1)
2758 {
2759 if (isdigit(buf[0]))
2760 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002761 // Change a choice.
Bram Moolenaar071d4272004-06-13 20:20:40 +00002762 i = atoi(buf);
2763 if (i > 0 && i <= choice_count && choices[i - 1].active)
2764 (choices[i - 1].changefunc)(i - 1);
2765 else
2766 printf("\nIllegal choice\n");
2767 }
2768 else if (buf[0] == 'h' || buf[0] == 'H')
2769 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002770 // Help
Bram Moolenaar071d4272004-06-13 20:20:40 +00002771 show_help();
2772 }
2773 else if (buf[0] == 'd' || buf[0] == 'D')
2774 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002775 // Install!
Bram Moolenaar071d4272004-06-13 20:20:40 +00002776 install();
2777 printf("\nThat finishes the installation. Happy Vimming!\n");
2778 break;
2779 }
2780 else if (buf[0] == 'q' || buf[0] == 'Q')
2781 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002782 // Quit
Bram Moolenaar071d4272004-06-13 20:20:40 +00002783 printf("\nExiting without anything done\n");
2784 break;
2785 }
2786 else
2787 printf("\nIllegal choice\n");
2788 }
2789 }
2790 printf("\n");
Bram Moolenaar442b4222010-05-24 21:34:22 +02002791 myexit(0);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002792 }
2793 else
2794 {
2795 /*
2796 * Run non-interactive - setup according to the command line switches
2797 */
2798 command_line_setup_choices(argc, argv);
2799 install();
Bram Moolenaar442b4222010-05-24 21:34:22 +02002800
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002801 // Avoid that the user has to hit Enter, just wait a little bit to
2802 // allow reading the messages.
Bram Moolenaarab8205e2010-07-07 15:14:03 +02002803 sleep(2);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002804 }
2805
Bram Moolenaar071d4272004-06-13 20:20:40 +00002806 return 0;
2807}