forked from OSchip/llvm-project
				
			
		
			
				
	
	
		
			287 lines
		
	
	
		
			7.4 KiB
		
	
	
	
		
			C++
		
	
	
	
			
		
		
	
	
			287 lines
		
	
	
		
			7.4 KiB
		
	
	
	
		
			C++
		
	
	
	
| //===-- Windows.cpp ---------------------------------------------*- C++ -*-===//
 | |
| //
 | |
| //                     The LLVM Compiler Infrastructure
 | |
| //
 | |
| // This file is distributed under the University of Illinois Open Source
 | |
| // License. See LICENSE.TXT for details.
 | |
| //
 | |
| //===----------------------------------------------------------------------===//
 | |
| 
 | |
| // This file provides Windows support functions
 | |
| 
 | |
| #include "lldb/Host/windows/windows.h"
 | |
| #include "lldb/Host/windows/win32.h"
 | |
| 
 | |
| #include "llvm/Support/ConvertUTF.h"
 | |
| 
 | |
| #include <assert.h>
 | |
| #include <stdio.h>
 | |
| #include <stdarg.h>
 | |
| #include <string.h>
 | |
| #include <stdlib.h>
 | |
| #include <io.h>
 | |
| #include <cerrno>
 | |
| #include <ctype.h>
 | |
| 
 | |
| // These prototypes are defined in <direct.h>, but it also defines chdir() and getcwd(), giving multiply defined errors
 | |
| extern "C"
 | |
| {
 | |
|     char *_getcwd(char *buffer, int maxlen);
 | |
|     int _chdir(const char *path);
 | |
| }
 | |
| 
 | |
| namespace
 | |
| {
 | |
| bool
 | |
| utf8ToWide(const char *utf8, wchar_t *buf, size_t bufSize)
 | |
| {
 | |
|     const UTF8 *sourceStart = reinterpret_cast<const UTF8 *>(utf8);
 | |
|     size_t sourceLen = strlen(utf8) + 1 /* convert null too */;
 | |
|     UTF16 *target = reinterpret_cast<UTF16 *>(buf);
 | |
|     ConversionFlags flags = strictConversion;
 | |
|     return ConvertUTF8toUTF16(&sourceStart, sourceStart + sourceLen, &target, target + bufSize, flags) == conversionOK;
 | |
| }
 | |
| 
 | |
| bool
 | |
| wideToUtf8(const wchar_t *wide, char *buf, size_t bufSize)
 | |
| {
 | |
|     const UTF16 *sourceStart = reinterpret_cast<const UTF16 *>(wide);
 | |
|     size_t sourceLen = wcslen(wide) + 1 /* convert null too */;
 | |
|     UTF8 *target = reinterpret_cast<UTF8 *>(buf);
 | |
|     ConversionFlags flags = strictConversion;
 | |
|     return ConvertUTF16toUTF8(&sourceStart, sourceStart + sourceLen, &target, target + bufSize, flags) == conversionOK;
 | |
| }
 | |
| }
 | |
| 
 | |
| int vasprintf(char **ret, const char *fmt, va_list ap)
 | |
| {
 | |
|     char *buf;
 | |
|     int len;
 | |
|     size_t buflen;
 | |
|     va_list ap2;
 | |
| 
 | |
| #if defined(_MSC_VER) || defined(__MINGW64)
 | |
|     ap2 = ap;
 | |
|     len = _vscprintf(fmt, ap2);
 | |
| #else
 | |
|     va_copy(ap2, ap);
 | |
|     len = vsnprintf(NULL, 0, fmt, ap2);
 | |
| #endif
 | |
| 
 | |
|     if (len >= 0 && (buf = (char*) malloc ((buflen = (size_t) (len + 1)))) != NULL) {
 | |
|         len = vsnprintf(buf, buflen, fmt, ap);
 | |
|         *ret = buf;
 | |
|     } else {
 | |
|         *ret = NULL;
 | |
|         len = -1;
 | |
|     }
 | |
| 
 | |
|     va_end(ap2);
 | |
|     return len;
 | |
| }
 | |
| 
 | |
| char* strcasestr(const char *s, const char* find)
 | |
