diff options
author | Bram Moolenaar <Bram@vim.org> | 2004-06-13 20:20:40 +0000 |
---|---|---|
committer | Bram Moolenaar <Bram@vim.org> | 2004-06-13 20:20:40 +0000 |
commit | 071d4279d6ab81b7187b48f3a0fc61e587b6db6c (patch) | |
tree | 221cbe3c40e043163c06f61c52a7ba2eb41e12ce /src/dosinst.c | |
parent | b4210b3bc14e2918f153a7307530fbe6eba659e1 (diff) |
updated for version 7.0001v7.0001
Diffstat (limited to 'src/dosinst.c')
-rw-r--r-- | src/dosinst.c | 2461 |
1 files changed, 2461 insertions, 0 deletions
diff --git a/src/dosinst.c b/src/dosinst.c new file mode 100644 index 0000000000..deaf15f7a6 --- /dev/null +++ b/src/dosinst.c @@ -0,0 +1,2461 @@ +/* vi:set ts=8 sts=4 sw=4: + * + * VIM - Vi IMproved by Bram Moolenaar + * + * Do ":help uganda" in Vim to read copying and usage conditions. + * Do ":help credits" in Vim to see a list of people who contributed. + * See README.txt for an overview of the Vim source code. + */ + +/* + * dosinst.c: Install program for Vim on MS-DOS and MS-Windows + * + * Compile with Make_mvc.mak, Make_bc3.mak, Make_bc5.mak or Make_djg.mak. + */ + +/* + * Include common code for dosinst.c and uninstal.c. + */ +#define DOSINST +#include "dosinst.h" + +/* Macro to do an error check I was typing over and over */ +#define CHECK_REG_ERROR(code) if (code != ERROR_SUCCESS) { printf("%ld error number: %ld\n", (long)__LINE__, (long)code); return 1; } + +int has_vim = 0; /* installable vim.exe exists */ +int has_gvim = 0; /* installable gvim.exe exists */ + +char oldvimrc[BUFSIZE]; /* name of existing vimrc file */ +char vimrc[BUFSIZE]; /* name of vimrc file to create */ + +char *default_bat_dir = NULL; /* when not NULL, use this as the default + directory to write .bat files in */ +char *default_vim_dir = NULL; /* when not NULL, use this as the default + install dir for NSIS */ +#if 0 +char homedir[BUFSIZE]; /* home directory or "" */ +#endif + +/* + * Structure used for each choice the user can make. + */ +struct choice +{ + int active; /* non-zero when choice is active */ + char *text; /* text displayed for this choice */ + void (*changefunc)(int idx); /* function to change this choice */ + int arg; /* argument for function */ + void (*installfunc)(int idx); /* function to install this choice */ +}; + +struct choice choices[30]; /* choices the user can make */ +int choice_count = 0; /* number of choices available */ + +#define TABLE_SIZE(s) (int)(sizeof(s) / sizeof(*s)) + +enum +{ + compat_vi = 1, + compat_some_enhancements, + compat_all_enhancements +}; +char *(compat_choices[]) = +{ + "\nChoose the default way to run Vim:", + "Vi compatible", + "with some Vim ehancements", + "with syntax highlighting and other features switched on", +}; +int compat_choice = (int)compat_all_enhancements; +char *compat_text = "- run Vim %s"; + +enum +{ + remap_no = 1, + remap_win +}; +char *(remap_choices[]) = +{ + "\nChoose:", + "Do not remap keys for Windows behavior", + "Remap a few keys for Windows behavior (<C-V>, <C-C>, etc)", +}; +int remap_choice = (int)remap_win; +char *remap_text = "- %s"; + +enum +{ + mouse_xterm = 1, + mouse_mswin +}; +char *(mouse_choices[]) = +{ + "\nChoose the way how Vim uses the mouse:", + "right button extends selection (the Unix way)", + "right button has a popup menu (the Windows way)", +}; +int mouse_choice = (int)mouse_mswin; +char *mouse_text = "- The mouse %s"; + +enum +{ + vimfiles_dir_none = 1, + vimfiles_dir_vim, + vimfiles_dir_home +}; +static char *(vimfiles_dir_choices[]) = +{ + "\nCreate plugin directories:", + "No", + "In the VIM directory", + "In your HOME directory", +}; +static int vimfiles_dir_choice; + +/* non-zero when selected to install the popup menu entry. */ +static int install_popup = 0; + +/* non-zero when selected to install the "Open with" entry. */ +static int install_openwith = 0; + +/* non-zero when need to add an uninstall entry in the registry */ +static int need_uninstall_entry = 0; + +/* + * Definitions of the directory name (under $VIM) of the vimfiles directory + * and its subdirectories: + */ +static char *(vimfiles_subdirs[]) = +{ + "colors", + "compiler", + "doc", + "ftdetect", + "ftplugin", + "indent", + "keymap", + "plugin", + "syntax", +}; + +/* + * Copy a directory name from "dir" to "buf", doubling backslashes. + * Also make sure it ends in a double backslash. + */ + static void +double_bs(char *dir, char *buf) +{ + char *d = buf; + char *s; + + for (s = dir; *s; ++s) + { + if (*s == '\\') + *d++ = '\\'; + *d++ = *s; + } + /* when dir is not empty, it must end in a double backslash */ + if (d > buf && d[-1] != '\\') + { + *d++ = '\\'; + *d++ = '\\'; + } + *d = NUL; +} + +/* + * Obtain a choice from a table. + * First entry is a question, others are choices. + */ + static int +get_choice(char **table, int entries) +{ + int answer; + int idx; + char dummy[100]; + + do + { + for (idx = 0; idx < entries; ++idx) + { + if (idx) + printf("%2d ", idx); + printf(table[idx]); + printf("\n"); + } + printf("Choice: "); + if (scanf("%d", &answer) != 1) + { + scanf("%99s", dummy); + answer = 0; + } + } + while (answer < 1 || answer >= entries); + + return answer; +} + +/* + * Check if the user unpacked the archives properly. + * Sets "runtimeidx". + */ + static void +check_unpack(void) +{ + char buf[BUFSIZE]; + FILE *fd; + struct stat st; + + /* check for presence of the correct version number in installdir[] */ + runtimeidx = strlen(installdir) - strlen(VIM_VERSION_NODOT); + if (runtimeidx <= 0 + || stricmp(installdir + runtimeidx, VIM_VERSION_NODOT) != 0 + || (installdir[runtimeidx - 1] != '/' + && installdir[runtimeidx - 1] != '\\')) + { + printf("ERROR: Install program not in directory \"%s\"\n", + VIM_VERSION_NODOT); + printf("This program can only work when it is located in its original directory\n"); + myexit(1); + } + + /* check if filetype.vim is present, which means the runtime archive has + * been unpacked */ + sprintf(buf, "%s\\filetype.vim", installdir); + if (stat(buf, &st) < 0) + { + printf("ERROR: Cannot find filetype.vim in \"%s\"\n", installdir); + printf("It looks like you did not unpack the runtime archive.\n"); + printf("You must unpack the runtime archive \"vim%srt.zip\" before installing.\n", + VIM_VERSION_NODOT + 3); + myexit(1); + } + + /* Check if vim.exe or gvim.exe is in the current directory. */ + if ((fd = fopen("gvim.exe", "r")) != NULL) + { + fclose(fd); + has_gvim = 1; + } + if ((fd = fopen("vim.exe", "r")) != NULL) + { + fclose(fd); + has_vim = 1; + } + if (!has_gvim && !has_vim) + { + printf("ERROR: Cannot find any Vim executables in \"%s\"\n\n", + installdir); + myexit(1); + } +} + +/* + * Compare paths "p[plen]" to "q[qlen]". Return 0 if they match. + * Ignores case and differences between '/' and '\'. + * "plen" and "qlen" can be negative, strlen() is used then. + */ + static int +pathcmp(char *p, int plen, char *q, int qlen) +{ + int i; + + if (plen < 0) + plen = strlen(p); + if (qlen < 0) + qlen = strlen(q); + for (i = 0; ; ++i) + { + /* End of "p": check if "q" also ends or just has a slash. */ + if (i == plen) + { + if (i == qlen) /* match */ + return 0; + if (i == qlen - 1 && (q[i] == '\\' || q[i] == '/')) + return 0; /* match with trailing slash */ + return 1; /* no match */ + } + + /* End of "q": check if "p" also ends or just has a slash. */ + if (i == qlen) + { + if (i == plen) /* match */ + return 0; + if (i == plen - 1 && (p[i] == '\\' || p[i] == '/')) + return 0; /* match with trailing slash */ + return 1; /* no match */ + } + + if (!(mytoupper(p[i]) == mytoupper(q[i]) + || ((p[i] == '/' || p[i] == '\\') + && (q[i] == '/' || q[i] == '\\')))) + return 1; /* no match */ + } + /*NOTREACHED*/ +} + +/* + * If the executable "**destination" is in the install directory, find another + * one in $PATH. + * On input "**destination" is the path of an executable in allocated memory + * (or NULL). + * "*destination" is set to NULL or the location of the file. + */ + static void +findoldfile(char **destination) +{ + char *bp = *destination; + size_t indir_l = strlen(installdir); + char *cp = bp + indir_l; + char *tmpname; + char *farname; + + /* + * No action needed if exe not found or not in this directory. + */ + if (bp == NULL + || strnicmp(bp, installdir, indir_l) != 0 + || strchr("/\\", *cp++) == NULL + || strchr(cp, '\\') != NULL + || strchr(cp, '/') != NULL) + return; + + tmpname = alloc((int)strlen(cp) + 1); + strcpy(tmpname, cp); + tmpname[strlen(tmpname) - 1] = 'x'; /* .exe -> .exx */ + + if (access(tmpname, 0) == 0) + { + printf("\nERROR: %s and %s clash. Remove or rename %s.\n", + tmpname, cp, tmpname); + myexit(1); + } + + if (rename(cp, tmpname) != 0) + { + printf("\nERROR: failed to rename %s to %s: %s\n", + cp, tmpname, strerror(0)); + myexit(1); + } + + farname = searchpath_save(cp); + + if (rename(tmpname, cp) != 0) + { + printf("\nERROR: failed to rename %s back to %s: %s\n", + tmpname, cp, strerror(0)); + myexit(1); + } + + free(*destination); + free(tmpname); + *destination = farname; +} + +/* + * Check if there is a vim.[exe|bat|, gvim.[exe|bat|, etc. in the path. + * When "check_bat_only" is TRUE, only find "default_bat_dir". + */ + static void +find_bat_exe(int check_bat_only) +{ + int i; + + mch_chdir(sysdrive); /* avoid looking in the "installdir" */ + + for (i = 1; i < TARGET_COUNT; ++i) + { + targets[i].oldbat = searchpath_save(targets[i].batname); + if (!check_bat_only) + targets[i].oldexe = searchpath_save(targets[i].exename); + + if (default_bat_dir == NULL && targets[i].oldbat != NULL) + { + default_bat_dir = alloc(strlen(targets[i].oldbat) + 1); + strcpy(default_bat_dir, targets[i].oldbat); + remove_tail(default_bat_dir); + } + if (check_bat_only && targets[i].oldbat != NULL) + free(targets[i].oldbat); + } + + mch_chdir(installdir); +} + +#ifdef WIN3264 +/* + * Get the value of $VIMRUNTIME or $VIM and write it in $TEMP/vimini.ini, so + * that NSIS can read it. + * When not set, use the directory of a previously installed Vim. + */ + static void +get_vim_env(void) +{ + char *vim; + char buf[BUFSIZE]; + FILE *fd; + char fname[BUFSIZE]; + + /* First get $VIMRUNTIME. If it's set, remove the tail. */ + vim = getenv("VIMRUNTIME"); + if (vim != NULL && *vim != 0) + { + strcpy(buf, vim); + remove_tail(buf); + vim = buf; + } + else + { + vim = getenv("VIM"); + if (vim == NULL || *vim == 0) + { + /* Use the directory from an old uninstall entry. */ + if (default_vim_dir != NULL) + vim = default_vim_dir; + else + /* Let NSIS know there is no default, it should use + * $PROGRAMFIlES. */ + vim = ""; + } + } + + /* NSIS also uses GetTempPath(), thus we should get the same directory + * name as where NSIS will look for vimini.ini. */ + GetTempPath(BUFSIZE, fname); + add_pathsep(fname); + strcat(fname, "vimini.ini"); + + fd = fopen(fname, "w"); + if (fd != NULL) + { + /* Make it look like an .ini file, so that NSIS can read it with a + * ReadINIStr command. */ + fprintf(fd, "[vimini]\n"); + fprintf(fd, "dir=\"%s\"\n", vim); + fclose(fd); + } + else + { + printf("Failed to open %s\n", fname); + Sleep(2000); + } +} + +/* + * Check for already installed Vims. + * Return non-zero when found one. + */ + static int +uninstall_check(void) +{ + HKEY key_handle; + HKEY uninstall_key_handle; + char *uninstall_key = "software\\Microsoft\\Windows\\CurrentVersion\\Uninstall"; + char subkey_name_buff[BUFSIZE]; + char temp_string_buffer[BUFSIZE]; + DWORD local_bufsize = BUFSIZE; + FILETIME temp_pfiletime; + DWORD key_index; + char input; + long code; + DWORD value_type; + DWORD orig_num_keys; + DWORD new_num_keys; + int foundone = 0; + + code = RegOpenKeyEx(HKEY_LOCAL_MACHINE, uninstall_key, 0, KEY_READ, + &key_handle); + CHECK_REG_ERROR(code); + + for (key_index = 0; + RegEnumKeyEx(key_handle, key_index, subkey_name_buff, &local_bufsize, + NULL, NULL, NULL, &temp_pfiletime) != ERROR_NO_MORE_ITEMS; + key_index++) + { + local_bufsize = BUFSIZE; + if (strncmp("Vim", subkey_name_buff, 3) == 0) + { + /* Open the key named Vim* */ + code = RegOpenKeyEx(key_handle, subkey_name_buff, 0, KEY_READ, + &uninstall_key_handle); + CHECK_REG_ERROR(code); + + /* get the DisplayName out of it to show the user */ + code = RegQueryValueEx(uninstall_key_handle, "displayname", 0, + &value_type, (LPBYTE)temp_string_buffer, + &local_bufsize); + local_bufsize = BUFSIZE; + CHECK_REG_ERROR(code); + + foundone = 1; + printf("\n*********************************************************\n"); + printf("Vim Install found what looks like an existing Vim version.\n"); + printf("The name of the entry is:\n"); + printf("\n \"%s\"\n\n", temp_string_buffer); + + printf("Installing the new version will disable part of the existing version.\n"); + printf("(The batch files used in a console and the \"Edit with Vim\" entry in\n"); + printf("the popup menu will use the new version)\n"); + + printf("\nDo you want to uninstall \"%s\" now?\n(y)es/(n)o) ", temp_string_buffer); + fflush(stdout); + + /* get the UninstallString */ + code = RegQueryValueEx(uninstall_key_handle, "uninstallstring", 0, + &value_type, (LPBYTE)temp_string_buffer, &local_bufsize); + local_bufsize = BUFSIZE; + CHECK_REG_ERROR(code); + + /* Remember the directory, it is used as the default for NSIS. */ + default_vim_dir = alloc(strlen(temp_string_buffer) + 1); + strcpy(default_vim_dir, temp_string_buffer); + remove_tail(default_vim_dir); + remove_tail(default_vim_dir); + + input = 'n'; + do + { + if (input != 'n') + printf("%c is an invalid reply. Please enter either 'y' or 'n'\n", input); + + rewind(stdin); + scanf("%c", &input); + switch (input) + { + case 'y': + case 'Y': + /* save the number of uninstall keys so we can know if + * it changed */ + RegQueryInfoKey(key_handle, NULL, NULL, NULL, + &orig_num_keys, NULL, NULL, NULL, + NULL, NULL, NULL, NULL); + + /* Delete the uninstall key. It has no subkeys, so + * this is easy. Do this before uninstalling, that + * may try to delete the key as well. */ + RegDeleteKey(key_handle, subkey_name_buff); + + /* Find existing .bat files before deleting them. */ + find_bat_exe(TRUE); + + /* Execute the uninstall program. Put it in double + * quotes if there is an embedded space. */ + if (strchr(temp_string_buffer, ' ') != NULL) + { + char buf[BUFSIZE]; + + strcpy(buf, temp_string_buffer); + sprintf(temp_string_buffer, "\"%s\"", buf); + } + run_command(temp_string_buffer); + + /* Check if an unistall reg key was deleted. + * if it was, we want to decrement key_index. + * if we don't do this, we will skip the key + * immediately after any key that we delete. */ + RegQueryInfoKey(key_handle, NULL, NULL, NULL, + &new_num_keys, NULL, NULL, NULL, + NULL, NULL, NULL, NULL); + if (new_num_keys < orig_num_keys) + key_index--; + + input = 'y'; + break; + + case 'n': + case 'N': + /* Do not uninstall */ + input = 'n'; + break; + + default: /* just drop through and redo the loop */ + break; + } + + } while (input != 'n' && input != 'y'); + + RegCloseKey(uninstall_key_handle); + } + } + RegCloseKey(key_handle); + + return foundone; +} +#endif + +/* + * Find out information about the system. + */ + static void +inspect_system(void) +{ + char *p; + char buf[BUFSIZE]; + FILE *fd; + int i; + int foundone; + + /* This may take a little while, let the user know what we're doing. */ + printf("Inspecting system...\n"); + + /* + * If $VIM is set, check that it's pointing to our directory. + */ + p = getenv("VIM"); + if (p != NULL && pathcmp(p, -1, installdir, runtimeidx - 1) != 0) + { + printf("------------------------------------------------------\n"); + printf("$VIM is set to \"%s\".\n", p); + printf("This is different from where this version of Vim is:\n"); + strcpy(buf, installdir); + *(buf + runtimeidx - 1) = NUL; + printf("\"%s\"\n", buf); + printf("You must adjust or remove the setting of $VIM,\n"); + if (interactive) + { + printf("to be able to use this install program.\n"); + myexit(1); + } + printf("otherwise Vim WILL NOT WORK properly!\n"); + printf("------------------------------------------------------\n"); + } + + /* + * If $VIMRUNTIME is set, check that it's pointing to our runtime directory. + */ + p = getenv("VIMRUNTIME"); + if (p != NULL && pathcmp(p, -1, installdir, -1) != 0) + { + printf("------------------------------------------------------\n"); + printf("$VIMRUNTIME is set to \"%s\".\n", p); + printf("This is different from where this version of Vim is:\n"); + printf("\"%s\"\n", installdir); + printf("You must adjust or remove the setting of $VIMRUNTIME,\n"); + if (interactive) + { + printf("to be able to use this install program.\n"); + myexit(1); + } + printf("otherwise Vim WILL NOT WORK properly!\n"); + printf("------------------------------------------------------\n"); + } + + /* + * Check if there is a vim.[exe|bat|, gvim.[exe|bat|, etc. in the path. + */ + find_bat_exe(FALSE); + + /* + * A .exe in the install directory may be found anyway on Windows 2000. + * Check for this situation and find another executable if necessary. + * w.briscoe@ponl.com 2001-01-20 + */ + foundone = 0; + for (i = 1; i < TARGET_COUNT; ++i) + { + findoldfile(&(targets[i].oldexe)); + if (targets[i].oldexe != NULL) + foundone = 1; + } + + if (foundone) + { + printf("Warning: Found Vim executable(s) in your $PATH:\n"); + for (i = 1; i < TARGET_COUNT; ++i) + if (targets[i].oldexe != NULL) + printf("%s\n", targets[i].oldexe); + printf("It will be used instead of the version you are installing.\n"); + printf("Please delete or rename it, or adjust your $PATH setting.\n"); + } + + /* + * Check if there is an existing ../_vimrc or ../.vimrc file. + */ + strcpy(oldvimrc, installdir); + strcpy(oldvimrc + runtimeidx, "_vimrc"); + if ((fd = fopen(oldvimrc, "r")) == NULL) + { + strcpy(oldvimrc + runtimeidx, "vimrc~1"); /* short version of .vimrc */ + if ((fd = fopen(oldvimrc, "r")) == NULL) + { + strcpy(oldvimrc + runtimeidx, ".vimrc"); + fd = fopen(oldvimrc, "r"); + } + } + if (fd != NULL) + fclose(fd); + else + *oldvimrc = NUL; + +#if 0 /* currently not used */ + /* + * Get default home directory. + * Prefer $HOME if it's set. For Win NT use $HOMEDRIVE and $HOMEPATH. + * Otherwise, if there is a "c:" drive use that. + */ + p = getenv("HOME"); + if (p != NULL && *p != NUL && strlen(p) < BUFSIZE) + strcpy(homedir, p); + else + { + p = getenv("HOMEDRIVE"); + if (p != NULL && *p != NUL && strlen(p) + 2 < BUFSIZE) + { + strcpy(homedir, p); + p = getenv("HOMEPATH"); + if (p != NULL && *p != NUL && strlen(homedir) + strlen(p) < BUFSIZE) + strcat(homedir, p); + else + strcat(homedir, "\\"); + } + else + { + struct stat st; + + if (stat("c:\\", &st) == 0) + strcpy(homedir, "c:\\"); + else + *homedir = NUL; + } + } +#endif +} + +/* + * Add a dummy choice to avoid that the numbering changes depending on items + * in the environment. The user may type a number he remembered without + * looking. + */ + static void +add_dummy_choice(void) +{ + choices[choice_count].installfunc = NULL; + choices[choice_count].active = 0; + choices[choice_count].changefunc = NULL; + choices[choice_count].installfunc = NULL; + ++choice_count; +} + +/*********************************************** + * stuff for creating the batch files. + */ + +/* + * Install the vim.bat, gvim.bat, etc. files. + */ + static void +install_bat_choice(int idx) +{ + char *batpath = targets[choices[idx].arg].batpath; + char *oldname = targets[choices[idx].arg].oldbat; + char *exename = targets[choices[idx].arg].exenamearg; + char *vimarg = targets[choices[idx].arg].exearg; + FILE *fd; + char buf[BUFSIZE]; + + if (*batpath != NUL) + { + fd = fopen(batpath, "w"); + if (fd == NULL) + printf("\nERROR: Cannot open \"%s\" for writing.\n", batpath); + else + { + need_uninstall_entry = 1; + + fprintf(fd, "@echo off\n"); + fprintf(fd, "rem -- Run Vim --\n\n"); + + strcpy(buf, installdir); + buf[runtimeidx - 1] = NUL; + /* Don't use double quotes for the value here, also when buf + * contains a space. The quotes would be included in the value + * for MSDOS and NT. */ + fprintf(fd, "set VIM=%s\n\n", buf); + + strcpy(buf, installdir + runtimeidx); + add_pathsep(buf); + strcat(buf, exename); + + /* Give an error message when the executable could not be found. */ + fprintf(fd, "if exist \"%%VIM%%\\%s\" goto havevim\n", buf); + fprintf(fd, "echo \"%%VIM%%\\%s\" not found\n", buf); + fprintf(fd, "goto eof\n\n"); + fprintf(fd, ":havevim\n"); + + fprintf(fd, "rem collect the arguments in VIMARGS for Win95\n"); + fprintf(fd, "set VIMARGS=\n"); + if (*exename == 'g') + fprintf(fd, "set VIMNOFORK=\n"); + fprintf(fd, ":loopstart\n"); + fprintf(fd, "if .%%1==. goto loopend\n"); + if (*exename == 'g') + { + fprintf(fd, "if NOT .%%1==.-f goto noforkarg\n"); + fprintf(fd, "set VIMNOFORK=1\n"); + fprintf(fd, ":noforkarg\n"); + } + fprintf(fd, "set VIMARGS=%%VIMARGS%% %%1\n"); + fprintf(fd, "shift\n"); + fprintf(fd, "goto loopstart\n\n"); + fprintf(fd, ":loopend\n"); + + fprintf(fd, "if .%%OS%%==.Windows_NT goto ntaction\n\n"); + + /* For gvim.exe use "start" to avoid that the console window stays + * open. */ + if (*exename == 'g') + { + fprintf(fd, "if .%%VIMNOFORK%%==.1 goto nofork\n"); + fprintf(fd, "start "); + } + + /* Do use quotes here if the path includes a space. */ + if (strchr(installdir, ' ') != NULL) + fprintf(fd, "\"%%VIM%%\\%s\" %s %%VIMARGS%%\n", buf, vimarg); + else + fprintf(fd, "%%VIM%%\\%s %s %%VIMARGS%%\n", buf, vimarg); + fprintf(fd, "goto eof\n\n"); + + if (*exename == 'g') + { + fprintf(fd, ":nofork\n"); + fprintf(fd, "start /w "); + /* Do use quotes here if the path includes a space. */ + if (strchr(installdir, ' ') != NULL) + fprintf(fd, "\"%%VIM%%\\%s\" %s %%VIMARGS%%\n", buf, + vimarg); + else + fprintf(fd, "%%VIM%%\\%s %s %%VIMARGS%%\n", buf, vimarg); + fprintf(fd, "goto eof\n\n"); + } + + fprintf(fd, ":ntaction\n"); + fprintf(fd, "rem for WinNT we can use %%*\n"); + + /* For gvim.exe use "start /b" to avoid that the console window + * stays open. */ + if (*exename == 'g') + { + fprintf(fd, "if .%%VIMNOFORK%%==.1 goto noforknt\n"); + fprintf(fd, "start \"dummy\" /b "); + } + + /* Do use quotes here if the path includes a space. */ + if (strchr(installdir, ' ') != NULL) + fprintf(fd, "\"%%VIM%%\\%s\" %s %%*\n", buf, vimarg); + else + fprintf(fd, "%%VIM%%\\%s %s %%*\n", buf, vimarg); + fprintf(fd, "goto eof\n\n"); + + if (*exename == 'g') + { + fprintf(fd, ":noforknt\n"); + fprintf(fd, "start \"dummy\" /b /wait "); + /* Do use quotes here if the path includes a space. */ + if (strchr(installdir, ' ') != NULL) + fprintf(fd, "\"%%VIM%%\\%s\" %s %%*\n", buf, vimarg); + else + fprintf(fd, "%%VIM%%\\%s %s %%*\n", buf, vimarg); + } + + fprintf(fd, "\n:eof\n"); + fprintf(fd, "set VIMARGS=\n"); + if (*exename == 'g') + fprintf(fd, "set VIMNOFORK=\n"); + + fclose(fd); + printf("%s has been %s\n", batpath, + oldname == NULL ? "created" : "overwritten"); + } + } +} + +/* + * Make the text string for choice "idx". + * The format "fmt" is must have one %s item, which "arg" is used for. + */ + static void +alloc_text(int idx, char *fmt, char *arg) +{ + if (choices[idx].text != NULL) + free(choices[idx].text); + + choices[idx].text = alloc((int)(strlen(fmt) + strlen(arg)) - 1); + sprintf(choices[idx].text, fmt, arg); +} + +/* + * Toggle the "Overwrite .../vim.bat" to "Don't overwrite". + */ + static void +toggle_bat_choice(int idx) +{ + char *batname = targets[choices[idx].arg].batpath; + char *oldname = targets[choices[idx].arg].oldbat; + + if (*batname == NUL) + { + alloc_text(idx, " Overwrite %s", oldname); + strcpy(batname, oldname); + } + else + { + alloc_text(idx, " Do NOT overwrite %s", oldname); + *batname = NUL; + } +} + +/* + * Do some work for a batch file entry: Append the batch file name to the path + * and set the text for the choice. + */ + static void +set_bat_text(int idx, char *batpath, char *name) +{ + strcat(batpath, name); + + alloc_text(idx, " Create %s", batpath); +} + +/* + * Select a directory to write the batch file line. + */ + static void +change_bat_choice(int idx) +{ + char *path; + char *batpath; + char *name; + int n; + char *s; + char *p; + int count; + char **names = NULL; + int i; + int target = choices[idx].arg; + + name = targets[target].batname; + batpath = targets[target].batpath; + + path = getenv("PATH"); + if (path == NULL) + { + printf("\nERROR: The variable $PATH is not set\n"); + return; + } + + /* + * first round: count number of names in path; + * second round: save names to names[]. + */ + for (;;) + { + count = 1; + for (p = path; *p; ) + { + s = strchr(p, ';'); + if (s == NULL) + s = p + strlen(p); + if (names != NULL) + { + names[count] = alloc((int)(s - p) + 1); + strncpy(names[count], p, s - p); + names[count][s - p] = NUL; + } + ++count; + p = s; + if (*p != NUL) + ++p; + } + if (names != NULL) + break; + names = alloc((int)(count + 1) * sizeof(char *)); + } + names[0] = alloc(50); + sprintf(names[0], "Select directory to create %s in:", name); + names[count] = alloc(50); + if (choices[idx].arg == 0) + sprintf(names[count], "Do not create any .bat file."); + else + sprintf(names[count], "Do not create a %s file.", name); + n = get_choice(names, count + 1); + + if (n == count) + { + /* Selected last item, don't create bat file. */ + *batpath = NUL; + if (choices[idx].arg != 0) + alloc_text(idx, " Do NOT create %s", name); + } + else + { + /* Selected one of the paths. For the first item only keep the path, + * for the others append the batch file name. */ + strcpy(batpath, names[n]); + add_pathsep(batpath); + if (choices[idx].arg != 0) + set_bat_text(idx, batpath, name); + } + + for (i = 0; i <= count; ++i) + free(names[i]); + free(names); +} + +char *bat_text_yes = "Install .bat files to use Vim at the command line:"; +char *bat_text_no = "do NOT install .bat files to use Vim at the command line"; + + static void +change_main_bat_choice(int idx) +{ + int i; + + /* let the user select a default directory or NONE */ + change_bat_choice(idx); + + if (targets[0].batpath[0] != NUL) + choices[idx].text = bat_text_yes; + else + choices[idx].text = bat_text_no; + + /* update the individual batch file selections */ + for (i = 1; i < TARGET_COUNT; ++i) + { + /* Only make it active when the first item has a path and the vim.exe + * or gvim.exe exists (there is a changefunc then). */ + if (targets[0].batpath[0] != NUL + && choices[idx + i].changefunc != NULL) + { + choices[idx + i].active = 1; + if (choices[idx + i].changefunc == change_bat_choice + && targets[i].batpath[0] != NUL) + { + strcpy(targets[i].batpath, targets[0].batpath); + set_bat_text(idx + i, targets[i].batpath, targets[i].batname); + } + } + else + choices[idx + i].active = 0; + } +} + +/* + * Initialize a choice for creating a batch file. + */ + static void +init_bat_choice(int target) +{ + char *batpath = targets[target].batpath; + char *oldbat = targets[target].oldbat; + char *p; + int i; + + choices[choice_count].arg = target; + choices[choice_count].installfunc = install_bat_choice; + choices[choice_count].active = 1; + choices[choice_count].text = NULL; /* will be set below */ + if (oldbat != NULL) + { + /* A [g]vim.bat exists: Only choice is to overwrite it or not. */ + choices[choice_count].changefunc = toggle_bat_choice; + *batpath = NUL; + toggle_bat_choice(choice_count); + } + else + { + if (default_bat_dir != NULL) + /* Prefer using the same path as an existing .bat file. */ + strcpy(batpath, default_bat_dir); + else + { + /* No [g]vim.bat exists: Write it to a directory in $PATH. Use + * $WINDIR by default, if it's empty the first item in $PATH. */ + p = getenv("WINDIR"); + if (p != NULL && *p != NUL) + strcpy(batpath, p); + else + { + p = getenv("PATH"); + if (p == NULL || *p == NUL) /* "cannot happen" */ + strcpy(batpath, "C:/Windows"); + else + { + i = 0; + while (*p != NUL && *p != ';') + batpath[i++] = *p++; + batpath[i] = NUL; + } + } + } + add_pathsep(batpath); + set_bat_text(choice_count, batpath, targets[target].batname); + + choices[choice_count].changefunc = change_bat_choice; + } + ++choice_count; +} + +/* + * Set up the choices for installing .bat files. + * For these items "arg" is the index in targets[]. + */ + static void +init_bat_choices(void) +{ + int i; + + /* The first item is used to switch installing batch files on/off and + * setting the default path. */ + choices[choice_count].text = bat_text_yes; + choices[choice_count].changefunc = change_main_bat_choice; + choices[choice_count].installfunc = NULL; + choices[choice_count].active = 1; + choices[choice_count].arg = 0; + ++choice_count; + + /* Add items for each batch file target. Only used when not disabled by + * the first item. When a .exe exists, don't offer to create a .bat. */ + for (i = 1; i < TARGET_COUNT; ++i) + if (targets[i].oldexe == NULL + && (targets[i].exenamearg[0] == 'g' ? has_gvim : has_vim)) + init_bat_choice(i); + else + add_dummy_choice(); +} + +/* + * Install the vimrc file. + */ +/*ARGSUSED*/ + static void +install_vimrc(int idx) +{ + FILE *fd, *tfd; + char *fname; + char *p; + + /* If an old vimrc file exists, overwrite it. + * Otherwise create a new one. */ + if (*oldvimrc != NUL) + fname = oldvimrc; + else + fname = vimrc; + + fd = fopen(fname, "w"); + if (fd == NULL) + { + printf("\nERROR: Cannot open \"%s\" for writing.\n", fname); + return; + } + switch (compat_choice) + { + case compat_vi: + fprintf(fd, "set compatible\n"); + break; + case compat_some_enhancements: + fprintf(fd, "set nocompatible\n"); + break; + case compat_all_enhancements: + fprintf(fd, "set nocompatible\n"); + fprintf(fd, "source $VIMRUNTIME/vimrc_example.vim\n"); + break; + } + switch (remap_choice) + { + case remap_no: + break; + case remap_win: + fprintf(fd, "source $VIMRUNTIME/mswin.vim\n"); + break; + } + switch (mouse_choice) + { + case mouse_xterm: + fprintf(fd, "behave xterm\n"); + break; + case mouse_mswin: + fprintf(fd, "behave mswin\n"); + break; + } + if ((tfd = fopen("diff.exe", "r")) != NULL) + { + /* Use the diff.exe that comes with the self-extracting gvim.exe. */ + fclose(tfd); + fprintf(fd, "\n"); + fprintf(fd, "set diffexpr=MyDiff()\n"); + fprintf(fd, "function MyDiff()\n"); + fprintf(fd, " let opt = '-a --binary '\n"); + fprintf(fd, " if &diffopt =~ 'icase' | let opt = opt . '-i ' | endif\n"); + fprintf(fd, " if &diffopt =~ 'iwhite' | let opt = opt . '-b ' | endif\n"); + /* Use quotes only when needed, they may cause trouble. */ + fprintf(fd, " let arg1 = v:fname_in\n"); + fprintf(fd, " if arg1 =~ ' ' | let arg1 = '\"' . arg1 . '\"' | endif\n"); |