]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - source/Host/windows/Windows.cpp
Vendor import of lldb release_39 branch r276489:
[FreeBSD/FreeBSD.git] / source / Host / windows / Windows.cpp
1 //===-- Windows.cpp ---------------------------------------------*- C++ -*-===//
2 //
3 //                     The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9
10 // This file provides Windows support functions
11
12 #include "lldb/Host/windows/windows.h"
13 #include "lldb/Host/windows/win32.h"
14
15 #include "llvm/Support/ConvertUTF.h"
16
17 #include <assert.h>
18 #include <stdio.h>
19 #include <stdarg.h>
20 #include <string.h>
21 #include <stdlib.h>
22 #include <io.h>
23 #include <cerrno>
24 #include <ctype.h>
25
26 // These prototypes are defined in <direct.h>, but it also defines chdir() and getcwd(), giving multiply defined errors
27 extern "C"
28 {
29     char *_getcwd(char *buffer, int maxlen);
30     int _chdir(const char *path);
31 }
32
33 namespace
34 {
35 bool
36 utf8ToWide(const char *utf8, wchar_t *buf, size_t bufSize)
37 {
38     const UTF8 *sourceStart = reinterpret_cast<const UTF8 *>(utf8);
39     size_t sourceLen = strlen(utf8) + 1 /* convert null too */;
40     UTF16 *target = reinterpret_cast<UTF16 *>(buf);
41     ConversionFlags flags = strictConversion;
42     return ConvertUTF8toUTF16(&sourceStart, sourceStart + sourceLen, &target, target + bufSize, flags) == conversionOK;
43 }
44
45 bool
46 wideToUtf8(const wchar_t *wide, char *buf, size_t bufSize)
47 {
48     const UTF16 *sourceStart = reinterpret_cast<const UTF16 *>(wide);
49     size_t sourceLen = wcslen(wide) + 1 /* convert null too */;
50     UTF8 *target = reinterpret_cast<UTF8 *>(buf);
51     ConversionFlags flags = strictConversion;
52     return ConvertUTF16toUTF8(&sourceStart, sourceStart + sourceLen, &target, target + bufSize, flags) == conversionOK;
53 }
54 }
55
56 int vasprintf(char **ret, const char *fmt, va_list ap)
57 {
58     char *buf;
59     int len;
60     size_t buflen;
61     va_list ap2;
62
63 #if defined(_MSC_VER) || defined(__MINGW64)
64     ap2 = ap;
65     len = _vscprintf(fmt, ap2);
66 #else
67     va_copy(ap2, ap);
68     len = vsnprintf(NULL, 0, fmt, ap2);
69 #endif
70
71     if (len >= 0 && (buf = (char*) malloc ((buflen = (size_t) (len + 1)))) != NULL) {
72         len = vsnprintf(buf, buflen, fmt, ap);
73         *ret = buf;
74     } else {
75         *ret = NULL;
76         len = -1;
77     }
78
79     va_end(ap2);
80     return len;
81 }
82
83 char* strcasestr(const char *s, const char* find)
84 {
85     char c, sc;
86     size_t len;
87
88     if ((c = *find++) != 0) {
89         c = tolower((unsigned char) c);
90         len = strlen(find);
91         do {
92             do {
93                 if ((sc = *s++) == 0)
94                     return 0;
95             } while ((char) tolower((unsigned char) sc) != c);
96         } while (strncasecmp(s, find, len) != 0);
97         s--;
98     }
99     return ((char *) s);
100 }
101
102 char* realpath(const char * name, char * resolved)
103 {
104     char *retname = NULL;
105
106     /* SUSv3 says we must set `errno = EINVAL', and return NULL,
107     * if `name' is passed as a NULL pointer.
108     */
109     if (name == NULL)
110     {
111         errno = EINVAL;
112         return NULL;
113     }
114
115     /* Otherwise, `name' must refer to a readable filesystem object,
116     * if we are going to resolve its absolute path name.
117     */
118     wchar_t wideNameBuffer[PATH_MAX];
119     wchar_t *wideName = wideNameBuffer;
120     if (!utf8ToWide(name, wideName, PATH_MAX))
121     {
122         errno = EINVAL;
123         return NULL;
124     }
125
126     if (_waccess(wideName, 4) != 0)
127         return NULL;
128
129     /* If `name' didn't point to an existing entity,
130     * then we don't get to here; we simply fall past this block,
131     * returning NULL, with `errno' appropriately set by `access'.
132     *
133     * When we _do_ get to here, then we can use `_fullpath' to
134     * resolve the full path for `name' into `resolved', but first,
135     * check that we have a suitable buffer, in which to return it.
136     */
137
138     if ((retname = resolved) == NULL)
139     {
140         /* Caller didn't give us a buffer, so we'll exercise the
141         * option granted by SUSv3, and allocate one.
142         *
143         * `_fullpath' would do this for us, but it uses `malloc', and
144         * Microsoft's implementation doesn't set `errno' on failure.
145         * If we don't do this explicitly ourselves, then we will not
146         * know if `_fullpath' fails on `malloc' failure, or for some
147         * other reason, and we want to set `errno = ENOMEM' for the
148         * `malloc' failure case.
149         */
150
151         retname = (char *)malloc(PATH_MAX);
152         if (retname == NULL)
153         {
154             errno = ENOMEM;
155             return NULL;
156         }
157     }
158
159     /* Otherwise, when we do have a valid buffer,
160     * `_fullpath' should only fail if the path name is too long.
161     */
162
163     wchar_t wideFullPathBuffer[PATH_MAX];
164     wchar_t *wideFullPath;
165     if ((wideFullPath = _wfullpath(wideFullPathBuffer, wideName, PATH_MAX)) == NULL)
166     {
167         errno = ENAMETOOLONG;
168         return NULL;
169     }
170
171     // Do a LongPath<->ShortPath roundtrip so that case is resolved by OS
172     // FIXME: Check for failure
173     size_t initialLength = wcslen(wideFullPath);
174     GetShortPathNameW(wideFullPath, wideNameBuffer, PATH_MAX);
175     GetLongPathNameW(wideNameBuffer, wideFullPathBuffer, initialLength + 1);
176
177     // Convert back to UTF-8
178     if (!wideToUtf8(wideFullPathBuffer, retname, PATH_MAX))
179     {
180         errno = EINVAL;
181         return NULL;
182     }
183
184     // Force drive to be upper case
185     if (retname[1] == ':')
186         retname[0] = toupper(retname[0]);
187
188     return retname;
189 }
190
191 #ifdef _MSC_VER
192
193 char* basename(char *path)
194 {
195     char* l1 = strrchr(path, '\\');
196     char* l2 = strrchr(path, '/');
197     if (l2 > l1) l1 = l2;
198     if (!l1) return path; // no base name
199     return &l1[1];
200 }
201
202 // use _getcwd() instead of GetCurrentDirectory() because it updates errno
203 char* getcwd(char* path, int max)
204 {
205     assert(path == NULL || max <= PATH_MAX);
206     wchar_t wpath[PATH_MAX];
207     if (wchar_t *wresult = _wgetcwd(wpath, PATH_MAX))
208     {
209         // Caller is allowed to pass in NULL for `path`.
210         // In that case, we're supposed to allocate a
211         // buffer on the caller's behalf.
212         if (path == NULL)
213         {
214             max = UNI_MAX_UTF8_BYTES_PER_CODE_POINT * wcslen(wresult) + 1;
215             path = (char *)malloc(max);
216             if (path == NULL)
217             {
218                 errno = ENOMEM;
219                 return NULL;
220             }
221         }
222         if (wideToUtf8(wresult, path, max))
223             return path;
224     }
225     return NULL;
226 }
227
228 // use _chdir() instead of SetCurrentDirectory() because it updates errno
229 int chdir(const char* path)
230 {
231     return _chdir(path);
232 }
233
234 char *dirname(char *path)
235 {
236     char* l1 = strrchr(path, '\\');
237     char* l2 = strrchr(path, '/');
238     if (l2 > l1) l1 = l2;
239     if (!l1) return NULL; // no dir name
240     *l1 = 0;
241     return path;
242 }
243
244 int strcasecmp(const char* s1, const char* s2)
245 {
246     return stricmp(s1, s2);
247 }
248
249 int strncasecmp(const char* s1, const char* s2, size_t n)
250 {
251     return strnicmp(s1, s2, n);
252 }
253
254 int usleep(uint32_t useconds)
255 {
256     Sleep(useconds / 1000);
257     return 0;
258 }
259
260 #if _MSC_VER < 1900
261 namespace lldb_private {
262 int vsnprintf(char *buffer, size_t count, const char *format, va_list argptr)
263 {
264     int old_errno = errno;
265     int r = ::vsnprintf(buffer, count, format, argptr);
266     int new_errno = errno;
267     buffer[count-1] = '\0';
268     if (r == -1 || r == count)
269     {
270         FILE *nul = fopen("nul", "w");
271         int bytes_written = ::vfprintf(nul, format, argptr);
272         fclose(nul);
273         if (bytes_written < count)
274             errno = new_errno;
275         else
276         {
277             errno = old_errno;
278             r = bytes_written;
279         }
280     }
281     return r;
282 }
283 } // namespace lldb_private
284 #endif
285
286 #endif // _MSC_VER