/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

Large files are truncated click here to view the full 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], "…