//===-- 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 #include #include #include #include #include #include #include // These prototypes are defined in , 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(utf8); size_t sourceLen = strlen(utf8) + 1 /* convert null too */; UTF16 *target = reinterpret_cast(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(wide); size_t sourceLen = wcslen(wide) + 1 /* convert null too */; UTF8 *target = reinterpret_cast(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