summaryrefslogtreecommitdiffstats
path: root/src/dosinst.c
diff options
context:
space:
mode:
authorBram Moolenaar <Bram@vim.org>2004-06-13 20:20:40 +0000
committerBram Moolenaar <Bram@vim.org>2004-06-13 20:20:40 +0000
commit071d4279d6ab81b7187b48f3a0fc61e587b6db6c (patch)
tree221cbe3c40e043163c06f61c52a7ba2eb41e12ce /src/dosinst.c
parentb4210b3bc14e2918f153a7307530fbe6eba659e1 (diff)
updated for version 7.0001v7.0001
Diffstat (limited to 'src/dosinst.c')
-rw-r--r--src/dosinst.c2461
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");
+ fprintf(