summaryrefslogtreecommitdiffstats
path: root/src/dosinst.h
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--src/dosinst.h531
1 files changed, 531 insertions, 0 deletions
diff --git a/src/dosinst.h b/src/dosinst.h
new file mode 100644
index 0000000..59de932
--- /dev/null
+++ b/src/dosinst.h
@@ -0,0 +1,531 @@
+/* vi:set ts=8 sts=4 sw=4 noet:
+ *
+ * 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.h: Common code for dosinst.c and uninstal.c
+ */
+
+/* Visual Studio 2005 has 'deprecated' many of the standard CRT functions */
+#if _MSC_VER >= 1400
+# define _CRT_SECURE_NO_DEPRECATE
+# define _CRT_NONSTDC_NO_DEPRECATE
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+
+#ifndef UNIX_LINT
+# include "vimio.h"
+# include <ctype.h>
+
+# include <direct.h>
+
+# include <windows.h>
+# include <shlobj.h>
+#endif
+
+#ifdef UNIX_LINT
+/* Running lint on Unix: Some things are missing. */
+char *searchpath(char *name);
+#endif
+
+#if defined(UNIX_LINT)
+# include <unistd.h>
+# include <errno.h>
+#endif
+
+#include "version.h"
+
+#if defined(UNIX_LINT)
+# define vim_mkdir(x, y) mkdir((char *)(x), y)
+#else
+# ifndef __BORLANDC__
+# define vim_mkdir(x, y) _mkdir((char *)(x))
+# else
+# define vim_mkdir(x, y) mkdir((char *)(x))
+# endif
+#endif
+
+#define sleep(n) Sleep((n) * 1000)
+
+/* ---------------------------------------- */
+
+
+#define BUFSIZE 512 /* long enough to hold a file name path */
+#define NUL 0
+
+#define FAIL 0
+#define OK 1
+
+#ifndef FALSE
+# define FALSE 0
+#endif
+#ifndef TRUE
+# define TRUE 1
+#endif
+
+/*
+ * Modern way of creating registry entries, also works on 64 bit windows when
+ * compiled as a 32 bit program.
+ */
+# ifndef KEY_WOW64_64KEY
+# define KEY_WOW64_64KEY 0x0100
+# endif
+# ifndef KEY_WOW64_32KEY
+# define KEY_WOW64_32KEY 0x0200
+# endif
+
+#define VIM_STARTMENU "Programs\\Vim " VIM_VERSION_SHORT
+
+int interactive; /* non-zero when running interactively */
+
+/*
+ * Call malloc() and exit when out of memory.
+ */
+ static void *
+alloc(int len)
+{
+ char *s;
+
+ s = malloc(len);
+ if (s == NULL)
+ {
+ printf("ERROR: out of memory\n");
+ exit(1);
+ }
+ return (void *)s;
+}
+
+/*
+ * The toupper() in Bcc 5.5 doesn't work, use our own implementation.
+ */
+ static int
+mytoupper(int c)
+{
+ if (c >= 'a' && c <= 'z')
+ return c - 'a' + 'A';
+ return c;
+}
+
+ static void
+myexit(int n)
+{
+ if (!interactive)
+ {
+ /* Present a prompt, otherwise error messages can't be read. */
+ printf("Press Enter to continue\n");
+ rewind(stdin);
+ (void)getchar();
+ }
+ exit(n);
+}
+
+
+typedef BOOL (WINAPI *LPFN_ISWOW64PROCESS)(HANDLE, PBOOL);
+/*
+ * Check if this is a 64-bit OS.
+ */
+ static BOOL
+is_64bit_os(void)
+{
+#ifdef _WIN64
+ return TRUE;
+#else
+ BOOL bIsWow64 = FALSE;
+ LPFN_ISWOW64PROCESS pIsWow64Process;
+
+ pIsWow64Process = (LPFN_ISWOW64PROCESS)GetProcAddress(
+ GetModuleHandle("kernel32"), "IsWow64Process");
+ if (pIsWow64Process != NULL)
+ pIsWow64Process(GetCurrentProcess(), &bIsWow64);
+ return bIsWow64;
+#endif
+}
+
+#ifdef __BORLANDC__
+/* Borland defines its own searchpath() in dir.h */
+# include <dir.h>
+#else
+ static char *
+searchpath(char *name)
+{
+ static char widename[2 * BUFSIZE];
+ static char location[2 * BUFSIZE + 2];
+
+ /* There appears to be a bug in FindExecutableA() on Windows NT.
+ * Use FindExecutableW() instead... */
+ MultiByteToWideChar(CP_ACP, 0, (LPCTSTR)name, -1,
+ (LPWSTR)widename, BUFSIZE);
+ if (FindExecutableW((LPCWSTR)widename, (LPCWSTR)"",
+ (LPWSTR)location) > (HINSTANCE)32)
+ {
+ WideCharToMultiByte(CP_ACP, 0, (LPWSTR)location, -1,
+ (LPSTR)widename, 2 * BUFSIZE, NULL, NULL);
+ return widename;
+ }
+ return NULL;
+}
+#endif
+
+/*
+ * Call searchpath() and save the result in allocated memory, or return NULL.
+ */
+ static char *
+searchpath_save(char *name)
+{
+ char *p;
+ char *s;
+
+ p = searchpath(name);
+ if (p == NULL)
+ return NULL;
+ s = alloc(strlen(p) + 1);
+ strcpy(s, p);
+ return s;
+}
+
+
+#ifndef CSIDL_COMMON_PROGRAMS
+# define CSIDL_COMMON_PROGRAMS 0x0017
+#endif
+#ifndef CSIDL_COMMON_DESKTOPDIRECTORY
+# define CSIDL_COMMON_DESKTOPDIRECTORY 0x0019
+#endif
+
+/*
+ * Get the path to a requested Windows shell folder.
+ *
+ * Return FAIL on error, OK on success
+ */
+ int
+get_shell_folder_path(
+ char *shell_folder_path,
+ const char *shell_folder_name)
+{
+ /*
+ * The following code was successfully built with make_mvc.mak.
+ * The resulting executable worked on Windows 95, Millennium Edition, and
+ * 2000 Professional. But it was changed after testing...
+ */
+ LPITEMIDLIST pidl = 0; /* Pointer to an Item ID list allocated below */
+ LPMALLOC pMalloc; /* Pointer to an IMalloc interface */
+ int csidl;
+ int alt_csidl = -1;
+ static int desktop_csidl = -1;
+ static int programs_csidl = -1;
+ int *pcsidl;
+ int r;
+
+ if (strcmp(shell_folder_name, "desktop") == 0)
+ {
+ pcsidl = &desktop_csidl;
+ csidl = CSIDL_COMMON_DESKTOPDIRECTORY;
+ alt_csidl = CSIDL_DESKTOP;
+ }
+ else if (strncmp(shell_folder_name, "Programs", 8) == 0)
+ {
+ pcsidl = &programs_csidl;
+ csidl = CSIDL_COMMON_PROGRAMS;
+ alt_csidl = CSIDL_PROGRAMS;
+ }
+ else
+ {
+ printf("\nERROR (internal) unrecognised shell_folder_name: \"%s\"\n\n",
+ shell_folder_name);
+ return FAIL;
+ }
+
+ /* Did this stuff before, use the same ID again. */
+ if (*pcsidl >= 0)
+ {
+ csidl = *pcsidl;
+ alt_csidl = -1;
+ }
+
+retry:
+ /* Initialize pointer to IMalloc interface */
+ if (NOERROR != SHGetMalloc(&pMalloc))
+ {
+ printf("\nERROR getting interface for shell_folder_name: \"%s\"\n\n",
+ shell_folder_name);
+ return FAIL;
+ }
+
+ /* Get an ITEMIDLIST corresponding to the folder code */
+ if (NOERROR != SHGetSpecialFolderLocation(0, csidl, &pidl))
+ {
+ if (alt_csidl < 0 || NOERROR != SHGetSpecialFolderLocation(0,
+ alt_csidl, &pidl))
+ {
+ printf("\nERROR getting ITEMIDLIST for shell_folder_name: \"%s\"\n\n",
+ shell_folder_name);
+ return FAIL;
+ }
+ csidl = alt_csidl;
+ alt_csidl = -1;
+ }
+
+ /* Translate that ITEMIDLIST to a string */
+ r = SHGetPathFromIDList(pidl, shell_folder_path);
+
+ /* Free the data associated with pidl */
+ pMalloc->lpVtbl->Free(pMalloc, pidl);
+ /* Release the IMalloc interface */
+ pMalloc->lpVtbl->Release(pMalloc);
+
+ if (!r)
+ {
+ if (alt_csidl >= 0)
+ {
+ /* We probably get here for Windows 95: the "all users"
+ * desktop/start menu entry doesn't exist. */
+ csidl = alt_csidl;
+ alt_csidl = -1;
+ goto retry;
+ }
+ printf("\nERROR translating ITEMIDLIST for shell_folder_name: \"%s\"\n\n",
+ shell_folder_name);
+ return FAIL;
+ }
+
+ /* If there is an alternative: verify we can write in this directory.
+ * This should cause a retry when the "all users" directory exists but we
+ * are a normal user and can't write there. */
+ if (alt_csidl >= 0)
+ {
+ char tbuf[BUFSIZE];
+ FILE *fd;
+
+ strcpy(tbuf, shell_folder_path);
+ strcat(tbuf, "\\vim write test");
+ fd = fopen(tbuf, "w");
+ if (fd == NULL)
+ {
+ csidl = alt_csidl;
+ alt_csidl = -1;
+ goto retry;
+ }
+ fclose(fd);
+ unlink(tbuf);
+ }
+
+ /*
+ * Keep the found csidl for next time, so that we don't have to do the
+ * write test every time.
+ */
+ if (*pcsidl < 0)
+ *pcsidl = csidl;
+
+ if (strncmp(shell_folder_name, "Programs\\", 9) == 0)
+ strcat(shell_folder_path, shell_folder_name + 8);
+
+ return OK;
+}
+
+/*
+ * List of targets. The first one (index zero) is used for the default path
+ * for the batch files.
+ */
+#define TARGET_COUNT 9
+
+struct
+{
+ char *name; /* Vim exe name (without .exe) */
+ char *batname; /* batch file name */
+ char *lnkname; /* shortcut file name */
+ char *exename; /* exe file name */
+ char *exenamearg; /* exe file name when using exearg */
+ char *exearg; /* argument for vim.exe or gvim.exe */
+ char *oldbat; /* path to existing xxx.bat or NULL */
+ char *oldexe; /* path to existing xxx.exe or NULL */
+ char batpath[BUFSIZE]; /* path of batch file to create; not
+ created when it's empty */
+} targets[TARGET_COUNT] =
+{
+ {"all", "batch files"},
+ {"vim", "vim.bat", "Vim.lnk",
+ "vim.exe", "vim.exe", ""},
+ {"gvim", "gvim.bat", "gVim.lnk",
+ "gvim.exe", "gvim.exe", ""},
+ {"evim", "evim.bat", "gVim Easy.lnk",
+ "evim.exe", "gvim.exe", "-y"},
+ {"view", "view.bat", "Vim Read-only.lnk",
+ "view.exe", "vim.exe", "-R"},
+ {"gview", "gview.bat", "gVim Read-only.lnk",
+ "gview.exe", "gvim.exe", "-R"},
+ {"vimdiff", "vimdiff.bat", "Vim Diff.lnk",
+ "vimdiff.exe","vim.exe", "-d"},
+ {"gvimdiff","gvimdiff.bat", "gVim Diff.lnk",
+ "gvimdiff.exe","gvim.exe", "-d"},
+ {"vimtutor","vimtutor.bat", "Vim tutor.lnk",
+ "vimtutor.bat", "vimtutor.bat", ""},
+};
+
+#define ICON_COUNT 3
+char *(icon_names[ICON_COUNT]) =
+ {"gVim " VIM_VERSION_SHORT,
+ "gVim Easy " VIM_VERSION_SHORT,
+ "gVim Read only " VIM_VERSION_SHORT};
+char *(icon_link_names[ICON_COUNT]) =
+ {"gVim " VIM_VERSION_SHORT ".lnk",
+ "gVim Easy " VIM_VERSION_SHORT ".lnk",
+ "gVim Read only " VIM_VERSION_SHORT ".lnk"};
+
+/* This is only used for dosinst.c. */
+#if defined(DOSINST)
+/*
+ * Run an external command and wait for it to finish.
+ */
+ static void
+run_command(char *cmd)
+{
+ char *cmd_path;
+ char cmd_buf[BUFSIZE];
+ char *p;
+
+ /* On WinNT, 'start' is a shell built-in for cmd.exe rather than an
+ * executable (start.exe) like in Win9x. */
+ cmd_path = searchpath_save("cmd.exe");
+ if (cmd_path != NULL)
+ {
+ /* There is a cmd.exe, so this might be Windows NT. If it is,
+ * we need to call cmd.exe explicitly. If it is a later OS,
+ * calling cmd.exe won't hurt if it is present.
+ * Also, "start" on NT expects a window title argument.
+ */
+ /* Replace the slashes with backslashes. */
+ while ((p = strchr(cmd_path, '/')) != NULL)
+ *p = '\\';
+ sprintf(cmd_buf, "%s /c start \"vimcmd\" /wait %s", cmd_path, cmd);
+ free(cmd_path);
+ }
+ else
+ {
+ /* No cmd.exe, just make the call and let the system handle it. */
+ sprintf(cmd_buf, "start /w %s", cmd);
+ }
+ system(cmd_buf);
+}
+#endif
+
+/*
+ * Append a backslash to "name" if there isn't one yet.
+ */
+ void
+add_pathsep(char *name)
+{
+ int len = strlen(name);
+
+ if (len > 0 && name[len - 1] != '\\' && name[len - 1] != '/')
+ strcat(name, "\\");
+}
+
+/*
+ * The normal chdir() does not change the default drive. This one does.
+ */
+/*ARGSUSED*/
+ int
+change_drive(int drive)
+{
+ char temp[3] = "-:";
+ temp[0] = (char)(drive + 'A' - 1);
+ return !SetCurrentDirectory(temp);
+}
+
+/*
+ * Change directory to "path".
+ * Return 0 for success, -1 for failure.
+ */
+ int
+mch_chdir(char *path)
+{
+ if (path[0] == NUL) /* just checking... */
+ return 0;
+ if (path[1] == ':') /* has a drive name */
+ {
+ if (change_drive(mytoupper(path[0]) - 'A' + 1))
+ return -1; /* invalid drive name */
+ path += 2;
+ }
+ if (*path == NUL) /* drive name only */
+ return 0;
+ return chdir(path); /* let the normal chdir() do the rest */
+}
+
+/*
+ * Expand the executable name into a full path name.
+ */
+#if defined(__BORLANDC__)
+
+/* Only Borland C++ has this. */
+# define my_fullpath(b, n, l) _fullpath(b, n, l)
+
+#else
+ static char *
+my_fullpath(char *buf, char *fname, int len)
+{
+ /* Only GetModuleFileName() will get the long file name path.
+ * GetFullPathName() may still use the short (FAT) name. */
+ DWORD len_read = GetModuleFileName(NULL, buf, (size_t)len);
+
+ return (len_read > 0 && len_read < (DWORD)len) ? buf : NULL;
+}
+#endif
+
+/*
+ * Remove the tail from a file or directory name.
+ * Puts a NUL on the last '/' or '\'.
+ */
+ static void
+remove_tail(char *path)
+{
+ int i;
+
+ for (i = strlen(path) - 1; i > 0; --i)
+ if (path[i] == '/' || path[i] == '\\')
+ {
+ path[i] = NUL;
+ break;
+ }
+}
+
+
+char installdir[BUFSIZE]; /* top of the installation dir, where the
+ install.exe is located, E.g.:
+ "c:\vim\vim60" */
+int runtimeidx; /* index in installdir[] where "vim60" starts */
+char *sysdrive; /* system drive or "c:\" */
+
+/*
+ * Setup for using this program.
+ * Sets "installdir[]".
+ */
+ static void
+do_inits(char **argv)
+{
+ /* Find out the full path of our executable. */
+ if (my_fullpath(installdir, argv[0], BUFSIZE) == NULL)
+ {
+ printf("ERROR: Cannot get name of executable\n");
+ myexit(1);
+ }
+ /* remove the tail, the executable name "install.exe" */
+ remove_tail(installdir);
+
+ /* change to the installdir */
+ mch_chdir(installdir);
+
+ /* Find the system drive. Only used for searching the Vim executable, not
+ * very important. */
+ sysdrive = getenv("SYSTEMDRIVE");
+ if (sysdrive == NULL || *sysdrive == NUL)
+ sysdrive = "C:\\";
+}