blob: 2ded88ef3b0a70c77f8eeba3b2a5899b0dcd6f83 [file] [log] [blame]
Bram Moolenaaredf3f972016-08-29 22:49:24 +02001/* vi:set ts=8 sts=4 sw=4 noet:
Bram Moolenaar071d4272004-06-13 20:20:40 +00002 *
3 * VIM - Vi IMproved by Bram Moolenaar
4 *
5 * Do ":help uganda" in Vim to read copying and usage conditions.
6 * Do ":help credits" in Vim to see a list of people who contributed.
7 * See README.txt for an overview of the Vim source code.
8 */
9
10/*
11 * dosinst.c: Install program for Vim on MS-DOS and MS-Windows
12 *
Bram Moolenaareae1b912019-05-09 15:12:55 +020013 * Compile with Make_mvc.mak, Make_cyg.mak or Make_ming.mak.
Bram Moolenaar071d4272004-06-13 20:20:40 +000014 */
15
16/*
Bram Moolenaar30e8e732019-09-27 13:08:36 +020017 * Include common code for dosinst.c and uninstall.c.
Bram Moolenaar071d4272004-06-13 20:20:40 +000018 */
19#define DOSINST
20#include "dosinst.h"
Bram Moolenaar6cdb2c92018-10-13 17:25:27 +020021#include <io.h>
Bram Moolenaar071d4272004-06-13 20:20:40 +000022
Bram Moolenaar6199d432017-10-14 19:05:44 +020023#define GVIMEXT64_PATH "GvimExt64\\gvimext.dll"
24#define GVIMEXT32_PATH "GvimExt32\\gvimext.dll"
25
Bram Moolenaar5d18efe2019-12-01 21:11:22 +010026// Macro to do an error check I was typing over and over
Bram Moolenaar6f470022018-04-10 18:47:20 +020027#define CHECK_REG_ERROR(code) \
28 do { \
29 if (code != ERROR_SUCCESS) \
30 { \
31 printf("%ld error number: %ld\n", (long)__LINE__, (long)code); \
32 return 1; \
33 } \
34 } while (0)
Bram Moolenaar071d4272004-06-13 20:20:40 +000035
Bram Moolenaar5d18efe2019-12-01 21:11:22 +010036int has_vim = 0; // installable vim.exe exists
37int has_gvim = 0; // installable gvim.exe exists
Bram Moolenaar071d4272004-06-13 20:20:40 +000038
Bram Moolenaar5d18efe2019-12-01 21:11:22 +010039char oldvimrc[BUFSIZE]; // name of existing vimrc file
40char vimrc[BUFSIZE]; // name of vimrc file to create
Bram Moolenaar071d4272004-06-13 20:20:40 +000041
Bram Moolenaar5d18efe2019-12-01 21:11:22 +010042char *default_bat_dir = NULL; // when not NULL, use this as the default
43 // directory to write .bat files in
44char *default_vim_dir = NULL; // when not NULL, use this as the default
45 // install dir for NSIS
Bram Moolenaar071d4272004-06-13 20:20:40 +000046
47/*
48 * Structure used for each choice the user can make.
49 */
50struct choice
51{
Bram Moolenaar5d18efe2019-12-01 21:11:22 +010052 int active; // non-zero when choice is active
53 char *text; // text displayed for this choice
54 void (*changefunc)(int idx); // function to change this choice
55 int arg; // argument for function
56 void (*installfunc)(int idx); // function to install this choice
Bram Moolenaar071d4272004-06-13 20:20:40 +000057};
58
Bram Moolenaar5d18efe2019-12-01 21:11:22 +010059struct choice choices[30]; // choices the user can make
60int choice_count = 0; // number of choices available
Bram Moolenaar071d4272004-06-13 20:20:40 +000061
62#define TABLE_SIZE(s) (int)(sizeof(s) / sizeof(*s))
63
64enum
65{
66 compat_vi = 1,
Bram Moolenaar6cdb2c92018-10-13 17:25:27 +020067 compat_vim,
Bram Moolenaar071d4272004-06-13 20:20:40 +000068 compat_some_enhancements,
69 compat_all_enhancements
70};
71char *(compat_choices[]) =
72{
73 "\nChoose the default way to run Vim:",
74 "Vi compatible",
Bram Moolenaar6cdb2c92018-10-13 17:25:27 +020075 "Vim default",
Bram Moolenaarfff2bee2010-05-15 13:56:02 +020076 "with some Vim enhancements",
Bram Moolenaar071d4272004-06-13 20:20:40 +000077 "with syntax highlighting and other features switched on",
78};
79int compat_choice = (int)compat_all_enhancements;
80char *compat_text = "- run Vim %s";
81
82enum
83{
84 remap_no = 1,
85 remap_win
86};
87char *(remap_choices[]) =
88{
89 "\nChoose:",
90 "Do not remap keys for Windows behavior",
Bram Moolenaar6199d432017-10-14 19:05:44 +020091 "Remap a few keys for Windows behavior (CTRL-V, CTRL-C, CTRL-F, etc)",
Bram Moolenaar071d4272004-06-13 20:20:40 +000092};
Bram Moolenaarc3fdf7f2017-10-28 18:36:48 +020093int remap_choice = (int)remap_no;
Bram Moolenaar071d4272004-06-13 20:20:40 +000094char *remap_text = "- %s";
95
96enum
97{
98 mouse_xterm = 1,
Bram Moolenaarb9fce6c2017-10-28 18:50:01 +020099 mouse_mswin,
Bram Moolenaarc3fdf7f2017-10-28 18:36:48 +0200100 mouse_default
Bram Moolenaar071d4272004-06-13 20:20:40 +0000101};
102char *(mouse_choices[]) =
103{
104 "\nChoose the way how Vim uses the mouse:",
105 "right button extends selection (the Unix way)",
Bram Moolenaarc3fdf7f2017-10-28 18:36:48 +0200106 "right button has a popup menu, left button starts select mode (the Windows way)",
107 "right button has a popup menu, left button starts visual mode",
Bram Moolenaar071d4272004-06-13 20:20:40 +0000108};
Bram Moolenaarc3fdf7f2017-10-28 18:36:48 +0200109int mouse_choice = (int)mouse_default;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000110char *mouse_text = "- The mouse %s";
111
112enum
113{
114 vimfiles_dir_none = 1,
115 vimfiles_dir_vim,
116 vimfiles_dir_home
117};
Bram Moolenaar25a494c2018-11-16 19:39:50 +0100118static char *(vimfiles_dir_choices[]) =
Bram Moolenaar071d4272004-06-13 20:20:40 +0000119{
120 "\nCreate plugin directories:",
121 "No",
122 "In the VIM directory",
123 "In your HOME directory",
124};
Bram Moolenaar071d4272004-06-13 20:20:40 +0000125
Bram Moolenaar5d18efe2019-12-01 21:11:22 +0100126// non-zero when selected to install the popup menu entry.
Bram Moolenaar071d4272004-06-13 20:20:40 +0000127static int install_popup = 0;
128
Bram Moolenaar5d18efe2019-12-01 21:11:22 +0100129// non-zero when selected to install the "Open with" entry.
Bram Moolenaar071d4272004-06-13 20:20:40 +0000130static int install_openwith = 0;
131
Bram Moolenaar5d18efe2019-12-01 21:11:22 +0100132// non-zero when need to add an uninstall entry in the registry
Bram Moolenaar071d4272004-06-13 20:20:40 +0000133static int need_uninstall_entry = 0;
134
135/*
136 * Definitions of the directory name (under $VIM) of the vimfiles directory
137 * and its subdirectories:
138 */
139static char *(vimfiles_subdirs[]) =
140{
141 "colors",
142 "compiler",
143 "doc",
144 "ftdetect",
145 "ftplugin",
146 "indent",
147 "keymap",
148 "plugin",
149 "syntax",
150};
151
152/*
Bram Moolenaar071d4272004-06-13 20:20:40 +0000153 * Obtain a choice from a table.
154 * First entry is a question, others are choices.
155 */
156 static int
157get_choice(char **table, int entries)
158{
159 int answer;
160 int idx;
161 char dummy[100];
162
163 do
164 {
165 for (idx = 0; idx < entries; ++idx)
166 {
167 if (idx)
168 printf("%2d ", idx);
Bram Moolenaarc3fdf7f2017-10-28 18:36:48 +0200169 puts(table[idx]);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000170 }
171 printf("Choice: ");
172 if (scanf("%d", &answer) != 1)
173 {
174 scanf("%99s", dummy);
175 answer = 0;
176 }
177 }
178 while (answer < 1 || answer >= entries);
179
180 return answer;
181}
182
183/*
184 * Check if the user unpacked the archives properly.
185 * Sets "runtimeidx".
186 */
187 static void
188check_unpack(void)
189{
190 char buf[BUFSIZE];
191 FILE *fd;
192 struct stat st;
193
Bram Moolenaar5d18efe2019-12-01 21:11:22 +0100194 // check for presence of the correct version number in installdir[]
Bram Moolenaar071d4272004-06-13 20:20:40 +0000195 runtimeidx = strlen(installdir) - strlen(VIM_VERSION_NODOT);
196 if (runtimeidx <= 0
197 || stricmp(installdir + runtimeidx, VIM_VERSION_NODOT) != 0
198 || (installdir[runtimeidx - 1] != '/'
199 && installdir[runtimeidx - 1] != '\\'))
200 {
201 printf("ERROR: Install program not in directory \"%s\"\n",
202 VIM_VERSION_NODOT);
203 printf("This program can only work when it is located in its original directory\n");
204 myexit(1);
205 }
206
Bram Moolenaar5d18efe2019-12-01 21:11:22 +0100207 // check if filetype.vim is present, which means the runtime archive has
208 // been unpacked
Bram Moolenaar071d4272004-06-13 20:20:40 +0000209 sprintf(buf, "%s\\filetype.vim", installdir);
210 if (stat(buf, &st) < 0)
211 {
212 printf("ERROR: Cannot find filetype.vim in \"%s\"\n", installdir);
213 printf("It looks like you did not unpack the runtime archive.\n");
214 printf("You must unpack the runtime archive \"vim%srt.zip\" before installing.\n",
215 VIM_VERSION_NODOT + 3);
216 myexit(1);
217 }
218
Bram Moolenaar5d18efe2019-12-01 21:11:22 +0100219 // Check if vim.exe or gvim.exe is in the current directory.
Bram Moolenaar071d4272004-06-13 20:20:40 +0000220 if ((fd = fopen("gvim.exe", "r")) != NULL)
221 {
222 fclose(fd);
223 has_gvim = 1;
224 }
225 if ((fd = fopen("vim.exe", "r")) != NULL)
226 {
227 fclose(fd);
228 has_vim = 1;
229 }
230 if (!has_gvim && !has_vim)
231 {
232 printf("ERROR: Cannot find any Vim executables in \"%s\"\n\n",
233 installdir);
234 myexit(1);
235 }
236}
237
238/*
239 * Compare paths "p[plen]" to "q[qlen]". Return 0 if they match.
240 * Ignores case and differences between '/' and '\'.
241 * "plen" and "qlen" can be negative, strlen() is used then.
242 */
243 static int
244pathcmp(char *p, int plen, char *q, int qlen)
245{
246 int i;
247
248 if (plen < 0)
249 plen = strlen(p);
250 if (qlen < 0)
251 qlen = strlen(q);
252 for (i = 0; ; ++i)
253 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +0100254 // End of "p": check if "q" also ends or just has a slash.
Bram Moolenaar071d4272004-06-13 20:20:40 +0000255 if (i == plen)
256 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +0100257 if (i == qlen) // match
Bram Moolenaar071d4272004-06-13 20:20:40 +0000258 return 0;
259 if (i == qlen - 1 && (q[i] == '\\' || q[i] == '/'))
Bram Moolenaar5d18efe2019-12-01 21:11:22 +0100260 return 0; // match with trailing slash
261 return 1; // no match
Bram Moolenaar071d4272004-06-13 20:20:40 +0000262 }
263
Bram Moolenaar5d18efe2019-12-01 21:11:22 +0100264 // End of "q": check if "p" also ends or just has a slash.
Bram Moolenaar071d4272004-06-13 20:20:40 +0000265 if (i == qlen)
266 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +0100267 if (i == plen) // match
Bram Moolenaar071d4272004-06-13 20:20:40 +0000268 return 0;
269 if (i == plen - 1 && (p[i] == '\\' || p[i] == '/'))
Bram Moolenaar5d18efe2019-12-01 21:11:22 +0100270 return 0; // match with trailing slash
271 return 1; // no match
Bram Moolenaar071d4272004-06-13 20:20:40 +0000272 }
273
274 if (!(mytoupper(p[i]) == mytoupper(q[i])
275 || ((p[i] == '/' || p[i] == '\\')
276 && (q[i] == '/' || q[i] == '\\'))))
Bram Moolenaar5d18efe2019-12-01 21:11:22 +0100277 return 1; // no match
Bram Moolenaar071d4272004-06-13 20:20:40 +0000278 }
Bram Moolenaar5d18efe2019-12-01 21:11:22 +0100279 //NOTREACHED
Bram Moolenaar071d4272004-06-13 20:20:40 +0000280}
281
282/*
283 * If the executable "**destination" is in the install directory, find another
284 * one in $PATH.
285 * On input "**destination" is the path of an executable in allocated memory
286 * (or NULL).
287 * "*destination" is set to NULL or the location of the file.
288 */
289 static void
290findoldfile(char **destination)
291{
292 char *bp = *destination;
293 size_t indir_l = strlen(installdir);
Bram Moolenaarb7633612019-02-10 21:48:25 +0100294 char *cp;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000295 char *tmpname;
296 char *farname;
297
298 /*
299 * No action needed if exe not found or not in this directory.
300 */
Bram Moolenaarb7633612019-02-10 21:48:25 +0100301 if (bp == NULL || strnicmp(bp, installdir, indir_l) != 0)
302 return;
303 cp = bp + indir_l;
304 if (strchr("/\\", *cp++) == NULL
Bram Moolenaar071d4272004-06-13 20:20:40 +0000305 || strchr(cp, '\\') != NULL
306 || strchr(cp, '/') != NULL)
307 return;
308
Bram Moolenaar51e14382019-05-25 20:21:28 +0200309 tmpname = alloc(strlen(cp) + 1);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000310 strcpy(tmpname, cp);
Bram Moolenaar5d18efe2019-12-01 21:11:22 +0100311 tmpname[strlen(tmpname) - 1] = 'x'; // .exe -> .exx
Bram Moolenaar071d4272004-06-13 20:20:40 +0000312
313 if (access(tmpname, 0) == 0)
314 {
315 printf("\nERROR: %s and %s clash. Remove or rename %s.\n",
316 tmpname, cp, tmpname);
317 myexit(1);
318 }
319
320 if (rename(cp, tmpname) != 0)
321 {
322 printf("\nERROR: failed to rename %s to %s: %s\n",
323 cp, tmpname, strerror(0));
324 myexit(1);
325 }
326
327 farname = searchpath_save(cp);
328
329 if (rename(tmpname, cp) != 0)
330 {
331 printf("\nERROR: failed to rename %s back to %s: %s\n",
332 tmpname, cp, strerror(0));
333 myexit(1);
334 }
335
336 free(*destination);
337 free(tmpname);
338 *destination = farname;
339}
340
341/*
342 * Check if there is a vim.[exe|bat|, gvim.[exe|bat|, etc. in the path.
343 * When "check_bat_only" is TRUE, only find "default_bat_dir".
344 */
345 static void
346find_bat_exe(int check_bat_only)
347{
348 int i;
349
Bram Moolenaar5d18efe2019-12-01 21:11:22 +0100350 // avoid looking in the "installdir" by chdir to system root
Bram Moolenaar42bbef42006-03-25 22:02:07 +0000351 mch_chdir(sysdrive);
352 mch_chdir("\\");
Bram Moolenaar071d4272004-06-13 20:20:40 +0000353
354 for (i = 1; i < TARGET_COUNT; ++i)
355 {
356 targets[i].oldbat = searchpath_save(targets[i].batname);
357 if (!check_bat_only)
358 targets[i].oldexe = searchpath_save(targets[i].exename);
359
360 if (default_bat_dir == NULL && targets[i].oldbat != NULL)
361 {
362 default_bat_dir = alloc(strlen(targets[i].oldbat) + 1);
363 strcpy(default_bat_dir, targets[i].oldbat);
364 remove_tail(default_bat_dir);
365 }
366 if (check_bat_only && targets[i].oldbat != NULL)
Bram Moolenaar42bbef42006-03-25 22:02:07 +0000367 {
Bram Moolenaar071d4272004-06-13 20:20:40 +0000368 free(targets[i].oldbat);
Bram Moolenaar42bbef42006-03-25 22:02:07 +0000369 targets[i].oldbat = NULL;
370 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000371 }
372
373 mch_chdir(installdir);
374}
375
Bram Moolenaar071d4272004-06-13 20:20:40 +0000376/*
377 * Get the value of $VIMRUNTIME or $VIM and write it in $TEMP/vimini.ini, so
378 * that NSIS can read it.
379 * When not set, use the directory of a previously installed Vim.
380 */
381 static void
382get_vim_env(void)
383{
384 char *vim;
385 char buf[BUFSIZE];
386 FILE *fd;
387 char fname[BUFSIZE];
388
Bram Moolenaar5d18efe2019-12-01 21:11:22 +0100389 // First get $VIMRUNTIME. If it's set, remove the tail.
Bram Moolenaar071d4272004-06-13 20:20:40 +0000390 vim = getenv("VIMRUNTIME");
Bram Moolenaare4963c52019-02-22 19:41:08 +0100391 if (vim != NULL && *vim != 0 && strlen(vim) < sizeof(buf))
Bram Moolenaar071d4272004-06-13 20:20:40 +0000392 {
393 strcpy(buf, vim);
394 remove_tail(buf);
395 vim = buf;
396 }
397 else
398 {
399 vim = getenv("VIM");
400 if (vim == NULL || *vim == 0)
401 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +0100402 // Use the directory from an old uninstall entry.
Bram Moolenaar071d4272004-06-13 20:20:40 +0000403 if (default_vim_dir != NULL)
404 vim = default_vim_dir;
405 else
Bram Moolenaar5d18efe2019-12-01 21:11:22 +0100406 // Let NSIS know there is no default, it should use
407 // $PROGRAMFILES.
Bram Moolenaar071d4272004-06-13 20:20:40 +0000408 vim = "";
409 }
410 }
411
Bram Moolenaar5d18efe2019-12-01 21:11:22 +0100412 // NSIS also uses GetTempPath(), thus we should get the same directory
413 // name as where NSIS will look for vimini.ini.
Bram Moolenaare4963c52019-02-22 19:41:08 +0100414 GetTempPath(sizeof(fname) - 12, fname);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000415 add_pathsep(fname);
416 strcat(fname, "vimini.ini");
417
418 fd = fopen(fname, "w");
419 if (fd != NULL)
420 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +0100421 // Make it look like an .ini file, so that NSIS can read it with a
422 // ReadINIStr command.
Bram Moolenaar071d4272004-06-13 20:20:40 +0000423 fprintf(fd, "[vimini]\n");
424 fprintf(fd, "dir=\"%s\"\n", vim);
425 fclose(fd);
426 }
427 else
428 {
429 printf("Failed to open %s\n", fname);
Bram Moolenaarab8205e2010-07-07 15:14:03 +0200430 sleep(2);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000431 }
432}
433
Bram Moolenaarb230bd52010-05-25 21:02:00 +0200434static int num_windows;
435
436/*
437 * Callback used for EnumWindows():
438 * Count the window if the title looks like it is for the uninstaller.
439 */
Bram Moolenaar5d18efe2019-12-01 21:11:22 +0100440//ARGSUSED
Bram Moolenaarb230bd52010-05-25 21:02:00 +0200441 static BOOL CALLBACK
442window_cb(HWND hwnd, LPARAM lparam)
443{
444 char title[256];
445
446 title[0] = 0;
447 GetWindowText(hwnd, title, 256);
Bram Moolenaaraf610b82018-12-21 16:22:50 +0100448 if (strstr(title, "Vim ") != NULL && strstr(title, " Uninstall") != NULL)
Bram Moolenaarb230bd52010-05-25 21:02:00 +0200449 ++num_windows;
450 return TRUE;
451}
452
Bram Moolenaar071d4272004-06-13 20:20:40 +0000453/*
Bram Moolenaaraf610b82018-12-21 16:22:50 +0100454 * Run the uninstaller silently.
455 */
456 static int
457run_silent_uninstall(char *uninst_exe)
458{
Bram Moolenaare4963c52019-02-22 19:41:08 +0100459 char vimrt_dir[BUFSIZE];
Bram Moolenaaraf610b82018-12-21 16:22:50 +0100460 char temp_uninst[BUFSIZE];
461 char temp_dir[MAX_PATH];
462 char buf[BUFSIZE * 2 + 10];
463 int i;
464 DWORD tick;
465
466 strcpy(vimrt_dir, uninst_exe);
467 remove_tail(vimrt_dir);
468
469 if (!GetTempPath(sizeof(temp_dir), temp_dir))
470 return FAIL;
471
Bram Moolenaar5d18efe2019-12-01 21:11:22 +0100472 // Copy the uninstaller to a temporary exe.
Bram Moolenaaraf610b82018-12-21 16:22:50 +0100473 tick = GetTickCount();
474 for (i = 0; ; i++)
475 {
476 sprintf(temp_uninst, "%s\\vimun%04X.exe", temp_dir,
Bram Moolenaar44a7db42019-01-11 20:47:31 +0100477 (unsigned int)((i + tick) & 0xFFFF));
Bram Moolenaaraf610b82018-12-21 16:22:50 +0100478 if (CopyFile(uninst_exe, temp_uninst, TRUE))
479 break;
480 if (GetLastError() != ERROR_FILE_EXISTS)
481 return FAIL;
482 if (i == 65535)
483 return FAIL;
484 }
485
Bram Moolenaar5d18efe2019-12-01 21:11:22 +0100486 // Run the copied uninstaller silently.
Bram Moolenaaraf610b82018-12-21 16:22:50 +0100487 if (strchr(temp_uninst, ' ') != NULL)
488 sprintf(buf, "\"%s\" /S _?=%s", temp_uninst, vimrt_dir);
489 else
490 sprintf(buf, "%s /S _?=%s", temp_uninst, vimrt_dir);
491 run_command(buf);
492
493 DeleteFile(temp_uninst);
494 return OK;
495}
496
497/*
Bram Moolenaar071d4272004-06-13 20:20:40 +0000498 * Check for already installed Vims.
499 * Return non-zero when found one.
500 */
501 static int
Bram Moolenaar442b4222010-05-24 21:34:22 +0200502uninstall_check(int skip_question)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000503{
504 HKEY key_handle;
505 HKEY uninstall_key_handle;
506 char *uninstall_key = "software\\Microsoft\\Windows\\CurrentVersion\\Uninstall";
507 char subkey_name_buff[BUFSIZE];
Bram Moolenaarbbd854d2019-02-18 22:19:33 +0100508 char temp_string_buffer[BUFSIZE-2];
Bram Moolenaare4963c52019-02-22 19:41:08 +0100509 DWORD local_bufsize;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000510 FILETIME temp_pfiletime;
511 DWORD key_index;
512 char input;
513 long code;
514 DWORD value_type;
515 DWORD orig_num_keys;
516 DWORD new_num_keys;
Bram Moolenaaraf610b82018-12-21 16:22:50 +0100517 DWORD allow_silent;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000518 int foundone = 0;
519
Bram Moolenaar760d14a2010-07-31 22:03:44 +0200520 code = RegOpenKeyEx(HKEY_LOCAL_MACHINE, uninstall_key, 0,
521 KEY_WOW64_64KEY | KEY_READ, &key_handle);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000522 CHECK_REG_ERROR(code);
523
Bram Moolenaare4963c52019-02-22 19:41:08 +0100524 key_index = 0;
525 while (TRUE)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000526 {
Bram Moolenaare4963c52019-02-22 19:41:08 +0100527 local_bufsize = sizeof(subkey_name_buff);
528 if (RegEnumKeyEx(key_handle, key_index, subkey_name_buff, &local_bufsize,
529 NULL, NULL, NULL, &temp_pfiletime) == ERROR_NO_MORE_ITEMS)
530 break;
531
Bram Moolenaar071d4272004-06-13 20:20:40 +0000532 if (strncmp("Vim", subkey_name_buff, 3) == 0)
533 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +0100534 // Open the key named Vim*
Bram Moolenaar760d14a2010-07-31 22:03:44 +0200535 code = RegOpenKeyEx(key_handle, subkey_name_buff, 0,
536 KEY_WOW64_64KEY | KEY_READ, &uninstall_key_handle);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000537 CHECK_REG_ERROR(code);
538
Bram Moolenaar5d18efe2019-12-01 21:11:22 +0100539 // get the DisplayName out of it to show the user
Bram Moolenaare4963c52019-02-22 19:41:08 +0100540 local_bufsize = sizeof(temp_string_buffer);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000541 code = RegQueryValueEx(uninstall_key_handle, "displayname", 0,
542 &value_type, (LPBYTE)temp_string_buffer,
543 &local_bufsize);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000544 CHECK_REG_ERROR(code);
545
Bram Moolenaaraf610b82018-12-21 16:22:50 +0100546 allow_silent = 0;
547 if (skip_question)
548 {
549 DWORD varsize = sizeof(DWORD);
550
551 RegQueryValueEx(uninstall_key_handle, "AllowSilent", 0,
552 &value_type, (LPBYTE)&allow_silent,
553 &varsize);
554 }
555
Bram Moolenaar071d4272004-06-13 20:20:40 +0000556 foundone = 1;
557 printf("\n*********************************************************\n");
558 printf("Vim Install found what looks like an existing Vim version.\n");
559 printf("The name of the entry is:\n");
560 printf("\n \"%s\"\n\n", temp_string_buffer);
561
562 printf("Installing the new version will disable part of the existing version.\n");
563 printf("(The batch files used in a console and the \"Edit with Vim\" entry in\n");
564 printf("the popup menu will use the new version)\n");
565
Bram Moolenaar442b4222010-05-24 21:34:22 +0200566 if (skip_question)
567 printf("\nRunning uninstall program for \"%s\"\n", temp_string_buffer);
568 else
569 printf("\nDo you want to uninstall \"%s\" now?\n(y)es/(n)o) ", temp_string_buffer);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000570 fflush(stdout);
571
Bram Moolenaar5d18efe2019-12-01 21:11:22 +0100572 // get the UninstallString
Bram Moolenaare4963c52019-02-22 19:41:08 +0100573 local_bufsize = sizeof(temp_string_buffer);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000574 code = RegQueryValueEx(uninstall_key_handle, "uninstallstring", 0,
575 &value_type, (LPBYTE)temp_string_buffer, &local_bufsize);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000576 CHECK_REG_ERROR(code);
577
Bram Moolenaar5d18efe2019-12-01 21:11:22 +0100578 // Remember the directory, it is used as the default for NSIS.
Bram Moolenaar071d4272004-06-13 20:20:40 +0000579 default_vim_dir = alloc(strlen(temp_string_buffer) + 1);
580 strcpy(default_vim_dir, temp_string_buffer);
581 remove_tail(default_vim_dir);
582 remove_tail(default_vim_dir);
583
584 input = 'n';
585 do
586 {
587 if (input != 'n')
588 printf("%c is an invalid reply. Please enter either 'y' or 'n'\n", input);
589
Bram Moolenaar442b4222010-05-24 21:34:22 +0200590 if (skip_question)
591 input = 'y';
592 else
593 {
594 rewind(stdin);
595 scanf("%c", &input);
596 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000597 switch (input)
598 {
599 case 'y':
600 case 'Y':
Bram Moolenaar5d18efe2019-12-01 21:11:22 +0100601 // save the number of uninstall keys so we can know if
602 // it changed
Bram Moolenaar071d4272004-06-13 20:20:40 +0000603 RegQueryInfoKey(key_handle, NULL, NULL, NULL,
604 &orig_num_keys, NULL, NULL, NULL,
605 NULL, NULL, NULL, NULL);
606
Bram Moolenaar5d18efe2019-12-01 21:11:22 +0100607 // Find existing .bat files before deleting them.
Bram Moolenaar071d4272004-06-13 20:20:40 +0000608 find_bat_exe(TRUE);
609
Bram Moolenaaraf610b82018-12-21 16:22:50 +0100610 if (allow_silent)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000611 {
Bram Moolenaaraf610b82018-12-21 16:22:50 +0100612 if (run_silent_uninstall(temp_string_buffer)
613 == FAIL)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +0100614 allow_silent = 0; // Retry with non silent.
Bram Moolenaar071d4272004-06-13 20:20:40 +0000615 }
Bram Moolenaaraf610b82018-12-21 16:22:50 +0100616 if (!allow_silent)
Bram Moolenaarb230bd52010-05-25 21:02:00 +0200617 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +0100618 // Execute the uninstall program. Put it in double
619 // quotes if there is an embedded space.
Bram Moolenaarb230bd52010-05-25 21:02:00 +0200620 {
Bram Moolenaaraf610b82018-12-21 16:22:50 +0100621 char buf[BUFSIZE];
622
623 if (strchr(temp_string_buffer, ' ') != NULL)
624 sprintf(buf, "\"%s\"", temp_string_buffer);
625 else
626 strcpy(buf, temp_string_buffer);
627 run_command(buf);
628 }
629
Bram Moolenaar5d18efe2019-12-01 21:11:22 +0100630 // Count the number of windows with a title that
631 // match the installer, so that we can check when
632 // it's done. The uninstaller copies itself,
633 // executes the copy and exits, thus we can't wait
634 // for the process to finish.
635 sleep(1); // wait for uninstaller to start up
Bram Moolenaaraf610b82018-12-21 16:22:50 +0100636 num_windows = 0;
637 EnumWindows(window_cb, 0);
638 if (num_windows == 0)
639 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +0100640 // Did not find the uninstaller, ask user to
641 // press Enter when done. Just in case.
Bram Moolenaaraf610b82018-12-21 16:22:50 +0100642 printf("Press Enter when the uninstaller is finished\n");
643 rewind(stdin);
644 (void)getchar();
645 }
646 else
647 {
648 printf("Waiting for the uninstaller to finish (press CTRL-C to abort).");
649 do
650 {
651 printf(".");
652 fflush(stdout);
Bram Moolenaar5d18efe2019-12-01 21:11:22 +0100653 sleep(1); // wait for the uninstaller to
654 // finish
Bram Moolenaaraf610b82018-12-21 16:22:50 +0100655 num_windows = 0;
656 EnumWindows(window_cb, 0);
657 } while (num_windows > 0);
658 }
Bram Moolenaarb230bd52010-05-25 21:02:00 +0200659 }
660 printf("\nDone!\n");
Bram Moolenaar071d4272004-06-13 20:20:40 +0000661
Bram Moolenaar5d18efe2019-12-01 21:11:22 +0100662 // Check if an uninstall reg key was deleted.
663 // if it was, we want to decrement key_index.
664 // if we don't do this, we will skip the key
665 // immediately after any key that we delete.
Bram Moolenaar071d4272004-06-13 20:20:40 +0000666 RegQueryInfoKey(key_handle, NULL, NULL, NULL,
667 &new_num_keys, NULL, NULL, NULL,
668 NULL, NULL, NULL, NULL);
669 if (new_num_keys < orig_num_keys)
670 key_index--;
671
672 input = 'y';
673 break;
674
675 case 'n':
676 case 'N':
Bram Moolenaar5d18efe2019-12-01 21:11:22 +0100677 // Do not uninstall
Bram Moolenaar071d4272004-06-13 20:20:40 +0000678 input = 'n';
679 break;
680
Bram Moolenaar5d18efe2019-12-01 21:11:22 +0100681 default: // just drop through and redo the loop
Bram Moolenaar071d4272004-06-13 20:20:40 +0000682 break;
683 }
684
685 } while (input != 'n' && input != 'y');
686
687 RegCloseKey(uninstall_key_handle);
688 }
Bram Moolenaare4963c52019-02-22 19:41:08 +0100689
690 key_index++;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000691 }
692 RegCloseKey(key_handle);
693
694 return foundone;
695}
Bram Moolenaar071d4272004-06-13 20:20:40 +0000696
697/*
698 * Find out information about the system.
699 */
700 static void
701inspect_system(void)
702{
703 char *p;
704 char buf[BUFSIZE];
705 FILE *fd;
706 int i;
707 int foundone;
708
Bram Moolenaar5d18efe2019-12-01 21:11:22 +0100709 // This may take a little while, let the user know what we're doing.
Bram Moolenaar071d4272004-06-13 20:20:40 +0000710 printf("Inspecting system...\n");
711
712 /*
713 * If $VIM is set, check that it's pointing to our directory.
714 */
715 p = getenv("VIM");
716 if (p != NULL && pathcmp(p, -1, installdir, runtimeidx - 1) != 0)
717 {
718 printf("------------------------------------------------------\n");
719 printf("$VIM is set to \"%s\".\n", p);
720 printf("This is different from where this version of Vim is:\n");
721 strcpy(buf, installdir);
722 *(buf + runtimeidx - 1) = NUL;
723 printf("\"%s\"\n", buf);
724 printf("You must adjust or remove the setting of $VIM,\n");
725 if (interactive)
726 {
727 printf("to be able to use this install program.\n");
728 myexit(1);
729 }
730 printf("otherwise Vim WILL NOT WORK properly!\n");
731 printf("------------------------------------------------------\n");
732 }
733
734 /*
735 * If $VIMRUNTIME is set, check that it's pointing to our runtime directory.
736 */
737 p = getenv("VIMRUNTIME");
738 if (p != NULL && pathcmp(p, -1, installdir, -1) != 0)
739 {
740 printf("------------------------------------------------------\n");
741 printf("$VIMRUNTIME is set to \"%s\".\n", p);
742 printf("This is different from where this version of Vim is:\n");
743 printf("\"%s\"\n", installdir);
744 printf("You must adjust or remove the setting of $VIMRUNTIME,\n");
745 if (interactive)
746 {
747 printf("to be able to use this install program.\n");
748 myexit(1);
749 }
750 printf("otherwise Vim WILL NOT WORK properly!\n");
751 printf("------------------------------------------------------\n");
752 }
753
754 /*
755 * Check if there is a vim.[exe|bat|, gvim.[exe|bat|, etc. in the path.
756 */
757 find_bat_exe(FALSE);
758
759 /*
760 * A .exe in the install directory may be found anyway on Windows 2000.
761 * Check for this situation and find another executable if necessary.
762 * w.briscoe@ponl.com 2001-01-20
763 */
764 foundone = 0;
765 for (i = 1; i < TARGET_COUNT; ++i)
766 {
767 findoldfile(&(targets[i].oldexe));
768 if (targets[i].oldexe != NULL)
769 foundone = 1;
770 }
771
772 if (foundone)
773 {
774 printf("Warning: Found Vim executable(s) in your $PATH:\n");
775 for (i = 1; i < TARGET_COUNT; ++i)
776 if (targets[i].oldexe != NULL)
777 printf("%s\n", targets[i].oldexe);
778 printf("It will be used instead of the version you are installing.\n");
779 printf("Please delete or rename it, or adjust your $PATH setting.\n");
780 }
781
782 /*
783 * Check if there is an existing ../_vimrc or ../.vimrc file.
784 */
785 strcpy(oldvimrc, installdir);
786 strcpy(oldvimrc + runtimeidx, "_vimrc");
787 if ((fd = fopen(oldvimrc, "r")) == NULL)
788 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +0100789 strcpy(oldvimrc + runtimeidx, "vimrc~1"); // short version of .vimrc
Bram Moolenaar071d4272004-06-13 20:20:40 +0000790 if ((fd = fopen(oldvimrc, "r")) == NULL)
791 {
792 strcpy(oldvimrc + runtimeidx, ".vimrc");
793 fd = fopen(oldvimrc, "r");
794 }
795 }
796 if (fd != NULL)
797 fclose(fd);
798 else
799 *oldvimrc = NUL;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000800}
801
802/*
803 * Add a dummy choice to avoid that the numbering changes depending on items
804 * in the environment. The user may type a number he remembered without
805 * looking.
806 */
807 static void
808add_dummy_choice(void)
809{
810 choices[choice_count].installfunc = NULL;
811 choices[choice_count].active = 0;
812 choices[choice_count].changefunc = NULL;
Bram Moolenaar25a494c2018-11-16 19:39:50 +0100813 choices[choice_count].text = NULL;
814 choices[choice_count].arg = 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000815 ++choice_count;
816}
817
Bram Moolenaar5d18efe2019-12-01 21:11:22 +0100818////////////////////////////////////////////////
819// stuff for creating the batch files.
Bram Moolenaar071d4272004-06-13 20:20:40 +0000820
821/*
822 * Install the vim.bat, gvim.bat, etc. files.
823 */
824 static void
825install_bat_choice(int idx)
826{
827 char *batpath = targets[choices[idx].arg].batpath;
828 char *oldname = targets[choices[idx].arg].oldbat;
829 char *exename = targets[choices[idx].arg].exenamearg;
830 char *vimarg = targets[choices[idx].arg].exearg;
831 FILE *fd;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000832
833 if (*batpath != NUL)
834 {
835 fd = fopen(batpath, "w");
836 if (fd == NULL)
837 printf("\nERROR: Cannot open \"%s\" for writing.\n", batpath);
838 else
839 {
840 need_uninstall_entry = 1;
841
842 fprintf(fd, "@echo off\n");
Bram Moolenaar97b2ad32006-03-18 21:40:56 +0000843 fprintf(fd, "rem -- Run Vim --\n");
844 fprintf(fd, "\n");
Bram Moolenaare609ad52016-03-28 23:05:48 +0200845 fprintf(fd, "setlocal\n");
Bram Moolenaar071d4272004-06-13 20:20:40 +0000846
Bram Moolenaar5d18efe2019-12-01 21:11:22 +0100847 /*
848 * Don't use double quotes for the "set" argument, also when it
Bram Moolenaar071d4272004-06-13 20:20:40 +0000849 * contains a space. The quotes would be included in the value
Bram Moolenaar97b2ad32006-03-18 21:40:56 +0000850 * for MSDOS and NT.
851 * 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 Moolenaar97b2ad32006-03-18 21:40:56 +0000863 fprintf(fd, "if exist \"%%VIM_EXE_DIR%%\\%s\" goto havevim\n",
864 exename);
865 fprintf(fd, "echo \"%%VIM_EXE_DIR%%\\%s\" not found\n", exename);
866 fprintf(fd, "goto eof\n");
867 fprintf(fd, "\n");
Bram Moolenaar071d4272004-06-13 20:20:40 +0000868 fprintf(fd, ":havevim\n");
869
870 fprintf(fd, "rem collect the arguments in VIMARGS for Win95\n");
871 fprintf(fd, "set VIMARGS=\n");
872 if (*exename == 'g')
873 fprintf(fd, "set VIMNOFORK=\n");
874 fprintf(fd, ":loopstart\n");
875 fprintf(fd, "if .%%1==. goto loopend\n");
876 if (*exename == 'g')
877 {
Bram Moolenaare609ad52016-03-28 23:05:48 +0200878 fprintf(fd, "if NOT .%%1==.--nofork goto noforklongarg\n");
879 fprintf(fd, "set VIMNOFORK=1\n");
880 fprintf(fd, ":noforklongarg\n");
Bram Moolenaar071d4272004-06-13 20:20:40 +0000881 fprintf(fd, "if NOT .%%1==.-f goto noforkarg\n");
882 fprintf(fd, "set VIMNOFORK=1\n");
883 fprintf(fd, ":noforkarg\n");
884 }
885 fprintf(fd, "set VIMARGS=%%VIMARGS%% %%1\n");
886 fprintf(fd, "shift\n");
Bram Moolenaar97b2ad32006-03-18 21:40:56 +0000887 fprintf(fd, "goto loopstart\n");
Bram Moolenaar071d4272004-06-13 20:20:40 +0000888 fprintf(fd, ":loopend\n");
Bram Moolenaar97b2ad32006-03-18 21:40:56 +0000889 fprintf(fd, "\n");
Bram Moolenaar071d4272004-06-13 20:20:40 +0000890
Bram Moolenaar97b2ad32006-03-18 21:40:56 +0000891 fprintf(fd, "if .%%OS%%==.Windows_NT goto ntaction\n");
892 fprintf(fd, "\n");
Bram Moolenaar071d4272004-06-13 20:20:40 +0000893
Bram Moolenaar5d18efe2019-12-01 21:11:22 +0100894 // For gvim.exe use "start" to avoid that the console window stays
895 // open.
Bram Moolenaar071d4272004-06-13 20:20:40 +0000896 if (*exename == 'g')
897 {
898 fprintf(fd, "if .%%VIMNOFORK%%==.1 goto nofork\n");
899 fprintf(fd, "start ");
900 }
901
Bram Moolenaar5d18efe2019-12-01 21:11:22 +0100902 // Always use quotes, $VIM or $VIMRUNTIME might have a space.
Bram Moolenaar97b2ad32006-03-18 21:40:56 +0000903 fprintf(fd, "\"%%VIM_EXE_DIR%%\\%s\" %s %%VIMARGS%%\n",
904 exename, vimarg);
905 fprintf(fd, "goto eof\n");
906 fprintf(fd, "\n");
Bram Moolenaar071d4272004-06-13 20:20:40 +0000907
908 if (*exename == 'g')
909 {
910 fprintf(fd, ":nofork\n");
911 fprintf(fd, "start /w ");
Bram Moolenaar5d18efe2019-12-01 21:11:22 +0100912 // Always use quotes, $VIM or $VIMRUNTIME might have a space.
Bram Moolenaar97b2ad32006-03-18 21:40:56 +0000913 fprintf(fd, "\"%%VIM_EXE_DIR%%\\%s\" %s %%VIMARGS%%\n",
914 exename, vimarg);
915 fprintf(fd, "goto eof\n");
916 fprintf(fd, "\n");
Bram Moolenaar071d4272004-06-13 20:20:40 +0000917 }
918
919 fprintf(fd, ":ntaction\n");
920 fprintf(fd, "rem for WinNT we can use %%*\n");
921
Bram Moolenaar5d18efe2019-12-01 21:11:22 +0100922 // For gvim.exe use "start /b" to avoid that the console window
923 // stays open.
Bram Moolenaar071d4272004-06-13 20:20:40 +0000924 if (*exename == 'g')
925 {
926 fprintf(fd, "if .%%VIMNOFORK%%==.1 goto noforknt\n");
927 fprintf(fd, "start \"dummy\" /b ");
928 }
929
Bram Moolenaar5d18efe2019-12-01 21:11:22 +0100930 // Always use quotes, $VIM or $VIMRUNTIME might have a space.
Bram Moolenaar97b2ad32006-03-18 21:40:56 +0000931 fprintf(fd, "\"%%VIM_EXE_DIR%%\\%s\" %s %%*\n", exename, vimarg);
932 fprintf(fd, "goto eof\n");
933 fprintf(fd, "\n");
Bram Moolenaar071d4272004-06-13 20:20:40 +0000934
935 if (*exename == 'g')
936 {
937 fprintf(fd, ":noforknt\n");
938 fprintf(fd, "start \"dummy\" /b /wait ");
Bram Moolenaar5d18efe2019-12-01 21:11:22 +0100939 // Always use quotes, $VIM or $VIMRUNTIME might have a space.
Bram Moolenaar97b2ad32006-03-18 21:40:56 +0000940 fprintf(fd, "\"%%VIM_EXE_DIR%%\\%s\" %s %%*\n",
941 exename, vimarg);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000942 }
943
944 fprintf(fd, "\n:eof\n");
945 fprintf(fd, "set VIMARGS=\n");
946 if (*exename == 'g')
947 fprintf(fd, "set VIMNOFORK=\n");
948
949 fclose(fd);
950 printf("%s has been %s\n", batpath,
951 oldname == NULL ? "created" : "overwritten");
952 }
953 }
954}
955
956/*
957 * Make the text string for choice "idx".
958 * The format "fmt" is must have one %s item, which "arg" is used for.
959 */
960 static void
961alloc_text(int idx, char *fmt, char *arg)
962{
963 if (choices[idx].text != NULL)
964 free(choices[idx].text);
965
Bram Moolenaar51e14382019-05-25 20:21:28 +0200966 choices[idx].text = alloc(strlen(fmt) + strlen(arg) - 1);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000967 sprintf(choices[idx].text, fmt, arg);
968}
969
970/*
971 * Toggle the "Overwrite .../vim.bat" to "Don't overwrite".
972 */
973 static void
974toggle_bat_choice(int idx)
975{
976 char *batname = targets[choices[idx].arg].batpath;
977 char *oldname = targets[choices[idx].arg].oldbat;
978
979 if (*batname == NUL)
980 {
981 alloc_text(idx, " Overwrite %s", oldname);
982 strcpy(batname, oldname);
983 }
984 else
985 {
986 alloc_text(idx, " Do NOT overwrite %s", oldname);
987 *batname = NUL;
988 }
989}
990
991/*
992 * Do some work for a batch file entry: Append the batch file name to the path
993 * and set the text for the choice.
994 */
995 static void
996set_bat_text(int idx, char *batpath, char *name)
997{
998 strcat(batpath, name);
999
1000 alloc_text(idx, " Create %s", batpath);
1001}
1002
1003/*
1004 * Select a directory to write the batch file line.
1005 */
1006 static void
1007change_bat_choice(int idx)
1008{
1009 char *path;
1010 char *batpath;
1011 char *name;
1012 int n;
1013 char *s;
1014 char *p;
1015 int count;
1016 char **names = NULL;
1017 int i;
1018 int target = choices[idx].arg;
1019
1020 name = targets[target].batname;
1021 batpath = targets[target].batpath;
1022
1023 path = getenv("PATH");
1024 if (path == NULL)
1025 {
1026 printf("\nERROR: The variable $PATH is not set\n");
1027 return;
1028 }
1029
1030 /*
1031 * first round: count number of names in path;
1032 * second round: save names to names[].
1033 */
1034 for (;;)
1035 {
1036 count = 1;
1037 for (p = path; *p; )
1038 {
1039 s = strchr(p, ';');
1040 if (s == NULL)
1041 s = p + strlen(p);
1042 if (names != NULL)
1043 {
Bram Moolenaar51e14382019-05-25 20:21:28 +02001044 names[count] = alloc(s - p + 1);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001045 strncpy(names[count], p, s - p);
1046 names[count][s - p] = NUL;
1047 }
1048 ++count;
1049 p = s;
1050 if (*p != NUL)
1051 ++p;
1052 }
1053 if (names != NULL)
1054 break;
Bram Moolenaar51e14382019-05-25 20:21:28 +02001055 names = alloc((count + 1) * sizeof(char *));
Bram Moolenaar071d4272004-06-13 20:20:40 +00001056 }
1057 names[0] = alloc(50);
1058 sprintf(names[0], "Select directory to create %s in:", name);
1059 names[count] = alloc(50);
1060 if (choices[idx].arg == 0)
1061 sprintf(names[count], "Do not create any .bat file.");
1062 else
1063 sprintf(names[count], "Do not create a %s file.", name);
1064 n = get_choice(names, count + 1);
1065
1066 if (n == count)
1067 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01001068 // Selected last item, don't create bat file.
Bram Moolenaar071d4272004-06-13 20:20:40 +00001069 *batpath = NUL;
1070 if (choices[idx].arg != 0)
1071 alloc_text(idx, " Do NOT create %s", name);
1072 }
1073 else
1074 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01001075 // Selected one of the paths. For the first item only keep the path,
1076 // for the others append the batch file name.
Bram Moolenaar071d4272004-06-13 20:20:40 +00001077 strcpy(batpath, names[n]);
1078 add_pathsep(batpath);
1079 if (choices[idx].arg != 0)
1080 set_bat_text(idx, batpath, name);
1081 }
1082
1083 for (i = 0; i <= count; ++i)
1084 free(names[i]);
1085 free(names);
1086}
1087
1088char *bat_text_yes = "Install .bat files to use Vim at the command line:";
1089char *bat_text_no = "do NOT install .bat files to use Vim at the command line";
1090
1091 static void
1092change_main_bat_choice(int idx)
1093{
1094 int i;
1095
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01001096 // let the user select a default directory or NONE
Bram Moolenaar071d4272004-06-13 20:20:40 +00001097 change_bat_choice(idx);
1098
1099 if (targets[0].batpath[0] != NUL)
1100 choices[idx].text = bat_text_yes;
1101 else
1102 choices[idx].text = bat_text_no;
1103
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01001104 // update the individual batch file selections
Bram Moolenaar071d4272004-06-13 20:20:40 +00001105 for (i = 1; i < TARGET_COUNT; ++i)
1106 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01001107 // Only make it active when the first item has a path and the vim.exe
1108 // or gvim.exe exists (there is a changefunc then).
Bram Moolenaar071d4272004-06-13 20:20:40 +00001109 if (targets[0].batpath[0] != NUL
1110 && choices[idx + i].changefunc != NULL)
1111 {
1112 choices[idx + i].active = 1;
1113 if (choices[idx + i].changefunc == change_bat_choice
1114 && targets[i].batpath[0] != NUL)
1115 {
1116 strcpy(targets[i].batpath, targets[0].batpath);
1117 set_bat_text(idx + i, targets[i].batpath, targets[i].batname);
1118 }
1119 }
1120 else
1121 choices[idx + i].active = 0;
1122 }
1123}
1124
1125/*
1126 * Initialize a choice for creating a batch file.
1127 */
1128 static void
1129init_bat_choice(int target)
1130{
1131 char *batpath = targets[target].batpath;
1132 char *oldbat = targets[target].oldbat;
1133 char *p;
1134 int i;
1135
1136 choices[choice_count].arg = target;
1137 choices[choice_count].installfunc = install_bat_choice;
1138 choices[choice_count].active = 1;
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01001139 choices[choice_count].text = NULL; // will be set below
Bram Moolenaar071d4272004-06-13 20:20:40 +00001140 if (oldbat != NULL)
1141 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01001142 // A [g]vim.bat exists: Only choice is to overwrite it or not.
Bram Moolenaar071d4272004-06-13 20:20:40 +00001143 choices[choice_count].changefunc = toggle_bat_choice;
1144 *batpath = NUL;
1145 toggle_bat_choice(choice_count);
1146 }
1147 else
1148 {
1149 if (default_bat_dir != NULL)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01001150 // Prefer using the same path as an existing .bat file.
Bram Moolenaar071d4272004-06-13 20:20:40 +00001151 strcpy(batpath, default_bat_dir);
1152 else
1153 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01001154 // No [g]vim.bat exists: Write it to a directory in $PATH. Use
1155 // $WINDIR by default, if it's empty the first item in $PATH.
Bram Moolenaar071d4272004-06-13 20:20:40 +00001156 p = getenv("WINDIR");
1157 if (p != NULL && *p != NUL)
1158 strcpy(batpath, p);
1159 else
1160 {
1161 p = getenv("PATH");
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01001162 if (p == NULL || *p == NUL) // "cannot happen"
Bram Moolenaar071d4272004-06-13 20:20:40 +00001163 strcpy(batpath, "C:/Windows");
1164 else
1165 {
1166 i = 0;
1167 while (*p != NUL && *p != ';')
1168 batpath[i++] = *p++;
1169 batpath[i] = NUL;
1170 }
1171 }
1172 }
1173 add_pathsep(batpath);
1174 set_bat_text(choice_count, batpath, targets[target].batname);
1175
1176 choices[choice_count].changefunc = change_bat_choice;
1177 }
1178 ++choice_count;
1179}
1180
1181/*
1182 * Set up the choices for installing .bat files.
1183 * For these items "arg" is the index in targets[].
1184 */
1185 static void
1186init_bat_choices(void)
1187{
1188 int i;
1189
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01001190 // The first item is used to switch installing batch files on/off and
1191 // setting the default path.
Bram Moolenaar071d4272004-06-13 20:20:40 +00001192 choices[choice_count].text = bat_text_yes;
1193 choices[choice_count].changefunc = change_main_bat_choice;
1194 choices[choice_count].installfunc = NULL;
1195 choices[choice_count].active = 1;
1196 choices[choice_count].arg = 0;
1197 ++choice_count;
1198
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01001199 // Add items for each batch file target. Only used when not disabled by
1200 // the first item. When a .exe exists, don't offer to create a .bat.
Bram Moolenaar071d4272004-06-13 20:20:40 +00001201 for (i = 1; i < TARGET_COUNT; ++i)
1202 if (targets[i].oldexe == NULL
1203 && (targets[i].exenamearg[0] == 'g' ? has_gvim : has_vim))
1204 init_bat_choice(i);
1205 else
1206 add_dummy_choice();
1207}
1208
1209/*
1210 * Install the vimrc file.
1211 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001212 static void
1213install_vimrc(int idx)
1214{
1215 FILE *fd, *tfd;
1216 char *fname;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001217
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01001218 // If an old vimrc file exists, overwrite it.
1219 // Otherwise create a new one.
Bram Moolenaar071d4272004-06-13 20:20:40 +00001220 if (*oldvimrc != NUL)
1221 fname = oldvimrc;
1222 else
1223 fname = vimrc;
1224
1225 fd = fopen(fname, "w");
1226 if (fd == NULL)
1227 {
1228 printf("\nERROR: Cannot open \"%s\" for writing.\n", fname);
1229 return;
1230 }
1231 switch (compat_choice)
1232 {
1233 case compat_vi:
Bram Moolenaar6cdb2c92018-10-13 17:25:27 +02001234 fprintf(fd, "\" Vi compatible\n");
Bram Moolenaar071d4272004-06-13 20:20:40 +00001235 fprintf(fd, "set compatible\n");
1236 break;
Bram Moolenaar6cdb2c92018-10-13 17:25:27 +02001237 case compat_vim:
1238 fprintf(fd, "\" Vim's default behavior\n");
1239 fprintf(fd, "if &compatible\n");
1240 fprintf(fd, " set nocompatible\n");
1241 fprintf(fd, "endif\n");
1242 break;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001243 case compat_some_enhancements:
Bram Moolenaar6cdb2c92018-10-13 17:25:27 +02001244 fprintf(fd, "\" Vim with some enhancements\n");
Bram Moolenaarc73e4472016-07-29 18:33:38 +02001245 fprintf(fd, "source $VIMRUNTIME/defaults.vim\n");
Bram Moolenaar071d4272004-06-13 20:20:40 +00001246 break;
1247 case compat_all_enhancements:
Bram Moolenaar6cdb2c92018-10-13 17:25:27 +02001248 fprintf(fd, "\" Vim with all enhancements\n");
Bram Moolenaar071d4272004-06-13 20:20:40 +00001249 fprintf(fd, "source $VIMRUNTIME/vimrc_example.vim\n");
1250 break;
1251 }
1252 switch (remap_choice)
1253 {
1254 case remap_no:
1255 break;
1256 case remap_win:
Bram Moolenaar6cdb2c92018-10-13 17:25:27 +02001257 fprintf(fd, "\n");
1258 fprintf(fd, "\" Remap a few keys for Windows behavior\n");
Bram Moolenaar071d4272004-06-13 20:20:40 +00001259 fprintf(fd, "source $VIMRUNTIME/mswin.vim\n");
1260 break;
1261 }
1262 switch (mouse_choice)
1263 {
1264 case mouse_xterm:
Bram Moolenaar6cdb2c92018-10-13 17:25:27 +02001265 fprintf(fd, "\n");
1266 fprintf(fd, "\" Mouse behavior (the Unix way)\n");
Bram Moolenaar071d4272004-06-13 20:20:40 +00001267 fprintf(fd, "behave xterm\n");
1268 break;
1269 case mouse_mswin:
Bram Moolenaar6cdb2c92018-10-13 17:25:27 +02001270 fprintf(fd, "\n");
1271 fprintf(fd, "\" Mouse behavior (the Windows way)\n");
Bram Moolenaar071d4272004-06-13 20:20:40 +00001272 fprintf(fd, "behave mswin\n");
1273 break;
Bram Moolenaarc3fdf7f2017-10-28 18:36:48 +02001274 case mouse_default:
1275 break;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001276 }
1277 if ((tfd = fopen("diff.exe", "r")) != NULL)
1278 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01001279 // Use the diff.exe that comes with the self-extracting gvim.exe.
Bram Moolenaar071d4272004-06-13 20:20:40 +00001280 fclose(tfd);
1281 fprintf(fd, "\n");
Bram Moolenaar6cdb2c92018-10-13 17:25:27 +02001282 fprintf(fd, "\" Use the internal diff if available.\n");
1283 fprintf(fd, "\" Otherwise use the special 'diffexpr' for Windows.\n");
1284 fprintf(fd, "if &diffopt !~# 'internal'\n");
1285 fprintf(fd, " set diffexpr=MyDiff()\n");
1286 fprintf(fd, "endif\n");
Bram Moolenaar071d4272004-06-13 20:20:40 +00001287 fprintf(fd, "function MyDiff()\n");
1288 fprintf(fd, " let opt = '-a --binary '\n");
1289 fprintf(fd, " if &diffopt =~ 'icase' | let opt = opt . '-i ' | endif\n");
1290 fprintf(fd, " if &diffopt =~ 'iwhite' | let opt = opt . '-b ' | endif\n");
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01001291 // Use quotes only when needed, they may cause trouble.
1292 // Always escape "!".
Bram Moolenaar071d4272004-06-13 20:20:40 +00001293 fprintf(fd, " let arg1 = v:fname_in\n");
1294 fprintf(fd, " if arg1 =~ ' ' | let arg1 = '\"' . arg1 . '\"' | endif\n");
Bram Moolenaar12365ce2018-05-13 14:45:25 +02001295 fprintf(fd, " let arg1 = substitute(arg1, '!', '\\!', 'g')\n");
Bram Moolenaar071d4272004-06-13 20:20:40 +00001296 fprintf(fd, " let arg2 = v:fname_new\n");
1297 fprintf(fd, " if arg2 =~ ' ' | let arg2 = '\"' . arg2 . '\"' | endif\n");
Bram Moolenaar12365ce2018-05-13 14:45:25 +02001298 fprintf(fd, " let arg2 = substitute(arg2, '!', '\\!', 'g')\n");
Bram Moolenaar071d4272004-06-13 20:20:40 +00001299 fprintf(fd, " let arg3 = v:fname_out\n");
1300 fprintf(fd, " if arg3 =~ ' ' | let arg3 = '\"' . arg3 . '\"' | endif\n");
Bram Moolenaar12365ce2018-05-13 14:45:25 +02001301 fprintf(fd, " let arg3 = substitute(arg3, '!', '\\!', 'g')\n");
Bram Moolenaar33aec762006-01-22 23:30:12 +00001302
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01001303 // If the path has a space: When using cmd.exe (Win NT/2000/XP) put
1304 // quotes around the diff command and rely on the default value of
1305 // shellxquote to solve the quoting problem for the whole command.
1306 //
1307 // Otherwise put a double quote just before the space and at the
1308 // end of the command. Putting quotes around the whole thing
1309 // doesn't work on Win 95/98/ME. This is mostly guessed!
Bram Moolenaar33aec762006-01-22 23:30:12 +00001310 fprintf(fd, " if $VIMRUNTIME =~ ' '\n");
1311 fprintf(fd, " if &sh =~ '\\<cmd'\n");
Bram Moolenaarc62a6442013-11-21 18:13:37 +01001312 fprintf(fd, " if empty(&shellxquote)\n");
1313 fprintf(fd, " let l:shxq_sav = ''\n");
1314 fprintf(fd, " set shellxquote&\n");
1315 fprintf(fd, " endif\n");
1316 fprintf(fd, " let cmd = '\"' . $VIMRUNTIME . '\\diff\"'\n");
Bram Moolenaar33aec762006-01-22 23:30:12 +00001317 fprintf(fd, " else\n");
1318 fprintf(fd, " let cmd = substitute($VIMRUNTIME, ' ', '\" ', '') . '\\diff\"'\n");
1319 fprintf(fd, " endif\n");
1320 fprintf(fd, " else\n");
1321 fprintf(fd, " let cmd = $VIMRUNTIME . '\\diff'\n");
1322 fprintf(fd, " endif\n");
Bram Moolenaar12365ce2018-05-13 14:45:25 +02001323 fprintf(fd, " let cmd = substitute(cmd, '!', '\\!', 'g')\n");
Bram Moolenaarc62a6442013-11-21 18:13:37 +01001324 fprintf(fd, " silent execute '!' . cmd . ' ' . opt . arg1 . ' ' . arg2 . ' > ' . arg3\n");
1325 fprintf(fd, " if exists('l:shxq_sav')\n");
1326 fprintf(fd, " let &shellxquote=l:shxq_sav\n");
1327 fprintf(fd, " endif\n");
Bram Moolenaar071d4272004-06-13 20:20:40 +00001328 fprintf(fd, "endfunction\n");
1329 fprintf(fd, "\n");
1330 }
1331 fclose(fd);
1332 printf("%s has been written\n", fname);
1333}
1334
1335 static void
1336change_vimrc_choice(int idx)
1337{
1338 if (choices[idx].installfunc != NULL)
1339 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01001340 // Switch to NOT change or create a vimrc file.
Bram Moolenaar071d4272004-06-13 20:20:40 +00001341 if (*oldvimrc != NUL)
1342 alloc_text(idx, "Do NOT change startup file %s", oldvimrc);
1343 else
1344 alloc_text(idx, "Do NOT create startup file %s", vimrc);
1345 choices[idx].installfunc = NULL;
1346 choices[idx + 1].active = 0;
1347 choices[idx + 2].active = 0;
1348 choices[idx + 3].active = 0;
1349 }
1350 else
1351 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01001352 // Switch to change or create a vimrc file.
Bram Moolenaar071d4272004-06-13 20:20:40 +00001353 if (*oldvimrc != NUL)
1354 alloc_text(idx, "Overwrite startup file %s with:", oldvimrc);
1355 else
1356 alloc_text(idx, "Create startup file %s with:", vimrc);
1357 choices[idx].installfunc = install_vimrc;
1358 choices[idx + 1].active = 1;
1359 choices[idx + 2].active = 1;
1360 choices[idx + 3].active = 1;
1361 }
1362}
1363
1364/*
1365 * Change the choice how to run Vim.
1366 */
1367 static void
1368change_run_choice(int idx)
1369{
1370 compat_choice = get_choice(compat_choices, TABLE_SIZE(compat_choices));
1371 alloc_text(idx, compat_text, compat_choices[compat_choice]);
1372}
1373
1374/*
1375 * Change the choice if keys are to be remapped.
1376 */
1377 static void
1378change_remap_choice(int idx)
1379{
1380 remap_choice = get_choice(remap_choices, TABLE_SIZE(remap_choices));
1381 alloc_text(idx, remap_text, remap_choices[remap_choice]);
1382}
1383
1384/*
1385 * Change the choice how to select text.
1386 */
1387 static void
1388change_mouse_choice(int idx)
1389{
1390 mouse_choice = get_choice(mouse_choices, TABLE_SIZE(mouse_choices));
1391 alloc_text(idx, mouse_text, mouse_choices[mouse_choice]);
1392}
1393
1394 static void
1395init_vimrc_choices(void)
1396{
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01001397 // set path for a new _vimrc file (also when not used)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001398 strcpy(vimrc, installdir);
1399 strcpy(vimrc + runtimeidx, "_vimrc");
1400
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01001401 // Set opposite value and then toggle it by calling change_vimrc_choice()
Bram Moolenaar071d4272004-06-13 20:20:40 +00001402 if (*oldvimrc == NUL)
1403 choices[choice_count].installfunc = NULL;
1404 else
1405 choices[choice_count].installfunc = install_vimrc;
1406 choices[choice_count].text = NULL;
1407 change_vimrc_choice(choice_count);
1408 choices[choice_count].changefunc = change_vimrc_choice;
1409 choices[choice_count].active = 1;
1410 ++choice_count;
1411
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01001412 // default way to run Vim
Bram Moolenaar071d4272004-06-13 20:20:40 +00001413 alloc_text(choice_count, compat_text, compat_choices[compat_choice]);
1414 choices[choice_count].changefunc = change_run_choice;
1415 choices[choice_count].installfunc = NULL;
1416 choices[choice_count].active = (*oldvimrc == NUL);
1417 ++choice_count;
1418
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01001419 // Whether to remap keys
Bram Moolenaar071d4272004-06-13 20:20:40 +00001420 alloc_text(choice_count, remap_text , remap_choices[remap_choice]);
1421 choices[choice_count].changefunc = change_remap_choice;
Bram Moolenaar945ec092016-06-08 21:17:43 +02001422 choices[choice_count].installfunc = NULL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001423 choices[choice_count].active = (*oldvimrc == NUL);
1424 ++choice_count;
1425
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01001426 // default way to use the mouse
Bram Moolenaar071d4272004-06-13 20:20:40 +00001427 alloc_text(choice_count, mouse_text, mouse_choices[mouse_choice]);
1428 choices[choice_count].changefunc = change_mouse_choice;
Bram Moolenaar945ec092016-06-08 21:17:43 +02001429 choices[choice_count].installfunc = NULL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001430 choices[choice_count].active = (*oldvimrc == NUL);
1431 ++choice_count;
1432}
1433
Bram Moolenaarccd9ccf2010-07-07 13:19:55 +02001434 static LONG
1435reg_create_key(
1436 HKEY root,
1437 const char *subkey,
Bram Moolenaar6199d432017-10-14 19:05:44 +02001438 PHKEY phKey,
1439 DWORD flag)
Bram Moolenaarccd9ccf2010-07-07 13:19:55 +02001440{
1441 DWORD disp;
1442
1443 *phKey = NULL;
1444 return RegCreateKeyEx(
Bram Moolenaarcc448b32010-07-14 16:52:17 +02001445 root, subkey,
1446 0, NULL, REG_OPTION_NON_VOLATILE,
Bram Moolenaar6199d432017-10-14 19:05:44 +02001447 flag | KEY_WRITE,
Bram Moolenaarcc448b32010-07-14 16:52:17 +02001448 NULL, phKey, &disp);
Bram Moolenaarccd9ccf2010-07-07 13:19:55 +02001449}
1450
1451 static LONG
1452reg_set_string_value(
1453 HKEY hKey,
1454 const char *value_name,
1455 const char *data)
1456{
1457 return RegSetValueEx(hKey, value_name, 0, REG_SZ,
1458 (LPBYTE)data, (DWORD)(1 + strlen(data)));
1459}
1460
1461 static LONG
1462reg_create_key_and_value(
1463 HKEY hRootKey,
1464 const char *subkey,
1465 const char *value_name,
Bram Moolenaar6199d432017-10-14 19:05:44 +02001466 const char *data,
1467 DWORD flag)
Bram Moolenaarccd9ccf2010-07-07 13:19:55 +02001468{
1469 HKEY hKey;
Bram Moolenaar6199d432017-10-14 19:05:44 +02001470 LONG lRet = reg_create_key(hRootKey, subkey, &hKey, flag);
Bram Moolenaarccd9ccf2010-07-07 13:19:55 +02001471
1472 if (ERROR_SUCCESS == lRet)
1473 {
Bram Moolenaarcc448b32010-07-14 16:52:17 +02001474 lRet = reg_set_string_value(hKey, value_name, data);
1475 RegCloseKey(hKey);
Bram Moolenaarccd9ccf2010-07-07 13:19:55 +02001476 }
1477 return lRet;
1478}
1479
1480 static LONG
1481register_inproc_server(
1482 HKEY hRootKey,
1483 const char *clsid,
1484 const char *extname,
1485 const char *module,
Bram Moolenaar6199d432017-10-14 19:05:44 +02001486 const char *threading_model,
1487 DWORD flag)
Bram Moolenaarccd9ccf2010-07-07 13:19:55 +02001488{
1489 CHAR subkey[BUFSIZE];
1490 LONG lRet;
1491
1492 sprintf(subkey, "CLSID\\%s", clsid);
Bram Moolenaar6199d432017-10-14 19:05:44 +02001493 lRet = reg_create_key_and_value(hRootKey, subkey, NULL, extname, flag);
Bram Moolenaarccd9ccf2010-07-07 13:19:55 +02001494 if (ERROR_SUCCESS == lRet)
1495 {
Bram Moolenaarcc448b32010-07-14 16:52:17 +02001496 sprintf(subkey, "CLSID\\%s\\InProcServer32", clsid);
Bram Moolenaar6199d432017-10-14 19:05:44 +02001497 lRet = reg_create_key_and_value(hRootKey, subkey, NULL, module, flag);
Bram Moolenaarcc448b32010-07-14 16:52:17 +02001498 if (ERROR_SUCCESS == lRet)
1499 {
1500 lRet = reg_create_key_and_value(hRootKey, subkey,
Bram Moolenaar6199d432017-10-14 19:05:44 +02001501 "ThreadingModel", threading_model, flag);
Bram Moolenaarcc448b32010-07-14 16:52:17 +02001502 }
Bram Moolenaarccd9ccf2010-07-07 13:19:55 +02001503 }
1504 return lRet;
1505}
1506
1507 static LONG
1508register_shellex(
1509 HKEY hRootKey,
1510 const char *clsid,
1511 const char *name,
Bram Moolenaar6199d432017-10-14 19:05:44 +02001512 const char *exe_path,
1513 DWORD flag)
Bram Moolenaarccd9ccf2010-07-07 13:19:55 +02001514{
1515 LONG lRet = reg_create_key_and_value(
Bram Moolenaarcc448b32010-07-14 16:52:17 +02001516 hRootKey,
1517 "*\\shellex\\ContextMenuHandlers\\gvim",
1518 NULL,
Bram Moolenaar6199d432017-10-14 19:05:44 +02001519 clsid,
1520 flag);
Bram Moolenaarccd9ccf2010-07-07 13:19:55 +02001521
1522 if (ERROR_SUCCESS == lRet)
1523 {
Bram Moolenaarcc448b32010-07-14 16:52:17 +02001524 lRet = reg_create_key_and_value(
1525 HKEY_LOCAL_MACHINE,
1526 "Software\\Microsoft\\Windows\\CurrentVersion\\Shell Extensions\\Approved",
1527 clsid,
Bram Moolenaar6199d432017-10-14 19:05:44 +02001528 name,
1529 flag);
Bram Moolenaarccd9ccf2010-07-07 13:19:55 +02001530
Bram Moolenaarcc448b32010-07-14 16:52:17 +02001531 if (ERROR_SUCCESS == lRet)
1532 {
1533 lRet = reg_create_key_and_value(
1534 HKEY_LOCAL_MACHINE,
1535 "Software\\Vim\\Gvim",
1536 "path",
Bram Moolenaar6199d432017-10-14 19:05:44 +02001537 exe_path,
1538 flag);
Bram Moolenaarcc448b32010-07-14 16:52:17 +02001539 }
Bram Moolenaarccd9ccf2010-07-07 13:19:55 +02001540 }
1541 return lRet;
1542}
1543
1544 static LONG
1545register_openwith(
1546 HKEY hRootKey,
Bram Moolenaar6199d432017-10-14 19:05:44 +02001547 const char *exe_path,
1548 DWORD flag)
Bram Moolenaarccd9ccf2010-07-07 13:19:55 +02001549{
Bram Moolenaar78050042010-07-31 20:53:54 +02001550 char exe_cmd[BUFSIZE];
1551 LONG lRet;
1552
Bram Moolenaarbbdcb482010-08-02 20:45:27 +02001553 sprintf(exe_cmd, "\"%s\" \"%%1\"", exe_path);
Bram Moolenaar78050042010-07-31 20:53:54 +02001554 lRet = reg_create_key_and_value(
Bram Moolenaarcc448b32010-07-14 16:52:17 +02001555 hRootKey,
1556 "Applications\\gvim.exe\\shell\\edit\\command",
1557 NULL,
Bram Moolenaar6199d432017-10-14 19:05:44 +02001558 exe_cmd,
1559 flag);
Bram Moolenaarccd9ccf2010-07-07 13:19:55 +02001560
1561 if (ERROR_SUCCESS == lRet)
1562 {
Bram Moolenaarcc448b32010-07-14 16:52:17 +02001563 int i;
1564 static const char *openwith[] = {
1565 ".htm\\OpenWithList\\gvim.exe",
1566 ".vim\\OpenWithList\\gvim.exe",
1567 "*\\OpenWithList\\gvim.exe",
1568 };
Bram Moolenaarccd9ccf2010-07-07 13:19:55 +02001569
Bram Moolenaarcc448b32010-07-14 16:52:17 +02001570 for (i = 0; ERROR_SUCCESS == lRet
Bram Moolenaarccd9ccf2010-07-07 13:19:55 +02001571 && i < sizeof(openwith) / sizeof(openwith[0]); i++)
Bram Moolenaar6199d432017-10-14 19:05:44 +02001572 lRet = reg_create_key_and_value(hRootKey, openwith[i], NULL, "", flag);
Bram Moolenaarccd9ccf2010-07-07 13:19:55 +02001573 }
1574
1575 return lRet;
1576}
1577
1578 static LONG
1579register_uninstall(
1580 HKEY hRootKey,
1581 const char *appname,
1582 const char *display_name,
Bram Moolenaar6cdb2c92018-10-13 17:25:27 +02001583 const char *uninstall_string,
1584 const char *display_icon,
1585 const char *display_version,
1586 const char *publisher)
Bram Moolenaarccd9ccf2010-07-07 13:19:55 +02001587{
1588 LONG lRet = reg_create_key_and_value(hRootKey, appname,
Bram Moolenaar6199d432017-10-14 19:05:44 +02001589 "DisplayName", display_name, KEY_WOW64_64KEY);
Bram Moolenaarccd9ccf2010-07-07 13:19:55 +02001590
1591 if (ERROR_SUCCESS == lRet)
Bram Moolenaarcc448b32010-07-14 16:52:17 +02001592 lRet = reg_create_key_and_value(hRootKey, appname,
Bram Moolenaar6199d432017-10-14 19:05:44 +02001593 "UninstallString", uninstall_string, KEY_WOW64_64KEY);
Bram Moolenaar6cdb2c92018-10-13 17:25:27 +02001594 if (ERROR_SUCCESS == lRet)
1595 lRet = reg_create_key_and_value(hRootKey, appname,
1596 "DisplayIcon", display_icon, KEY_WOW64_64KEY);
1597 if (ERROR_SUCCESS == lRet)
1598 lRet = reg_create_key_and_value(hRootKey, appname,
1599 "DisplayVersion", display_version, KEY_WOW64_64KEY);
1600 if (ERROR_SUCCESS == lRet)
1601 lRet = reg_create_key_and_value(hRootKey, appname,
1602 "Publisher", publisher, KEY_WOW64_64KEY);
Bram Moolenaarccd9ccf2010-07-07 13:19:55 +02001603 return lRet;
1604}
Bram Moolenaarccd9ccf2010-07-07 13:19:55 +02001605
Bram Moolenaar071d4272004-06-13 20:20:40 +00001606/*
1607 * Add some entries to the registry:
1608 * - to add "Edit with Vim" to the context * menu
1609 * - to add Vim to the "Open with..." list
1610 * - to uninstall Vim
1611 */
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01001612//ARGSUSED
Bram Moolenaarab8205e2010-07-07 15:14:03 +02001613 static int
Bram Moolenaar071d4272004-06-13 20:20:40 +00001614install_registry(void)
1615{
Bram Moolenaarcc448b32010-07-14 16:52:17 +02001616 LONG lRet = ERROR_SUCCESS;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001617 const char *vim_ext_ThreadingModel = "Apartment";
1618 const char *vim_ext_name = "Vim Shell Extension";
1619 const char *vim_ext_clsid = "{51EEE242-AD87-11d3-9C1E-0090278BBD99}";
Bram Moolenaarbbd854d2019-02-18 22:19:33 +01001620 char vim_exe_path[MAX_PATH];
Bram Moolenaarcc448b32010-07-14 16:52:17 +02001621 char display_name[BUFSIZE];
1622 char uninstall_string[BUFSIZE];
Bram Moolenaar6cdb2c92018-10-13 17:25:27 +02001623 char icon_string[BUFSIZE];
Bram Moolenaar6199d432017-10-14 19:05:44 +02001624 int i;
1625 int loop_count = is_64bit_os() ? 2 : 1;
1626 DWORD flag;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001627
Bram Moolenaarccd9ccf2010-07-07 13:19:55 +02001628 sprintf(vim_exe_path, "%s\\gvim.exe", installdir);
1629
1630 if (install_popup)
1631 {
Bram Moolenaarcc448b32010-07-14 16:52:17 +02001632 char bufg[BUFSIZE];
Bram Moolenaarccd9ccf2010-07-07 13:19:55 +02001633
Bram Moolenaarcc448b32010-07-14 16:52:17 +02001634 printf("Creating \"Edit with Vim\" popup menu entry\n");
Bram Moolenaarccd9ccf2010-07-07 13:19:55 +02001635
Bram Moolenaar6199d432017-10-14 19:05:44 +02001636 for (i = 0; i < loop_count; i++)
1637 {
1638 if (i == 0)
1639 {
1640 sprintf(bufg, "%s\\" GVIMEXT32_PATH, installdir);
1641 flag = KEY_WOW64_32KEY;
1642 }
1643 else
1644 {
1645 sprintf(bufg, "%s\\" GVIMEXT64_PATH, installdir);
1646 flag = KEY_WOW64_64KEY;
1647 }
1648
1649 lRet = register_inproc_server(
1650 HKEY_CLASSES_ROOT, vim_ext_clsid, vim_ext_name,
1651 bufg, vim_ext_ThreadingModel, flag);
1652 if (ERROR_SUCCESS != lRet)
1653 return FAIL;
1654 lRet = register_shellex(
1655 HKEY_CLASSES_ROOT, vim_ext_clsid, vim_ext_name,
1656 vim_exe_path, flag);
1657 if (ERROR_SUCCESS != lRet)
1658 return FAIL;
1659 }
Bram Moolenaarccd9ccf2010-07-07 13:19:55 +02001660 }
1661
1662 if (install_openwith)
1663 {
Bram Moolenaarcc448b32010-07-14 16:52:17 +02001664 printf("Creating \"Open with ...\" list entry\n");
Bram Moolenaarccd9ccf2010-07-07 13:19:55 +02001665
Bram Moolenaar6199d432017-10-14 19:05:44 +02001666 for (i = 0; i < loop_count; i++)
1667 {
1668 if (i == 0)
1669 flag = KEY_WOW64_32KEY;
1670 else
1671 flag = KEY_WOW64_64KEY;
1672
1673 lRet = register_openwith(HKEY_CLASSES_ROOT, vim_exe_path, flag);
1674 if (ERROR_SUCCESS != lRet)
1675 return FAIL;
1676 }
Bram Moolenaarccd9ccf2010-07-07 13:19:55 +02001677 }
1678
1679 printf("Creating an uninstall entry\n");
Bram Moolenaaraf610b82018-12-21 16:22:50 +01001680 sprintf(display_name, "Vim " VIM_VERSION_SHORT
Bram Moolenaar577fadf2019-04-04 20:32:24 +02001681#ifdef _M_ARM64
1682 " (arm64)"
1683#elif _M_X64
Bram Moolenaaraf610b82018-12-21 16:22:50 +01001684 " (x64)"
1685#endif
1686 );
Bram Moolenaarccd9ccf2010-07-07 13:19:55 +02001687
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01001688 // For the NSIS installer use the generated uninstaller.
Bram Moolenaarccd9ccf2010-07-07 13:19:55 +02001689 if (interactive)
Bram Moolenaar30e8e732019-09-27 13:08:36 +02001690 sprintf(uninstall_string, "%s\\uninstall.exe", installdir);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001691 else
Bram Moolenaar16d79a32010-07-18 22:33:56 +02001692 sprintf(uninstall_string, "%s\\uninstall-gui.exe", installdir);
Bram Moolenaarccd9ccf2010-07-07 13:19:55 +02001693
Bram Moolenaar6cdb2c92018-10-13 17:25:27 +02001694 sprintf(icon_string, "%s\\gvim.exe,0", installdir);
1695
Bram Moolenaarccd9ccf2010-07-07 13:19:55 +02001696 lRet = register_uninstall(
Bram Moolenaarcc448b32010-07-14 16:52:17 +02001697 HKEY_LOCAL_MACHINE,
1698 "Software\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\Vim " VIM_VERSION_SHORT,
1699 display_name,
Bram Moolenaar6cdb2c92018-10-13 17:25:27 +02001700 uninstall_string,
1701 icon_string,
1702 VIM_VERSION_SHORT,
1703 "Bram Moolenaar et al.");
Bram Moolenaarab8205e2010-07-07 15:14:03 +02001704 if (ERROR_SUCCESS != lRet)
1705 return FAIL;
Bram Moolenaarccd9ccf2010-07-07 13:19:55 +02001706
Bram Moolenaarab8205e2010-07-07 15:14:03 +02001707 return OK;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001708}
1709
1710 static void
1711change_popup_choice(int idx)
1712{
1713 if (install_popup == 0)
1714 {
1715 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";
1716 install_popup = 1;
1717 }
1718 else
1719 {
1720 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";
1721 install_popup = 0;
1722 }
1723}
1724
1725/*
1726 * Only add the choice for the popup menu entry when gvim.exe was found and
1727 * both gvimext.dll and regedit.exe exist.
1728 */
1729 static void
1730init_popup_choice(void)
1731{
1732 struct stat st;
1733
1734 if (has_gvim
Bram Moolenaar6199d432017-10-14 19:05:44 +02001735 && (stat(GVIMEXT32_PATH, &st) >= 0
1736 || stat(GVIMEXT64_PATH, &st) >= 0))
Bram Moolenaar071d4272004-06-13 20:20:40 +00001737 {
1738 choices[choice_count].changefunc = change_popup_choice;
1739 choices[choice_count].installfunc = NULL;
1740 choices[choice_count].active = 1;
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01001741 change_popup_choice(choice_count); // set the text
Bram Moolenaar071d4272004-06-13 20:20:40 +00001742 ++choice_count;
1743 }
1744 else
1745 add_dummy_choice();
1746}
1747
1748 static void
1749change_openwith_choice(int idx)
1750{
1751 if (install_openwith == 0)
1752 {
1753 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";
1754 install_openwith = 1;
1755 }
1756 else
1757 {
1758 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";
1759 install_openwith = 0;
1760 }
1761}
1762
1763/*
1764 * Only add the choice for the open-with menu entry when gvim.exe was found
Bram Moolenaar84a05ac2013-05-06 04:24:17 +02001765 * and regedit.exe exist.
Bram Moolenaar071d4272004-06-13 20:20:40 +00001766 */
1767 static void
1768init_openwith_choice(void)
1769{
Bram Moolenaar6199d432017-10-14 19:05:44 +02001770 if (has_gvim)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001771 {
1772 choices[choice_count].changefunc = change_openwith_choice;
1773 choices[choice_count].installfunc = NULL;
1774 choices[choice_count].active = 1;
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01001775 change_openwith_choice(choice_count); // set the text
Bram Moolenaar071d4272004-06-13 20:20:40 +00001776 ++choice_count;
1777 }
1778 else
1779 add_dummy_choice();
1780}
1781
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01001782/*
Bram Moolenaar071d4272004-06-13 20:20:40 +00001783 * Create a shell link.
1784 *
1785 * returns 0 on failure, non-zero on successful completion.
1786 *
1787 * NOTE: Currently untested with mingw.
1788 */
1789 int
1790create_shortcut(
1791 const char *shortcut_name,
1792 const char *iconfile_path,
1793 int iconindex,
1794 const char *shortcut_target,
1795 const char *shortcut_args,
1796 const char *workingdir
1797 )
1798{
1799 IShellLink *shelllink_ptr;
1800 HRESULT hres;
1801 IPersistFile *persistfile_ptr;
1802
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01001803 // Initialize COM library
Bram Moolenaar071d4272004-06-13 20:20:40 +00001804 hres = CoInitialize(NULL);
1805 if (!SUCCEEDED(hres))
1806 {
1807 printf("Error: Could not open the COM library. Not creating shortcut.\n");
1808 return FAIL;
1809 }
1810
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01001811 // Instantiate a COM object for the ShellLink, store a pointer to it
1812 // in shelllink_ptr.
Bram Moolenaar071d4272004-06-13 20:20:40 +00001813 hres = CoCreateInstance(&CLSID_ShellLink,
1814 NULL,
1815 CLSCTX_INPROC_SERVER,
1816 &IID_IShellLink,
1817 (void **) &shelllink_ptr);
1818
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01001819 if (SUCCEEDED(hres)) // If the instantiation was successful...
Bram Moolenaar071d4272004-06-13 20:20:40 +00001820 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01001821 // ...Then build a PersistFile interface for the ShellLink so we can
1822 // save it as a file after we build it.
Bram Moolenaar071d4272004-06-13 20:20:40 +00001823 hres = shelllink_ptr->lpVtbl->QueryInterface(shelllink_ptr,
1824 &IID_IPersistFile, (void **) &persistfile_ptr);
1825
1826 if (SUCCEEDED(hres))
1827 {
1828 wchar_t wsz[BUFSIZE];
1829
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01001830 // translate the (possibly) multibyte shortcut filename to windows
1831 // Unicode so it can be used as a file name.
Bram Moolenaare4963c52019-02-22 19:41:08 +01001832 MultiByteToWideChar(CP_ACP, 0, shortcut_name, -1, wsz, sizeof(wsz)/sizeof(wsz[0]));
Bram Moolenaar071d4272004-06-13 20:20:40 +00001833
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01001834 // set the attributes
Bram Moolenaar071d4272004-06-13 20:20:40 +00001835 shelllink_ptr->lpVtbl->SetPath(shelllink_ptr, shortcut_target);
1836 shelllink_ptr->lpVtbl->SetWorkingDirectory(shelllink_ptr,
1837 workingdir);
1838 shelllink_ptr->lpVtbl->SetIconLocation(shelllink_ptr,
1839 iconfile_path, iconindex);
1840 shelllink_ptr->lpVtbl->SetArguments(shelllink_ptr, shortcut_args);
1841
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01001842 // save the shortcut to a file and return the PersistFile object
Bram Moolenaar071d4272004-06-13 20:20:40 +00001843 persistfile_ptr->lpVtbl->Save(persistfile_ptr, wsz, 1);
1844 persistfile_ptr->lpVtbl->Release(persistfile_ptr);
1845 }
1846 else
1847 {
1848 printf("QueryInterface Error\n");
1849 return FAIL;
1850 }
1851
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01001852 // Return the ShellLink object
Bram Moolenaar071d4272004-06-13 20:20:40 +00001853 shelllink_ptr->lpVtbl->Release(shelllink_ptr);
1854 }
1855 else
1856 {
1857 printf("CoCreateInstance Error - hres = %08x\n", (int)hres);
1858 return FAIL;
1859 }
1860
1861 return OK;
1862}
1863
1864/*
1865 * Build a path to where we will put a specified link.
1866 *
1867 * Return 0 on error, non-zero on success
1868 */
1869 int
1870build_link_name(
1871 char *link_path,
1872 const char *link_name,
1873 const char *shell_folder_name)
1874{
Bram Moolenaarbbd854d2019-02-18 22:19:33 +01001875 char shell_folder_path[MAX_PATH];
Bram Moolenaar071d4272004-06-13 20:20:40 +00001876
1877 if (get_shell_folder_path(shell_folder_path, shell_folder_name) == FAIL)
1878 {
1879 printf("An error occurred while attempting to find the path to %s.\n",
1880 shell_folder_name);
1881 return FAIL;
1882 }
1883
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01001884 // Make sure the directory exists (create Start Menu\Programs\Vim).
1885 // Ignore errors if it already exists.
Bram Moolenaar071d4272004-06-13 20:20:40 +00001886 vim_mkdir(shell_folder_path, 0755);
1887
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01001888 // build the path to the shortcut and the path to gvim.exe
Bram Moolenaar071d4272004-06-13 20:20:40 +00001889 sprintf(link_path, "%s\\%s.lnk", shell_folder_path, link_name);
1890
1891 return OK;
1892}
1893
1894 static int
1895build_shortcut(
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01001896 const char *name, // Name of the shortcut
1897 const char *exename, // Name of the executable (e.g., vim.exe)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001898 const char *args,
1899 const char *shell_folder,
1900 const char *workingdir)
1901{
1902 char executable_path[BUFSIZE];
1903 char link_name[BUFSIZE];
1904
1905 sprintf(executable_path, "%s\\%s", installdir, exename);
1906
1907 if (build_link_name(link_name, name, shell_folder) == FAIL)
1908 {
1909 printf("An error has occurred. A shortcut to %s will not be created %s.\n",
1910 name,
1911 *shell_folder == 'd' ? "on the desktop" : "in the Start menu");
1912 return FAIL;
1913 }
1914
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01001915 // Create the shortcut:
Bram Moolenaar071d4272004-06-13 20:20:40 +00001916 return create_shortcut(link_name, executable_path, 0,
1917 executable_path, args, workingdir);
1918}
1919
1920/*
1921 * We used to use "homedir" as the working directory, but that is a bad choice
Bram Moolenaar03e228a2013-11-07 04:49:27 +01001922 * on multi-user systems. However, not specifying a directory results in the
1923 * current directory to be c:\Windows\system32 on Windows 7. Use environment
1924 * variables instead.
Bram Moolenaar071d4272004-06-13 20:20:40 +00001925 */
Bram Moolenaar03e228a2013-11-07 04:49:27 +01001926#define WORKDIR "%HOMEDRIVE%%HOMEPATH%"
Bram Moolenaar071d4272004-06-13 20:20:40 +00001927
1928/*
1929 * Create shortcut(s) in the Start Menu\Programs\Vim folder.
1930 */
1931 static void
1932install_start_menu(int idx)
1933{
1934 need_uninstall_entry = 1;
1935 printf("Creating start menu\n");
1936 if (has_vim)
1937 {
1938 if (build_shortcut("Vim", "vim.exe", "",
1939 VIM_STARTMENU, WORKDIR) == FAIL)
1940 return;
1941 if (build_shortcut("Vim Read-only", "vim.exe", "-R",
1942 VIM_STARTMENU, WORKDIR) == FAIL)
1943 return;
1944 if (build_shortcut("Vim Diff", "vim.exe", "-d",
1945 VIM_STARTMENU, WORKDIR) == FAIL)
1946 return;
1947 }
1948 if (has_gvim)
1949 {
1950 if (build_shortcut("gVim", "gvim.exe", "",
1951 VIM_STARTMENU, WORKDIR) == FAIL)
1952 return;
1953 if (build_shortcut("gVim Easy", "gvim.exe", "-y",
1954 VIM_STARTMENU, WORKDIR) == FAIL)
1955 return;
1956 if (build_shortcut("gVim Read-only", "gvim.exe", "-R",
1957 VIM_STARTMENU, WORKDIR) == FAIL)
1958 return;
1959 if (build_shortcut("gVim Diff", "gvim.exe", "-d",
1960 VIM_STARTMENU, WORKDIR) == FAIL)
1961 return;
1962 }
1963 if (build_shortcut("Uninstall",
Bram Moolenaar30e8e732019-09-27 13:08:36 +02001964 interactive ? "uninstall.exe" : "uninstall-gui.exe", "",
Bram Moolenaar071d4272004-06-13 20:20:40 +00001965 VIM_STARTMENU, installdir) == FAIL)
1966 return;
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01001967 // For Windows NT the working dir of the vimtutor.bat must be right,
1968 // otherwise gvim.exe won't be found and using gvimbat doesn't work.
Bram Moolenaar071d4272004-06-13 20:20:40 +00001969 if (build_shortcut("Vim tutor", "vimtutor.bat", "",
1970 VIM_STARTMENU, installdir) == FAIL)
1971 return;
1972 if (build_shortcut("Help", has_gvim ? "gvim.exe" : "vim.exe", "-c h",
1973 VIM_STARTMENU, WORKDIR) == FAIL)
1974 return;
1975 {
1976 char shell_folder_path[BUFSIZE];
1977
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01001978 // Creating the URL shortcut works a bit differently...
Bram Moolenaar071d4272004-06-13 20:20:40 +00001979 if (get_shell_folder_path(shell_folder_path, VIM_STARTMENU) == FAIL)
1980 {
1981 printf("Finding the path of the Start menu failed\n");
1982 return ;
1983 }
1984 add_pathsep(shell_folder_path);
1985 strcat(shell_folder_path, "Vim Online.url");
1986 if (!WritePrivateProfileString("InternetShortcut", "URL",
Bram Moolenaarbd87eb32018-06-26 23:18:45 +02001987 "https://www.vim.org/", shell_folder_path))
Bram Moolenaar071d4272004-06-13 20:20:40 +00001988 {
1989 printf("Creating the Vim online URL failed\n");
1990 return;
1991 }
1992 }
1993}
1994
1995 static void
1996toggle_startmenu_choice(int idx)
1997{
1998 if (choices[idx].installfunc == NULL)
1999 {
2000 choices[idx].installfunc = install_start_menu;
2001 choices[idx].text = "Add Vim to the Start menu";
2002 }
2003 else
2004 {
2005 choices[idx].installfunc = NULL;
2006 choices[idx].text = "Do NOT add Vim to the Start menu";
2007 }
2008}
2009
2010/*
2011 * Function to actually create the shortcuts
2012 *
2013 * Currently I am supplying no working directory to the shortcut. This
2014 * means that the initial working dir will be:
2015 * - the location of the shortcut if no file is supplied
2016 * - the location of the file being edited if a file is supplied (ie via
2017 * drag and drop onto the shortcut).
2018 */
2019 void
2020install_shortcut_gvim(int idx)
2021{
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002022 // Create shortcut(s) on the desktop
Bram Moolenaar071d4272004-06-13 20:20:40 +00002023 if (choices[idx].arg)
2024 {
2025 (void)build_shortcut(icon_names[0], "gvim.exe",
2026 "", "desktop", WORKDIR);
2027 need_uninstall_entry = 1;
2028 }
2029}
2030
2031 void
2032install_shortcut_evim(int idx)
2033{
2034 if (choices[idx].arg)
2035 {
2036 (void)build_shortcut(icon_names[1], "gvim.exe",
2037 "-y", "desktop", WORKDIR);
2038 need_uninstall_entry = 1;
2039 }
2040}
2041
2042 void
2043install_shortcut_gview(int idx)
2044{
2045 if (choices[idx].arg)
2046 {
2047 (void)build_shortcut(icon_names[2], "gvim.exe",
2048 "-R", "desktop", WORKDIR);
2049 need_uninstall_entry = 1;
2050 }
2051}
2052
2053 void
2054toggle_shortcut_choice(int idx)
2055{
2056 char *arg;
2057
2058 if (choices[idx].installfunc == install_shortcut_gvim)
2059 arg = "gVim";
2060 else if (choices[idx].installfunc == install_shortcut_evim)
2061 arg = "gVim Easy";
2062 else
2063 arg = "gVim Read-only";
2064 if (choices[idx].arg)
2065 {
2066 choices[idx].arg = 0;
2067 alloc_text(idx, "Do NOT create a desktop icon for %s", arg);
2068 }
2069 else
2070 {
2071 choices[idx].arg = 1;
2072 alloc_text(idx, "Create a desktop icon for %s", arg);
2073 }
2074}
Bram Moolenaar071d4272004-06-13 20:20:40 +00002075
2076 static void
2077init_startmenu_choice(void)
2078{
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002079 // Start menu
Bram Moolenaar071d4272004-06-13 20:20:40 +00002080 choices[choice_count].changefunc = toggle_startmenu_choice;
2081 choices[choice_count].installfunc = NULL;
2082 choices[choice_count].active = 1;
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002083 toggle_startmenu_choice(choice_count); // set the text
Bram Moolenaar071d4272004-06-13 20:20:40 +00002084 ++choice_count;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002085}
2086
2087/*
2088 * Add the choice for the desktop shortcuts.
2089 */
2090 static void
2091init_shortcut_choices(void)
2092{
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002093 // Shortcut to gvim
Bram Moolenaar071d4272004-06-13 20:20:40 +00002094 choices[choice_count].text = NULL;
2095 choices[choice_count].arg = 0;
2096 choices[choice_count].active = has_gvim;
2097 choices[choice_count].changefunc = toggle_shortcut_choice;
2098 choices[choice_count].installfunc = install_shortcut_gvim;
2099 toggle_shortcut_choice(choice_count);
2100 ++choice_count;
2101
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002102 // Shortcut to evim
Bram Moolenaar071d4272004-06-13 20:20:40 +00002103 choices[choice_count].text = NULL;
2104 choices[choice_count].arg = 0;
2105 choices[choice_count].active = has_gvim;
2106 choices[choice_count].changefunc = toggle_shortcut_choice;
2107 choices[choice_count].installfunc = install_shortcut_evim;
2108 toggle_shortcut_choice(choice_count);
2109 ++choice_count;
2110
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002111 // Shortcut to gview
Bram Moolenaar071d4272004-06-13 20:20:40 +00002112 choices[choice_count].text = NULL;
2113 choices[choice_count].arg = 0;
2114 choices[choice_count].active = has_gvim;
2115 choices[choice_count].changefunc = toggle_shortcut_choice;
2116 choices[choice_count].installfunc = install_shortcut_gview;
2117 toggle_shortcut_choice(choice_count);
2118 ++choice_count;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002119}
2120
Bram Moolenaar071d4272004-06-13 20:20:40 +00002121/*
2122 * Attempt to register OLE for Vim.
2123 */
2124 static void
2125install_OLE_register(void)
2126{
2127 char register_command_string[BUFSIZE + 30];
2128
2129 printf("\n--- Attempting to register Vim with OLE ---\n");
2130 printf("(There is no message whether this works or not.)\n");
2131
Bram Moolenaar071d4272004-06-13 20:20:40 +00002132 sprintf(register_command_string, "\"%s\\gvim.exe\" -silent -register", installdir);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002133 system(register_command_string);
2134}
Bram Moolenaar071d4272004-06-13 20:20:40 +00002135
2136/*
2137 * Remove the last part of directory "path[]" to get its parent, and put the
2138 * result in "to[]".
2139 */
2140 static void
Bram Moolenaare4963c52019-02-22 19:41:08 +01002141dir_remove_last(const char *path, char to[MAX_PATH])
Bram Moolenaar071d4272004-06-13 20:20:40 +00002142{
2143 char c;
2144 long last_char_to_copy;
2145 long path_length = strlen(path);
2146
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002147 // skip the last character just in case it is a '\\'
Bram Moolenaar071d4272004-06-13 20:20:40 +00002148 last_char_to_copy = path_length - 2;
2149 c = path[last_char_to_copy];
2150
2151 while (c != '\\')
2152 {
2153 last_char_to_copy--;
2154 c = path[last_char_to_copy];
2155 }
2156
2157 strncpy(to, path, (size_t)last_char_to_copy);
2158 to[last_char_to_copy] = NUL;
2159}
2160
2161 static void
2162set_directories_text(int idx)
2163{
Bram Moolenaar25a494c2018-11-16 19:39:50 +01002164 int vimfiles_dir_choice = choices[idx].arg;
2165
Bram Moolenaar071d4272004-06-13 20:20:40 +00002166 if (vimfiles_dir_choice == (int)vimfiles_dir_none)
2167 alloc_text(idx, "Do NOT create plugin directories%s", "");
2168 else
2169 alloc_text(idx, "Create plugin directories: %s",
2170 vimfiles_dir_choices[vimfiles_dir_choice]);
2171}
2172
2173/*
Bram Moolenaar25a494c2018-11-16 19:39:50 +01002174 * To get the "real" home directory:
2175 * - get value of $HOME
2176 * - if not found, get value of $HOMEDRIVE$HOMEPATH
2177 * - if not found, get value of $USERPROFILE
2178 *
2179 * This code is based on init_homedir() in misc1.c, keep in sync!
2180 */
2181static char *homedir = NULL;
2182
2183 void
2184init_homedir(void)
2185{
2186 char *var;
2187 char buf[MAX_PATH];
2188
2189 if (homedir != NULL)
2190 {
2191 free(homedir);
2192 homedir = NULL;
2193 }
2194
2195 var = getenv("HOME");
2196
2197 /*
2198 * Typically, $HOME is not defined on Windows, unless the user has
2199 * specifically defined it for Vim's sake. However, on Windows NT
2200 * platforms, $HOMEDRIVE and $HOMEPATH are automatically defined for
2201 * each user. Try constructing $HOME from these.
2202 */
2203 if (var == NULL || *var == NUL)
2204 {
2205 char *homedrive, *homepath;
2206
2207 homedrive = getenv("HOMEDRIVE");
2208 homepath = getenv("HOMEPATH");
2209 if (homepath == NULL || *homepath == NUL)
2210 homepath = "\\";
2211 if (homedrive != NULL
Bram Moolenaare4963c52019-02-22 19:41:08 +01002212 && strlen(homedrive) + strlen(homepath) < sizeof(buf))
Bram Moolenaar25a494c2018-11-16 19:39:50 +01002213 {
2214 sprintf(buf, "%s%s", homedrive, homepath);
2215 if (buf[0] != NUL)
2216 var = buf;
2217 }
2218 }
2219
2220 if (var == NULL)
2221 var = getenv("USERPROFILE");
2222
2223 /*
2224 * Weird but true: $HOME may contain an indirect reference to another
2225 * variable, esp. "%USERPROFILE%". Happens when $USERPROFILE isn't set
2226 * when $HOME is being set.
2227 */
2228 if (var != NULL && *var == '%')
2229 {
2230 char *p;
2231 char *exp;
2232
2233 p = strchr(var + 1, '%');
2234 if (p != NULL)
2235 {
2236 strncpy(buf, var + 1, p - (var + 1));
2237 buf[p - (var + 1)] = NUL;
2238 exp = getenv(buf);
2239 if (exp != NULL && *exp != NUL
Bram Moolenaare4963c52019-02-22 19:41:08 +01002240 && strlen(exp) + strlen(p) < sizeof(buf))
Bram Moolenaar25a494c2018-11-16 19:39:50 +01002241 {
Bram Moolenaare4963c52019-02-22 19:41:08 +01002242 sprintf(buf, "%s%s", exp, p + 1);
Bram Moolenaar25a494c2018-11-16 19:39:50 +01002243 var = buf;
2244 }
2245 }
2246 }
2247
2248 if (var != NULL && *var == NUL) // empty is same as not set
2249 var = NULL;
2250
2251 if (var == NULL)
2252 homedir = NULL;
2253 else
2254 homedir = _strdup(var);
2255}
2256
2257/*
Bram Moolenaar071d4272004-06-13 20:20:40 +00002258 * Change the directory that the vim plugin directories will be created in:
2259 * $HOME, $VIM or nowhere.
2260 */
2261 static void
2262change_directories_choice(int idx)
2263{
2264 int choice_count = TABLE_SIZE(vimfiles_dir_choices);
2265
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002266 // Don't offer the $HOME choice if $HOME isn't set.
Bram Moolenaar25a494c2018-11-16 19:39:50 +01002267 if (homedir == NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002268 --choice_count;
Bram Moolenaar25a494c2018-11-16 19:39:50 +01002269 choices[idx].arg = get_choice(vimfiles_dir_choices, choice_count);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002270 set_directories_text(idx);
2271}
2272
2273/*
2274 * Create the plugin directories...
2275 */
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002276//ARGSUSED
Bram Moolenaar071d4272004-06-13 20:20:40 +00002277 static void
2278install_vimfilesdir(int idx)
2279{
2280 int i;
Bram Moolenaar25a494c2018-11-16 19:39:50 +01002281 int vimfiles_dir_choice = choices[idx].arg;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002282 char *p;
Bram Moolenaarbbd854d2019-02-18 22:19:33 +01002283 char vimdir_path[MAX_PATH];
2284 char vimfiles_path[MAX_PATH + 9];
Bram Moolenaar071d4272004-06-13 20:20:40 +00002285 char tmp_dirname[BUFSIZE];
2286
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002287 // switch on the location that the user wants the plugin directories
2288 // built in
Bram Moolenaar071d4272004-06-13 20:20:40 +00002289 switch (vimfiles_dir_choice)
2290 {
2291 case vimfiles_dir_vim:
2292 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002293 // Go to the %VIM% directory - check env first, then go one dir
2294 // below installdir if there is no %VIM% environment variable.
2295 // The accuracy of $VIM is checked in inspect_system(), so we
2296 // can be sure it is ok to use here.
Bram Moolenaar071d4272004-06-13 20:20:40 +00002297 p = getenv("VIM");
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002298 if (p == NULL) // No $VIM in path
Bram Moolenaar071d4272004-06-13 20:20:40 +00002299 dir_remove_last(installdir, vimdir_path);
2300 else
2301 strcpy(vimdir_path, p);
2302 break;
2303 }
2304 case vimfiles_dir_home:
2305 {
Bram Moolenaar25a494c2018-11-16 19:39:50 +01002306 // Find the $HOME directory. Its existence was already checked.
2307 p = homedir;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002308 if (p == NULL)
2309 {
2310 printf("Internal error: $HOME is NULL\n");
2311 p = "c:\\";
2312 }
2313 strcpy(vimdir_path, p);
2314 break;
2315 }
2316 case vimfiles_dir_none:
2317 {
Bram Moolenaar25a494c2018-11-16 19:39:50 +01002318 // Do not create vim plugin directory.
Bram Moolenaar071d4272004-06-13 20:20:40 +00002319 return;
2320 }
2321 }
2322
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002323 // Now, just create the directory. If it already exists, it will fail
2324 // silently.
Bram Moolenaar071d4272004-06-13 20:20:40 +00002325 sprintf(vimfiles_path, "%s\\vimfiles", vimdir_path);
2326 vim_mkdir(vimfiles_path, 0755);
2327
2328 printf("Creating the following directories in \"%s\":\n", vimfiles_path);
2329 for (i = 0; i < TABLE_SIZE(vimfiles_subdirs); i++)
2330 {
2331 sprintf(tmp_dirname, "%s\\%s", vimfiles_path, vimfiles_subdirs[i]);
2332 printf(" %s", vimfiles_subdirs[i]);
2333 vim_mkdir(tmp_dirname, 0755);
2334 }
2335 printf("\n");
2336}
2337
2338/*
2339 * Add the creation of runtime files to the setup sequence.
2340 */
2341 static void
2342init_directories_choice(void)
2343{
2344 struct stat st;
2345 char tmp_dirname[BUFSIZE];
2346 char *p;
Bram Moolenaar25a494c2018-11-16 19:39:50 +01002347 int vimfiles_dir_choice;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002348
2349 choices[choice_count].text = alloc(150);
2350 choices[choice_count].changefunc = change_directories_choice;
2351 choices[choice_count].installfunc = install_vimfilesdir;
2352 choices[choice_count].active = 1;
2353
Bram Moolenaar25a494c2018-11-16 19:39:50 +01002354 // Check if the "compiler" directory already exists. That's a good
2355 // indication that the plugin directories were already created.
Bram Moolenaare4963c52019-02-22 19:41:08 +01002356 p = getenv("HOME");
2357 if (p != NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002358 {
2359 vimfiles_dir_choice = (int)vimfiles_dir_home;
Bram Moolenaare4963c52019-02-22 19:41:08 +01002360 sprintf(tmp_dirname, "%s\\vimfiles\\compiler", p);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002361 if (stat(tmp_dirname, &st) == 0)
2362 vimfiles_dir_choice = (int)vimfiles_dir_none;
2363 }
2364 else
2365 {
2366 vimfiles_dir_choice = (int)vimfiles_dir_vim;
2367 p = getenv("VIM");
Bram Moolenaar25a494c2018-11-16 19:39:50 +01002368 if (p == NULL) // No $VIM in path, use the install dir.
Bram Moolenaar071d4272004-06-13 20:20:40 +00002369 dir_remove_last(installdir, tmp_dirname);
2370 else
2371 strcpy(tmp_dirname, p);
2372 strcat(tmp_dirname, "\\vimfiles\\compiler");
2373 if (stat(tmp_dirname, &st) == 0)
2374 vimfiles_dir_choice = (int)vimfiles_dir_none;
2375 }
2376
Bram Moolenaar25a494c2018-11-16 19:39:50 +01002377 choices[choice_count].arg = vimfiles_dir_choice;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002378 set_directories_text(choice_count);
2379 ++choice_count;
2380}
2381
2382/*
2383 * Setup the choices and the default values.
2384 */
2385 static void
2386setup_choices(void)
2387{
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002388 // install the batch files
Bram Moolenaar071d4272004-06-13 20:20:40 +00002389 init_bat_choices();
2390
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002391 // (over) write _vimrc file
Bram Moolenaar071d4272004-06-13 20:20:40 +00002392 init_vimrc_choices();
2393
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002394 // Whether to add Vim to the popup menu
Bram Moolenaar071d4272004-06-13 20:20:40 +00002395 init_popup_choice();
2396
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002397 // Whether to add Vim to the "Open With..." menu
Bram Moolenaar071d4272004-06-13 20:20:40 +00002398 init_openwith_choice();
2399
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002400 // Whether to add Vim to the Start Menu.
Bram Moolenaar071d4272004-06-13 20:20:40 +00002401 init_startmenu_choice();
2402
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002403 // Whether to add shortcuts to the Desktop.
Bram Moolenaar071d4272004-06-13 20:20:40 +00002404 init_shortcut_choices();
2405
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002406 // Whether to create the runtime directories.
Bram Moolenaar071d4272004-06-13 20:20:40 +00002407 init_directories_choice();
2408}
2409
2410 static void
2411print_cmd_line_help(void)
2412{
2413 printf("Vim installer non-interactive command line arguments:\n");
2414 printf("\n");
2415 printf("-create-batfiles [vim gvim evim view gview vimdiff gvimdiff]\n");
2416 printf(" Create .bat files for Vim variants in the Windows directory.\n");
2417 printf("-create-vimrc\n");
2418 printf(" Create a default _vimrc file if one does not already exist.\n");
Bram Moolenaarc3fdf7f2017-10-28 18:36:48 +02002419 printf("-vimrc-remap [no|win]\n");
2420 printf(" Remap keys when creating a default _vimrc file.\n");
2421 printf("-vimrc-behave [unix|mswin|default]\n");
2422 printf(" Set mouse behavior when creating a default _vimrc file.\n");
Bram Moolenaar6cdb2c92018-10-13 17:25:27 +02002423 printf("-vimrc-compat [vi|vim|defaults|all]\n");
2424 printf(" Set Vi compatibility when creating a default _vimrc file.\n");
Bram Moolenaar071d4272004-06-13 20:20:40 +00002425 printf("-install-popup\n");
2426 printf(" Install the Edit-with-Vim context menu entry\n");
2427 printf("-install-openwith\n");
2428 printf(" Add Vim to the \"Open With...\" context menu list\n");
Bram Moolenaar071d4272004-06-13 20:20:40 +00002429 printf("-add-start-menu");
2430 printf(" Add Vim to the start menu\n");
2431 printf("-install-icons");
2432 printf(" Create icons for gVim executables on the desktop\n");
Bram Moolenaar071d4272004-06-13 20:20:40 +00002433 printf("-create-directories [vim|home]\n");
2434 printf(" Create runtime directories to drop plugins into; in the $VIM\n");
2435 printf(" or $HOME directory\n");
Bram Moolenaar071d4272004-06-13 20:20:40 +00002436 printf("-register-OLE");
Bram Moolenaarce0842a2005-07-18 21:58:11 +00002437 printf(" Ignored\n");
Bram Moolenaar071d4272004-06-13 20:20:40 +00002438 printf("\n");
2439}
2440
2441/*
2442 * Setup installation choices based on command line switches
2443 */
2444 static void
2445command_line_setup_choices(int argc, char **argv)
2446{
2447 int i, j;
2448
2449 for (i = 1; i < argc; i++)
2450 {
2451 if (strcmp(argv[i], "-create-batfiles") == 0)
2452 {
2453 if (i + 1 == argc)
2454 continue;
2455 while (argv[i + 1][0] != '-' && i < argc)
2456 {
2457 i++;
2458 for (j = 1; j < TARGET_COUNT; ++j)
2459 if ((targets[j].exenamearg[0] == 'g' ? has_gvim : has_vim)
2460 && strcmp(argv[i], targets[j].name) == 0)
2461 {
2462 init_bat_choice(j);
2463 break;
2464 }
2465 if (j == TARGET_COUNT)
2466 printf("%s is not a valid choice for -create-batfiles\n",
2467 argv[i]);
2468
2469 if (i + 1 == argc)
2470 break;
2471 }
2472 }
2473 else if (strcmp(argv[i], "-create-vimrc") == 0)
2474 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002475 // Setup default vimrc choices. If there is already a _vimrc file,
2476 // it will NOT be overwritten.
Bram Moolenaar071d4272004-06-13 20:20:40 +00002477 init_vimrc_choices();
2478 }
Bram Moolenaarc3fdf7f2017-10-28 18:36:48 +02002479 else if (strcmp(argv[i], "-vimrc-remap") == 0)
2480 {
2481 if (i + 1 == argc)
2482 break;
2483 i++;
2484 if (strcmp(argv[i], "no") == 0)
2485 remap_choice = remap_no;
2486 else if (strcmp(argv[i], "win") == 0)
2487 remap_choice = remap_win;
2488 }
2489 else if (strcmp(argv[i], "-vimrc-behave") == 0)
2490 {
2491 if (i + 1 == argc)
2492 break;
2493 i++;
2494 if (strcmp(argv[i], "unix") == 0)
2495 mouse_choice = mouse_xterm;
2496 else if (strcmp(argv[i], "mswin") == 0)
2497 mouse_choice = mouse_mswin;
2498 else if (strcmp(argv[i], "default") == 0)
2499 mouse_choice = mouse_default;
2500 }
Bram Moolenaar6cdb2c92018-10-13 17:25:27 +02002501 else if (strcmp(argv[i], "-vimrc-compat") == 0)
2502 {
2503 if (i + 1 == argc)
2504 break;
2505 i++;
2506 if (strcmp(argv[i], "vi") == 0)
2507 compat_choice = compat_vi;
2508 else if (strcmp(argv[i], "vim") == 0)
2509 compat_choice = compat_vim;
2510 else if (strcmp(argv[i], "defaults") == 0)
2511 compat_choice = compat_some_enhancements;
2512 else if (strcmp(argv[i], "all") == 0)
2513 compat_choice = compat_all_enhancements;
2514 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00002515 else if (strcmp(argv[i], "-install-popup") == 0)
2516 {
2517 init_popup_choice();
2518 }
2519 else if (strcmp(argv[i], "-install-openwith") == 0)
2520 {
2521 init_openwith_choice();
2522 }
2523 else if (strcmp(argv[i], "-add-start-menu") == 0)
2524 {
2525 init_startmenu_choice();
2526 }
2527 else if (strcmp(argv[i], "-install-icons") == 0)
2528 {
2529 init_shortcut_choices();
2530 }
2531 else if (strcmp(argv[i], "-create-directories") == 0)
2532 {
Bram Moolenaar142a9752018-12-14 19:54:39 +01002533 int vimfiles_dir_choice = (int)vimfiles_dir_none;
Bram Moolenaar25a494c2018-11-16 19:39:50 +01002534
Bram Moolenaar071d4272004-06-13 20:20:40 +00002535 init_directories_choice();
2536 if (argv[i + 1][0] != '-')
2537 {
2538 i++;
2539 if (strcmp(argv[i], "vim") == 0)
2540 vimfiles_dir_choice = (int)vimfiles_dir_vim;
2541 else if (strcmp(argv[i], "home") == 0)
2542 {
Bram Moolenaar25a494c2018-11-16 19:39:50 +01002543 if (homedir == NULL) // No $HOME in environment
2544 vimfiles_dir_choice = (int)vimfiles_dir_none;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002545 else
2546 vimfiles_dir_choice = (int)vimfiles_dir_home;
2547 }
2548 else
2549 {
2550 printf("Unknown argument for -create-directories: %s\n",
2551 argv[i]);
2552 print_cmd_line_help();
2553 }
2554 }
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002555 else // No choice specified, default to vim directory
Bram Moolenaar071d4272004-06-13 20:20:40 +00002556 vimfiles_dir_choice = (int)vimfiles_dir_vim;
Bram Moolenaar25a494c2018-11-16 19:39:50 +01002557 choices[choice_count - 1].arg = vimfiles_dir_choice;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002558 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00002559 else if (strcmp(argv[i], "-register-OLE") == 0)
2560 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002561 // This is always done when gvim is found
Bram Moolenaar071d4272004-06-13 20:20:40 +00002562 }
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002563 else // Unknown switch
Bram Moolenaar071d4272004-06-13 20:20:40 +00002564 {
2565 printf("Got unknown argument argv[%d] = %s\n", i, argv[i]);
2566 print_cmd_line_help();
2567 }
2568 }
2569}
2570
2571
2572/*
2573 * Show a few screens full of helpful information.
2574 */
2575 static void
2576show_help(void)
2577{
2578 static char *(items[]) =
2579 {
2580"Installing .bat files\n"
2581"---------------------\n"
2582"The vim.bat file is written in one of the directories in $PATH.\n"
2583"This makes it possible to start Vim from the command line.\n"
2584"If vim.exe can be found in $PATH, the choice for vim.bat will not be\n"
2585"present. It is assumed you will use the existing vim.exe.\n"
2586"If vim.bat can already be found in $PATH this is probably for an old\n"
2587"version of Vim (but this is not checked!). You can overwrite it.\n"
2588"If no vim.bat already exists, you can select one of the directories in\n"
2589"$PATH for creating the batch file, or disable creating a vim.bat file.\n"
2590"\n"
2591"If you choose not to create the vim.bat file, Vim can still be executed\n"
2592"in other ways, but not from the command line.\n"
2593"\n"
2594"The same applies to choices for gvim, evim, (g)view, and (g)vimdiff.\n"
2595"The first item can be used to change the path for all of them.\n"
2596,
2597"Creating a _vimrc file\n"
2598"----------------------\n"
2599"The _vimrc file is used to set options for how Vim behaves.\n"
2600"The install program can create a _vimrc file with a few basic choices.\n"
2601"You can edit this file later to tune your preferences.\n"
2602"If you already have a _vimrc or .vimrc file it can be overwritten.\n"
2603"Don't do that if you have made changes to it.\n"
2604,
2605"Vim features\n"
2606"------------\n"
2607"(this choice is only available when creating a _vimrc file)\n"
2608"1. Vim can run in Vi-compatible mode. Many nice Vim features are then\n"
Bram Moolenaar2b849492018-11-21 13:58:35 +01002609" disabled. Only choose Vi-compatible if you really need full Vi\n"
2610" compatibility.\n"
2611"2. Vim runs in not-Vi-compatible mode. Vim is still mostly Vi compatible,\n"
2612" but adds nice features like multi-level undo.\n"
2613"3. Running Vim with some enhancements is useful when you want some of\n"
Bram Moolenaar071d4272004-06-13 20:20:40 +00002614" the nice Vim features, but have a slow computer and want to keep it\n"
2615" really fast.\n"
Bram Moolenaar2b849492018-11-21 13:58:35 +01002616"4. Syntax highlighting shows many files in color. Not only does this look\n"
Bram Moolenaar071d4272004-06-13 20:20:40 +00002617" nice, it also makes it easier to spot errors and you can work faster.\n"
2618" The other features include editing compressed files.\n"
2619,
2620"Windows key mapping\n"
2621"-------------------\n"
2622"(this choice is only available when creating a _vimrc file)\n"
2623"Under MS-Windows the CTRL-C key copies text to the clipboard and CTRL-V\n"
2624"pastes text from the clipboard. There are a few more keys like these.\n"
2625"Unfortunately, in Vim these keys normally have another meaning.\n"
2626"1. Choose to have the keys like they normally are in Vim (useful if you\n"
2627" also use Vim on other systems).\n"
2628"2. Choose to have the keys work like they are used on MS-Windows (useful\n"
2629" if you mostly work on MS-Windows).\n"
2630,
2631"Mouse use\n"
2632"---------\n"
2633"(this choice is only available when creating a _vimrc file)\n"
2634"The right mouse button can be used in two ways:\n"
2635"1. The Unix way is to extend an existing selection. The popup menu is\n"
2636" not available.\n"
2637"2. The MS-Windows way is to show a popup menu, which allows you to\n"
2638" copy/paste text, undo/redo, etc. Extending the selection can still be\n"
2639" done by keeping SHIFT pressed while using the left mouse button\n"
2640,
2641"Edit-with-Vim context menu entry\n"
2642"--------------------------------\n"
2643"(this choice is only available when gvim.exe and gvimext.dll are present)\n"
2644"You can associate different file types with Vim, so that you can (double)\n"
2645"click on a file to edit it with Vim. This means you have to individually\n"
2646"select each file type.\n"
2647"An alternative is the option offered here: Install an \"Edit with Vim\"\n"
2648"entry in the popup menu for the right mouse button. This means you can\n"
2649"edit any file with Vim.\n"
2650,
2651"\"Open With...\" context menu entry\n"
2652"--------------------------------\n"
2653"(this choice is only available when gvim.exe is present)\n"
2654"This option adds Vim to the \"Open With...\" entry in the popup menu for\n"
2655"the right mouse button. This also makes it possible to edit HTML files\n"
2656"directly from Internet Explorer.\n"
2657,
2658"Add Vim to the Start menu\n"
2659"-------------------------\n"
2660"In Windows 95 and later, Vim can be added to the Start menu. This will\n"
2661"create a submenu with an entry for vim, gvim, evim, vimdiff, etc..\n"
2662,
2663"Icons on the desktop\n"
2664"--------------------\n"
2665"(these choices are only available when installing gvim)\n"
2666"In Windows 95 and later, shortcuts (icons) can be created on the Desktop.\n"
2667,
2668"Create plugin directories\n"
2669"-------------------------\n"
2670"Plugin directories allow extending Vim by dropping a file into a directory.\n"
2671"This choice allows creating them in $HOME (if you have a home directory) or\n"
2672"$VIM (used for everybody on the system).\n"
2673,
2674NULL
2675 };
2676 int i;
2677 int c;
2678
2679 rewind(stdin);
2680 printf("\n");
2681 for (i = 0; items[i] != NULL; ++i)
2682 {
Bram Moolenaarc3fdf7f2017-10-28 18:36:48 +02002683 puts(items[i]);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002684 printf("Hit Enter to continue, b (back) or q (quit help): ");
2685 c = getchar();
2686 rewind(stdin);
2687 if (c == 'b' || c == 'B')
2688 {
2689 if (i == 0)
2690 --i;
2691 else
2692 i -= 2;
2693 }
2694 if (c == 'q' || c == 'Q')
2695 break;
2696 printf("\n");
2697 }
2698}
2699
2700/*
2701 * Install the choices.
2702 */
2703 static void
2704install(void)
2705{
2706 int i;
2707
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002708 // Install the selected choices.
Bram Moolenaar071d4272004-06-13 20:20:40 +00002709 for (i = 0; i < choice_count; ++i)
2710 if (choices[i].installfunc != NULL && choices[i].active)
2711 (choices[i].installfunc)(i);
2712
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002713 // Add some entries to the registry, if needed.
Bram Moolenaar071d4272004-06-13 20:20:40 +00002714 if (install_popup
2715 || install_openwith
2716 || (need_uninstall_entry && interactive)
2717 || !interactive)
2718 install_registry();
2719
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002720 // Register gvim with OLE.
Bram Moolenaar071d4272004-06-13 20:20:40 +00002721 if (has_gvim)
2722 install_OLE_register();
Bram Moolenaar071d4272004-06-13 20:20:40 +00002723}
2724
2725/*
2726 * request_choice
2727 */
2728 static void
2729request_choice(void)
2730{
2731 int i;
2732
2733 printf("\n\nInstall will do for you:\n");
2734 for (i = 0; i < choice_count; ++i)
2735 if (choices[i].active)
2736 printf("%2d %s\n", i + 1, choices[i].text);
2737 printf("To change an item, enter its number\n\n");
2738 printf("Enter item number, h (help), d (do it) or q (quit): ");
2739}
2740
2741 int
2742main(int argc, char **argv)
2743{
2744 int i;
2745 char buf[BUFSIZE];
2746
2747 /*
2748 * Run interactively if there are no command line arguments.
2749 */
2750 if (argc > 1)
2751 interactive = 0;
2752 else
2753 interactive = 1;
2754
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002755 // Initialize this program.
Bram Moolenaar071d4272004-06-13 20:20:40 +00002756 do_inits(argv);
Bram Moolenaar25a494c2018-11-16 19:39:50 +01002757 init_homedir();
Bram Moolenaar071d4272004-06-13 20:20:40 +00002758
Bram Moolenaar071d4272004-06-13 20:20:40 +00002759 if (argc > 1 && strcmp(argv[1], "-uninstall-check") == 0)
2760 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002761 // Only check for already installed Vims. Used by NSIS installer.
Bram Moolenaar442b4222010-05-24 21:34:22 +02002762 i = uninstall_check(1);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002763
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002764 // Find the value of $VIM, because NSIS isn't able to do this by
2765 // itself.
Bram Moolenaar071d4272004-06-13 20:20:40 +00002766 get_vim_env();
2767
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002768 // When nothing found exit quietly. If something found wait for
2769 // a little while, so that the user can read the messages.
Bram Moolenaar6cdb2c92018-10-13 17:25:27 +02002770 if (i && _isatty(1))
Bram Moolenaarab8205e2010-07-07 15:14:03 +02002771 sleep(3);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002772 exit(0);
2773 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00002774
2775 printf("This program sets up the installation of Vim "
2776 VIM_VERSION_MEDIUM "\n\n");
2777
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002778 // Check if the user unpacked the archives properly.
Bram Moolenaar071d4272004-06-13 20:20:40 +00002779 check_unpack();
2780
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002781 // Check for already installed Vims.
Bram Moolenaar071d4272004-06-13 20:20:40 +00002782 if (interactive)
Bram Moolenaar442b4222010-05-24 21:34:22 +02002783 uninstall_check(0);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002784
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002785 // Find out information about the system.
Bram Moolenaar071d4272004-06-13 20:20:40 +00002786 inspect_system();
2787
2788 if (interactive)
2789 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002790 // Setup all the choices.
Bram Moolenaar071d4272004-06-13 20:20:40 +00002791 setup_choices();
2792
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002793 // Let the user change choices and finally install (or quit).
Bram Moolenaar071d4272004-06-13 20:20:40 +00002794 for (;;)
2795 {
2796 request_choice();
2797 rewind(stdin);
2798 if (scanf("%99s", buf) == 1)
2799 {
2800 if (isdigit(buf[0]))
2801 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002802 // Change a choice.
Bram Moolenaar071d4272004-06-13 20:20:40 +00002803 i = atoi(buf);
2804 if (i > 0 && i <= choice_count && choices[i - 1].active)
2805 (choices[i - 1].changefunc)(i - 1);
2806 else
2807 printf("\nIllegal choice\n");
2808 }
2809 else if (buf[0] == 'h' || buf[0] == 'H')
2810 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002811 // Help
Bram Moolenaar071d4272004-06-13 20:20:40 +00002812 show_help();
2813 }
2814 else if (buf[0] == 'd' || buf[0] == 'D')
2815 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002816 // Install!
Bram Moolenaar071d4272004-06-13 20:20:40 +00002817 install();
2818 printf("\nThat finishes the installation. Happy Vimming!\n");
2819 break;
2820 }
2821 else if (buf[0] == 'q' || buf[0] == 'Q')
2822 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002823 // Quit
Bram Moolenaar071d4272004-06-13 20:20:40 +00002824 printf("\nExiting without anything done\n");
2825 break;
2826 }
2827 else
2828 printf("\nIllegal choice\n");
2829 }
2830 }
2831 printf("\n");
Bram Moolenaar442b4222010-05-24 21:34:22 +02002832 myexit(0);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002833 }
2834 else
2835 {
2836 /*
2837 * Run non-interactive - setup according to the command line switches
2838 */
2839 command_line_setup_choices(argc, argv);
2840 install();
Bram Moolenaar442b4222010-05-24 21:34:22 +02002841
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002842 // Avoid that the user has to hit Enter, just wait a little bit to
2843 // allow reading the messages.
Bram Moolenaarab8205e2010-07-07 15:14:03 +02002844 sleep(2);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002845 }
2846
Bram Moolenaar071d4272004-06-13 20:20:40 +00002847 return 0;
2848}