| {
 | |
|     char c, sc;
 | |
|     size_t len;
 | |
| 
 | |
|     if ((c = *find++) != 0) {
 | |
|         c = tolower((unsigned char) c);
 | |
|         len = strlen(find);
 | |
|         do {
 | |
|             do {
 | |
|                 if ((sc = *s++) == 0)
 | |
|                     return 0;
 | |
|             } while ((char) tolower((unsigned char) sc) != c);
 | |
|         } while (strncasecmp(s, find, len) != 0);
 | |
|         s--;
 | |
|     }
 | |
|     return ((char *) s);
 | |
| }
 | |
| 
 | |
| char* realpath(const char * name, char * resolved)
 | |
| {
 | |
|     char *retname = NULL;
 | |
| 
 | |
|     /* SUSv3 says we must set `errno = EINVAL', and return NULL,
 | |
|     * if `name' is passed as a NULL pointer.
 | |
|     */
 | |
|     if (name == NULL)
 | |
|     {
 | |
|         errno = EINVAL;
 | |
|         return NULL;
 | |
|     }
 | |
| 
 | |
|     /* Otherwise, `name' must refer to a readable filesystem object,
 | |
|     * if we are going to resolve its absolute path name.
 | |
|     */
 | |
|     wchar_t wideNameBuffer[PATH_MAX];
 | |
|     wchar_t *wideName = wideNameBuffer;
 | |
|     if (!utf8ToWide(name, wideName, PATH_MAX))
 | |
|     {
 | |
|         errno = EINVAL;
 | |
|         return NULL;
 | |
|     }
 | |
| 
 | |
|     if (_waccess(wideName, 4) != 0)
 | |
|         return NULL;
 | |
| 
 | |
|     /* If `name' didn't point to an existing entity,
 | |
|     * then we don't get to here; we simply fall past this block,
 | |
|     * returning NULL, with `errno' appropriately set by `access'.
 | |
|     *
 | |
|     * When we _do_ get to here, then we can use `_fullpath' to
 | |
|     * resolve the full path for `name' into `resolved', but first,
 | |
|     * check that we have a suitable buffer, in which to return it.
 | |
|     */
 | |
| 
 | |
|     if ((retname = resolved) == NULL)
 | |
|     {
 | |
|         /* Caller didn't give us a buffer, so we'll exercise the
 | |
|         * option granted by SUSv3, and allocate one.
 | |
|         *
 | |
|         * `_fullpath' would do this for us, but it uses `malloc', and
 | |
|         * Microsoft's implementation doesn't set `errno' on failure.
 | |
|         * If we don't do this explicitly ourselves, then we will not
 | |
|         * know if `_fullpath' fails on `malloc' failure, or for some
 | |
|         * other reason, and we want to set `errno = ENOMEM' for the
 | |
|         * `malloc' failure case.
 | |
|         */
 | |
| 
 | |
|         retname = (char *)malloc(PATH_MAX);
 | |
|         if (retname == NULL)
 | |
|         {
 | |
|             errno = ENOMEM;
 | |
|             return NULL;
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     /* Otherwise, when we do have a valid buffer,
 | |
|     * `_fullpath' should only fail if the path name is too long.
 | |
|     */
 | |
| 
 | |
|     wchar_t wideFullPathBuffer[PATH_MAX];
 | |
|     wchar_t *wideFullPath;
 | |
|     if ((wideFullPath = _wfullpath(wideFullPathBuffer, wideName, PATH_MAX)) == NULL)
 | |
|     {
 | |
|         errno = ENAMETOOLONG;
 | |
|         return NULL;
 | |
|     }
 | |
| 
 | |
|     // Do a LongPath<->ShortPath roundtrip so that case is resolved by OS
 | |
|     // FIXME: Check for failure
 | |
|     size_t initialLength = wcslen(wideFullPath);
 | |
|     GetShortPathNameW(wideFullPath, wideNameBuffer, PATH_MAX);
 | |
|     GetLongPathNameW(wideNameBuffer, wideFullPathBuffer, initialLength + 1);
 | |
| 
 | |
|     // Convert back to UTF-8
 | |
|     if (!wideToUtf8(wideFullPathBuffer, retname, PATH_MAX))
 | |
|     {
 | |
|         errno = EINVAL;
 | |
|         return NULL;
 | |
|     }
 | |
| 
 | |
|     // Force drive to be upper case
 | |
|     if (retname[1] == ':')
 | |
|         retname[0] = toupper(retname[0]);
 | |
| 
 | |
|     return retname;
 | |
| }
 | |
| 
 | |
| #ifdef _MSC_VER
 | |
| 
 | |
| char* basename(char *path)
 | |
| {
 | |
|     char* l1 = strrchr(path, '\\');
 | |
|     char* l2 = strrchr(path, '/');
 | |
|     if (l2 > l1) l1 = l2;
 | |
|     if (!l1) return path; // no base name
 | |
|     return &l1[1];
 | |
| }
 | |
| 
 | |
| // use _getcwd() instead of GetCurrentDirectory() because it updates errno
 | |
| char* getcwd(char* path, int max)
 | |
| {
 | |
|     assert(path == NULL || max <= PATH_MAX);
 | |
|     wchar_t wpath[PATH_MAX];
 | |
|     if (wchar_t *wresult = _wgetcwd(wpath, PATH_MAX))
 | |
|     {
 | |
|         // Caller is allowed to pass in NULL for `path`.
 | |
|         // In that case, we're supposed to allocate a
 | |
|         // buffer on the caller's behalf.
 | |
|         if (path == NULL)
 | |
|         {
 | |
|             max = UNI_MAX_UTF8_BYTES_PER_CODE_POINT * wcslen(wresult) + 1;
 | |
|             path = (char *)malloc(max);
 | |
|             if (path == NULL)
 | |
|             {
 | |
|                 errno = ENOMEM;
 | |
|                 return NULL;
 | |
|             }
 | |
|         }
 | |
|         if (wideToUtf8(wresult, path, max))
 | |
|             return path;
 | |
|     }
 | |
|     return NULL;
 | |
| }
 | |
| 
 | |
| // use _chdir() instead of SetCurrentDirectory() because it updates errno
 | |
| int chdir(const char* path)
 | |
| {
 | |
|     return _chdir(path);
 | |
| }
 | |
| 
 | |
| char *dirname(char *path)
 | |
| {
 | |
|     char* l1 = strrchr(path, '\\');
 | |
|     char* l2 = strrchr(path, '/');
 | |
|     if (l2 > l1) l1 = l2;
 | |
|     if (!l1) return NULL; // no dir name
 | |
|     *l1 = 0;
 | |
|     return path;
 | |
| }
 | |
| 
 | |
| int strcasecmp(const char* s1, const char* s2)
 | |
| {
 | |
|     return stricmp(s1, s2);
 | |
| }
 | |
| 
 | |
| int strncasecmp(const char* s1, const char* s2, size_t n)
 | |
| {
 | |
|     return strnicmp(s1, s2, n);
 | |
| }
 | |
| 
 | |
| int usleep(uint32_t useconds)
 | |
| {
 | |
|     Sleep(useconds / 1000);
 | |
|     return 0;
 | |
| }
 | |
| 
 | |
| #if _MSC_VER < 1900
 | |
| namespace lldb_private {
 | |
| int vsnprintf(char *buffer, size_t count, const char *format, va_list argptr)
 | |
| {
 | |
|     int old_errno = errno;
 | |
|     int r = ::vsnprintf(buffer, count, format, argptr);
 | |
|     int new_errno = errno;
 | |
|     buffer[count-1] = '\0';
 | |
|     if (r == -1 || r == count)
 | |
|     {
 | |
|         FILE *nul = fopen("nul", "w");
 | |
|         int bytes_written = ::vfprintf(nul, format, argptr);
 | |
|         fclose(nul);
 | |
|         if (bytes_written < count)
 | |
|             errno = new_errno;
 | |
|         else
 | |
|         {
 | |
|             errno = old_errno;
 | |
|             r = bytes_written;
 | |
|         }
 | |
|     }
 | |
|     return r;
 | |
| }
 | |
| } // namespace lldb_private
 | |
| #endif
 | |
| 
 | |
| #endif // _MSC_VER
 |