1 /* vi:set ts=8 sts=4 sw=4:
3 * VIM - Vi IMproved by Bram Moolenaar
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.
10 * dosinst.h: Common code for dosinst.c and uninstal.c
13 /* Visual Studio 2005 has 'deprecated' many of the standard CRT functions */
15 # define _CRT_SECURE_NO_DEPRECATE
16 # define _CRT_NONSTDC_NO_DEPRECATE
33 # if defined(_WIN64) || defined(WIN32)
45 /* Running lint on Unix: Some things are missing. */
46 char *searchpath(char *name
);
49 #if defined(DJGPP) || defined(UNIX_LINT)
56 #if defined(DJGPP) || defined(UNIX_LINT)
57 # define vim_mkdir(x, y) mkdir((char *)(x), y)
59 # if defined(WIN3264) && !defined(__BORLANDC__)
60 # define vim_mkdir(x, y) _mkdir((char *)(x))
62 # define vim_mkdir(x, y) mkdir((char *)(x))
65 /* ---------------------------------------- */
68 #define BUFSIZE 512 /* long enough to hold a file name path */
81 #define VIM_STARTMENU "Programs\\Vim " VIM_VERSION_SHORT
83 int interactive
; /* non-zero when running interactively */
86 * Call malloc() and exit when out of memory.
96 printf("ERROR: out of memory\n");
103 * The toupper() in Bcc 5.5 doesn't work, use our own implementation.
108 if (c
>= 'a' && c
<= 'z')
109 return c
- 'a' + 'A';
118 /* Present a prompt, otherwise error messages can't be read. */
119 printf("Press Enter to continue\n");
127 /* This symbol is not defined in older versions of the SDK or Visual C++ */
129 #ifndef VER_PLATFORM_WIN32_WINDOWS
130 # define VER_PLATFORM_WIN32_WINDOWS 1
133 static DWORD g_PlatformId
;
136 * Set g_PlatformId to VER_PLATFORM_WIN32_NT (NT) or
137 * VER_PLATFORM_WIN32_WINDOWS (Win95).
142 static int done
= FALSE
;
148 ovi
.dwOSVersionInfoSize
= sizeof(ovi
);
151 g_PlatformId
= ovi
.dwPlatformId
;
157 /* Borland defines its own searchpath() in dir.h */
161 searchpath(char *name
)
163 static char widename
[2 * BUFSIZE
];
164 static char location
[2 * BUFSIZE
+ 2];
166 /* There appears to be a bug in FindExecutableA() on Windows NT.
167 * Use FindExecutableW() instead... */
169 if (g_PlatformId
== VER_PLATFORM_WIN32_NT
)
171 MultiByteToWideChar(CP_ACP
, 0, (LPCTSTR
)name
, -1,
172 (LPWSTR
)widename
, BUFSIZE
);
173 if (FindExecutableW((LPCWSTR
)widename
, (LPCWSTR
)"",
174 (LPWSTR
)location
) > (HINSTANCE
)32)
176 WideCharToMultiByte(CP_ACP
, 0, (LPWSTR
)location
, -1,
177 (LPSTR
)widename
, 2 * BUFSIZE
, NULL
, NULL
);
183 if (FindExecutableA((LPCTSTR
)name
, (LPCTSTR
)"",
184 (LPTSTR
)location
) > (HINSTANCE
)32)
193 * Call searchpath() and save the result in allocated memory, or return NULL.
196 searchpath_save(char *name
)
201 p
= searchpath(name
);
204 s
= alloc(strlen(p
) + 1);
211 #ifndef CSIDL_COMMON_PROGRAMS
212 # define CSIDL_COMMON_PROGRAMS 0x0017
214 #ifndef CSIDL_COMMON_DESKTOPDIRECTORY
215 # define CSIDL_COMMON_DESKTOPDIRECTORY 0x0019
219 * Get the path to a requested Windows shell folder.
221 * Return FAIL on error, OK on success
224 get_shell_folder_path(
225 char *shell_folder_path
,
226 const char *shell_folder_name
)
229 * The following code was successfully built with make_mvc.mak.
230 * The resulting executable worked on Windows 95, Millennium Edition, and
231 * 2000 Professional. But it was changed after testing...
233 LPITEMIDLIST pidl
= 0; /* Pointer to an Item ID list allocated below */
234 LPMALLOC pMalloc
; /* Pointer to an IMalloc interface */
237 static int desktop_csidl
= -1;
238 static int programs_csidl
= -1;
242 if (strcmp(shell_folder_name
, "desktop") == 0)
244 pcsidl
= &desktop_csidl
;
245 csidl
= CSIDL_COMMON_DESKTOPDIRECTORY
;
246 alt_csidl
= CSIDL_DESKTOP
;
248 else if (strncmp(shell_folder_name
, "Programs", 8) == 0)
250 pcsidl
= &programs_csidl
;
251 csidl
= CSIDL_COMMON_PROGRAMS
;
252 alt_csidl
= CSIDL_PROGRAMS
;
256 printf("\nERROR (internal) unrecognised shell_folder_name: \"%s\"\n\n",
261 /* Did this stuff before, use the same ID again. */
269 /* Initialize pointer to IMalloc interface */
270 if (NOERROR
!= SHGetMalloc(&pMalloc
))
272 printf("\nERROR getting interface for shell_folder_name: \"%s\"\n\n",
277 /* Get an ITEMIDLIST corresponding to the folder code */
278 if (NOERROR
!= SHGetSpecialFolderLocation(0, csidl
, &pidl
))
280 if (alt_csidl
< 0 || NOERROR
!= SHGetSpecialFolderLocation(0,
283 printf("\nERROR getting ITEMIDLIST for shell_folder_name: \"%s\"\n\n",
291 /* Translate that ITEMIDLIST to a string */
292 r
= SHGetPathFromIDList(pidl
, shell_folder_path
);
294 /* Free the data associated with pidl */
295 pMalloc
->lpVtbl
->Free(pMalloc
, pidl
);
296 /* Release the IMalloc interface */
297 pMalloc
->lpVtbl
->Release(pMalloc
);
303 /* We probably get here for Windows 95: the "all users"
304 * desktop/start menu entry doesn't exist. */
309 printf("\nERROR translating ITEMIDLIST for shell_folder_name: \"%s\"\n\n",
314 /* If there is an alternative: verify we can write in this directory.
315 * This should cause a retry when the "all users" directory exists but we
316 * are a normal user and can't write there. */
322 strcpy(tbuf
, shell_folder_path
);
323 strcat(tbuf
, "\\vim write test");
324 fd
= fopen(tbuf
, "w");
336 * Keep the found csidl for next time, so that we don't have to do the
337 * write test every time.
342 if (strncmp(shell_folder_name
, "Programs\\", 9) == 0)
343 strcat(shell_folder_path
, shell_folder_name
+ 8);
350 * List of targets. The first one (index zero) is used for the default path
351 * for the batch files.
353 #define TARGET_COUNT 9
357 char *name
; /* Vim exe name (without .exe) */
358 char *batname
; /* batch file name */
359 char *lnkname
; /* shortcut file name */
360 char *exename
; /* exe file name */
361 char *exenamearg
; /* exe file name when using exearg */
362 char *exearg
; /* argument for vim.exe or gvim.exe */
363 char *oldbat
; /* path to existing xxx.bat or NULL */
364 char *oldexe
; /* path to existing xxx.exe or NULL */
365 char batpath
[BUFSIZE
]; /* path of batch file to create; not
366 created when it's empty */
367 } targets
[TARGET_COUNT
] =
369 {"all", "batch files"},
370 {"vim", "vim.bat", "Vim.lnk",
371 "vim.exe", "vim.exe", ""},
372 {"gvim", "gvim.bat", "gVim.lnk",
373 "gvim.exe", "gvim.exe", ""},
374 {"evim", "evim.bat", "gVim Easy.lnk",
375 "evim.exe", "gvim.exe", "-y"},
376 {"view", "view.bat", "Vim Read-only.lnk",
377 "view.exe", "vim.exe", "-R"},
378 {"gview", "gview.bat", "gVim Read-only.lnk",
379 "gview.exe", "gvim.exe", "-R"},
380 {"vimdiff", "vimdiff.bat", "Vim Diff.lnk",
381 "vimdiff.exe","vim.exe", "-d"},
382 {"gvimdiff","gvimdiff.bat", "gVim Diff.lnk",
383 "gvimdiff.exe","gvim.exe", "-d"},
384 {"vimtutor","vimtutor.bat", "Vim tutor.lnk",
385 "vimtutor.bat", "vimtutor.bat", ""},
389 char *(icon_names
[ICON_COUNT
]) =
390 {"gVim " VIM_VERSION_SHORT
,
391 "gVim Easy " VIM_VERSION_SHORT
,
392 "gVim Read only " VIM_VERSION_SHORT
};
393 char *(icon_link_names
[ICON_COUNT
]) =
394 {"gVim " VIM_VERSION_SHORT
".lnk",
395 "gVim Easy " VIM_VERSION_SHORT
".lnk",
396 "gVim Read only " VIM_VERSION_SHORT
".lnk"};
398 /* This is only used for dosinst.c and for uninstal.c when not being able to
399 * directly access registry entries. */
400 #if !defined(WIN3264) || defined(DOSINST)
402 * Run an external command and wait for it to finish.
405 run_command(char *cmd
)
408 char cmd_buf
[BUFSIZE
];
411 /* On WinNT, 'start' is a shell built-in for cmd.exe rather than an
412 * executable (start.exe) like in Win9x. DJGPP, being a DOS program,
413 * is given the COMSPEC command.com by WinNT, so we have to find
414 * cmd.exe manually and use it. */
415 cmd_path
= searchpath_save("cmd.exe");
416 if (cmd_path
!= NULL
)
418 /* There is a cmd.exe, so this might be Windows NT. If it is,
419 * we need to call cmd.exe explicitly. If it is a later OS,
420 * calling cmd.exe won't hurt if it is present.
421 * Also, "wait" on NT expects a window title argument.
423 /* Replace the slashes with backslashes. */
424 while ((p
= strchr(cmd_path
, '/')) != NULL
)
426 sprintf(cmd_buf
, "%s /c start \"vimcmd\" /w %s", cmd_path
, cmd
);
431 /* No cmd.exe, just make the call and let the system handle it. */
432 sprintf(cmd_buf
, "start /w %s", cmd
);
439 * Append a backslash to "name" if there isn't one yet.
442 add_pathsep(char *name
)
444 int len
= strlen(name
);
446 if (len
> 0 && name
[len
- 1] != '\\' && name
[len
- 1] != '/')
451 * The normal chdir() does not change the default drive. This one does.
455 change_drive(int drive
)
459 temp
[0] = (char)(drive
+ 'A' - 1);
460 return !SetCurrentDirectory(temp
);
466 regs
.h
.dl
= drive
- 1;
467 intdos(®s
, ®s
); /* set default drive */
469 intdos(®s
, ®s
); /* get default drive */
470 if (regs
.h
.al
== drive
- 1)
478 * Change directory to "path".
479 * Return 0 for success, -1 for failure.
482 mch_chdir(char *path
)
484 if (path
[0] == NUL
) /* just checking... */
486 if (path
[1] == ':') /* has a drive name */
488 if (change_drive(mytoupper(path
[0]) - 'A' + 1))
489 return -1; /* invalid drive name */
492 if (*path
== NUL
) /* drive name only */
494 return chdir(path
); /* let the normal chdir() do the rest */
498 * Expand the executable name into a full path name.
500 #if defined(__BORLANDC__) && !defined(WIN3264)
502 /* Only Borland C++ has this. */
503 # define my_fullpath(b, n, l) _fullpath(b, n, l)
507 my_fullpath(char *buf
, char *fname
, int len
)
510 /* Only GetModuleFileName() will get the long file name path.
511 * GetFullPathName() may still use the short (FAT) name. */
512 DWORD len_read
= GetModuleFileName(NULL
, buf
, (size_t)len
);
514 return (len_read
> 0 && len_read
< (DWORD
)len
) ? buf
: NULL
;
516 char olddir
[BUFSIZE
];
521 if (strchr(fname
, ':') != NULL
) /* already expanded */
523 strncpy(buf
, fname
, len
);
529 * change to the directory for a moment,
530 * and then do the getwd() (and get back to where we were).
531 * This will get the correct path name with "../" things.
533 p
= strrchr(fname
, '/');
534 q
= strrchr(fname
, '\\');
535 if (q
!= NULL
&& (p
== NULL
|| q
> p
))
537 q
= strrchr(fname
, ':');
538 if (q
!= NULL
&& (p
== NULL
|| q
> p
))
542 if (getcwd(olddir
, BUFSIZE
) == NULL
)
544 p
= NULL
; /* can't get current dir: don't chdir */
549 if (p
== fname
) /* /fname */
550 q
= p
+ 1; /* -> / */
551 else if (q
+ 1 == p
) /* ... c:\foo */
552 q
= p
+ 1; /* -> c:\ */
553 else /* but c:\foo\bar */
554 q
= p
; /* -> c:\foo */
556 c
= *q
; /* truncate at start of fname */
558 if (mch_chdir(fname
)) /* change to the directory */
563 if (c
== '\\') /* if we cut the name at a */
564 fname
++; /* '\', don't add it again */
569 if (getcwd(buf
, len
) == NULL
)
575 * Concatenate the file name to the path.
577 if (strlen(buf
) + strlen(fname
) >= len
- 1)
579 printf("ERROR: File name too long!\n");
588 /* Replace forward slashes with backslashes, required for the path to a
590 while ((p
= strchr(buf
, '/')) != NULL
)
599 * Remove the tail from a file or directory name.
600 * Puts a NUL on the last '/' or '\'.
603 remove_tail(char *path
)
607 for (i
= strlen(path
) - 1; i
> 0; --i
)
608 if (path
[i
] == '/' || path
[i
] == '\\')
616 char installdir
[BUFSIZE
]; /* top of the installation dir, where the
617 install.exe is located, E.g.:
619 int runtimeidx
; /* index in installdir[] where "vim60" starts */
620 char *sysdrive
; /* system drive or "c:\" */
623 * Setup for using this program.
624 * Sets "installdir[]".
627 do_inits(char **argv
)
631 * Use Long File Names by default, if $LFN not set.
633 if (getenv("LFN") == NULL
)
637 /* Find out the full path of our executable. */
638 if (my_fullpath(installdir
, argv
[0], BUFSIZE
) == NULL
)
640 printf("ERROR: Cannot get name of executable\n");
643 /* remove the tail, the executable name "install.exe" */
644 remove_tail(installdir
);
646 /* change to the installdir */
647 mch_chdir(installdir
);
649 /* Find the system drive. Only used for searching the Vim executable, not
651 sysdrive
= getenv("SYSTEMDRIVE");
652 if (sysdrive
== NULL
|| *sysdrive
== NUL
)