/src/dosinst.c

https://bitbucket.org/ultra_iter/vim-qt · C · 2596 lines · 1963 code · 251 blank · 382 comment · 441 complexity · b4a5e61b5f3d3338a94b37d3ea4d356f MD5 · raw file

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