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