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