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