Mercurial > vim
annotate src/dosinst.h @ 32936:c517845bd10e v9.0.1776
patch 9.0.1776: No support for stable Python 3 ABI
Commit: https://github.com/vim/vim/commit/c13b3d1350b60b94fe87f0761ea31c0e7fb6ebf3
Author: Yee Cheng Chin <ychin.git@gmail.com>
Date: Sun Aug 20 21:18:38 2023 +0200
patch 9.0.1776: No support for stable Python 3 ABI
Problem: No support for stable Python 3 ABI
Solution: Support Python 3 stable ABI
Commits:
1) Support Python 3 stable ABI to allow mixed version interoperatbility
Vim currently supports embedding Python for use with plugins, and the
"dynamic" linking option allows the user to specify a locally installed
version of Python by setting `pythonthreedll`. However, one caveat is
that the Python 3 libs are not binary compatible across minor versions,
and mixing versions can potentially be dangerous (e.g. let's say Vim was
linked against the Python 3.10 SDK, but the user sets `pythonthreedll`
to a 3.11 lib). Usually, nothing bad happens, but in theory this could
lead to crashes, memory corruption, and other unpredictable behaviors.
It's also difficult for the user to tell something is wrong because Vim
has no way of reporting what Python 3 version Vim was linked with.
For Vim installed via a package manager, this usually isn't an issue
because all the dependencies would already be figured out. For prebuilt
Vim binaries like MacVim (my motivation for working on this), AppImage,
and Win32 installer this could potentially be an issue as usually a
single binary is distributed. This is more tricky when a new Python
version is released, as there's a chicken-and-egg issue with deciding
what Python version to build against and hard to keep in sync when a new
Python version just drops and we have a mix of users of different Python
versions, and a user just blindly upgrading to a new Python could lead to
bad interactions with Vim.
Python 3 does have a solution for this problem: stable ABI / limited API
(see https://docs.python.org/3/c-api/stable.html). The C SDK limits the
API to a set of functions that are promised to be stable across
versions. This pull request adds an ifdef config that allows us to turn
it on when building Vim. Vim binaries built with this option should be
safe to freely link with any Python 3 libraies without having the
constraint of having to use the same minor version.
Note: Python 2 has no such concept and this doesn't change how Python 2
integration works (not that there is going to be a new version of Python
2 that would cause compatibility issues in the future anyway).
---
Technical details:
======
The stable ABI can be accessed when we compile with the Python 3 limited
API (by defining `Py_LIMITED_API`). The Python 3 code (in `if_python3.c`
and `if_py_both.h`) would now handle this and switch to limited API
mode. Without it set, Vim will still use the full API as before so this
is an opt-in change.
The main difference is that `PyType_Object` is now an opaque struct that
we can't directly create "static types" out of, and we have to create
type objects as "heap types" instead. This is because the struct is not
stable and changes from version to version (e.g. 3.8 added a
`tp_vectorcall` field to it). I had to change all the types to be
allocated on the heap instead with just a pointer to them.
Other functions are also simply missing in limited API, or they are
introduced too late (e.g. `PyUnicode_AsUTF8AndSize` in 3.10) to it that
we need some other ways to do the same thing, so I had to abstract a few
things into macros, and sometimes re-implement functions like
`PyObject_NEW`.
One caveat is that in limited API, `OutputType` (used for replacing
`sys.stdout`) no longer inherits from `PyStdPrinter_Type` which I don't
think has any real issue other than minor differences in how they
convert to a string and missing a couple functions like `mode()` and
`fileno()`.
Also fixed an existing bug where `tp_basicsize` was set incorrectly for
`BufferObject`, `TabListObject, `WinListObject`.
Technically, there could be a small performance drop, there is a little
more indirection with accessing type objects, and some APIs like
`PyUnicode_AsUTF8AndSize` are missing, but in practice I didn't see any
difference, and any well-written Python plugin should try to avoid
excessing callbacks to the `vim` module in Python anyway.
I only tested limited API mode down to Python 3.7, which seemes to
compile and work fine. I haven't tried earlier Python versions.
2) Fix PyIter_Check on older Python vers / type##Ptr unused warning
For PyIter_Check, older versions exposed them as either macros (used in
full API), or a function (for use in limited API). A previous change
exposed PyIter_Check to the dynamic build because Python just moved it
to function-only in 3.10 anyway. Because of that, just make sure we
always grab the function in dynamic builds in earlier versions since
that's what Python eventually did anyway.
3) Move Py_LIMITED_API define to configure script
Can now use --with-python-stable-abi flag to customize what stable ABI
version to target. Can also use an env var to do so as well.
4) Show +python/dyn-stable in :version, and allow has() feature query
Not sure if the "/dyn-stable" suffix would break things, or whether we
should do it another way. Or just don't show it in version and rely on
has() feature checking.
5) Documentation first draft. Still need to implement v:python3_version
6) Fix PyIter_Check build breaks when compiling against Python 3.8
7) Add CI coverage stable ABI on Linux/Windows / make configurable on Windows
This adds configurable options for Windows make files (both MinGW and
MSVC). CI will also now exercise both traditional full API and stable
ABI for Linux and Windows in the matrix for coverage.
Also added a "dynamic" option to Linux matrix as a drive-by change to
make other scripting languages like Ruby / Perl testable under both
static and dynamic builds.
8) Fix inaccuracy in Windows docs
Python's own docs are confusing but you don't actually want to use
`python3.dll` for the dynamic linkage.
9) Add generated autoconf file
10) Add v:python3_version support
This variable indicates the version of Python3 that Vim was built
against (PY_VERSION_HEX), and will be useful to check whether the Python
library you are loading in dynamically actually fits it. When built with
stable ABI, it will be the limited ABI version instead
(`Py_LIMITED_API`), which indicates the minimum version of Python 3 the
user should have, rather than the exact match. When stable ABI is used,
we won't be exposing PY_VERSION_HEX in this var because it just doesn't
seem necessary to do so (the whole point of stable ABI is the promise
that it will work across versions), and I don't want to confuse the user
with too many variables.
Also, cleaned up some documentation, and added help tags.
11) Fix Python 3.7 compat issues
Fix a couple issues when using limited API < 3.8
- Crash on exit: In Python 3.7, if a heap-allocated type is destroyed
before all instances are, it would cause a crash later. This happens
when we destroyed `OptionsType` before calling `Py_Finalize` when
using the limited API. To make it worse, later versions changed the
semantics and now each instance has a strong reference to its own type
and the recommendation has changed to have each instance de-ref its
own type and have its type in GC traversal. To avoid dealing with
these cross-version variations, we just don't free the heap type. They
are static types in non-limited-API anyway and are designed to last
through the entirety of the app, and we also don't restart the Python
runtime and therefore do not need it to have absolutely 0 leaks.
See:
- https://docs.python.org/3/whatsnew/3.8.html#changes-in-the-c-api
- https://docs.python.org/3/whatsnew/3.9.html#changes-in-the-c-api
- PyIter_Check: This function is not provided in limited APIs older than
3.8. Previously I was trying to mock it out using manual
PyType_GetSlot() but it was brittle and also does not actually work
properly for static types (it will generate a Python error). Just
return false. It does mean using limited API < 3.8 is not recommended
as you lose the functionality to handle iterators, but from playing
with plugins I couldn't find it to be an issue.
- Fix loading of PyIter_Check so it will be done when limited API < 3.8.
Otherwise loading a 3.7 Python lib will fail even if limited API was
specified to use it.
12) Make sure to only load `PyUnicode_AsUTF8AndSize` in needed in limited API
We don't use this function unless limited API >= 3.10, but we were
loading it regardless. Usually it's ok in Unix-like systems where Python
just has a single lib that we load from, but in Windows where there is a
separate python3.dll this would not work as the symbol would not have
been exposed in this more limited DLL file. This makes it much clearer
under what condition is this function needed.
closes: #12032
Signed-off-by: Christian Brabandt <cb@256bit.org>
Co-authored-by: Yee Cheng Chin <ychin.git@gmail.com>
author | Christian Brabandt <cb@256bit.org> |
---|---|
date | Sun, 20 Aug 2023 21:30:04 +0200 |
parents | 495d55210aac |
children |
rev | line source |
---|---|
10042
4aead6a9b7a9
commit https://github.com/vim/vim/commit/edf3f97ae2af024708ebb4ac614227327033ca47
Christian Brabandt <cb@256bit.org>
parents:
8212
diff
changeset
|
1 /* vi:set ts=8 sts=4 sw=4 noet: |
7 | 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 /* | |
18174
1ec6539cef68
patch 8.1.2082: some files have a weird name to fit in 8.3 characters
Bram Moolenaar <Bram@vim.org>
parents:
16606
diff
changeset
|
10 * dosinst.h: Common code for dosinst.c and uninstall.c |
7 | 11 */ |
714 | 12 |
7 | 13 #include <stdio.h> |
14 #include <stdlib.h> | |
15 #include <string.h> | |
16 #include <sys/stat.h> | |
17 #include <fcntl.h> | |
18 | |
19 #ifndef UNIX_LINT | |
19380
1e78bf92f168
patch 8.2.0248: MS-Windows: dealing with deprecation is too complicated
Bram Moolenaar <Bram@vim.org>
parents:
18753
diff
changeset
|
20 # include <io.h> |
7 | 21 # include <ctype.h> |
22 | |
12626
aca41efd888c
patch 8.0.1191: MS-Windows: missing 32 and 64 bit files in installer
Christian Brabandt <cb@256bit.org>
parents:
10042
diff
changeset
|
23 # include <direct.h> |
7 | 24 |
12626
aca41efd888c
patch 8.0.1191: MS-Windows: missing 32 and 64 bit files in installer
Christian Brabandt <cb@256bit.org>
parents:
10042
diff
changeset
|
25 # include <windows.h> |
aca41efd888c
patch 8.0.1191: MS-Windows: missing 32 and 64 bit files in installer
Christian Brabandt <cb@256bit.org>
parents:
10042
diff
changeset
|
26 # include <shlobj.h> |
7 | 27 #endif |
28 | |
29 #ifdef UNIX_LINT | |
18753
6e3dc2d630c2
patch 8.1.2366: using old C style comments
Bram Moolenaar <Bram@vim.org>
parents:
18174
diff
changeset
|
30 // Running lint on Unix: Some things are missing. |
7 | 31 char *searchpath(char *name); |
32 #endif | |
33 | |
8212
05b88224cea1
commit https://github.com/vim/vim/commit/48e330aff911be1c798c88a973af6437a8141fce
Christian Brabandt <cb@256bit.org>
parents:
8080
diff
changeset
|
34 #if defined(UNIX_LINT) |
7 | 35 # include <unistd.h> |
36 # include <errno.h> | |
37 #endif | |
38 | |
39 #include "version.h" | |
40 | |
8212
05b88224cea1
commit https://github.com/vim/vim/commit/48e330aff911be1c798c88a973af6437a8141fce
Christian Brabandt <cb@256bit.org>
parents:
8080
diff
changeset
|
41 #if defined(UNIX_LINT) |
7 | 42 # define vim_mkdir(x, y) mkdir((char *)(x), y) |
43 #else | |
16606
7e733046db1d
patch 8.1.1306: Borland support is outdated and doesn't work
Bram Moolenaar <Bram@vim.org>
parents:
15941
diff
changeset
|
44 # define vim_mkdir(x, y) _mkdir((char *)(x)) |
7 | 45 #endif |
2287
573da4dac306
Make the dos installer work with more compilers.
Bram Moolenaar <bram@vim.org>
parents:
2217
diff
changeset
|
46 |
8212
05b88224cea1
commit https://github.com/vim/vim/commit/48e330aff911be1c798c88a973af6437a8141fce
Christian Brabandt <cb@256bit.org>
parents:
8080
diff
changeset
|
47 #define sleep(n) Sleep((n) * 1000) |
2287
573da4dac306
Make the dos installer work with more compilers.
Bram Moolenaar <bram@vim.org>
parents:
2217
diff
changeset
|
48 |
18753
6e3dc2d630c2
patch 8.1.2366: using old C style comments
Bram Moolenaar <Bram@vim.org>
parents:
18174
diff
changeset
|
49 // ---------------------------------------- |
7 | 50 |
51 | |
18753
6e3dc2d630c2
patch 8.1.2366: using old C style comments
Bram Moolenaar <Bram@vim.org>
parents:
18174
diff
changeset
|
52 #define BUFSIZE (MAX_PATH*2) // long enough to hold a file name path |
7 | 53 #define NUL 0 |
54 | |
55 #define FAIL 0 | |
56 #define OK 1 | |
57 | |
58 #ifndef FALSE | |
59 # define FALSE 0 | |
60 #endif | |
61 #ifndef TRUE | |
62 # define TRUE 1 | |
63 #endif | |
64 | |
2449
943280505f72
Fix that uninstaller isn't found on 64-bit Windows.
Bram Moolenaar <bram@vim.org>
parents:
2287
diff
changeset
|
65 /* |
943280505f72
Fix that uninstaller isn't found on 64-bit Windows.
Bram Moolenaar <bram@vim.org>
parents:
2287
diff
changeset
|
66 * Modern way of creating registry entries, also works on 64 bit windows when |
943280505f72
Fix that uninstaller isn't found on 64-bit Windows.
Bram Moolenaar <bram@vim.org>
parents:
2287
diff
changeset
|
67 * compiled as a 32 bit program. |
943280505f72
Fix that uninstaller isn't found on 64-bit Windows.
Bram Moolenaar <bram@vim.org>
parents:
2287
diff
changeset
|
68 */ |
943280505f72
Fix that uninstaller isn't found on 64-bit Windows.
Bram Moolenaar <bram@vim.org>
parents:
2287
diff
changeset
|
69 # ifndef KEY_WOW64_64KEY |
943280505f72
Fix that uninstaller isn't found on 64-bit Windows.
Bram Moolenaar <bram@vim.org>
parents:
2287
diff
changeset
|
70 # define KEY_WOW64_64KEY 0x0100 |
943280505f72
Fix that uninstaller isn't found on 64-bit Windows.
Bram Moolenaar <bram@vim.org>
parents:
2287
diff
changeset
|
71 # endif |
12626
aca41efd888c
patch 8.0.1191: MS-Windows: missing 32 and 64 bit files in installer
Christian Brabandt <cb@256bit.org>
parents:
10042
diff
changeset
|
72 # ifndef KEY_WOW64_32KEY |
aca41efd888c
patch 8.0.1191: MS-Windows: missing 32 and 64 bit files in installer
Christian Brabandt <cb@256bit.org>
parents:
10042
diff
changeset
|
73 # define KEY_WOW64_32KEY 0x0200 |
aca41efd888c
patch 8.0.1191: MS-Windows: missing 32 and 64 bit files in installer
Christian Brabandt <cb@256bit.org>
parents:
10042
diff
changeset
|
74 # endif |
2449
943280505f72
Fix that uninstaller isn't found on 64-bit Windows.
Bram Moolenaar <bram@vim.org>
parents:
2287
diff
changeset
|
75 |
29105
faf7fcd1c8d5
patch 8.2.5073: clang on MS-Windows produces warnings
Bram Moolenaar <Bram@vim.org>
parents:
19431
diff
changeset
|
76 #ifdef __MINGW32__ |
faf7fcd1c8d5
patch 8.2.5073: clang on MS-Windows produces warnings
Bram Moolenaar <Bram@vim.org>
parents:
19431
diff
changeset
|
77 # define UNUSED __attribute__((unused)) |
faf7fcd1c8d5
patch 8.2.5073: clang on MS-Windows produces warnings
Bram Moolenaar <Bram@vim.org>
parents:
19431
diff
changeset
|
78 #else |
faf7fcd1c8d5
patch 8.2.5073: clang on MS-Windows produces warnings
Bram Moolenaar <Bram@vim.org>
parents:
19431
diff
changeset
|
79 # define UNUSED |
faf7fcd1c8d5
patch 8.2.5073: clang on MS-Windows produces warnings
Bram Moolenaar <Bram@vim.org>
parents:
19431
diff
changeset
|
80 #endif |
faf7fcd1c8d5
patch 8.2.5073: clang on MS-Windows produces warnings
Bram Moolenaar <Bram@vim.org>
parents:
19431
diff
changeset
|
81 |
7 | 82 #define VIM_STARTMENU "Programs\\Vim " VIM_VERSION_SHORT |
83 | |
18753
6e3dc2d630c2
patch 8.1.2366: using old C style comments
Bram Moolenaar <Bram@vim.org>
parents:
18174
diff
changeset
|
84 int interactive; // non-zero when running interactively |
7 | 85 |
86 /* | |
87 * Call malloc() and exit when out of memory. | |
88 */ | |
89 static void * | |
90 alloc(int len) | |
91 { | |
15941
b9098585d945
patch 8.1.0976: dosinstall still has buffer overflow problems
Bram Moolenaar <Bram@vim.org>
parents:
15892
diff
changeset
|
92 void *p; |
7 | 93 |
15941
b9098585d945
patch 8.1.0976: dosinstall still has buffer overflow problems
Bram Moolenaar <Bram@vim.org>
parents:
15892
diff
changeset
|
94 p = malloc(len); |
b9098585d945
patch 8.1.0976: dosinstall still has buffer overflow problems
Bram Moolenaar <Bram@vim.org>
parents:
15892
diff
changeset
|
95 if (p == NULL) |
7 | 96 { |
97 printf("ERROR: out of memory\n"); | |
98 exit(1); | |
99 } | |
15941
b9098585d945
patch 8.1.0976: dosinstall still has buffer overflow problems
Bram Moolenaar <Bram@vim.org>
parents:
15892
diff
changeset
|
100 return p; |
7 | 101 } |
102 | |
103 /* | |
104 * The toupper() in Bcc 5.5 doesn't work, use our own implementation. | |
105 */ | |
106 static int | |
107 mytoupper(int c) | |
108 { | |
109 if (c >= 'a' && c <= 'z') | |
110 return c - 'a' + 'A'; | |
111 return c; | |
112 } | |
113 | |
114 static void | |
115 myexit(int n) | |
116 { | |
117 if (!interactive) | |
118 { | |
18753
6e3dc2d630c2
patch 8.1.2366: using old C style comments
Bram Moolenaar <Bram@vim.org>
parents:
18174
diff
changeset
|
119 // Present a prompt, otherwise error messages can't be read. |
7 | 120 printf("Press Enter to continue\n"); |
121 rewind(stdin); | |
122 (void)getchar(); | |
123 } | |
124 exit(n); | |
125 } | |
126 | |
127 | |
12626
aca41efd888c
patch 8.0.1191: MS-Windows: missing 32 and 64 bit files in installer
Christian Brabandt <cb@256bit.org>
parents:
10042
diff
changeset
|
128 typedef BOOL (WINAPI *LPFN_ISWOW64PROCESS)(HANDLE, PBOOL); |
7 | 129 /* |
12626
aca41efd888c
patch 8.0.1191: MS-Windows: missing 32 and 64 bit files in installer
Christian Brabandt <cb@256bit.org>
parents:
10042
diff
changeset
|
130 * Check if this is a 64-bit OS. |
7 | 131 */ |
12626
aca41efd888c
patch 8.0.1191: MS-Windows: missing 32 and 64 bit files in installer
Christian Brabandt <cb@256bit.org>
parents:
10042
diff
changeset
|
132 static BOOL |
aca41efd888c
patch 8.0.1191: MS-Windows: missing 32 and 64 bit files in installer
Christian Brabandt <cb@256bit.org>
parents:
10042
diff
changeset
|
133 is_64bit_os(void) |
7 | 134 { |
12626
aca41efd888c
patch 8.0.1191: MS-Windows: missing 32 and 64 bit files in installer
Christian Brabandt <cb@256bit.org>
parents:
10042
diff
changeset
|
135 #ifdef _WIN64 |
aca41efd888c
patch 8.0.1191: MS-Windows: missing 32 and 64 bit files in installer
Christian Brabandt <cb@256bit.org>
parents:
10042
diff
changeset
|
136 return TRUE; |
aca41efd888c
patch 8.0.1191: MS-Windows: missing 32 and 64 bit files in installer
Christian Brabandt <cb@256bit.org>
parents:
10042
diff
changeset
|
137 #else |
aca41efd888c
patch 8.0.1191: MS-Windows: missing 32 and 64 bit files in installer
Christian Brabandt <cb@256bit.org>
parents:
10042
diff
changeset
|
138 BOOL bIsWow64 = FALSE; |
aca41efd888c
patch 8.0.1191: MS-Windows: missing 32 and 64 bit files in installer
Christian Brabandt <cb@256bit.org>
parents:
10042
diff
changeset
|
139 LPFN_ISWOW64PROCESS pIsWow64Process; |
7 | 140 |
12626
aca41efd888c
patch 8.0.1191: MS-Windows: missing 32 and 64 bit files in installer
Christian Brabandt <cb@256bit.org>
parents:
10042
diff
changeset
|
141 pIsWow64Process = (LPFN_ISWOW64PROCESS)GetProcAddress( |
aca41efd888c
patch 8.0.1191: MS-Windows: missing 32 and 64 bit files in installer
Christian Brabandt <cb@256bit.org>
parents:
10042
diff
changeset
|
142 GetModuleHandle("kernel32"), "IsWow64Process"); |
aca41efd888c
patch 8.0.1191: MS-Windows: missing 32 and 64 bit files in installer
Christian Brabandt <cb@256bit.org>
parents:
10042
diff
changeset
|
143 if (pIsWow64Process != NULL) |
aca41efd888c
patch 8.0.1191: MS-Windows: missing 32 and 64 bit files in installer
Christian Brabandt <cb@256bit.org>
parents:
10042
diff
changeset
|
144 pIsWow64Process(GetCurrentProcess(), &bIsWow64); |
aca41efd888c
patch 8.0.1191: MS-Windows: missing 32 and 64 bit files in installer
Christian Brabandt <cb@256bit.org>
parents:
10042
diff
changeset
|
145 return bIsWow64; |
aca41efd888c
patch 8.0.1191: MS-Windows: missing 32 and 64 bit files in installer
Christian Brabandt <cb@256bit.org>
parents:
10042
diff
changeset
|
146 #endif |
7 | 147 } |
148 | |
149 static char * | |
150 searchpath(char *name) | |
151 { | |
152 static char widename[2 * BUFSIZE]; | |
153 static char location[2 * BUFSIZE + 2]; | |
154 | |
18753
6e3dc2d630c2
patch 8.1.2366: using old C style comments
Bram Moolenaar <Bram@vim.org>
parents:
18174
diff
changeset
|
155 // There appears to be a bug in FindExecutableA() on Windows NT. |
6e3dc2d630c2
patch 8.1.2366: using old C style comments
Bram Moolenaar <Bram@vim.org>
parents:
18174
diff
changeset
|
156 // Use FindExecutableW() instead... |
12626
aca41efd888c
patch 8.0.1191: MS-Windows: missing 32 and 64 bit files in installer
Christian Brabandt <cb@256bit.org>
parents:
10042
diff
changeset
|
157 MultiByteToWideChar(CP_ACP, 0, (LPCTSTR)name, -1, |
aca41efd888c
patch 8.0.1191: MS-Windows: missing 32 and 64 bit files in installer
Christian Brabandt <cb@256bit.org>
parents:
10042
diff
changeset
|
158 (LPWSTR)widename, BUFSIZE); |
aca41efd888c
patch 8.0.1191: MS-Windows: missing 32 and 64 bit files in installer
Christian Brabandt <cb@256bit.org>
parents:
10042
diff
changeset
|
159 if (FindExecutableW((LPCWSTR)widename, (LPCWSTR)"", |
aca41efd888c
patch 8.0.1191: MS-Windows: missing 32 and 64 bit files in installer
Christian Brabandt <cb@256bit.org>
parents:
10042
diff
changeset
|
160 (LPWSTR)location) > (HINSTANCE)32) |
7 | 161 { |
12626
aca41efd888c
patch 8.0.1191: MS-Windows: missing 32 and 64 bit files in installer
Christian Brabandt <cb@256bit.org>
parents:
10042
diff
changeset
|
162 WideCharToMultiByte(CP_ACP, 0, (LPWSTR)location, -1, |
aca41efd888c
patch 8.0.1191: MS-Windows: missing 32 and 64 bit files in installer
Christian Brabandt <cb@256bit.org>
parents:
10042
diff
changeset
|
163 (LPSTR)widename, 2 * BUFSIZE, NULL, NULL); |
aca41efd888c
patch 8.0.1191: MS-Windows: missing 32 and 64 bit files in installer
Christian Brabandt <cb@256bit.org>
parents:
10042
diff
changeset
|
164 return widename; |
7 | 165 } |
166 return NULL; | |
167 } | |
168 | |
169 /* | |
170 * Call searchpath() and save the result in allocated memory, or return NULL. | |
171 */ | |
172 static char * | |
173 searchpath_save(char *name) | |
174 { | |
175 char *p; | |
176 char *s; | |
177 | |
178 p = searchpath(name); | |
179 if (p == NULL) | |
180 return NULL; | |
181 s = alloc(strlen(p) + 1); | |
182 strcpy(s, p); | |
183 return s; | |
184 } | |
185 | |
826 | 186 |
187 #ifndef CSIDL_COMMON_PROGRAMS | |
188 # define CSIDL_COMMON_PROGRAMS 0x0017 | |
189 #endif | |
190 #ifndef CSIDL_COMMON_DESKTOPDIRECTORY | |
191 # define CSIDL_COMMON_DESKTOPDIRECTORY 0x0019 | |
192 #endif | |
193 | |
7 | 194 /* |
195 * Get the path to a requested Windows shell folder. | |
196 * | |
197 * Return FAIL on error, OK on success | |
198 */ | |
199 int | |
200 get_shell_folder_path( | |
201 char *shell_folder_path, | |
202 const char *shell_folder_name) | |
203 { | |
204 /* | |
205 * The following code was successfully built with make_mvc.mak. | |
206 * The resulting executable worked on Windows 95, Millennium Edition, and | |
207 * 2000 Professional. But it was changed after testing... | |
208 */ | |
18753
6e3dc2d630c2
patch 8.1.2366: using old C style comments
Bram Moolenaar <Bram@vim.org>
parents:
18174
diff
changeset
|
209 LPITEMIDLIST pidl = 0; // Pointer to an Item ID list allocated below |
6e3dc2d630c2
patch 8.1.2366: using old C style comments
Bram Moolenaar <Bram@vim.org>
parents:
18174
diff
changeset
|
210 LPMALLOC pMalloc; // Pointer to an IMalloc interface |
7 | 211 int csidl; |
212 int alt_csidl = -1; | |
213 static int desktop_csidl = -1; | |
214 static int programs_csidl = -1; | |
215 int *pcsidl; | |
216 int r; | |
217 | |
218 if (strcmp(shell_folder_name, "desktop") == 0) | |
219 { | |
220 pcsidl = &desktop_csidl; | |
221 csidl = CSIDL_COMMON_DESKTOPDIRECTORY; | |
222 alt_csidl = CSIDL_DESKTOP; | |
223 } | |
224 else if (strncmp(shell_folder_name, "Programs", 8) == 0) | |
225 { | |
226 pcsidl = &programs_csidl; | |
227 csidl = CSIDL_COMMON_PROGRAMS; | |
228 alt_csidl = CSIDL_PROGRAMS; | |
229 } | |
230 else | |
231 { | |
232 printf("\nERROR (internal) unrecognised shell_folder_name: \"%s\"\n\n", | |
233 shell_folder_name); | |
234 return FAIL; | |
235 } | |
236 | |
18753
6e3dc2d630c2
patch 8.1.2366: using old C style comments
Bram Moolenaar <Bram@vim.org>
parents:
18174
diff
changeset
|
237 // Did this stuff before, use the same ID again. |
7 | 238 if (*pcsidl >= 0) |
239 { | |
240 csidl = *pcsidl; | |
241 alt_csidl = -1; | |
242 } | |
243 | |
244 retry: | |
18753
6e3dc2d630c2
patch 8.1.2366: using old C style comments
Bram Moolenaar <Bram@vim.org>
parents:
18174
diff
changeset
|
245 // Initialize pointer to IMalloc interface |
7 | 246 if (NOERROR != SHGetMalloc(&pMalloc)) |
247 { | |
248 printf("\nERROR getting interface for shell_folder_name: \"%s\"\n\n", | |
249 shell_folder_name); | |
250 return FAIL; | |
251 } | |
252 | |
18753
6e3dc2d630c2
patch 8.1.2366: using old C style comments
Bram Moolenaar <Bram@vim.org>
parents:
18174
diff
changeset
|
253 // Get an ITEMIDLIST corresponding to the folder code |
7 | 254 if (NOERROR != SHGetSpecialFolderLocation(0, csidl, &pidl)) |
255 { | |
256 if (alt_csidl < 0 || NOERROR != SHGetSpecialFolderLocation(0, | |
257 alt_csidl, &pidl)) | |
258 { | |
259 printf("\nERROR getting ITEMIDLIST for shell_folder_name: \"%s\"\n\n", | |
260 shell_folder_name); | |
261 return FAIL; | |
262 } | |
263 csidl = alt_csidl; | |
264 alt_csidl = -1; | |
265 } | |
266 | |
18753
6e3dc2d630c2
patch 8.1.2366: using old C style comments
Bram Moolenaar <Bram@vim.org>
parents:
18174
diff
changeset
|
267 // Translate that ITEMIDLIST to a string |
7 | 268 r = SHGetPathFromIDList(pidl, shell_folder_path); |
269 | |
18753
6e3dc2d630c2
patch 8.1.2366: using old C style comments
Bram Moolenaar <Bram@vim.org>
parents:
18174
diff
changeset
|
270 // Free the data associated with pidl |
7 | 271 pMalloc->lpVtbl->Free(pMalloc, pidl); |
18753
6e3dc2d630c2
patch 8.1.2366: using old C style comments
Bram Moolenaar <Bram@vim.org>
parents:
18174
diff
changeset
|
272 // Release the IMalloc interface |
7 | 273 pMalloc->lpVtbl->Release(pMalloc); |
274 | |
275 if (!r) | |
276 { | |
277 if (alt_csidl >= 0) | |
278 { | |
18753
6e3dc2d630c2
patch 8.1.2366: using old C style comments
Bram Moolenaar <Bram@vim.org>
parents:
18174
diff
changeset
|
279 // We probably get here for Windows 95: the "all users" |
6e3dc2d630c2
patch 8.1.2366: using old C style comments
Bram Moolenaar <Bram@vim.org>
parents:
18174
diff
changeset
|
280 // desktop/start menu entry doesn't exist. |
7 | 281 csidl = alt_csidl; |
282 alt_csidl = -1; | |
283 goto retry; | |
284 } | |
285 printf("\nERROR translating ITEMIDLIST for shell_folder_name: \"%s\"\n\n", | |
286 shell_folder_name); | |
287 return FAIL; | |
288 } | |
289 | |
18753
6e3dc2d630c2
patch 8.1.2366: using old C style comments
Bram Moolenaar <Bram@vim.org>
parents:
18174
diff
changeset
|
290 // If there is an alternative: verify we can write in this directory. |
6e3dc2d630c2
patch 8.1.2366: using old C style comments
Bram Moolenaar <Bram@vim.org>
parents:
18174
diff
changeset
|
291 // This should cause a retry when the "all users" directory exists but we |
6e3dc2d630c2
patch 8.1.2366: using old C style comments
Bram Moolenaar <Bram@vim.org>
parents:
18174
diff
changeset
|
292 // are a normal user and can't write there. |
7 | 293 if (alt_csidl >= 0) |
294 { | |
295 char tbuf[BUFSIZE]; | |
296 FILE *fd; | |
297 | |
298 strcpy(tbuf, shell_folder_path); | |
299 strcat(tbuf, "\\vim write test"); | |
300 fd = fopen(tbuf, "w"); | |
301 if (fd == NULL) | |
302 { | |
303 csidl = alt_csidl; | |
304 alt_csidl = -1; | |
305 goto retry; | |
306 } | |
307 fclose(fd); | |
308 unlink(tbuf); | |
309 } | |
310 | |
311 /* | |
312 * Keep the found csidl for next time, so that we don't have to do the | |
313 * write test every time. | |
314 */ | |
315 if (*pcsidl < 0) | |
316 *pcsidl = csidl; | |
317 | |
318 if (strncmp(shell_folder_name, "Programs\\", 9) == 0) | |
319 strcat(shell_folder_path, shell_folder_name + 8); | |
320 | |
321 return OK; | |
322 } | |
323 | |
324 /* | |
325 * List of targets. The first one (index zero) is used for the default path | |
326 * for the batch files. | |
327 */ | |
782 | 328 #define TARGET_COUNT 9 |
7 | 329 |
330 struct | |
331 { | |
18753
6e3dc2d630c2
patch 8.1.2366: using old C style comments
Bram Moolenaar <Bram@vim.org>
parents:
18174
diff
changeset
|
332 char *name; // Vim exe name (without .exe) |
6e3dc2d630c2
patch 8.1.2366: using old C style comments
Bram Moolenaar <Bram@vim.org>
parents:
18174
diff
changeset
|
333 char *batname; // batch file name |
6e3dc2d630c2
patch 8.1.2366: using old C style comments
Bram Moolenaar <Bram@vim.org>
parents:
18174
diff
changeset
|
334 char *lnkname; // shortcut file name |
6e3dc2d630c2
patch 8.1.2366: using old C style comments
Bram Moolenaar <Bram@vim.org>
parents:
18174
diff
changeset
|
335 char *exename; // exe file name |
6e3dc2d630c2
patch 8.1.2366: using old C style comments
Bram Moolenaar <Bram@vim.org>
parents:
18174
diff
changeset
|
336 char *exenamearg; // exe file name when using exearg |
6e3dc2d630c2
patch 8.1.2366: using old C style comments
Bram Moolenaar <Bram@vim.org>
parents:
18174
diff
changeset
|
337 char *exearg; // argument for vim.exe or gvim.exe |
6e3dc2d630c2
patch 8.1.2366: using old C style comments
Bram Moolenaar <Bram@vim.org>
parents:
18174
diff
changeset
|
338 char *oldbat; // path to existing xxx.bat or NULL |
6e3dc2d630c2
patch 8.1.2366: using old C style comments
Bram Moolenaar <Bram@vim.org>
parents:
18174
diff
changeset
|
339 char *oldexe; // path to existing xxx.exe or NULL |
6e3dc2d630c2
patch 8.1.2366: using old C style comments
Bram Moolenaar <Bram@vim.org>
parents:
18174
diff
changeset
|
340 char batpath[BUFSIZE]; // path of batch file to create; not |
6e3dc2d630c2
patch 8.1.2366: using old C style comments
Bram Moolenaar <Bram@vim.org>
parents:
18174
diff
changeset
|
341 // created when it's empty |
7 | 342 } targets[TARGET_COUNT] = |
343 { | |
29113
495d55210aac
patch 8.2.5077: various warnings from clang on MS-Windows
Bram Moolenaar <Bram@vim.org>
parents:
29105
diff
changeset
|
344 {"all", "batch files", NULL, NULL, NULL, NULL, NULL, NULL, ""}, |
7 | 345 {"vim", "vim.bat", "Vim.lnk", |
29113
495d55210aac
patch 8.2.5077: various warnings from clang on MS-Windows
Bram Moolenaar <Bram@vim.org>
parents:
29105
diff
changeset
|
346 "vim.exe", "vim.exe", "", NULL, NULL, ""}, |
7 | 347 {"gvim", "gvim.bat", "gVim.lnk", |
29113
495d55210aac
patch 8.2.5077: various warnings from clang on MS-Windows
Bram Moolenaar <Bram@vim.org>
parents:
29105
diff
changeset
|
348 "gvim.exe", "gvim.exe", "", NULL, NULL, ""}, |
7 | 349 {"evim", "evim.bat", "gVim Easy.lnk", |
29113
495d55210aac
patch 8.2.5077: various warnings from clang on MS-Windows
Bram Moolenaar <Bram@vim.org>
parents:
29105
diff
changeset
|
350 "evim.exe", "gvim.exe", "-y", NULL, NULL, ""}, |
7 | 351 {"view", "view.bat", "Vim Read-only.lnk", |
29113
495d55210aac
patch 8.2.5077: various warnings from clang on MS-Windows
Bram Moolenaar <Bram@vim.org>
parents:
29105
diff
changeset
|
352 "view.exe", "vim.exe", "-R", NULL, NULL, ""}, |
7 | 353 {"gview", "gview.bat", "gVim Read-only.lnk", |
29113
495d55210aac
patch 8.2.5077: various warnings from clang on MS-Windows
Bram Moolenaar <Bram@vim.org>
parents:
29105
diff
changeset
|
354 "gview.exe", "gvim.exe", "-R", NULL, NULL, ""}, |
7 | 355 {"vimdiff", "vimdiff.bat", "Vim Diff.lnk", |
29113
495d55210aac
patch 8.2.5077: various warnings from clang on MS-Windows
Bram Moolenaar <Bram@vim.org>
parents:
29105
diff
changeset
|
356 "vimdiff.exe","vim.exe", "-d", NULL, NULL, ""}, |
7 | 357 {"gvimdiff","gvimdiff.bat", "gVim Diff.lnk", |
29113
495d55210aac
patch 8.2.5077: various warnings from clang on MS-Windows
Bram Moolenaar <Bram@vim.org>
parents:
29105
diff
changeset
|
358 "gvimdiff.exe","gvim.exe", "-d", NULL, NULL, ""}, |
782 | 359 {"vimtutor","vimtutor.bat", "Vim tutor.lnk", |
29113
495d55210aac
patch 8.2.5077: various warnings from clang on MS-Windows
Bram Moolenaar <Bram@vim.org>
parents:
29105
diff
changeset
|
360 "vimtutor.bat", "vimtutor.bat", "", NULL, NULL, ""}, |
7 | 361 }; |
362 | |
19431
9800e126eaa2
patch 8.2.0273: MS-Windows uninstall may delete wrong batch file
Bram Moolenaar <Bram@vim.org>
parents:
19380
diff
changeset
|
363 /* Uninstall key for vim.bat, etc. */ |
9800e126eaa2
patch 8.2.0273: MS-Windows uninstall may delete wrong batch file
Bram Moolenaar <Bram@vim.org>
parents:
19380
diff
changeset
|
364 #define VIMBAT_UNINSTKEY "rem # uninstall key: " VIM_VERSION_NODOT " #" |
9800e126eaa2
patch 8.2.0273: MS-Windows uninstall may delete wrong batch file
Bram Moolenaar <Bram@vim.org>
parents:
19380
diff
changeset
|
365 |
7 | 366 #define ICON_COUNT 3 |
367 char *(icon_names[ICON_COUNT]) = | |
368 {"gVim " VIM_VERSION_SHORT, | |
369 "gVim Easy " VIM_VERSION_SHORT, | |
370 "gVim Read only " VIM_VERSION_SHORT}; | |
371 char *(icon_link_names[ICON_COUNT]) = | |
372 {"gVim " VIM_VERSION_SHORT ".lnk", | |
373 "gVim Easy " VIM_VERSION_SHORT ".lnk", | |
374 "gVim Read only " VIM_VERSION_SHORT ".lnk"}; | |
375 | |
12626
aca41efd888c
patch 8.0.1191: MS-Windows: missing 32 and 64 bit files in installer
Christian Brabandt <cb@256bit.org>
parents:
10042
diff
changeset
|
376 /* This is only used for dosinst.c. */ |
aca41efd888c
patch 8.0.1191: MS-Windows: missing 32 and 64 bit files in installer
Christian Brabandt <cb@256bit.org>
parents:
10042
diff
changeset
|
377 #if defined(DOSINST) |
7 | 378 /* |
379 * Run an external command and wait for it to finish. | |
380 */ | |
381 static void | |
382 run_command(char *cmd) | |
383 { | |
384 char *cmd_path; | |
15892
e43b5e6d9190
patch 8.1.0952: compilation warnings when building the MS-Windows installer
Bram Moolenaar <Bram@vim.org>
parents:
12626
diff
changeset
|
385 char cmd_buf[BUFSIZE * 2 + 35]; |
7 | 386 char *p; |
387 | |
18753
6e3dc2d630c2
patch 8.1.2366: using old C style comments
Bram Moolenaar <Bram@vim.org>
parents:
18174
diff
changeset
|
388 // On WinNT, 'start' is a shell built-in for cmd.exe rather than an |
6e3dc2d630c2
patch 8.1.2366: using old C style comments
Bram Moolenaar <Bram@vim.org>
parents:
18174
diff
changeset
|
389 // executable (start.exe) like in Win9x. |
7 | 390 cmd_path = searchpath_save("cmd.exe"); |
391 if (cmd_path != NULL) | |
392 { | |
18753
6e3dc2d630c2
patch 8.1.2366: using old C style comments
Bram Moolenaar <Bram@vim.org>
parents:
18174
diff
changeset
|
393 // There is a cmd.exe, so this might be Windows NT. If it is, |
6e3dc2d630c2
patch 8.1.2366: using old C style comments
Bram Moolenaar <Bram@vim.org>
parents:
18174
diff
changeset
|
394 // we need to call cmd.exe explicitly. If it is a later OS, |
6e3dc2d630c2
patch 8.1.2366: using old C style comments
Bram Moolenaar <Bram@vim.org>
parents:
18174
diff
changeset
|
395 // calling cmd.exe won't hurt if it is present. |
6e3dc2d630c2
patch 8.1.2366: using old C style comments
Bram Moolenaar <Bram@vim.org>
parents:
18174
diff
changeset
|
396 // Also, "start" on NT expects a window title argument. |
6e3dc2d630c2
patch 8.1.2366: using old C style comments
Bram Moolenaar <Bram@vim.org>
parents:
18174
diff
changeset
|
397 // Replace the slashes with backslashes. |
7 | 398 while ((p = strchr(cmd_path, '/')) != NULL) |
399 *p = '\\'; | |
2217
120502692d82
Improve the MS-Windows installer.
Bram Moolenaar <bram@vim.org>
parents:
1222
diff
changeset
|
400 sprintf(cmd_buf, "%s /c start \"vimcmd\" /wait %s", cmd_path, cmd); |
7 | 401 free(cmd_path); |
402 } | |
403 else | |
404 { | |
18753
6e3dc2d630c2
patch 8.1.2366: using old C style comments
Bram Moolenaar <Bram@vim.org>
parents:
18174
diff
changeset
|
405 // No cmd.exe, just make the call and let the system handle it. |
7 | 406 sprintf(cmd_buf, "start /w %s", cmd); |
407 } | |
408 system(cmd_buf); | |
409 } | |
410 #endif | |
411 | |
412 /* | |
413 * Append a backslash to "name" if there isn't one yet. | |
414 */ | |
8080
b6cb94ad97a4
commit https://github.com/vim/vim/commit/6aa2cd4be287f35f95f35c2cec6d5a24f53c4d3c
Christian Brabandt <cb@256bit.org>
parents:
2475
diff
changeset
|
415 void |
7 | 416 add_pathsep(char *name) |
417 { | |
418 int len = strlen(name); | |
419 | |
420 if (len > 0 && name[len - 1] != '\\' && name[len - 1] != '/') | |
421 strcat(name, "\\"); | |
422 } | |
423 | |
424 /* | |
425 * The normal chdir() does not change the default drive. This one does. | |
426 */ | |
427 int | |
428 change_drive(int drive) | |
429 { | |
430 char temp[3] = "-:"; | |
431 temp[0] = (char)(drive + 'A' - 1); | |
432 return !SetCurrentDirectory(temp); | |
433 } | |
434 | |
435 /* | |
436 * Change directory to "path". | |
437 * Return 0 for success, -1 for failure. | |
438 */ | |
439 int | |
440 mch_chdir(char *path) | |
441 { | |
18753
6e3dc2d630c2
patch 8.1.2366: using old C style comments
Bram Moolenaar <Bram@vim.org>
parents:
18174
diff
changeset
|
442 if (path[0] == NUL) // just checking... |
7 | 443 return 0; |
18753
6e3dc2d630c2
patch 8.1.2366: using old C style comments
Bram Moolenaar <Bram@vim.org>
parents:
18174
diff
changeset
|
444 if (path[1] == ':') // has a drive name |
7 | 445 { |
446 if (change_drive(mytoupper(path[0]) - 'A' + 1)) | |
18753
6e3dc2d630c2
patch 8.1.2366: using old C style comments
Bram Moolenaar <Bram@vim.org>
parents:
18174
diff
changeset
|
447 return -1; // invalid drive name |
7 | 448 path += 2; |
449 } | |
18753
6e3dc2d630c2
patch 8.1.2366: using old C style comments
Bram Moolenaar <Bram@vim.org>
parents:
18174
diff
changeset
|
450 if (*path == NUL) // drive name only |
7 | 451 return 0; |
18753
6e3dc2d630c2
patch 8.1.2366: using old C style comments
Bram Moolenaar <Bram@vim.org>
parents:
18174
diff
changeset
|
452 return chdir(path); // let the normal chdir() do the rest |
7 | 453 } |
454 | |
455 /* | |
456 * Expand the executable name into a full path name. | |
457 */ | |
458 static char * | |
29105
faf7fcd1c8d5
patch 8.2.5073: clang on MS-Windows produces warnings
Bram Moolenaar <Bram@vim.org>
parents:
19431
diff
changeset
|
459 my_fullpath(char *buf, char *fname UNUSED, int len) |
7 | 460 { |
18753
6e3dc2d630c2
patch 8.1.2366: using old C style comments
Bram Moolenaar <Bram@vim.org>
parents:
18174
diff
changeset
|
461 // Only GetModuleFileName() will get the long file name path. |
6e3dc2d630c2
patch 8.1.2366: using old C style comments
Bram Moolenaar <Bram@vim.org>
parents:
18174
diff
changeset
|
462 // GetFullPathName() may still use the short (FAT) name. |
7 | 463 DWORD len_read = GetModuleFileName(NULL, buf, (size_t)len); |
464 | |
465 return (len_read > 0 && len_read < (DWORD)len) ? buf : NULL; | |
466 } | |
467 | |
468 /* | |
469 * Remove the tail from a file or directory name. | |
470 * Puts a NUL on the last '/' or '\'. | |
471 */ | |
472 static void | |
473 remove_tail(char *path) | |
474 { | |
475 int i; | |
476 | |
477 for (i = strlen(path) - 1; i > 0; --i) | |
478 if (path[i] == '/' || path[i] == '\\') | |
479 { | |
480 path[i] = NUL; | |
481 break; | |
482 } | |
483 } | |
484 | |
485 | |
18753
6e3dc2d630c2
patch 8.1.2366: using old C style comments
Bram Moolenaar <Bram@vim.org>
parents:
18174
diff
changeset
|
486 char installdir[MAX_PATH-9]; // top of the installation dir, where the |
6e3dc2d630c2
patch 8.1.2366: using old C style comments
Bram Moolenaar <Bram@vim.org>
parents:
18174
diff
changeset
|
487 // install.exe is located, E.g.: |
6e3dc2d630c2
patch 8.1.2366: using old C style comments
Bram Moolenaar <Bram@vim.org>
parents:
18174
diff
changeset
|
488 // "c:\vim\vim60" |
6e3dc2d630c2
patch 8.1.2366: using old C style comments
Bram Moolenaar <Bram@vim.org>
parents:
18174
diff
changeset
|
489 int runtimeidx; // index in installdir[] where "vim60" starts |
6e3dc2d630c2
patch 8.1.2366: using old C style comments
Bram Moolenaar <Bram@vim.org>
parents:
18174
diff
changeset
|
490 char *sysdrive; // system drive or "c:\" |
7 | 491 |
492 /* | |
493 * Setup for using this program. | |
494 * Sets "installdir[]". | |
495 */ | |
496 static void | |
497 do_inits(char **argv) | |
498 { | |
18753
6e3dc2d630c2
patch 8.1.2366: using old C style comments
Bram Moolenaar <Bram@vim.org>
parents:
18174
diff
changeset
|
499 // Find out the full path of our executable. |
15941
b9098585d945
patch 8.1.0976: dosinstall still has buffer overflow problems
Bram Moolenaar <Bram@vim.org>
parents:
15892
diff
changeset
|
500 if (my_fullpath(installdir, argv[0], sizeof(installdir)) == NULL) |
7 | 501 { |
502 printf("ERROR: Cannot get name of executable\n"); | |
503 myexit(1); | |
504 } | |
18753
6e3dc2d630c2
patch 8.1.2366: using old C style comments
Bram Moolenaar <Bram@vim.org>
parents:
18174
diff
changeset
|
505 // remove the tail, the executable name "install.exe" |
7 | 506 remove_tail(installdir); |
507 | |
18753
6e3dc2d630c2
patch 8.1.2366: using old C style comments
Bram Moolenaar <Bram@vim.org>
parents:
18174
diff
changeset
|
508 // change to the installdir |
7 | 509 mch_chdir(installdir); |
510 | |
18753
6e3dc2d630c2
patch 8.1.2366: using old C style comments
Bram Moolenaar <Bram@vim.org>
parents:
18174
diff
changeset
|
511 // Find the system drive. Only used for searching the Vim executable, not |
6e3dc2d630c2
patch 8.1.2366: using old C style comments
Bram Moolenaar <Bram@vim.org>
parents:
18174
diff
changeset
|
512 // very important. |
7 | 513 sysdrive = getenv("SYSTEMDRIVE"); |
514 if (sysdrive == NULL || *sysdrive == NUL) | |
515 sysdrive = "C:\\"; | |
516 } |