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