113481Sgiacomo.travaglini@arm.com// Copyright 2008, Google Inc. 213481Sgiacomo.travaglini@arm.com// All rights reserved. 313481Sgiacomo.travaglini@arm.com// 413481Sgiacomo.travaglini@arm.com// Redistribution and use in source and binary forms, with or without 513481Sgiacomo.travaglini@arm.com// modification, are permitted provided that the following conditions are 613481Sgiacomo.travaglini@arm.com// met: 713481Sgiacomo.travaglini@arm.com// 813481Sgiacomo.travaglini@arm.com// * Redistributions of source code must retain the above copyright 913481Sgiacomo.travaglini@arm.com// notice, this list of conditions and the following disclaimer. 1013481Sgiacomo.travaglini@arm.com// * Redistributions in binary form must reproduce the above 1113481Sgiacomo.travaglini@arm.com// copyright notice, this list of conditions and the following disclaimer 1213481Sgiacomo.travaglini@arm.com// in the documentation and/or other materials provided with the 1313481Sgiacomo.travaglini@arm.com// distribution. 1413481Sgiacomo.travaglini@arm.com// * Neither the name of Google Inc. nor the names of its 1513481Sgiacomo.travaglini@arm.com// contributors may be used to endorse or promote products derived from 1613481Sgiacomo.travaglini@arm.com// this software without specific prior written permission. 1713481Sgiacomo.travaglini@arm.com// 1813481Sgiacomo.travaglini@arm.com// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 1913481Sgiacomo.travaglini@arm.com// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 2013481Sgiacomo.travaglini@arm.com// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 2113481Sgiacomo.travaglini@arm.com// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 2213481Sgiacomo.travaglini@arm.com// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 2313481Sgiacomo.travaglini@arm.com// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 2413481Sgiacomo.travaglini@arm.com// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 2513481Sgiacomo.travaglini@arm.com// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 2613481Sgiacomo.travaglini@arm.com// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 2713481Sgiacomo.travaglini@arm.com// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 2813481Sgiacomo.travaglini@arm.com// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 2913481Sgiacomo.travaglini@arm.com// 3013481Sgiacomo.travaglini@arm.com// Author: wan@google.com (Zhanyong Wan) 3113481Sgiacomo.travaglini@arm.com 3213481Sgiacomo.travaglini@arm.com#include "gtest/internal/gtest-port.h" 3313481Sgiacomo.travaglini@arm.com 3413481Sgiacomo.travaglini@arm.com#include <limits.h> 3513481Sgiacomo.travaglini@arm.com#include <stdlib.h> 3613481Sgiacomo.travaglini@arm.com#include <stdio.h> 3713481Sgiacomo.travaglini@arm.com#include <string.h> 3813481Sgiacomo.travaglini@arm.com#include <fstream> 3913481Sgiacomo.travaglini@arm.com 4013481Sgiacomo.travaglini@arm.com#if GTEST_OS_WINDOWS 4113481Sgiacomo.travaglini@arm.com# include <windows.h> 4213481Sgiacomo.travaglini@arm.com# include <io.h> 4313481Sgiacomo.travaglini@arm.com# include <sys/stat.h> 4413481Sgiacomo.travaglini@arm.com# include <map> // Used in ThreadLocal. 4513481Sgiacomo.travaglini@arm.com#else 4613481Sgiacomo.travaglini@arm.com# include <unistd.h> 4713481Sgiacomo.travaglini@arm.com#endif // GTEST_OS_WINDOWS 4813481Sgiacomo.travaglini@arm.com 4913481Sgiacomo.travaglini@arm.com#if GTEST_OS_MAC 5013481Sgiacomo.travaglini@arm.com# include <mach/mach_init.h> 5113481Sgiacomo.travaglini@arm.com# include <mach/task.h> 5213481Sgiacomo.travaglini@arm.com# include <mach/vm_map.h> 5313481Sgiacomo.travaglini@arm.com#endif // GTEST_OS_MAC 5413481Sgiacomo.travaglini@arm.com 5513481Sgiacomo.travaglini@arm.com#if GTEST_OS_QNX 5613481Sgiacomo.travaglini@arm.com# include <devctl.h> 5713481Sgiacomo.travaglini@arm.com# include <fcntl.h> 5813481Sgiacomo.travaglini@arm.com# include <sys/procfs.h> 5913481Sgiacomo.travaglini@arm.com#endif // GTEST_OS_QNX 6013481Sgiacomo.travaglini@arm.com 6113481Sgiacomo.travaglini@arm.com#if GTEST_OS_AIX 6213481Sgiacomo.travaglini@arm.com# include <procinfo.h> 6313481Sgiacomo.travaglini@arm.com# include <sys/types.h> 6413481Sgiacomo.travaglini@arm.com#endif // GTEST_OS_AIX 6513481Sgiacomo.travaglini@arm.com 6613481Sgiacomo.travaglini@arm.com#include "gtest/gtest-spi.h" 6713481Sgiacomo.travaglini@arm.com#include "gtest/gtest-message.h" 6813481Sgiacomo.travaglini@arm.com#include "gtest/internal/gtest-internal.h" 6913481Sgiacomo.travaglini@arm.com#include "gtest/internal/gtest-string.h" 7013481Sgiacomo.travaglini@arm.com 7113481Sgiacomo.travaglini@arm.com// Indicates that this translation unit is part of Google Test's 7213481Sgiacomo.travaglini@arm.com// implementation. It must come before gtest-internal-inl.h is 7313481Sgiacomo.travaglini@arm.com// included, or there will be a compiler error. This trick exists to 7413481Sgiacomo.travaglini@arm.com// prevent the accidental inclusion of gtest-internal-inl.h in the 7513481Sgiacomo.travaglini@arm.com// user's code. 7613481Sgiacomo.travaglini@arm.com#define GTEST_IMPLEMENTATION_ 1 7713481Sgiacomo.travaglini@arm.com#include "src/gtest-internal-inl.h" 7813481Sgiacomo.travaglini@arm.com#undef GTEST_IMPLEMENTATION_ 7913481Sgiacomo.travaglini@arm.com 8013481Sgiacomo.travaglini@arm.comnamespace testing { 8113481Sgiacomo.travaglini@arm.comnamespace internal { 8213481Sgiacomo.travaglini@arm.com 8313481Sgiacomo.travaglini@arm.com#if defined(_MSC_VER) || defined(__BORLANDC__) 8413481Sgiacomo.travaglini@arm.com// MSVC and C++Builder do not provide a definition of STDERR_FILENO. 8513481Sgiacomo.travaglini@arm.comconst int kStdOutFileno = 1; 8613481Sgiacomo.travaglini@arm.comconst int kStdErrFileno = 2; 8713481Sgiacomo.travaglini@arm.com#else 8813481Sgiacomo.travaglini@arm.comconst int kStdOutFileno = STDOUT_FILENO; 8913481Sgiacomo.travaglini@arm.comconst int kStdErrFileno = STDERR_FILENO; 9013481Sgiacomo.travaglini@arm.com#endif // _MSC_VER 9113481Sgiacomo.travaglini@arm.com 9213481Sgiacomo.travaglini@arm.com#if GTEST_OS_LINUX 9313481Sgiacomo.travaglini@arm.com 9413481Sgiacomo.travaglini@arm.comnamespace { 9513481Sgiacomo.travaglini@arm.comtemplate <typename T> 9613481Sgiacomo.travaglini@arm.comT ReadProcFileField(const string& filename, int field) { 9713481Sgiacomo.travaglini@arm.com std::string dummy; 9813481Sgiacomo.travaglini@arm.com std::ifstream file(filename.c_str()); 9913481Sgiacomo.travaglini@arm.com while (field-- > 0) { 10013481Sgiacomo.travaglini@arm.com file >> dummy; 10113481Sgiacomo.travaglini@arm.com } 10213481Sgiacomo.travaglini@arm.com T output = 0; 10313481Sgiacomo.travaglini@arm.com file >> output; 10413481Sgiacomo.travaglini@arm.com return output; 10513481Sgiacomo.travaglini@arm.com} 10613481Sgiacomo.travaglini@arm.com} // namespace 10713481Sgiacomo.travaglini@arm.com 10813481Sgiacomo.travaglini@arm.com// Returns the number of active threads, or 0 when there is an error. 10913481Sgiacomo.travaglini@arm.comsize_t GetThreadCount() { 11013481Sgiacomo.travaglini@arm.com const string filename = 11113481Sgiacomo.travaglini@arm.com (Message() << "/proc/" << getpid() << "/stat").GetString(); 11213481Sgiacomo.travaglini@arm.com return ReadProcFileField<int>(filename, 19); 11313481Sgiacomo.travaglini@arm.com} 11413481Sgiacomo.travaglini@arm.com 11513481Sgiacomo.travaglini@arm.com#elif GTEST_OS_MAC 11613481Sgiacomo.travaglini@arm.com 11713481Sgiacomo.travaglini@arm.comsize_t GetThreadCount() { 11813481Sgiacomo.travaglini@arm.com const task_t task = mach_task_self(); 11913481Sgiacomo.travaglini@arm.com mach_msg_type_number_t thread_count; 12013481Sgiacomo.travaglini@arm.com thread_act_array_t thread_list; 12113481Sgiacomo.travaglini@arm.com const kern_return_t status = task_threads(task, &thread_list, &thread_count); 12213481Sgiacomo.travaglini@arm.com if (status == KERN_SUCCESS) { 12313481Sgiacomo.travaglini@arm.com // task_threads allocates resources in thread_list and we need to free them 12413481Sgiacomo.travaglini@arm.com // to avoid leaks. 12513481Sgiacomo.travaglini@arm.com vm_deallocate(task, 12613481Sgiacomo.travaglini@arm.com reinterpret_cast<vm_address_t>(thread_list), 12713481Sgiacomo.travaglini@arm.com sizeof(thread_t) * thread_count); 12813481Sgiacomo.travaglini@arm.com return static_cast<size_t>(thread_count); 12913481Sgiacomo.travaglini@arm.com } else { 13013481Sgiacomo.travaglini@arm.com return 0; 13113481Sgiacomo.travaglini@arm.com } 13213481Sgiacomo.travaglini@arm.com} 13313481Sgiacomo.travaglini@arm.com 13413481Sgiacomo.travaglini@arm.com#elif GTEST_OS_QNX 13513481Sgiacomo.travaglini@arm.com 13613481Sgiacomo.travaglini@arm.com// Returns the number of threads running in the process, or 0 to indicate that 13713481Sgiacomo.travaglini@arm.com// we cannot detect it. 13813481Sgiacomo.travaglini@arm.comsize_t GetThreadCount() { 13913481Sgiacomo.travaglini@arm.com const int fd = open("/proc/self/as", O_RDONLY); 14013481Sgiacomo.travaglini@arm.com if (fd < 0) { 14113481Sgiacomo.travaglini@arm.com return 0; 14213481Sgiacomo.travaglini@arm.com } 14313481Sgiacomo.travaglini@arm.com procfs_info process_info; 14413481Sgiacomo.travaglini@arm.com const int status = 14513481Sgiacomo.travaglini@arm.com devctl(fd, DCMD_PROC_INFO, &process_info, sizeof(process_info), NULL); 14613481Sgiacomo.travaglini@arm.com close(fd); 14713481Sgiacomo.travaglini@arm.com if (status == EOK) { 14813481Sgiacomo.travaglini@arm.com return static_cast<size_t>(process_info.num_threads); 14913481Sgiacomo.travaglini@arm.com } else { 15013481Sgiacomo.travaglini@arm.com return 0; 15113481Sgiacomo.travaglini@arm.com } 15213481Sgiacomo.travaglini@arm.com} 15313481Sgiacomo.travaglini@arm.com 15413481Sgiacomo.travaglini@arm.com#elif GTEST_OS_AIX 15513481Sgiacomo.travaglini@arm.com 15613481Sgiacomo.travaglini@arm.comsize_t GetThreadCount() { 15713481Sgiacomo.travaglini@arm.com struct procentry64 entry; 15813481Sgiacomo.travaglini@arm.com pid_t pid = getpid(); 15913481Sgiacomo.travaglini@arm.com int status = getprocs64(&entry, sizeof(entry), NULL, 0, &pid, 1); 16013481Sgiacomo.travaglini@arm.com if (status == 1) { 16113481Sgiacomo.travaglini@arm.com return entry.pi_thcount; 16213481Sgiacomo.travaglini@arm.com } else { 16313481Sgiacomo.travaglini@arm.com return 0; 16413481Sgiacomo.travaglini@arm.com } 16513481Sgiacomo.travaglini@arm.com} 16613481Sgiacomo.travaglini@arm.com 16713481Sgiacomo.travaglini@arm.com#else 16813481Sgiacomo.travaglini@arm.com 16913481Sgiacomo.travaglini@arm.comsize_t GetThreadCount() { 17013481Sgiacomo.travaglini@arm.com // There's no portable way to detect the number of threads, so we just 17113481Sgiacomo.travaglini@arm.com // return 0 to indicate that we cannot detect it. 17213481Sgiacomo.travaglini@arm.com return 0; 17313481Sgiacomo.travaglini@arm.com} 17413481Sgiacomo.travaglini@arm.com 17513481Sgiacomo.travaglini@arm.com#endif // GTEST_OS_LINUX 17613481Sgiacomo.travaglini@arm.com 17713481Sgiacomo.travaglini@arm.com#if GTEST_IS_THREADSAFE && GTEST_OS_WINDOWS 17813481Sgiacomo.travaglini@arm.com 17913481Sgiacomo.travaglini@arm.comvoid SleepMilliseconds(int n) { 18013481Sgiacomo.travaglini@arm.com ::Sleep(n); 18113481Sgiacomo.travaglini@arm.com} 18213481Sgiacomo.travaglini@arm.com 18313481Sgiacomo.travaglini@arm.comAutoHandle::AutoHandle() 18413481Sgiacomo.travaglini@arm.com : handle_(INVALID_HANDLE_VALUE) {} 18513481Sgiacomo.travaglini@arm.com 18613481Sgiacomo.travaglini@arm.comAutoHandle::AutoHandle(Handle handle) 18713481Sgiacomo.travaglini@arm.com : handle_(handle) {} 18813481Sgiacomo.travaglini@arm.com 18913481Sgiacomo.travaglini@arm.comAutoHandle::~AutoHandle() { 19013481Sgiacomo.travaglini@arm.com Reset(); 19113481Sgiacomo.travaglini@arm.com} 19213481Sgiacomo.travaglini@arm.com 19313481Sgiacomo.travaglini@arm.comAutoHandle::Handle AutoHandle::Get() const { 19413481Sgiacomo.travaglini@arm.com return handle_; 19513481Sgiacomo.travaglini@arm.com} 19613481Sgiacomo.travaglini@arm.com 19713481Sgiacomo.travaglini@arm.comvoid AutoHandle::Reset() { 19813481Sgiacomo.travaglini@arm.com Reset(INVALID_HANDLE_VALUE); 19913481Sgiacomo.travaglini@arm.com} 20013481Sgiacomo.travaglini@arm.com 20113481Sgiacomo.travaglini@arm.comvoid AutoHandle::Reset(HANDLE handle) { 20213481Sgiacomo.travaglini@arm.com // Resetting with the same handle we already own is invalid. 20313481Sgiacomo.travaglini@arm.com if (handle_ != handle) { 20413481Sgiacomo.travaglini@arm.com if (IsCloseable()) { 20513481Sgiacomo.travaglini@arm.com ::CloseHandle(handle_); 20613481Sgiacomo.travaglini@arm.com } 20713481Sgiacomo.travaglini@arm.com handle_ = handle; 20813481Sgiacomo.travaglini@arm.com } else { 20913481Sgiacomo.travaglini@arm.com GTEST_CHECK_(!IsCloseable()) 21013481Sgiacomo.travaglini@arm.com << "Resetting a valid handle to itself is likely a programmer error " 21113481Sgiacomo.travaglini@arm.com "and thus not allowed."; 21213481Sgiacomo.travaglini@arm.com } 21313481Sgiacomo.travaglini@arm.com} 21413481Sgiacomo.travaglini@arm.com 21513481Sgiacomo.travaglini@arm.combool AutoHandle::IsCloseable() const { 21613481Sgiacomo.travaglini@arm.com // Different Windows APIs may use either of these values to represent an 21713481Sgiacomo.travaglini@arm.com // invalid handle. 21813481Sgiacomo.travaglini@arm.com return handle_ != NULL && handle_ != INVALID_HANDLE_VALUE; 21913481Sgiacomo.travaglini@arm.com} 22013481Sgiacomo.travaglini@arm.com 22113481Sgiacomo.travaglini@arm.comNotification::Notification() 22213481Sgiacomo.travaglini@arm.com : event_(::CreateEvent(NULL, // Default security attributes. 22313481Sgiacomo.travaglini@arm.com TRUE, // Do not reset automatically. 22413481Sgiacomo.travaglini@arm.com FALSE, // Initially unset. 22513481Sgiacomo.travaglini@arm.com NULL)) { // Anonymous event. 22613481Sgiacomo.travaglini@arm.com GTEST_CHECK_(event_.Get() != NULL); 22713481Sgiacomo.travaglini@arm.com} 22813481Sgiacomo.travaglini@arm.com 22913481Sgiacomo.travaglini@arm.comvoid Notification::Notify() { 23013481Sgiacomo.travaglini@arm.com GTEST_CHECK_(::SetEvent(event_.Get()) != FALSE); 23113481Sgiacomo.travaglini@arm.com} 23213481Sgiacomo.travaglini@arm.com 23313481Sgiacomo.travaglini@arm.comvoid Notification::WaitForNotification() { 23413481Sgiacomo.travaglini@arm.com GTEST_CHECK_( 23513481Sgiacomo.travaglini@arm.com ::WaitForSingleObject(event_.Get(), INFINITE) == WAIT_OBJECT_0); 23613481Sgiacomo.travaglini@arm.com} 23713481Sgiacomo.travaglini@arm.com 23813481Sgiacomo.travaglini@arm.comMutex::Mutex() 23913481Sgiacomo.travaglini@arm.com : owner_thread_id_(0), 24013481Sgiacomo.travaglini@arm.com type_(kDynamic), 24113481Sgiacomo.travaglini@arm.com critical_section_init_phase_(0), 24213481Sgiacomo.travaglini@arm.com critical_section_(new CRITICAL_SECTION) { 24313481Sgiacomo.travaglini@arm.com ::InitializeCriticalSection(critical_section_); 24413481Sgiacomo.travaglini@arm.com} 24513481Sgiacomo.travaglini@arm.com 24613481Sgiacomo.travaglini@arm.comMutex::~Mutex() { 24713481Sgiacomo.travaglini@arm.com // Static mutexes are leaked intentionally. It is not thread-safe to try 24813481Sgiacomo.travaglini@arm.com // to clean them up. 24913481Sgiacomo.travaglini@arm.com // TODO(yukawa): Switch to Slim Reader/Writer (SRW) Locks, which requires 25013481Sgiacomo.travaglini@arm.com // nothing to clean it up but is available only on Vista and later. 25113481Sgiacomo.travaglini@arm.com // http://msdn.microsoft.com/en-us/library/windows/desktop/aa904937.aspx 25213481Sgiacomo.travaglini@arm.com if (type_ == kDynamic) { 25313481Sgiacomo.travaglini@arm.com ::DeleteCriticalSection(critical_section_); 25413481Sgiacomo.travaglini@arm.com delete critical_section_; 25513481Sgiacomo.travaglini@arm.com critical_section_ = NULL; 25613481Sgiacomo.travaglini@arm.com } 25713481Sgiacomo.travaglini@arm.com} 25813481Sgiacomo.travaglini@arm.com 25913481Sgiacomo.travaglini@arm.comvoid Mutex::Lock() { 26013481Sgiacomo.travaglini@arm.com ThreadSafeLazyInit(); 26113481Sgiacomo.travaglini@arm.com ::EnterCriticalSection(critical_section_); 26213481Sgiacomo.travaglini@arm.com owner_thread_id_ = ::GetCurrentThreadId(); 26313481Sgiacomo.travaglini@arm.com} 26413481Sgiacomo.travaglini@arm.com 26513481Sgiacomo.travaglini@arm.comvoid Mutex::Unlock() { 26613481Sgiacomo.travaglini@arm.com ThreadSafeLazyInit(); 26713481Sgiacomo.travaglini@arm.com // We don't protect writing to owner_thread_id_ here, as it's the 26813481Sgiacomo.travaglini@arm.com // caller's responsibility to ensure that the current thread holds the 26913481Sgiacomo.travaglini@arm.com // mutex when this is called. 27013481Sgiacomo.travaglini@arm.com owner_thread_id_ = 0; 27113481Sgiacomo.travaglini@arm.com ::LeaveCriticalSection(critical_section_); 27213481Sgiacomo.travaglini@arm.com} 27313481Sgiacomo.travaglini@arm.com 27413481Sgiacomo.travaglini@arm.com// Does nothing if the current thread holds the mutex. Otherwise, crashes 27513481Sgiacomo.travaglini@arm.com// with high probability. 27613481Sgiacomo.travaglini@arm.comvoid Mutex::AssertHeld() { 27713481Sgiacomo.travaglini@arm.com ThreadSafeLazyInit(); 27813481Sgiacomo.travaglini@arm.com GTEST_CHECK_(owner_thread_id_ == ::GetCurrentThreadId()) 27913481Sgiacomo.travaglini@arm.com << "The current thread is not holding the mutex @" << this; 28013481Sgiacomo.travaglini@arm.com} 28113481Sgiacomo.travaglini@arm.com 28213481Sgiacomo.travaglini@arm.com// Initializes owner_thread_id_ and critical_section_ in static mutexes. 28313481Sgiacomo.travaglini@arm.comvoid Mutex::ThreadSafeLazyInit() { 28413481Sgiacomo.travaglini@arm.com // Dynamic mutexes are initialized in the constructor. 28513481Sgiacomo.travaglini@arm.com if (type_ == kStatic) { 28613481Sgiacomo.travaglini@arm.com switch ( 28713481Sgiacomo.travaglini@arm.com ::InterlockedCompareExchange(&critical_section_init_phase_, 1L, 0L)) { 28813481Sgiacomo.travaglini@arm.com case 0: 28913481Sgiacomo.travaglini@arm.com // If critical_section_init_phase_ was 0 before the exchange, we 29013481Sgiacomo.travaglini@arm.com // are the first to test it and need to perform the initialization. 29113481Sgiacomo.travaglini@arm.com owner_thread_id_ = 0; 29213481Sgiacomo.travaglini@arm.com critical_section_ = new CRITICAL_SECTION; 29313481Sgiacomo.travaglini@arm.com ::InitializeCriticalSection(critical_section_); 29413481Sgiacomo.travaglini@arm.com // Updates the critical_section_init_phase_ to 2 to signal 29513481Sgiacomo.travaglini@arm.com // initialization complete. 29613481Sgiacomo.travaglini@arm.com GTEST_CHECK_(::InterlockedCompareExchange( 29713481Sgiacomo.travaglini@arm.com &critical_section_init_phase_, 2L, 1L) == 29813481Sgiacomo.travaglini@arm.com 1L); 29913481Sgiacomo.travaglini@arm.com break; 30013481Sgiacomo.travaglini@arm.com case 1: 30113481Sgiacomo.travaglini@arm.com // Somebody else is already initializing the mutex; spin until they 30213481Sgiacomo.travaglini@arm.com // are done. 30313481Sgiacomo.travaglini@arm.com while (::InterlockedCompareExchange(&critical_section_init_phase_, 30413481Sgiacomo.travaglini@arm.com 2L, 30513481Sgiacomo.travaglini@arm.com 2L) != 2L) { 30613481Sgiacomo.travaglini@arm.com // Possibly yields the rest of the thread's time slice to other 30713481Sgiacomo.travaglini@arm.com // threads. 30813481Sgiacomo.travaglini@arm.com ::Sleep(0); 30913481Sgiacomo.travaglini@arm.com } 31013481Sgiacomo.travaglini@arm.com break; 31113481Sgiacomo.travaglini@arm.com 31213481Sgiacomo.travaglini@arm.com case 2: 31313481Sgiacomo.travaglini@arm.com break; // The mutex is already initialized and ready for use. 31413481Sgiacomo.travaglini@arm.com 31513481Sgiacomo.travaglini@arm.com default: 31613481Sgiacomo.travaglini@arm.com GTEST_CHECK_(false) 31713481Sgiacomo.travaglini@arm.com << "Unexpected value of critical_section_init_phase_ " 31813481Sgiacomo.travaglini@arm.com << "while initializing a static mutex."; 31913481Sgiacomo.travaglini@arm.com } 32013481Sgiacomo.travaglini@arm.com } 32113481Sgiacomo.travaglini@arm.com} 32213481Sgiacomo.travaglini@arm.com 32313481Sgiacomo.travaglini@arm.comnamespace { 32413481Sgiacomo.travaglini@arm.com 32513481Sgiacomo.travaglini@arm.comclass ThreadWithParamSupport : public ThreadWithParamBase { 32613481Sgiacomo.travaglini@arm.com public: 32713481Sgiacomo.travaglini@arm.com static HANDLE CreateThread(Runnable* runnable, 32813481Sgiacomo.travaglini@arm.com Notification* thread_can_start) { 32913481Sgiacomo.travaglini@arm.com ThreadMainParam* param = new ThreadMainParam(runnable, thread_can_start); 33013481Sgiacomo.travaglini@arm.com DWORD thread_id; 33113481Sgiacomo.travaglini@arm.com // TODO(yukawa): Consider to use _beginthreadex instead. 33213481Sgiacomo.travaglini@arm.com HANDLE thread_handle = ::CreateThread( 33313481Sgiacomo.travaglini@arm.com NULL, // Default security. 33413481Sgiacomo.travaglini@arm.com 0, // Default stack size. 33513481Sgiacomo.travaglini@arm.com &ThreadWithParamSupport::ThreadMain, 33613481Sgiacomo.travaglini@arm.com param, // Parameter to ThreadMainStatic 33713481Sgiacomo.travaglini@arm.com 0x0, // Default creation flags. 33813481Sgiacomo.travaglini@arm.com &thread_id); // Need a valid pointer for the call to work under Win98. 33913481Sgiacomo.travaglini@arm.com GTEST_CHECK_(thread_handle != NULL) << "CreateThread failed with error " 34013481Sgiacomo.travaglini@arm.com << ::GetLastError() << "."; 34113481Sgiacomo.travaglini@arm.com if (thread_handle == NULL) { 34213481Sgiacomo.travaglini@arm.com delete param; 34313481Sgiacomo.travaglini@arm.com } 34413481Sgiacomo.travaglini@arm.com return thread_handle; 34513481Sgiacomo.travaglini@arm.com } 34613481Sgiacomo.travaglini@arm.com 34713481Sgiacomo.travaglini@arm.com private: 34813481Sgiacomo.travaglini@arm.com struct ThreadMainParam { 34913481Sgiacomo.travaglini@arm.com ThreadMainParam(Runnable* runnable, Notification* thread_can_start) 35013481Sgiacomo.travaglini@arm.com : runnable_(runnable), 35113481Sgiacomo.travaglini@arm.com thread_can_start_(thread_can_start) { 35213481Sgiacomo.travaglini@arm.com } 35313481Sgiacomo.travaglini@arm.com scoped_ptr<Runnable> runnable_; 35413481Sgiacomo.travaglini@arm.com // Does not own. 35513481Sgiacomo.travaglini@arm.com Notification* thread_can_start_; 35613481Sgiacomo.travaglini@arm.com }; 35713481Sgiacomo.travaglini@arm.com 35813481Sgiacomo.travaglini@arm.com static DWORD WINAPI ThreadMain(void* ptr) { 35913481Sgiacomo.travaglini@arm.com // Transfers ownership. 36013481Sgiacomo.travaglini@arm.com scoped_ptr<ThreadMainParam> param(static_cast<ThreadMainParam*>(ptr)); 36113481Sgiacomo.travaglini@arm.com if (param->thread_can_start_ != NULL) 36213481Sgiacomo.travaglini@arm.com param->thread_can_start_->WaitForNotification(); 36313481Sgiacomo.travaglini@arm.com param->runnable_->Run(); 36413481Sgiacomo.travaglini@arm.com return 0; 36513481Sgiacomo.travaglini@arm.com } 36613481Sgiacomo.travaglini@arm.com 36713481Sgiacomo.travaglini@arm.com // Prohibit instantiation. 36813481Sgiacomo.travaglini@arm.com ThreadWithParamSupport(); 36913481Sgiacomo.travaglini@arm.com 37013481Sgiacomo.travaglini@arm.com GTEST_DISALLOW_COPY_AND_ASSIGN_(ThreadWithParamSupport); 37113481Sgiacomo.travaglini@arm.com}; 37213481Sgiacomo.travaglini@arm.com 37313481Sgiacomo.travaglini@arm.com} // namespace 37413481Sgiacomo.travaglini@arm.com 37513481Sgiacomo.travaglini@arm.comThreadWithParamBase::ThreadWithParamBase(Runnable *runnable, 37613481Sgiacomo.travaglini@arm.com Notification* thread_can_start) 37713481Sgiacomo.travaglini@arm.com : thread_(ThreadWithParamSupport::CreateThread(runnable, 37813481Sgiacomo.travaglini@arm.com thread_can_start)) { 37913481Sgiacomo.travaglini@arm.com} 38013481Sgiacomo.travaglini@arm.com 38113481Sgiacomo.travaglini@arm.comThreadWithParamBase::~ThreadWithParamBase() { 38213481Sgiacomo.travaglini@arm.com Join(); 38313481Sgiacomo.travaglini@arm.com} 38413481Sgiacomo.travaglini@arm.com 38513481Sgiacomo.travaglini@arm.comvoid ThreadWithParamBase::Join() { 38613481Sgiacomo.travaglini@arm.com GTEST_CHECK_(::WaitForSingleObject(thread_.Get(), INFINITE) == WAIT_OBJECT_0) 38713481Sgiacomo.travaglini@arm.com << "Failed to join the thread with error " << ::GetLastError() << "."; 38813481Sgiacomo.travaglini@arm.com} 38913481Sgiacomo.travaglini@arm.com 39013481Sgiacomo.travaglini@arm.com// Maps a thread to a set of ThreadIdToThreadLocals that have values 39113481Sgiacomo.travaglini@arm.com// instantiated on that thread and notifies them when the thread exits. A 39213481Sgiacomo.travaglini@arm.com// ThreadLocal instance is expected to persist until all threads it has 39313481Sgiacomo.travaglini@arm.com// values on have terminated. 39413481Sgiacomo.travaglini@arm.comclass ThreadLocalRegistryImpl { 39513481Sgiacomo.travaglini@arm.com public: 39613481Sgiacomo.travaglini@arm.com // Registers thread_local_instance as having value on the current thread. 39713481Sgiacomo.travaglini@arm.com // Returns a value that can be used to identify the thread from other threads. 39813481Sgiacomo.travaglini@arm.com static ThreadLocalValueHolderBase* GetValueOnCurrentThread( 39913481Sgiacomo.travaglini@arm.com const ThreadLocalBase* thread_local_instance) { 40013481Sgiacomo.travaglini@arm.com DWORD current_thread = ::GetCurrentThreadId(); 40113481Sgiacomo.travaglini@arm.com MutexLock lock(&mutex_); 40213481Sgiacomo.travaglini@arm.com ThreadIdToThreadLocals* const thread_to_thread_locals = 40313481Sgiacomo.travaglini@arm.com GetThreadLocalsMapLocked(); 40413481Sgiacomo.travaglini@arm.com ThreadIdToThreadLocals::iterator thread_local_pos = 40513481Sgiacomo.travaglini@arm.com thread_to_thread_locals->find(current_thread); 40613481Sgiacomo.travaglini@arm.com if (thread_local_pos == thread_to_thread_locals->end()) { 40713481Sgiacomo.travaglini@arm.com thread_local_pos = thread_to_thread_locals->insert( 40813481Sgiacomo.travaglini@arm.com std::make_pair(current_thread, ThreadLocalValues())).first; 40913481Sgiacomo.travaglini@arm.com StartWatcherThreadFor(current_thread); 41013481Sgiacomo.travaglini@arm.com } 41113481Sgiacomo.travaglini@arm.com ThreadLocalValues& thread_local_values = thread_local_pos->second; 41213481Sgiacomo.travaglini@arm.com ThreadLocalValues::iterator value_pos = 41313481Sgiacomo.travaglini@arm.com thread_local_values.find(thread_local_instance); 41413481Sgiacomo.travaglini@arm.com if (value_pos == thread_local_values.end()) { 41513481Sgiacomo.travaglini@arm.com value_pos = 41613481Sgiacomo.travaglini@arm.com thread_local_values 41713481Sgiacomo.travaglini@arm.com .insert(std::make_pair( 41813481Sgiacomo.travaglini@arm.com thread_local_instance, 41913481Sgiacomo.travaglini@arm.com linked_ptr<ThreadLocalValueHolderBase>( 42013481Sgiacomo.travaglini@arm.com thread_local_instance->NewValueForCurrentThread()))) 42113481Sgiacomo.travaglini@arm.com .first; 42213481Sgiacomo.travaglini@arm.com } 42313481Sgiacomo.travaglini@arm.com return value_pos->second.get(); 42413481Sgiacomo.travaglini@arm.com } 42513481Sgiacomo.travaglini@arm.com 42613481Sgiacomo.travaglini@arm.com static void OnThreadLocalDestroyed( 42713481Sgiacomo.travaglini@arm.com const ThreadLocalBase* thread_local_instance) { 42813481Sgiacomo.travaglini@arm.com std::vector<linked_ptr<ThreadLocalValueHolderBase> > value_holders; 42913481Sgiacomo.travaglini@arm.com // Clean up the ThreadLocalValues data structure while holding the lock, but 43013481Sgiacomo.travaglini@arm.com // defer the destruction of the ThreadLocalValueHolderBases. 43113481Sgiacomo.travaglini@arm.com { 43213481Sgiacomo.travaglini@arm.com MutexLock lock(&mutex_); 43313481Sgiacomo.travaglini@arm.com ThreadIdToThreadLocals* const thread_to_thread_locals = 43413481Sgiacomo.travaglini@arm.com GetThreadLocalsMapLocked(); 43513481Sgiacomo.travaglini@arm.com for (ThreadIdToThreadLocals::iterator it = 43613481Sgiacomo.travaglini@arm.com thread_to_thread_locals->begin(); 43713481Sgiacomo.travaglini@arm.com it != thread_to_thread_locals->end(); 43813481Sgiacomo.travaglini@arm.com ++it) { 43913481Sgiacomo.travaglini@arm.com ThreadLocalValues& thread_local_values = it->second; 44013481Sgiacomo.travaglini@arm.com ThreadLocalValues::iterator value_pos = 44113481Sgiacomo.travaglini@arm.com thread_local_values.find(thread_local_instance); 44213481Sgiacomo.travaglini@arm.com if (value_pos != thread_local_values.end()) { 44313481Sgiacomo.travaglini@arm.com value_holders.push_back(value_pos->second); 44413481Sgiacomo.travaglini@arm.com thread_local_values.erase(value_pos); 44513481Sgiacomo.travaglini@arm.com // This 'if' can only be successful at most once, so theoretically we 44613481Sgiacomo.travaglini@arm.com // could break out of the loop here, but we don't bother doing so. 44713481Sgiacomo.travaglini@arm.com } 44813481Sgiacomo.travaglini@arm.com } 44913481Sgiacomo.travaglini@arm.com } 45013481Sgiacomo.travaglini@arm.com // Outside the lock, let the destructor for 'value_holders' deallocate the 45113481Sgiacomo.travaglini@arm.com // ThreadLocalValueHolderBases. 45213481Sgiacomo.travaglini@arm.com } 45313481Sgiacomo.travaglini@arm.com 45413481Sgiacomo.travaglini@arm.com static void OnThreadExit(DWORD thread_id) { 45513481Sgiacomo.travaglini@arm.com GTEST_CHECK_(thread_id != 0) << ::GetLastError(); 45613481Sgiacomo.travaglini@arm.com std::vector<linked_ptr<ThreadLocalValueHolderBase> > value_holders; 45713481Sgiacomo.travaglini@arm.com // Clean up the ThreadIdToThreadLocals data structure while holding the 45813481Sgiacomo.travaglini@arm.com // lock, but defer the destruction of the ThreadLocalValueHolderBases. 45913481Sgiacomo.travaglini@arm.com { 46013481Sgiacomo.travaglini@arm.com MutexLock lock(&mutex_); 46113481Sgiacomo.travaglini@arm.com ThreadIdToThreadLocals* const thread_to_thread_locals = 46213481Sgiacomo.travaglini@arm.com GetThreadLocalsMapLocked(); 46313481Sgiacomo.travaglini@arm.com ThreadIdToThreadLocals::iterator thread_local_pos = 46413481Sgiacomo.travaglini@arm.com thread_to_thread_locals->find(thread_id); 46513481Sgiacomo.travaglini@arm.com if (thread_local_pos != thread_to_thread_locals->end()) { 46613481Sgiacomo.travaglini@arm.com ThreadLocalValues& thread_local_values = thread_local_pos->second; 46713481Sgiacomo.travaglini@arm.com for (ThreadLocalValues::iterator value_pos = 46813481Sgiacomo.travaglini@arm.com thread_local_values.begin(); 46913481Sgiacomo.travaglini@arm.com value_pos != thread_local_values.end(); 47013481Sgiacomo.travaglini@arm.com ++value_pos) { 47113481Sgiacomo.travaglini@arm.com value_holders.push_back(value_pos->second); 47213481Sgiacomo.travaglini@arm.com } 47313481Sgiacomo.travaglini@arm.com thread_to_thread_locals->erase(thread_local_pos); 47413481Sgiacomo.travaglini@arm.com } 47513481Sgiacomo.travaglini@arm.com } 47613481Sgiacomo.travaglini@arm.com // Outside the lock, let the destructor for 'value_holders' deallocate the 47713481Sgiacomo.travaglini@arm.com // ThreadLocalValueHolderBases. 47813481Sgiacomo.travaglini@arm.com } 47913481Sgiacomo.travaglini@arm.com 48013481Sgiacomo.travaglini@arm.com private: 48113481Sgiacomo.travaglini@arm.com // In a particular thread, maps a ThreadLocal object to its value. 48213481Sgiacomo.travaglini@arm.com typedef std::map<const ThreadLocalBase*, 48313481Sgiacomo.travaglini@arm.com linked_ptr<ThreadLocalValueHolderBase> > ThreadLocalValues; 48413481Sgiacomo.travaglini@arm.com // Stores all ThreadIdToThreadLocals having values in a thread, indexed by 48513481Sgiacomo.travaglini@arm.com // thread's ID. 48613481Sgiacomo.travaglini@arm.com typedef std::map<DWORD, ThreadLocalValues> ThreadIdToThreadLocals; 48713481Sgiacomo.travaglini@arm.com 48813481Sgiacomo.travaglini@arm.com // Holds the thread id and thread handle that we pass from 48913481Sgiacomo.travaglini@arm.com // StartWatcherThreadFor to WatcherThreadFunc. 49013481Sgiacomo.travaglini@arm.com typedef std::pair<DWORD, HANDLE> ThreadIdAndHandle; 49113481Sgiacomo.travaglini@arm.com 49213481Sgiacomo.travaglini@arm.com static void StartWatcherThreadFor(DWORD thread_id) { 49313481Sgiacomo.travaglini@arm.com // The returned handle will be kept in thread_map and closed by 49413481Sgiacomo.travaglini@arm.com // watcher_thread in WatcherThreadFunc. 49513481Sgiacomo.travaglini@arm.com HANDLE thread = ::OpenThread(SYNCHRONIZE | THREAD_QUERY_INFORMATION, 49613481Sgiacomo.travaglini@arm.com FALSE, 49713481Sgiacomo.travaglini@arm.com thread_id); 49813481Sgiacomo.travaglini@arm.com GTEST_CHECK_(thread != NULL); 49913481Sgiacomo.travaglini@arm.com // We need to to pass a valid thread ID pointer into CreateThread for it 50013481Sgiacomo.travaglini@arm.com // to work correctly under Win98. 50113481Sgiacomo.travaglini@arm.com DWORD watcher_thread_id; 50213481Sgiacomo.travaglini@arm.com HANDLE watcher_thread = ::CreateThread( 50313481Sgiacomo.travaglini@arm.com NULL, // Default security. 50413481Sgiacomo.travaglini@arm.com 0, // Default stack size 50513481Sgiacomo.travaglini@arm.com &ThreadLocalRegistryImpl::WatcherThreadFunc, 50613481Sgiacomo.travaglini@arm.com reinterpret_cast<LPVOID>(new ThreadIdAndHandle(thread_id, thread)), 50713481Sgiacomo.travaglini@arm.com CREATE_SUSPENDED, 50813481Sgiacomo.travaglini@arm.com &watcher_thread_id); 50913481Sgiacomo.travaglini@arm.com GTEST_CHECK_(watcher_thread != NULL); 51013481Sgiacomo.travaglini@arm.com // Give the watcher thread the same priority as ours to avoid being 51113481Sgiacomo.travaglini@arm.com // blocked by it. 51213481Sgiacomo.travaglini@arm.com ::SetThreadPriority(watcher_thread, 51313481Sgiacomo.travaglini@arm.com ::GetThreadPriority(::GetCurrentThread())); 51413481Sgiacomo.travaglini@arm.com ::ResumeThread(watcher_thread); 51513481Sgiacomo.travaglini@arm.com ::CloseHandle(watcher_thread); 51613481Sgiacomo.travaglini@arm.com } 51713481Sgiacomo.travaglini@arm.com 51813481Sgiacomo.travaglini@arm.com // Monitors exit from a given thread and notifies those 51913481Sgiacomo.travaglini@arm.com // ThreadIdToThreadLocals about thread termination. 52013481Sgiacomo.travaglini@arm.com static DWORD WINAPI WatcherThreadFunc(LPVOID param) { 52113481Sgiacomo.travaglini@arm.com const ThreadIdAndHandle* tah = 52213481Sgiacomo.travaglini@arm.com reinterpret_cast<const ThreadIdAndHandle*>(param); 52313481Sgiacomo.travaglini@arm.com GTEST_CHECK_( 52413481Sgiacomo.travaglini@arm.com ::WaitForSingleObject(tah->second, INFINITE) == WAIT_OBJECT_0); 52513481Sgiacomo.travaglini@arm.com OnThreadExit(tah->first); 52613481Sgiacomo.travaglini@arm.com ::CloseHandle(tah->second); 52713481Sgiacomo.travaglini@arm.com delete tah; 52813481Sgiacomo.travaglini@arm.com return 0; 52913481Sgiacomo.travaglini@arm.com } 53013481Sgiacomo.travaglini@arm.com 53113481Sgiacomo.travaglini@arm.com // Returns map of thread local instances. 53213481Sgiacomo.travaglini@arm.com static ThreadIdToThreadLocals* GetThreadLocalsMapLocked() { 53313481Sgiacomo.travaglini@arm.com mutex_.AssertHeld(); 53413481Sgiacomo.travaglini@arm.com static ThreadIdToThreadLocals* map = new ThreadIdToThreadLocals; 53513481Sgiacomo.travaglini@arm.com return map; 53613481Sgiacomo.travaglini@arm.com } 53713481Sgiacomo.travaglini@arm.com 53813481Sgiacomo.travaglini@arm.com // Protects access to GetThreadLocalsMapLocked() and its return value. 53913481Sgiacomo.travaglini@arm.com static Mutex mutex_; 54013481Sgiacomo.travaglini@arm.com // Protects access to GetThreadMapLocked() and its return value. 54113481Sgiacomo.travaglini@arm.com static Mutex thread_map_mutex_; 54213481Sgiacomo.travaglini@arm.com}; 54313481Sgiacomo.travaglini@arm.com 54413481Sgiacomo.travaglini@arm.comMutex ThreadLocalRegistryImpl::mutex_(Mutex::kStaticMutex); 54513481Sgiacomo.travaglini@arm.comMutex ThreadLocalRegistryImpl::thread_map_mutex_(Mutex::kStaticMutex); 54613481Sgiacomo.travaglini@arm.com 54713481Sgiacomo.travaglini@arm.comThreadLocalValueHolderBase* ThreadLocalRegistry::GetValueOnCurrentThread( 54813481Sgiacomo.travaglini@arm.com const ThreadLocalBase* thread_local_instance) { 54913481Sgiacomo.travaglini@arm.com return ThreadLocalRegistryImpl::GetValueOnCurrentThread( 55013481Sgiacomo.travaglini@arm.com thread_local_instance); 55113481Sgiacomo.travaglini@arm.com} 55213481Sgiacomo.travaglini@arm.com 55313481Sgiacomo.travaglini@arm.comvoid ThreadLocalRegistry::OnThreadLocalDestroyed( 55413481Sgiacomo.travaglini@arm.com const ThreadLocalBase* thread_local_instance) { 55513481Sgiacomo.travaglini@arm.com ThreadLocalRegistryImpl::OnThreadLocalDestroyed(thread_local_instance); 55613481Sgiacomo.travaglini@arm.com} 55713481Sgiacomo.travaglini@arm.com 55813481Sgiacomo.travaglini@arm.com#endif // GTEST_IS_THREADSAFE && GTEST_OS_WINDOWS 55913481Sgiacomo.travaglini@arm.com 56013481Sgiacomo.travaglini@arm.com#if GTEST_USES_POSIX_RE 56113481Sgiacomo.travaglini@arm.com 56213481Sgiacomo.travaglini@arm.com// Implements RE. Currently only needed for death tests. 56313481Sgiacomo.travaglini@arm.com 56413481Sgiacomo.travaglini@arm.comRE::~RE() { 56513481Sgiacomo.travaglini@arm.com if (is_valid_) { 56613481Sgiacomo.travaglini@arm.com // regfree'ing an invalid regex might crash because the content 56713481Sgiacomo.travaglini@arm.com // of the regex is undefined. Since the regex's are essentially 56813481Sgiacomo.travaglini@arm.com // the same, one cannot be valid (or invalid) without the other 56913481Sgiacomo.travaglini@arm.com // being so too. 57013481Sgiacomo.travaglini@arm.com regfree(&partial_regex_); 57113481Sgiacomo.travaglini@arm.com regfree(&full_regex_); 57213481Sgiacomo.travaglini@arm.com } 57313481Sgiacomo.travaglini@arm.com free(const_cast<char*>(pattern_)); 57413481Sgiacomo.travaglini@arm.com} 57513481Sgiacomo.travaglini@arm.com 57613481Sgiacomo.travaglini@arm.com// Returns true iff regular expression re matches the entire str. 57713481Sgiacomo.travaglini@arm.combool RE::FullMatch(const char* str, const RE& re) { 57813481Sgiacomo.travaglini@arm.com if (!re.is_valid_) return false; 57913481Sgiacomo.travaglini@arm.com 58013481Sgiacomo.travaglini@arm.com regmatch_t match; 58113481Sgiacomo.travaglini@arm.com return regexec(&re.full_regex_, str, 1, &match, 0) == 0; 58213481Sgiacomo.travaglini@arm.com} 58313481Sgiacomo.travaglini@arm.com 58413481Sgiacomo.travaglini@arm.com// Returns true iff regular expression re matches a substring of str 58513481Sgiacomo.travaglini@arm.com// (including str itself). 58613481Sgiacomo.travaglini@arm.combool RE::PartialMatch(const char* str, const RE& re) { 58713481Sgiacomo.travaglini@arm.com if (!re.is_valid_) return false; 58813481Sgiacomo.travaglini@arm.com 58913481Sgiacomo.travaglini@arm.com regmatch_t match; 59013481Sgiacomo.travaglini@arm.com return regexec(&re.partial_regex_, str, 1, &match, 0) == 0; 59113481Sgiacomo.travaglini@arm.com} 59213481Sgiacomo.travaglini@arm.com 59313481Sgiacomo.travaglini@arm.com// Initializes an RE from its string representation. 59413481Sgiacomo.travaglini@arm.comvoid RE::Init(const char* regex) { 59513481Sgiacomo.travaglini@arm.com pattern_ = posix::StrDup(regex); 59613481Sgiacomo.travaglini@arm.com 59713481Sgiacomo.travaglini@arm.com // Reserves enough bytes to hold the regular expression used for a 59813481Sgiacomo.travaglini@arm.com // full match. 59913481Sgiacomo.travaglini@arm.com const size_t full_regex_len = strlen(regex) + 10; 60013481Sgiacomo.travaglini@arm.com char* const full_pattern = new char[full_regex_len]; 60113481Sgiacomo.travaglini@arm.com 60213481Sgiacomo.travaglini@arm.com snprintf(full_pattern, full_regex_len, "^(%s)$", regex); 60313481Sgiacomo.travaglini@arm.com is_valid_ = regcomp(&full_regex_, full_pattern, REG_EXTENDED) == 0; 60413481Sgiacomo.travaglini@arm.com // We want to call regcomp(&partial_regex_, ...) even if the 60513481Sgiacomo.travaglini@arm.com // previous expression returns false. Otherwise partial_regex_ may 60613481Sgiacomo.travaglini@arm.com // not be properly initialized can may cause trouble when it's 60713481Sgiacomo.travaglini@arm.com // freed. 60813481Sgiacomo.travaglini@arm.com // 60913481Sgiacomo.travaglini@arm.com // Some implementation of POSIX regex (e.g. on at least some 61013481Sgiacomo.travaglini@arm.com // versions of Cygwin) doesn't accept the empty string as a valid 61113481Sgiacomo.travaglini@arm.com // regex. We change it to an equivalent form "()" to be safe. 61213481Sgiacomo.travaglini@arm.com if (is_valid_) { 61313481Sgiacomo.travaglini@arm.com const char* const partial_regex = (*regex == '\0') ? "()" : regex; 61413481Sgiacomo.travaglini@arm.com is_valid_ = regcomp(&partial_regex_, partial_regex, REG_EXTENDED) == 0; 61513481Sgiacomo.travaglini@arm.com } 61613481Sgiacomo.travaglini@arm.com EXPECT_TRUE(is_valid_) 61713481Sgiacomo.travaglini@arm.com << "Regular expression \"" << regex 61813481Sgiacomo.travaglini@arm.com << "\" is not a valid POSIX Extended regular expression."; 61913481Sgiacomo.travaglini@arm.com 62013481Sgiacomo.travaglini@arm.com delete[] full_pattern; 62113481Sgiacomo.travaglini@arm.com} 62213481Sgiacomo.travaglini@arm.com 62313481Sgiacomo.travaglini@arm.com#elif GTEST_USES_SIMPLE_RE 62413481Sgiacomo.travaglini@arm.com 62513481Sgiacomo.travaglini@arm.com// Returns true iff ch appears anywhere in str (excluding the 62613481Sgiacomo.travaglini@arm.com// terminating '\0' character). 62713481Sgiacomo.travaglini@arm.combool IsInSet(char ch, const char* str) { 62813481Sgiacomo.travaglini@arm.com return ch != '\0' && strchr(str, ch) != NULL; 62913481Sgiacomo.travaglini@arm.com} 63013481Sgiacomo.travaglini@arm.com 63113481Sgiacomo.travaglini@arm.com// Returns true iff ch belongs to the given classification. Unlike 63213481Sgiacomo.travaglini@arm.com// similar functions in <ctype.h>, these aren't affected by the 63313481Sgiacomo.travaglini@arm.com// current locale. 63413481Sgiacomo.travaglini@arm.combool IsAsciiDigit(char ch) { return '0' <= ch && ch <= '9'; } 63513481Sgiacomo.travaglini@arm.combool IsAsciiPunct(char ch) { 63613481Sgiacomo.travaglini@arm.com return IsInSet(ch, "^-!\"#$%&'()*+,./:;<=>?@[\\]_`{|}~"); 63713481Sgiacomo.travaglini@arm.com} 63813481Sgiacomo.travaglini@arm.combool IsRepeat(char ch) { return IsInSet(ch, "?*+"); } 63913481Sgiacomo.travaglini@arm.combool IsAsciiWhiteSpace(char ch) { return IsInSet(ch, " \f\n\r\t\v"); } 64013481Sgiacomo.travaglini@arm.combool IsAsciiWordChar(char ch) { 64113481Sgiacomo.travaglini@arm.com return ('a' <= ch && ch <= 'z') || ('A' <= ch && ch <= 'Z') || 64213481Sgiacomo.travaglini@arm.com ('0' <= ch && ch <= '9') || ch == '_'; 64313481Sgiacomo.travaglini@arm.com} 64413481Sgiacomo.travaglini@arm.com 64513481Sgiacomo.travaglini@arm.com// Returns true iff "\\c" is a supported escape sequence. 64613481Sgiacomo.travaglini@arm.combool IsValidEscape(char c) { 64713481Sgiacomo.travaglini@arm.com return (IsAsciiPunct(c) || IsInSet(c, "dDfnrsStvwW")); 64813481Sgiacomo.travaglini@arm.com} 64913481Sgiacomo.travaglini@arm.com 65013481Sgiacomo.travaglini@arm.com// Returns true iff the given atom (specified by escaped and pattern) 65113481Sgiacomo.travaglini@arm.com// matches ch. The result is undefined if the atom is invalid. 65213481Sgiacomo.travaglini@arm.combool AtomMatchesChar(bool escaped, char pattern_char, char ch) { 65313481Sgiacomo.travaglini@arm.com if (escaped) { // "\\p" where p is pattern_char. 65413481Sgiacomo.travaglini@arm.com switch (pattern_char) { 65513481Sgiacomo.travaglini@arm.com case 'd': return IsAsciiDigit(ch); 65613481Sgiacomo.travaglini@arm.com case 'D': return !IsAsciiDigit(ch); 65713481Sgiacomo.travaglini@arm.com case 'f': return ch == '\f'; 65813481Sgiacomo.travaglini@arm.com case 'n': return ch == '\n'; 65913481Sgiacomo.travaglini@arm.com case 'r': return ch == '\r'; 66013481Sgiacomo.travaglini@arm.com case 's': return IsAsciiWhiteSpace(ch); 66113481Sgiacomo.travaglini@arm.com case 'S': return !IsAsciiWhiteSpace(ch); 66213481Sgiacomo.travaglini@arm.com case 't': return ch == '\t'; 66313481Sgiacomo.travaglini@arm.com case 'v': return ch == '\v'; 66413481Sgiacomo.travaglini@arm.com case 'w': return IsAsciiWordChar(ch); 66513481Sgiacomo.travaglini@arm.com case 'W': return !IsAsciiWordChar(ch); 66613481Sgiacomo.travaglini@arm.com } 66713481Sgiacomo.travaglini@arm.com return IsAsciiPunct(pattern_char) && pattern_char == ch; 66813481Sgiacomo.travaglini@arm.com } 66913481Sgiacomo.travaglini@arm.com 67013481Sgiacomo.travaglini@arm.com return (pattern_char == '.' && ch != '\n') || pattern_char == ch; 67113481Sgiacomo.travaglini@arm.com} 67213481Sgiacomo.travaglini@arm.com 67313481Sgiacomo.travaglini@arm.com// Helper function used by ValidateRegex() to format error messages. 67413481Sgiacomo.travaglini@arm.comstd::string FormatRegexSyntaxError(const char* regex, int index) { 67513481Sgiacomo.travaglini@arm.com return (Message() << "Syntax error at index " << index 67613481Sgiacomo.travaglini@arm.com << " in simple regular expression \"" << regex << "\": ").GetString(); 67713481Sgiacomo.travaglini@arm.com} 67813481Sgiacomo.travaglini@arm.com 67913481Sgiacomo.travaglini@arm.com// Generates non-fatal failures and returns false if regex is invalid; 68013481Sgiacomo.travaglini@arm.com// otherwise returns true. 68113481Sgiacomo.travaglini@arm.combool ValidateRegex(const char* regex) { 68213481Sgiacomo.travaglini@arm.com if (regex == NULL) { 68313481Sgiacomo.travaglini@arm.com // TODO(wan@google.com): fix the source file location in the 68413481Sgiacomo.travaglini@arm.com // assertion failures to match where the regex is used in user 68513481Sgiacomo.travaglini@arm.com // code. 68613481Sgiacomo.travaglini@arm.com ADD_FAILURE() << "NULL is not a valid simple regular expression."; 68713481Sgiacomo.travaglini@arm.com return false; 68813481Sgiacomo.travaglini@arm.com } 68913481Sgiacomo.travaglini@arm.com 69013481Sgiacomo.travaglini@arm.com bool is_valid = true; 69113481Sgiacomo.travaglini@arm.com 69213481Sgiacomo.travaglini@arm.com // True iff ?, *, or + can follow the previous atom. 69313481Sgiacomo.travaglini@arm.com bool prev_repeatable = false; 69413481Sgiacomo.travaglini@arm.com for (int i = 0; regex[i]; i++) { 69513481Sgiacomo.travaglini@arm.com if (regex[i] == '\\') { // An escape sequence 69613481Sgiacomo.travaglini@arm.com i++; 69713481Sgiacomo.travaglini@arm.com if (regex[i] == '\0') { 69813481Sgiacomo.travaglini@arm.com ADD_FAILURE() << FormatRegexSyntaxError(regex, i - 1) 69913481Sgiacomo.travaglini@arm.com << "'\\' cannot appear at the end."; 70013481Sgiacomo.travaglini@arm.com return false; 70113481Sgiacomo.travaglini@arm.com } 70213481Sgiacomo.travaglini@arm.com 70313481Sgiacomo.travaglini@arm.com if (!IsValidEscape(regex[i])) { 70413481Sgiacomo.travaglini@arm.com ADD_FAILURE() << FormatRegexSyntaxError(regex, i - 1) 70513481Sgiacomo.travaglini@arm.com << "invalid escape sequence \"\\" << regex[i] << "\"."; 70613481Sgiacomo.travaglini@arm.com is_valid = false; 70713481Sgiacomo.travaglini@arm.com } 70813481Sgiacomo.travaglini@arm.com prev_repeatable = true; 70913481Sgiacomo.travaglini@arm.com } else { // Not an escape sequence. 71013481Sgiacomo.travaglini@arm.com const char ch = regex[i]; 71113481Sgiacomo.travaglini@arm.com 71213481Sgiacomo.travaglini@arm.com if (ch == '^' && i > 0) { 71313481Sgiacomo.travaglini@arm.com ADD_FAILURE() << FormatRegexSyntaxError(regex, i) 71413481Sgiacomo.travaglini@arm.com << "'^' can only appear at the beginning."; 71513481Sgiacomo.travaglini@arm.com is_valid = false; 71613481Sgiacomo.travaglini@arm.com } else if (ch == '$' && regex[i + 1] != '\0') { 71713481Sgiacomo.travaglini@arm.com ADD_FAILURE() << FormatRegexSyntaxError(regex, i) 71813481Sgiacomo.travaglini@arm.com << "'$' can only appear at the end."; 71913481Sgiacomo.travaglini@arm.com is_valid = false; 72013481Sgiacomo.travaglini@arm.com } else if (IsInSet(ch, "()[]{}|")) { 72113481Sgiacomo.travaglini@arm.com ADD_FAILURE() << FormatRegexSyntaxError(regex, i) 72213481Sgiacomo.travaglini@arm.com << "'" << ch << "' is unsupported."; 72313481Sgiacomo.travaglini@arm.com is_valid = false; 72413481Sgiacomo.travaglini@arm.com } else if (IsRepeat(ch) && !prev_repeatable) { 72513481Sgiacomo.travaglini@arm.com ADD_FAILURE() << FormatRegexSyntaxError(regex, i) 72613481Sgiacomo.travaglini@arm.com << "'" << ch << "' can only follow a repeatable token."; 72713481Sgiacomo.travaglini@arm.com is_valid = false; 72813481Sgiacomo.travaglini@arm.com } 72913481Sgiacomo.travaglini@arm.com 73013481Sgiacomo.travaglini@arm.com prev_repeatable = !IsInSet(ch, "^$?*+"); 73113481Sgiacomo.travaglini@arm.com } 73213481Sgiacomo.travaglini@arm.com } 73313481Sgiacomo.travaglini@arm.com 73413481Sgiacomo.travaglini@arm.com return is_valid; 73513481Sgiacomo.travaglini@arm.com} 73613481Sgiacomo.travaglini@arm.com 73713481Sgiacomo.travaglini@arm.com// Matches a repeated regex atom followed by a valid simple regular 73813481Sgiacomo.travaglini@arm.com// expression. The regex atom is defined as c if escaped is false, 73913481Sgiacomo.travaglini@arm.com// or \c otherwise. repeat is the repetition meta character (?, *, 74013481Sgiacomo.travaglini@arm.com// or +). The behavior is undefined if str contains too many 74113481Sgiacomo.travaglini@arm.com// characters to be indexable by size_t, in which case the test will 74213481Sgiacomo.travaglini@arm.com// probably time out anyway. We are fine with this limitation as 74313481Sgiacomo.travaglini@arm.com// std::string has it too. 74413481Sgiacomo.travaglini@arm.combool MatchRepetitionAndRegexAtHead( 74513481Sgiacomo.travaglini@arm.com bool escaped, char c, char repeat, const char* regex, 74613481Sgiacomo.travaglini@arm.com const char* str) { 74713481Sgiacomo.travaglini@arm.com const size_t min_count = (repeat == '+') ? 1 : 0; 74813481Sgiacomo.travaglini@arm.com const size_t max_count = (repeat == '?') ? 1 : 74913481Sgiacomo.travaglini@arm.com static_cast<size_t>(-1) - 1; 75013481Sgiacomo.travaglini@arm.com // We cannot call numeric_limits::max() as it conflicts with the 75113481Sgiacomo.travaglini@arm.com // max() macro on Windows. 75213481Sgiacomo.travaglini@arm.com 75313481Sgiacomo.travaglini@arm.com for (size_t i = 0; i <= max_count; ++i) { 75413481Sgiacomo.travaglini@arm.com // We know that the atom matches each of the first i characters in str. 75513481Sgiacomo.travaglini@arm.com if (i >= min_count && MatchRegexAtHead(regex, str + i)) { 75613481Sgiacomo.travaglini@arm.com // We have enough matches at the head, and the tail matches too. 75713481Sgiacomo.travaglini@arm.com // Since we only care about *whether* the pattern matches str 75813481Sgiacomo.travaglini@arm.com // (as opposed to *how* it matches), there is no need to find a 75913481Sgiacomo.travaglini@arm.com // greedy match. 76013481Sgiacomo.travaglini@arm.com return true; 76113481Sgiacomo.travaglini@arm.com } 76213481Sgiacomo.travaglini@arm.com if (str[i] == '\0' || !AtomMatchesChar(escaped, c, str[i])) 76313481Sgiacomo.travaglini@arm.com return false; 76413481Sgiacomo.travaglini@arm.com } 76513481Sgiacomo.travaglini@arm.com return false; 76613481Sgiacomo.travaglini@arm.com} 76713481Sgiacomo.travaglini@arm.com 76813481Sgiacomo.travaglini@arm.com// Returns true iff regex matches a prefix of str. regex must be a 76913481Sgiacomo.travaglini@arm.com// valid simple regular expression and not start with "^", or the 77013481Sgiacomo.travaglini@arm.com// result is undefined. 77113481Sgiacomo.travaglini@arm.combool MatchRegexAtHead(const char* regex, const char* str) { 77213481Sgiacomo.travaglini@arm.com if (*regex == '\0') // An empty regex matches a prefix of anything. 77313481Sgiacomo.travaglini@arm.com return true; 77413481Sgiacomo.travaglini@arm.com 77513481Sgiacomo.travaglini@arm.com // "$" only matches the end of a string. Note that regex being 77613481Sgiacomo.travaglini@arm.com // valid guarantees that there's nothing after "$" in it. 77713481Sgiacomo.travaglini@arm.com if (*regex == '$') 77813481Sgiacomo.travaglini@arm.com return *str == '\0'; 77913481Sgiacomo.travaglini@arm.com 78013481Sgiacomo.travaglini@arm.com // Is the first thing in regex an escape sequence? 78113481Sgiacomo.travaglini@arm.com const bool escaped = *regex == '\\'; 78213481Sgiacomo.travaglini@arm.com if (escaped) 78313481Sgiacomo.travaglini@arm.com ++regex; 78413481Sgiacomo.travaglini@arm.com if (IsRepeat(regex[1])) { 78513481Sgiacomo.travaglini@arm.com // MatchRepetitionAndRegexAtHead() calls MatchRegexAtHead(), so 78613481Sgiacomo.travaglini@arm.com // here's an indirect recursion. It terminates as the regex gets 78713481Sgiacomo.travaglini@arm.com // shorter in each recursion. 78813481Sgiacomo.travaglini@arm.com return MatchRepetitionAndRegexAtHead( 78913481Sgiacomo.travaglini@arm.com escaped, regex[0], regex[1], regex + 2, str); 79013481Sgiacomo.travaglini@arm.com } else { 79113481Sgiacomo.travaglini@arm.com // regex isn't empty, isn't "$", and doesn't start with a 79213481Sgiacomo.travaglini@arm.com // repetition. We match the first atom of regex with the first 79313481Sgiacomo.travaglini@arm.com // character of str and recurse. 79413481Sgiacomo.travaglini@arm.com return (*str != '\0') && AtomMatchesChar(escaped, *regex, *str) && 79513481Sgiacomo.travaglini@arm.com MatchRegexAtHead(regex + 1, str + 1); 79613481Sgiacomo.travaglini@arm.com } 79713481Sgiacomo.travaglini@arm.com} 79813481Sgiacomo.travaglini@arm.com 79913481Sgiacomo.travaglini@arm.com// Returns true iff regex matches any substring of str. regex must be 80013481Sgiacomo.travaglini@arm.com// a valid simple regular expression, or the result is undefined. 80113481Sgiacomo.travaglini@arm.com// 80213481Sgiacomo.travaglini@arm.com// The algorithm is recursive, but the recursion depth doesn't exceed 80313481Sgiacomo.travaglini@arm.com// the regex length, so we won't need to worry about running out of 80413481Sgiacomo.travaglini@arm.com// stack space normally. In rare cases the time complexity can be 80513481Sgiacomo.travaglini@arm.com// exponential with respect to the regex length + the string length, 80613481Sgiacomo.travaglini@arm.com// but usually it's must faster (often close to linear). 80713481Sgiacomo.travaglini@arm.combool MatchRegexAnywhere(const char* regex, const char* str) { 80813481Sgiacomo.travaglini@arm.com if (regex == NULL || str == NULL) 80913481Sgiacomo.travaglini@arm.com return false; 81013481Sgiacomo.travaglini@arm.com 81113481Sgiacomo.travaglini@arm.com if (*regex == '^') 81213481Sgiacomo.travaglini@arm.com return MatchRegexAtHead(regex + 1, str); 81313481Sgiacomo.travaglini@arm.com 81413481Sgiacomo.travaglini@arm.com // A successful match can be anywhere in str. 81513481Sgiacomo.travaglini@arm.com do { 81613481Sgiacomo.travaglini@arm.com if (MatchRegexAtHead(regex, str)) 81713481Sgiacomo.travaglini@arm.com return true; 81813481Sgiacomo.travaglini@arm.com } while (*str++ != '\0'); 81913481Sgiacomo.travaglini@arm.com return false; 82013481Sgiacomo.travaglini@arm.com} 82113481Sgiacomo.travaglini@arm.com 82213481Sgiacomo.travaglini@arm.com// Implements the RE class. 82313481Sgiacomo.travaglini@arm.com 82413481Sgiacomo.travaglini@arm.comRE::~RE() { 82513481Sgiacomo.travaglini@arm.com free(const_cast<char*>(pattern_)); 82613481Sgiacomo.travaglini@arm.com free(const_cast<char*>(full_pattern_)); 82713481Sgiacomo.travaglini@arm.com} 82813481Sgiacomo.travaglini@arm.com 82913481Sgiacomo.travaglini@arm.com// Returns true iff regular expression re matches the entire str. 83013481Sgiacomo.travaglini@arm.combool RE::FullMatch(const char* str, const RE& re) { 83113481Sgiacomo.travaglini@arm.com return re.is_valid_ && MatchRegexAnywhere(re.full_pattern_, str); 83213481Sgiacomo.travaglini@arm.com} 83313481Sgiacomo.travaglini@arm.com 83413481Sgiacomo.travaglini@arm.com// Returns true iff regular expression re matches a substring of str 83513481Sgiacomo.travaglini@arm.com// (including str itself). 83613481Sgiacomo.travaglini@arm.combool RE::PartialMatch(const char* str, const RE& re) { 83713481Sgiacomo.travaglini@arm.com return re.is_valid_ && MatchRegexAnywhere(re.pattern_, str); 83813481Sgiacomo.travaglini@arm.com} 83913481Sgiacomo.travaglini@arm.com 84013481Sgiacomo.travaglini@arm.com// Initializes an RE from its string representation. 84113481Sgiacomo.travaglini@arm.comvoid RE::Init(const char* regex) { 84213481Sgiacomo.travaglini@arm.com pattern_ = full_pattern_ = NULL; 84313481Sgiacomo.travaglini@arm.com if (regex != NULL) { 84413481Sgiacomo.travaglini@arm.com pattern_ = posix::StrDup(regex); 84513481Sgiacomo.travaglini@arm.com } 84613481Sgiacomo.travaglini@arm.com 84713481Sgiacomo.travaglini@arm.com is_valid_ = ValidateRegex(regex); 84813481Sgiacomo.travaglini@arm.com if (!is_valid_) { 84913481Sgiacomo.travaglini@arm.com // No need to calculate the full pattern when the regex is invalid. 85013481Sgiacomo.travaglini@arm.com return; 85113481Sgiacomo.travaglini@arm.com } 85213481Sgiacomo.travaglini@arm.com 85313481Sgiacomo.travaglini@arm.com const size_t len = strlen(regex); 85413481Sgiacomo.travaglini@arm.com // Reserves enough bytes to hold the regular expression used for a 85513481Sgiacomo.travaglini@arm.com // full match: we need space to prepend a '^', append a '$', and 85613481Sgiacomo.travaglini@arm.com // terminate the string with '\0'. 85713481Sgiacomo.travaglini@arm.com char* buffer = static_cast<char*>(malloc(len + 3)); 85813481Sgiacomo.travaglini@arm.com full_pattern_ = buffer; 85913481Sgiacomo.travaglini@arm.com 86013481Sgiacomo.travaglini@arm.com if (*regex != '^') 86113481Sgiacomo.travaglini@arm.com *buffer++ = '^'; // Makes sure full_pattern_ starts with '^'. 86213481Sgiacomo.travaglini@arm.com 86313481Sgiacomo.travaglini@arm.com // We don't use snprintf or strncpy, as they trigger a warning when 86413481Sgiacomo.travaglini@arm.com // compiled with VC++ 8.0. 86513481Sgiacomo.travaglini@arm.com memcpy(buffer, regex, len); 86613481Sgiacomo.travaglini@arm.com buffer += len; 86713481Sgiacomo.travaglini@arm.com 86813481Sgiacomo.travaglini@arm.com if (len == 0 || regex[len - 1] != '$') 86913481Sgiacomo.travaglini@arm.com *buffer++ = '$'; // Makes sure full_pattern_ ends with '$'. 87013481Sgiacomo.travaglini@arm.com 87113481Sgiacomo.travaglini@arm.com *buffer = '\0'; 87213481Sgiacomo.travaglini@arm.com} 87313481Sgiacomo.travaglini@arm.com 87413481Sgiacomo.travaglini@arm.com#endif // GTEST_USES_POSIX_RE 87513481Sgiacomo.travaglini@arm.com 87613481Sgiacomo.travaglini@arm.comconst char kUnknownFile[] = "unknown file"; 87713481Sgiacomo.travaglini@arm.com 87813481Sgiacomo.travaglini@arm.com// Formats a source file path and a line number as they would appear 87913481Sgiacomo.travaglini@arm.com// in an error message from the compiler used to compile this code. 88013481Sgiacomo.travaglini@arm.comGTEST_API_ ::std::string FormatFileLocation(const char* file, int line) { 88113481Sgiacomo.travaglini@arm.com const std::string file_name(file == NULL ? kUnknownFile : file); 88213481Sgiacomo.travaglini@arm.com 88313481Sgiacomo.travaglini@arm.com if (line < 0) { 88413481Sgiacomo.travaglini@arm.com return file_name + ":"; 88513481Sgiacomo.travaglini@arm.com } 88613481Sgiacomo.travaglini@arm.com#ifdef _MSC_VER 88713481Sgiacomo.travaglini@arm.com return file_name + "(" + StreamableToString(line) + "):"; 88813481Sgiacomo.travaglini@arm.com#else 88913481Sgiacomo.travaglini@arm.com return file_name + ":" + StreamableToString(line) + ":"; 89013481Sgiacomo.travaglini@arm.com#endif // _MSC_VER 89113481Sgiacomo.travaglini@arm.com} 89213481Sgiacomo.travaglini@arm.com 89313481Sgiacomo.travaglini@arm.com// Formats a file location for compiler-independent XML output. 89413481Sgiacomo.travaglini@arm.com// Although this function is not platform dependent, we put it next to 89513481Sgiacomo.travaglini@arm.com// FormatFileLocation in order to contrast the two functions. 89613481Sgiacomo.travaglini@arm.com// Note that FormatCompilerIndependentFileLocation() does NOT append colon 89713481Sgiacomo.travaglini@arm.com// to the file location it produces, unlike FormatFileLocation(). 89813481Sgiacomo.travaglini@arm.comGTEST_API_ ::std::string FormatCompilerIndependentFileLocation( 89913481Sgiacomo.travaglini@arm.com const char* file, int line) { 90013481Sgiacomo.travaglini@arm.com const std::string file_name(file == NULL ? kUnknownFile : file); 90113481Sgiacomo.travaglini@arm.com 90213481Sgiacomo.travaglini@arm.com if (line < 0) 90313481Sgiacomo.travaglini@arm.com return file_name; 90413481Sgiacomo.travaglini@arm.com else 90513481Sgiacomo.travaglini@arm.com return file_name + ":" + StreamableToString(line); 90613481Sgiacomo.travaglini@arm.com} 90713481Sgiacomo.travaglini@arm.com 90813481Sgiacomo.travaglini@arm.comGTestLog::GTestLog(GTestLogSeverity severity, const char* file, int line) 90913481Sgiacomo.travaglini@arm.com : severity_(severity) { 91013481Sgiacomo.travaglini@arm.com const char* const marker = 91113481Sgiacomo.travaglini@arm.com severity == GTEST_INFO ? "[ INFO ]" : 91213481Sgiacomo.travaglini@arm.com severity == GTEST_WARNING ? "[WARNING]" : 91313481Sgiacomo.travaglini@arm.com severity == GTEST_ERROR ? "[ ERROR ]" : "[ FATAL ]"; 91413481Sgiacomo.travaglini@arm.com GetStream() << ::std::endl << marker << " " 91513481Sgiacomo.travaglini@arm.com << FormatFileLocation(file, line).c_str() << ": "; 91613481Sgiacomo.travaglini@arm.com} 91713481Sgiacomo.travaglini@arm.com 91813481Sgiacomo.travaglini@arm.com// Flushes the buffers and, if severity is GTEST_FATAL, aborts the program. 91913481Sgiacomo.travaglini@arm.comGTestLog::~GTestLog() { 92013481Sgiacomo.travaglini@arm.com GetStream() << ::std::endl; 92113481Sgiacomo.travaglini@arm.com if (severity_ == GTEST_FATAL) { 92213481Sgiacomo.travaglini@arm.com fflush(stderr); 92313481Sgiacomo.travaglini@arm.com posix::Abort(); 92413481Sgiacomo.travaglini@arm.com } 92513481Sgiacomo.travaglini@arm.com} 92613481Sgiacomo.travaglini@arm.com// Disable Microsoft deprecation warnings for POSIX functions called from 92713481Sgiacomo.travaglini@arm.com// this class (creat, dup, dup2, and close) 92813481Sgiacomo.travaglini@arm.comGTEST_DISABLE_MSC_WARNINGS_PUSH_(4996) 92913481Sgiacomo.travaglini@arm.com 93013481Sgiacomo.travaglini@arm.com#if GTEST_HAS_STREAM_REDIRECTION 93113481Sgiacomo.travaglini@arm.com 93213481Sgiacomo.travaglini@arm.com// Object that captures an output stream (stdout/stderr). 93313481Sgiacomo.travaglini@arm.comclass CapturedStream { 93413481Sgiacomo.travaglini@arm.com public: 93513481Sgiacomo.travaglini@arm.com // The ctor redirects the stream to a temporary file. 93613481Sgiacomo.travaglini@arm.com explicit CapturedStream(int fd) : fd_(fd), uncaptured_fd_(dup(fd)) { 93713481Sgiacomo.travaglini@arm.com# if GTEST_OS_WINDOWS 93813481Sgiacomo.travaglini@arm.com char temp_dir_path[MAX_PATH + 1] = { '\0' }; // NOLINT 93913481Sgiacomo.travaglini@arm.com char temp_file_path[MAX_PATH + 1] = { '\0' }; // NOLINT 94013481Sgiacomo.travaglini@arm.com 94113481Sgiacomo.travaglini@arm.com ::GetTempPathA(sizeof(temp_dir_path), temp_dir_path); 94213481Sgiacomo.travaglini@arm.com const UINT success = ::GetTempFileNameA(temp_dir_path, 94313481Sgiacomo.travaglini@arm.com "gtest_redir", 94413481Sgiacomo.travaglini@arm.com 0, // Generate unique file name. 94513481Sgiacomo.travaglini@arm.com temp_file_path); 94613481Sgiacomo.travaglini@arm.com GTEST_CHECK_(success != 0) 94713481Sgiacomo.travaglini@arm.com << "Unable to create a temporary file in " << temp_dir_path; 94813481Sgiacomo.travaglini@arm.com const int captured_fd = creat(temp_file_path, _S_IREAD | _S_IWRITE); 94913481Sgiacomo.travaglini@arm.com GTEST_CHECK_(captured_fd != -1) << "Unable to open temporary file " 95013481Sgiacomo.travaglini@arm.com << temp_file_path; 95113481Sgiacomo.travaglini@arm.com filename_ = temp_file_path; 95213481Sgiacomo.travaglini@arm.com# else 95313481Sgiacomo.travaglini@arm.com // There's no guarantee that a test has write access to the current 95413481Sgiacomo.travaglini@arm.com // directory, so we create the temporary file in the /tmp directory 95513481Sgiacomo.travaglini@arm.com // instead. We use /tmp on most systems, and /sdcard on Android. 95613481Sgiacomo.travaglini@arm.com // That's because Android doesn't have /tmp. 95713481Sgiacomo.travaglini@arm.com# if GTEST_OS_LINUX_ANDROID 95813481Sgiacomo.travaglini@arm.com // Note: Android applications are expected to call the framework's 95913481Sgiacomo.travaglini@arm.com // Context.getExternalStorageDirectory() method through JNI to get 96013481Sgiacomo.travaglini@arm.com // the location of the world-writable SD Card directory. However, 96113481Sgiacomo.travaglini@arm.com // this requires a Context handle, which cannot be retrieved 96213481Sgiacomo.travaglini@arm.com // globally from native code. Doing so also precludes running the 96313481Sgiacomo.travaglini@arm.com // code as part of a regular standalone executable, which doesn't 96413481Sgiacomo.travaglini@arm.com // run in a Dalvik process (e.g. when running it through 'adb shell'). 96513481Sgiacomo.travaglini@arm.com // 96613481Sgiacomo.travaglini@arm.com // The location /sdcard is directly accessible from native code 96713481Sgiacomo.travaglini@arm.com // and is the only location (unofficially) supported by the Android 96813481Sgiacomo.travaglini@arm.com // team. It's generally a symlink to the real SD Card mount point 96913481Sgiacomo.travaglini@arm.com // which can be /mnt/sdcard, /mnt/sdcard0, /system/media/sdcard, or 97013481Sgiacomo.travaglini@arm.com // other OEM-customized locations. Never rely on these, and always 97113481Sgiacomo.travaglini@arm.com // use /sdcard. 97213481Sgiacomo.travaglini@arm.com char name_template[] = "/sdcard/gtest_captured_stream.XXXXXX"; 97313481Sgiacomo.travaglini@arm.com# else 97413481Sgiacomo.travaglini@arm.com char name_template[] = "/tmp/captured_stream.XXXXXX"; 97513481Sgiacomo.travaglini@arm.com# endif // GTEST_OS_LINUX_ANDROID 97613481Sgiacomo.travaglini@arm.com const int captured_fd = mkstemp(name_template); 97713481Sgiacomo.travaglini@arm.com filename_ = name_template; 97813481Sgiacomo.travaglini@arm.com# endif // GTEST_OS_WINDOWS 97913481Sgiacomo.travaglini@arm.com fflush(NULL); 98013481Sgiacomo.travaglini@arm.com dup2(captured_fd, fd_); 98113481Sgiacomo.travaglini@arm.com close(captured_fd); 98213481Sgiacomo.travaglini@arm.com } 98313481Sgiacomo.travaglini@arm.com 98413481Sgiacomo.travaglini@arm.com ~CapturedStream() { 98513481Sgiacomo.travaglini@arm.com remove(filename_.c_str()); 98613481Sgiacomo.travaglini@arm.com } 98713481Sgiacomo.travaglini@arm.com 98813481Sgiacomo.travaglini@arm.com std::string GetCapturedString() { 98913481Sgiacomo.travaglini@arm.com if (uncaptured_fd_ != -1) { 99013481Sgiacomo.travaglini@arm.com // Restores the original stream. 99113481Sgiacomo.travaglini@arm.com fflush(NULL); 99213481Sgiacomo.travaglini@arm.com dup2(uncaptured_fd_, fd_); 99313481Sgiacomo.travaglini@arm.com close(uncaptured_fd_); 99413481Sgiacomo.travaglini@arm.com uncaptured_fd_ = -1; 99513481Sgiacomo.travaglini@arm.com } 99613481Sgiacomo.travaglini@arm.com 99713481Sgiacomo.travaglini@arm.com FILE* const file = posix::FOpen(filename_.c_str(), "r"); 99813481Sgiacomo.travaglini@arm.com const std::string content = ReadEntireFile(file); 99913481Sgiacomo.travaglini@arm.com posix::FClose(file); 100013481Sgiacomo.travaglini@arm.com return content; 100113481Sgiacomo.travaglini@arm.com } 100213481Sgiacomo.travaglini@arm.com 100313481Sgiacomo.travaglini@arm.com private: 100413481Sgiacomo.travaglini@arm.com const int fd_; // A stream to capture. 100513481Sgiacomo.travaglini@arm.com int uncaptured_fd_; 100613481Sgiacomo.travaglini@arm.com // Name of the temporary file holding the stderr output. 100713481Sgiacomo.travaglini@arm.com ::std::string filename_; 100813481Sgiacomo.travaglini@arm.com 100913481Sgiacomo.travaglini@arm.com GTEST_DISALLOW_COPY_AND_ASSIGN_(CapturedStream); 101013481Sgiacomo.travaglini@arm.com}; 101113481Sgiacomo.travaglini@arm.com 101213481Sgiacomo.travaglini@arm.comGTEST_DISABLE_MSC_WARNINGS_POP_() 101313481Sgiacomo.travaglini@arm.com 101413481Sgiacomo.travaglini@arm.comstatic CapturedStream* g_captured_stderr = NULL; 101513481Sgiacomo.travaglini@arm.comstatic CapturedStream* g_captured_stdout = NULL; 101613481Sgiacomo.travaglini@arm.com 101713481Sgiacomo.travaglini@arm.com// Starts capturing an output stream (stdout/stderr). 101813481Sgiacomo.travaglini@arm.comvoid CaptureStream(int fd, const char* stream_name, CapturedStream** stream) { 101913481Sgiacomo.travaglini@arm.com if (*stream != NULL) { 102013481Sgiacomo.travaglini@arm.com GTEST_LOG_(FATAL) << "Only one " << stream_name 102113481Sgiacomo.travaglini@arm.com << " capturer can exist at a time."; 102213481Sgiacomo.travaglini@arm.com } 102313481Sgiacomo.travaglini@arm.com *stream = new CapturedStream(fd); 102413481Sgiacomo.travaglini@arm.com} 102513481Sgiacomo.travaglini@arm.com 102613481Sgiacomo.travaglini@arm.com// Stops capturing the output stream and returns the captured string. 102713481Sgiacomo.travaglini@arm.comstd::string GetCapturedStream(CapturedStream** captured_stream) { 102813481Sgiacomo.travaglini@arm.com const std::string content = (*captured_stream)->GetCapturedString(); 102913481Sgiacomo.travaglini@arm.com 103013481Sgiacomo.travaglini@arm.com delete *captured_stream; 103113481Sgiacomo.travaglini@arm.com *captured_stream = NULL; 103213481Sgiacomo.travaglini@arm.com 103313481Sgiacomo.travaglini@arm.com return content; 103413481Sgiacomo.travaglini@arm.com} 103513481Sgiacomo.travaglini@arm.com 103613481Sgiacomo.travaglini@arm.com// Starts capturing stdout. 103713481Sgiacomo.travaglini@arm.comvoid CaptureStdout() { 103813481Sgiacomo.travaglini@arm.com CaptureStream(kStdOutFileno, "stdout", &g_captured_stdout); 103913481Sgiacomo.travaglini@arm.com} 104013481Sgiacomo.travaglini@arm.com 104113481Sgiacomo.travaglini@arm.com// Starts capturing stderr. 104213481Sgiacomo.travaglini@arm.comvoid CaptureStderr() { 104313481Sgiacomo.travaglini@arm.com CaptureStream(kStdErrFileno, "stderr", &g_captured_stderr); 104413481Sgiacomo.travaglini@arm.com} 104513481Sgiacomo.travaglini@arm.com 104613481Sgiacomo.travaglini@arm.com// Stops capturing stdout and returns the captured string. 104713481Sgiacomo.travaglini@arm.comstd::string GetCapturedStdout() { 104813481Sgiacomo.travaglini@arm.com return GetCapturedStream(&g_captured_stdout); 104913481Sgiacomo.travaglini@arm.com} 105013481Sgiacomo.travaglini@arm.com 105113481Sgiacomo.travaglini@arm.com// Stops capturing stderr and returns the captured string. 105213481Sgiacomo.travaglini@arm.comstd::string GetCapturedStderr() { 105313481Sgiacomo.travaglini@arm.com return GetCapturedStream(&g_captured_stderr); 105413481Sgiacomo.travaglini@arm.com} 105513481Sgiacomo.travaglini@arm.com 105613481Sgiacomo.travaglini@arm.com#endif // GTEST_HAS_STREAM_REDIRECTION 105713481Sgiacomo.travaglini@arm.com 105813481Sgiacomo.travaglini@arm.comstd::string TempDir() { 105913481Sgiacomo.travaglini@arm.com#if GTEST_OS_WINDOWS_MOBILE 106013481Sgiacomo.travaglini@arm.com return "\\temp\\"; 106113481Sgiacomo.travaglini@arm.com#elif GTEST_OS_WINDOWS 106213481Sgiacomo.travaglini@arm.com const char* temp_dir = posix::GetEnv("TEMP"); 106313481Sgiacomo.travaglini@arm.com if (temp_dir == NULL || temp_dir[0] == '\0') 106413481Sgiacomo.travaglini@arm.com return "\\temp\\"; 106513481Sgiacomo.travaglini@arm.com else if (temp_dir[strlen(temp_dir) - 1] == '\\') 106613481Sgiacomo.travaglini@arm.com return temp_dir; 106713481Sgiacomo.travaglini@arm.com else 106813481Sgiacomo.travaglini@arm.com return std::string(temp_dir) + "\\"; 106913481Sgiacomo.travaglini@arm.com#elif GTEST_OS_LINUX_ANDROID 107013481Sgiacomo.travaglini@arm.com return "/sdcard/"; 107113481Sgiacomo.travaglini@arm.com#else 107213481Sgiacomo.travaglini@arm.com return "/tmp/"; 107313481Sgiacomo.travaglini@arm.com#endif // GTEST_OS_WINDOWS_MOBILE 107413481Sgiacomo.travaglini@arm.com} 107513481Sgiacomo.travaglini@arm.com 107613481Sgiacomo.travaglini@arm.comsize_t GetFileSize(FILE* file) { 107713481Sgiacomo.travaglini@arm.com fseek(file, 0, SEEK_END); 107813481Sgiacomo.travaglini@arm.com return static_cast<size_t>(ftell(file)); 107913481Sgiacomo.travaglini@arm.com} 108013481Sgiacomo.travaglini@arm.com 108113481Sgiacomo.travaglini@arm.comstd::string ReadEntireFile(FILE* file) { 108213481Sgiacomo.travaglini@arm.com const size_t file_size = GetFileSize(file); 108313481Sgiacomo.travaglini@arm.com char* const buffer = new char[file_size]; 108413481Sgiacomo.travaglini@arm.com 108513481Sgiacomo.travaglini@arm.com size_t bytes_last_read = 0; // # of bytes read in the last fread() 108613481Sgiacomo.travaglini@arm.com size_t bytes_read = 0; // # of bytes read so far 108713481Sgiacomo.travaglini@arm.com 108813481Sgiacomo.travaglini@arm.com fseek(file, 0, SEEK_SET); 108913481Sgiacomo.travaglini@arm.com 109013481Sgiacomo.travaglini@arm.com // Keeps reading the file until we cannot read further or the 109113481Sgiacomo.travaglini@arm.com // pre-determined file size is reached. 109213481Sgiacomo.travaglini@arm.com do { 109313481Sgiacomo.travaglini@arm.com bytes_last_read = fread(buffer+bytes_read, 1, file_size-bytes_read, file); 109413481Sgiacomo.travaglini@arm.com bytes_read += bytes_last_read; 109513481Sgiacomo.travaglini@arm.com } while (bytes_last_read > 0 && bytes_read < file_size); 109613481Sgiacomo.travaglini@arm.com 109713481Sgiacomo.travaglini@arm.com const std::string content(buffer, bytes_read); 109813481Sgiacomo.travaglini@arm.com delete[] buffer; 109913481Sgiacomo.travaglini@arm.com 110013481Sgiacomo.travaglini@arm.com return content; 110113481Sgiacomo.travaglini@arm.com} 110213481Sgiacomo.travaglini@arm.com 110313481Sgiacomo.travaglini@arm.com#if GTEST_HAS_DEATH_TEST 110413481Sgiacomo.travaglini@arm.com 110513481Sgiacomo.travaglini@arm.comstatic const ::std::vector<testing::internal::string>* g_injected_test_argvs = 110613481Sgiacomo.travaglini@arm.com NULL; // Owned. 110713481Sgiacomo.travaglini@arm.com 110813481Sgiacomo.travaglini@arm.comvoid SetInjectableArgvs(const ::std::vector<testing::internal::string>* argvs) { 110913481Sgiacomo.travaglini@arm.com if (g_injected_test_argvs != argvs) 111013481Sgiacomo.travaglini@arm.com delete g_injected_test_argvs; 111113481Sgiacomo.travaglini@arm.com g_injected_test_argvs = argvs; 111213481Sgiacomo.travaglini@arm.com} 111313481Sgiacomo.travaglini@arm.com 111413481Sgiacomo.travaglini@arm.comconst ::std::vector<testing::internal::string>& GetInjectableArgvs() { 111513481Sgiacomo.travaglini@arm.com if (g_injected_test_argvs != NULL) { 111613481Sgiacomo.travaglini@arm.com return *g_injected_test_argvs; 111713481Sgiacomo.travaglini@arm.com } 111813481Sgiacomo.travaglini@arm.com return GetArgvs(); 111913481Sgiacomo.travaglini@arm.com} 112013481Sgiacomo.travaglini@arm.com#endif // GTEST_HAS_DEATH_TEST 112113481Sgiacomo.travaglini@arm.com 112213481Sgiacomo.travaglini@arm.com#if GTEST_OS_WINDOWS_MOBILE 112313481Sgiacomo.travaglini@arm.comnamespace posix { 112413481Sgiacomo.travaglini@arm.comvoid Abort() { 112513481Sgiacomo.travaglini@arm.com DebugBreak(); 112613481Sgiacomo.travaglini@arm.com TerminateProcess(GetCurrentProcess(), 1); 112713481Sgiacomo.travaglini@arm.com} 112813481Sgiacomo.travaglini@arm.com} // namespace posix 112913481Sgiacomo.travaglini@arm.com#endif // GTEST_OS_WINDOWS_MOBILE 113013481Sgiacomo.travaglini@arm.com 113113481Sgiacomo.travaglini@arm.com// Returns the name of the environment variable corresponding to the 113213481Sgiacomo.travaglini@arm.com// given flag. For example, FlagToEnvVar("foo") will return 113313481Sgiacomo.travaglini@arm.com// "GTEST_FOO" in the open-source version. 113413481Sgiacomo.travaglini@arm.comstatic std::string FlagToEnvVar(const char* flag) { 113513481Sgiacomo.travaglini@arm.com const std::string full_flag = 113613481Sgiacomo.travaglini@arm.com (Message() << GTEST_FLAG_PREFIX_ << flag).GetString(); 113713481Sgiacomo.travaglini@arm.com 113813481Sgiacomo.travaglini@arm.com Message env_var; 113913481Sgiacomo.travaglini@arm.com for (size_t i = 0; i != full_flag.length(); i++) { 114013481Sgiacomo.travaglini@arm.com env_var << ToUpper(full_flag.c_str()[i]); 114113481Sgiacomo.travaglini@arm.com } 114213481Sgiacomo.travaglini@arm.com 114313481Sgiacomo.travaglini@arm.com return env_var.GetString(); 114413481Sgiacomo.travaglini@arm.com} 114513481Sgiacomo.travaglini@arm.com 114613481Sgiacomo.travaglini@arm.com// Parses 'str' for a 32-bit signed integer. If successful, writes 114713481Sgiacomo.travaglini@arm.com// the result to *value and returns true; otherwise leaves *value 114813481Sgiacomo.travaglini@arm.com// unchanged and returns false. 114913481Sgiacomo.travaglini@arm.combool ParseInt32(const Message& src_text, const char* str, Int32* value) { 115013481Sgiacomo.travaglini@arm.com // Parses the environment variable as a decimal integer. 115113481Sgiacomo.travaglini@arm.com char* end = NULL; 115213481Sgiacomo.travaglini@arm.com const long long_value = strtol(str, &end, 10); // NOLINT 115313481Sgiacomo.travaglini@arm.com 115413481Sgiacomo.travaglini@arm.com // Has strtol() consumed all characters in the string? 115513481Sgiacomo.travaglini@arm.com if (*end != '\0') { 115613481Sgiacomo.travaglini@arm.com // No - an invalid character was encountered. 115713481Sgiacomo.travaglini@arm.com Message msg; 115813481Sgiacomo.travaglini@arm.com msg << "WARNING: " << src_text 115913481Sgiacomo.travaglini@arm.com << " is expected to be a 32-bit integer, but actually" 116013481Sgiacomo.travaglini@arm.com << " has value \"" << str << "\".\n"; 116113481Sgiacomo.travaglini@arm.com printf("%s", msg.GetString().c_str()); 116213481Sgiacomo.travaglini@arm.com fflush(stdout); 116313481Sgiacomo.travaglini@arm.com return false; 116413481Sgiacomo.travaglini@arm.com } 116513481Sgiacomo.travaglini@arm.com 116613481Sgiacomo.travaglini@arm.com // Is the parsed value in the range of an Int32? 116713481Sgiacomo.travaglini@arm.com const Int32 result = static_cast<Int32>(long_value); 116813481Sgiacomo.travaglini@arm.com if (long_value == LONG_MAX || long_value == LONG_MIN || 116913481Sgiacomo.travaglini@arm.com // The parsed value overflows as a long. (strtol() returns 117013481Sgiacomo.travaglini@arm.com // LONG_MAX or LONG_MIN when the input overflows.) 117113481Sgiacomo.travaglini@arm.com result != long_value 117213481Sgiacomo.travaglini@arm.com // The parsed value overflows as an Int32. 117313481Sgiacomo.travaglini@arm.com ) { 117413481Sgiacomo.travaglini@arm.com Message msg; 117513481Sgiacomo.travaglini@arm.com msg << "WARNING: " << src_text 117613481Sgiacomo.travaglini@arm.com << " is expected to be a 32-bit integer, but actually" 117713481Sgiacomo.travaglini@arm.com << " has value " << str << ", which overflows.\n"; 117813481Sgiacomo.travaglini@arm.com printf("%s", msg.GetString().c_str()); 117913481Sgiacomo.travaglini@arm.com fflush(stdout); 118013481Sgiacomo.travaglini@arm.com return false; 118113481Sgiacomo.travaglini@arm.com } 118213481Sgiacomo.travaglini@arm.com 118313481Sgiacomo.travaglini@arm.com *value = result; 118413481Sgiacomo.travaglini@arm.com return true; 118513481Sgiacomo.travaglini@arm.com} 118613481Sgiacomo.travaglini@arm.com 118713481Sgiacomo.travaglini@arm.com// Reads and returns the Boolean environment variable corresponding to 118813481Sgiacomo.travaglini@arm.com// the given flag; if it's not set, returns default_value. 118913481Sgiacomo.travaglini@arm.com// 119013481Sgiacomo.travaglini@arm.com// The value is considered true iff it's not "0". 119113481Sgiacomo.travaglini@arm.combool BoolFromGTestEnv(const char* flag, bool default_value) { 119213481Sgiacomo.travaglini@arm.com#if defined(GTEST_GET_BOOL_FROM_ENV_) 119313481Sgiacomo.travaglini@arm.com return GTEST_GET_BOOL_FROM_ENV_(flag, default_value); 119413481Sgiacomo.travaglini@arm.com#endif // defined(GTEST_GET_BOOL_FROM_ENV_) 119513481Sgiacomo.travaglini@arm.com const std::string env_var = FlagToEnvVar(flag); 119613481Sgiacomo.travaglini@arm.com const char* const string_value = posix::GetEnv(env_var.c_str()); 119713481Sgiacomo.travaglini@arm.com return string_value == NULL ? 119813481Sgiacomo.travaglini@arm.com default_value : strcmp(string_value, "0") != 0; 119913481Sgiacomo.travaglini@arm.com} 120013481Sgiacomo.travaglini@arm.com 120113481Sgiacomo.travaglini@arm.com// Reads and returns a 32-bit integer stored in the environment 120213481Sgiacomo.travaglini@arm.com// variable corresponding to the given flag; if it isn't set or 120313481Sgiacomo.travaglini@arm.com// doesn't represent a valid 32-bit integer, returns default_value. 120413481Sgiacomo.travaglini@arm.comInt32 Int32FromGTestEnv(const char* flag, Int32 default_value) { 120513481Sgiacomo.travaglini@arm.com#if defined(GTEST_GET_INT32_FROM_ENV_) 120613481Sgiacomo.travaglini@arm.com return GTEST_GET_INT32_FROM_ENV_(flag, default_value); 120713481Sgiacomo.travaglini@arm.com#endif // defined(GTEST_GET_INT32_FROM_ENV_) 120813481Sgiacomo.travaglini@arm.com const std::string env_var = FlagToEnvVar(flag); 120913481Sgiacomo.travaglini@arm.com const char* const string_value = posix::GetEnv(env_var.c_str()); 121013481Sgiacomo.travaglini@arm.com if (string_value == NULL) { 121113481Sgiacomo.travaglini@arm.com // The environment variable is not set. 121213481Sgiacomo.travaglini@arm.com return default_value; 121313481Sgiacomo.travaglini@arm.com } 121413481Sgiacomo.travaglini@arm.com 121513481Sgiacomo.travaglini@arm.com Int32 result = default_value; 121613481Sgiacomo.travaglini@arm.com if (!ParseInt32(Message() << "Environment variable " << env_var, 121713481Sgiacomo.travaglini@arm.com string_value, &result)) { 121813481Sgiacomo.travaglini@arm.com printf("The default value %s is used.\n", 121913481Sgiacomo.travaglini@arm.com (Message() << default_value).GetString().c_str()); 122013481Sgiacomo.travaglini@arm.com fflush(stdout); 122113481Sgiacomo.travaglini@arm.com return default_value; 122213481Sgiacomo.travaglini@arm.com } 122313481Sgiacomo.travaglini@arm.com 122413481Sgiacomo.travaglini@arm.com return result; 122513481Sgiacomo.travaglini@arm.com} 122613481Sgiacomo.travaglini@arm.com 122713481Sgiacomo.travaglini@arm.com// Reads and returns the string environment variable corresponding to 122813481Sgiacomo.travaglini@arm.com// the given flag; if it's not set, returns default_value. 122913481Sgiacomo.travaglini@arm.comstd::string StringFromGTestEnv(const char* flag, const char* default_value) { 123013481Sgiacomo.travaglini@arm.com#if defined(GTEST_GET_STRING_FROM_ENV_) 123113481Sgiacomo.travaglini@arm.com return GTEST_GET_STRING_FROM_ENV_(flag, default_value); 123213481Sgiacomo.travaglini@arm.com#endif // defined(GTEST_GET_STRING_FROM_ENV_) 123313481Sgiacomo.travaglini@arm.com const std::string env_var = FlagToEnvVar(flag); 123413481Sgiacomo.travaglini@arm.com const char* value = posix::GetEnv(env_var.c_str()); 123513481Sgiacomo.travaglini@arm.com if (value != NULL) { 123613481Sgiacomo.travaglini@arm.com return value; 123713481Sgiacomo.travaglini@arm.com } 123813481Sgiacomo.travaglini@arm.com 123913481Sgiacomo.travaglini@arm.com // As a special case for the 'output' flag, if GTEST_OUTPUT is not 124013481Sgiacomo.travaglini@arm.com // set, we look for XML_OUTPUT_FILE, which is set by the Bazel build 124113481Sgiacomo.travaglini@arm.com // system. The value of XML_OUTPUT_FILE is a filename without the 124213481Sgiacomo.travaglini@arm.com // "xml:" prefix of GTEST_OUTPUT. 124313481Sgiacomo.travaglini@arm.com // 124413481Sgiacomo.travaglini@arm.com // The net priority order after flag processing is thus: 124513481Sgiacomo.travaglini@arm.com // --gtest_output command line flag 124613481Sgiacomo.travaglini@arm.com // GTEST_OUTPUT environment variable 124713481Sgiacomo.travaglini@arm.com // XML_OUTPUT_FILE environment variable 124813481Sgiacomo.travaglini@arm.com // 'default_value' 124913481Sgiacomo.travaglini@arm.com if (strcmp(flag, "output") == 0) { 125013481Sgiacomo.travaglini@arm.com value = posix::GetEnv("XML_OUTPUT_FILE"); 125113481Sgiacomo.travaglini@arm.com if (value != NULL) { 125213481Sgiacomo.travaglini@arm.com return std::string("xml:") + value; 125313481Sgiacomo.travaglini@arm.com } 125413481Sgiacomo.travaglini@arm.com } 125513481Sgiacomo.travaglini@arm.com return default_value; 125613481Sgiacomo.travaglini@arm.com} 125713481Sgiacomo.travaglini@arm.com 125813481Sgiacomo.travaglini@arm.com} // namespace internal 125913481Sgiacomo.travaglini@arm.com} // namespace testing 1260