1fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt// Copyright 2008, Google Inc. 2fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt// All rights reserved. 3fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt// 4fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt// Redistribution and use in source and binary forms, with or without 5fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt// modification, are permitted provided that the following conditions are 6fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt// met: 7fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt// 8fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt// * Redistributions of source code must retain the above copyright 9fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt// notice, this list of conditions and the following disclaimer. 10fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt// * Redistributions in binary form must reproduce the above 11fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt// copyright notice, this list of conditions and the following disclaimer 12fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt// in the documentation and/or other materials provided with the 13fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt// distribution. 14fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt// * Neither the name of Google Inc. nor the names of its 15fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt// contributors may be used to endorse or promote products derived from 16fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt// this software without specific prior written permission. 17fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt// 18fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 19fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 20fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 21fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 22fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 23fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 24fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 25fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 26fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 28fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt// 30fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt// Author: wan@google.com (Zhanyong Wan) 31fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt 32fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt#include "gtest/internal/gtest-port.h" 33fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt 34fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt#include <limits.h> 35fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt#include <stdlib.h> 36fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt#include <stdio.h> 37fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt#include <string.h> 38fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt 39fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt#if GTEST_OS_WINDOWS_MOBILE 40fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt# include <windows.h> // For TerminateProcess() 41fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt#elif GTEST_OS_WINDOWS 42fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt# include <io.h> 43fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt# include <sys/stat.h> 44fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt#else 45fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt# include <unistd.h> 46fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt#endif // GTEST_OS_WINDOWS_MOBILE 47fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt 48fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt#if GTEST_OS_MAC 49fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt# include <mach/mach_init.h> 50fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt# include <mach/task.h> 51fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt# include <mach/vm_map.h> 52fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt#endif // GTEST_OS_MAC 53fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt 54fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt#include "gtest/gtest-spi.h" 55fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt#include "gtest/gtest-message.h" 56fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt#include "gtest/internal/gtest-internal.h" 57fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt#include "gtest/internal/gtest-string.h" 58fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt 59fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt// Indicates that this translation unit is part of Google Test's 60fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt// implementation. It must come before gtest-internal-inl.h is 61fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt// included, or there will be a compiler error. This trick is to 62fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt// prevent a user from accidentally including gtest-internal-inl.h in 63fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt// his code. 64fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt#define GTEST_IMPLEMENTATION_ 1 65fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt#include "src/gtest-internal-inl.h" 66fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt#undef GTEST_IMPLEMENTATION_ 67fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt 68fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholtnamespace testing { 69fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholtnamespace internal { 70fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt 71fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt#if defined(_MSC_VER) || defined(__BORLANDC__) 72fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt// MSVC and C++Builder do not provide a definition of STDERR_FILENO. 73fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholtconst int kStdOutFileno = 1; 74fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholtconst int kStdErrFileno = 2; 75fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt#else 76fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholtconst int kStdOutFileno = STDOUT_FILENO; 77fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholtconst int kStdErrFileno = STDERR_FILENO; 78fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt#endif // _MSC_VER 79fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt 80fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt#if GTEST_OS_MAC 81fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt 82fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt// Returns the number of threads running in the process, or 0 to indicate that 83fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt// we cannot detect it. 84fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholtsize_t GetThreadCount() { 85fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt const task_t task = mach_task_self(); 86fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt mach_msg_type_number_t thread_count; 87fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt thread_act_array_t thread_list; 88fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt const kern_return_t status = task_threads(task, &thread_list, &thread_count); 89fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt if (status == KERN_SUCCESS) { 90fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt // task_threads allocates resources in thread_list and we need to free them 91fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt // to avoid leaks. 92fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt vm_deallocate(task, 93fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt reinterpret_cast<vm_address_t>(thread_list), 94fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt sizeof(thread_t) * thread_count); 95fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt return static_cast<size_t>(thread_count); 96fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt } else { 97fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt return 0; 98fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt } 99fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt} 100fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt 101fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt#else 102fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt 103fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholtsize_t GetThreadCount() { 104fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt // There's no portable way to detect the number of threads, so we just 105fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt // return 0 to indicate that we cannot detect it. 106fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt return 0; 107fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt} 108fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt 109fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt#endif // GTEST_OS_MAC 110fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt 111fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt#if GTEST_USES_POSIX_RE 112fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt 113fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt// Implements RE. Currently only needed for death tests. 114fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt 115fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric AnholtRE::~RE() { 116fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt if (is_valid_) { 117fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt // regfree'ing an invalid regex might crash because the content 118fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt // of the regex is undefined. Since the regex's are essentially 119fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt // the same, one cannot be valid (or invalid) without the other 120fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt // being so too. 121fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt regfree(&partial_regex_); 122fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt regfree(&full_regex_); 123fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt } 124fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt free(const_cast<char*>(pattern_)); 125fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt} 126fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt 127fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt// Returns true iff regular expression re matches the entire str. 128fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholtbool RE::FullMatch(const char* str, const RE& re) { 129fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt if (!re.is_valid_) return false; 130fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt 131fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt regmatch_t match; 132fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt return regexec(&re.full_regex_, str, 1, &match, 0) == 0; 133fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt} 134fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt 135fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt// Returns true iff regular expression re matches a substring of str 136fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt// (including str itself). 137fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholtbool RE::PartialMatch(const char* str, const RE& re) { 138fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt if (!re.is_valid_) return false; 139fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt 140fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt regmatch_t match; 141fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt return regexec(&re.partial_regex_, str, 1, &match, 0) == 0; 142fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt} 143fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt 144fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt// Initializes an RE from its string representation. 145fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholtvoid RE::Init(const char* regex) { 146fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt pattern_ = posix::StrDup(regex); 147fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt 148fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt // Reserves enough bytes to hold the regular expression used for a 149fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt // full match. 150fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt const size_t full_regex_len = strlen(regex) + 10; 151fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt char* const full_pattern = new char[full_regex_len]; 152fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt 153fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt snprintf(full_pattern, full_regex_len, "^(%s)$", regex); 154fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt is_valid_ = regcomp(&full_regex_, full_pattern, REG_EXTENDED) == 0; 155fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt // We want to call regcomp(&partial_regex_, ...) even if the 156fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt // previous expression returns false. Otherwise partial_regex_ may 157fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt // not be properly initialized can may cause trouble when it's 158fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt // freed. 159fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt // 160fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt // Some implementation of POSIX regex (e.g. on at least some 161fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt // versions of Cygwin) doesn't accept the empty string as a valid 162fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt // regex. We change it to an equivalent form "()" to be safe. 163fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt if (is_valid_) { 164fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt const char* const partial_regex = (*regex == '\0') ? "()" : regex; 165fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt is_valid_ = regcomp(&partial_regex_, partial_regex, REG_EXTENDED) == 0; 166fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt } 167fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt EXPECT_TRUE(is_valid_) 168fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt << "Regular expression \"" << regex 169fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt << "\" is not a valid POSIX Extended regular expression."; 170fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt 171fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt delete[] full_pattern; 172fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt} 173fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt 174fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt#elif GTEST_USES_SIMPLE_RE 175fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt 176fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt// Returns true iff ch appears anywhere in str (excluding the 177fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt// terminating '\0' character). 178fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholtbool IsInSet(char ch, const char* str) { 179fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt return ch != '\0' && strchr(str, ch) != NULL; 180fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt} 181fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt 182fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt// Returns true iff ch belongs to the given classification. Unlike 183fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt// similar functions in <ctype.h>, these aren't affected by the 184fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt// current locale. 185fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholtbool IsAsciiDigit(char ch) { return '0' <= ch && ch <= '9'; } 186fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholtbool IsAsciiPunct(char ch) { 187fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt return IsInSet(ch, "^-!\"#$%&'()*+,./:;<=>?@[\\]_`{|}~"); 188fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt} 189fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholtbool IsRepeat(char ch) { return IsInSet(ch, "?*+"); } 190fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholtbool IsAsciiWhiteSpace(char ch) { return IsInSet(ch, " \f\n\r\t\v"); } 191fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholtbool IsAsciiWordChar(char ch) { 192fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt return ('a' <= ch && ch <= 'z') || ('A' <= ch && ch <= 'Z') || 193fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt ('0' <= ch && ch <= '9') || ch == '_'; 194fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt} 195fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt 196fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt// Returns true iff "\\c" is a supported escape sequence. 197fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholtbool IsValidEscape(char c) { 198fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt return (IsAsciiPunct(c) || IsInSet(c, "dDfnrsStvwW")); 199fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt} 200fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt 201fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt// Returns true iff the given atom (specified by escaped and pattern) 202fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt// matches ch. The result is undefined if the atom is invalid. 203fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholtbool AtomMatchesChar(bool escaped, char pattern_char, char ch) { 204fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt if (escaped) { // "\\p" where p is pattern_char. 205fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt switch (pattern_char) { 206fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt case 'd': return IsAsciiDigit(ch); 207fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt case 'D': return !IsAsciiDigit(ch); 208fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt case 'f': return ch == '\f'; 209fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt case 'n': return ch == '\n'; 210fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt case 'r': return ch == '\r'; 211fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt case 's': return IsAsciiWhiteSpace(ch); 212fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt case 'S': return !IsAsciiWhiteSpace(ch); 213fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt case 't': return ch == '\t'; 214fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt case 'v': return ch == '\v'; 215fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt case 'w': return IsAsciiWordChar(ch); 216fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt case 'W': return !IsAsciiWordChar(ch); 217fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt } 218fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt return IsAsciiPunct(pattern_char) && pattern_char == ch; 219fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt } 220fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt 221fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt return (pattern_char == '.' && ch != '\n') || pattern_char == ch; 222fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt} 223fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt 224fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt// Helper function used by ValidateRegex() to format error messages. 225fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric AnholtString FormatRegexSyntaxError(const char* regex, int index) { 226fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt return (Message() << "Syntax error at index " << index 227fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt << " in simple regular expression \"" << regex << "\": ").GetString(); 228fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt} 229fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt 230fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt// Generates non-fatal failures and returns false if regex is invalid; 231fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt// otherwise returns true. 232fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholtbool ValidateRegex(const char* regex) { 233fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt if (regex == NULL) { 234fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt // TODO(wan@google.com): fix the source file location in the 235fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt // assertion failures to match where the regex is used in user 236fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt // code. 237fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt ADD_FAILURE() << "NULL is not a valid simple regular expression."; 238fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt return false; 239fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt } 240fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt 241fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt bool is_valid = true; 242fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt 243fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt // True iff ?, *, or + can follow the previous atom. 244fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt bool prev_repeatable = false; 245fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt for (int i = 0; regex[i]; i++) { 246fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt if (regex[i] == '\\') { // An escape sequence 247fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt i++; 248fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt if (regex[i] == '\0') { 249fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt ADD_FAILURE() << FormatRegexSyntaxError(regex, i - 1) 250fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt << "'\\' cannot appear at the end."; 251fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt return false; 252fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt } 253fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt 254fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt if (!IsValidEscape(regex[i])) { 255fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt ADD_FAILURE() << FormatRegexSyntaxError(regex, i - 1) 256fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt << "invalid escape sequence \"\\" << regex[i] << "\"."; 257fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt is_valid = false; 258fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt } 259fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt prev_repeatable = true; 260fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt } else { // Not an escape sequence. 261fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt const char ch = regex[i]; 262fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt 263fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt if (ch == '^' && i > 0) { 264fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt ADD_FAILURE() << FormatRegexSyntaxError(regex, i) 265fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt << "'^' can only appear at the beginning."; 266fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt is_valid = false; 267fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt } else if (ch == '$' && regex[i + 1] != '\0') { 268fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt ADD_FAILURE() << FormatRegexSyntaxError(regex, i) 269fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt << "'$' can only appear at the end."; 270fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt is_valid = false; 271fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt } else if (IsInSet(ch, "()[]{}|")) { 272fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt ADD_FAILURE() << FormatRegexSyntaxError(regex, i) 273fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt << "'" << ch << "' is unsupported."; 274fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt is_valid = false; 275fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt } else if (IsRepeat(ch) && !prev_repeatable) { 276fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt ADD_FAILURE() << FormatRegexSyntaxError(regex, i) 277fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt << "'" << ch << "' can only follow a repeatable token."; 278fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt is_valid = false; 279fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt } 280fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt 281fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt prev_repeatable = !IsInSet(ch, "^$?*+"); 282fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt } 283fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt } 284fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt 285fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt return is_valid; 286fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt} 287fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt 288fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt// Matches a repeated regex atom followed by a valid simple regular 289fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt// expression. The regex atom is defined as c if escaped is false, 290fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt// or \c otherwise. repeat is the repetition meta character (?, *, 291fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt// or +). The behavior is undefined if str contains too many 292fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt// characters to be indexable by size_t, in which case the test will 293fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt// probably time out anyway. We are fine with this limitation as 294fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt// std::string has it too. 295fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholtbool MatchRepetitionAndRegexAtHead( 296fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt bool escaped, char c, char repeat, const char* regex, 297fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt const char* str) { 298fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt const size_t min_count = (repeat == '+') ? 1 : 0; 299fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt const size_t max_count = (repeat == '?') ? 1 : 300fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt static_cast<size_t>(-1) - 1; 301fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt // We cannot call numeric_limits::max() as it conflicts with the 302fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt // max() macro on Windows. 303fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt 304fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt for (size_t i = 0; i <= max_count; ++i) { 305fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt // We know that the atom matches each of the first i characters in str. 306fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt if (i >= min_count && MatchRegexAtHead(regex, str + i)) { 307fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt // We have enough matches at the head, and the tail matches too. 308fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt // Since we only care about *whether* the pattern matches str 309fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt // (as opposed to *how* it matches), there is no need to find a 310fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt // greedy match. 311fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt return true; 312fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt } 313fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt if (str[i] == '\0' || !AtomMatchesChar(escaped, c, str[i])) 314fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt return false; 315fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt } 316fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt return false; 317fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt} 318fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt 319fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt// Returns true iff regex matches a prefix of str. regex must be a 320fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt// valid simple regular expression and not start with "^", or the 321fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt// result is undefined. 322fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholtbool MatchRegexAtHead(const char* regex, const char* str) { 323fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt if (*regex == '\0') // An empty regex matches a prefix of anything. 324fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt return true; 325fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt 326fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt // "$" only matches the end of a string. Note that regex being 327fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt // valid guarantees that there's nothing after "$" in it. 328fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt if (*regex == '$') 329fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt return *str == '\0'; 330fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt 331fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt // Is the first thing in regex an escape sequence? 332fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt const bool escaped = *regex == '\\'; 333fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt if (escaped) 334fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt ++regex; 335fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt if (IsRepeat(regex[1])) { 336fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt // MatchRepetitionAndRegexAtHead() calls MatchRegexAtHead(), so 337fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt // here's an indirect recursion. It terminates as the regex gets 338fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt // shorter in each recursion. 339fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt return MatchRepetitionAndRegexAtHead( 340fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt escaped, regex[0], regex[1], regex + 2, str); 341fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt } else { 342fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt // regex isn't empty, isn't "$", and doesn't start with a 343fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt // repetition. We match the first atom of regex with the first 344fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt // character of str and recurse. 345fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt return (*str != '\0') && AtomMatchesChar(escaped, *regex, *str) && 346fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt MatchRegexAtHead(regex + 1, str + 1); 347fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt } 348fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt} 349fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt 350fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt// Returns true iff regex matches any substring of str. regex must be 351fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt// a valid simple regular expression, or the result is undefined. 352fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt// 353fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt// The algorithm is recursive, but the recursion depth doesn't exceed 354fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt// the regex length, so we won't need to worry about running out of 355fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt// stack space normally. In rare cases the time complexity can be 356fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt// exponential with respect to the regex length + the string length, 357fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt// but usually it's must faster (often close to linear). 358fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholtbool MatchRegexAnywhere(const char* regex, const char* str) { 359fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt if (regex == NULL || str == NULL) 360fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt return false; 361fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt 362fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt if (*regex == '^') 363fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt return MatchRegexAtHead(regex + 1, str); 364fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt 365fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt // A successful match can be anywhere in str. 366fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt do { 367fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt if (MatchRegexAtHead(regex, str)) 368fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt return true; 369fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt } while (*str++ != '\0'); 370fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt return false; 371fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt} 372fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt 373fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt// Implements the RE class. 374fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt 375fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric AnholtRE::~RE() { 376fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt free(const_cast<char*>(pattern_)); 377fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt free(const_cast<char*>(full_pattern_)); 378fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt} 379fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt 380fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt// Returns true iff regular expression re matches the entire str. 381fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholtbool RE::FullMatch(const char* str, const RE& re) { 382fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt return re.is_valid_ && MatchRegexAnywhere(re.full_pattern_, str); 383fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt} 384fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt 385fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt// Returns true iff regular expression re matches a substring of str 386fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt// (including str itself). 387fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholtbool RE::PartialMatch(const char* str, const RE& re) { 388fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt return re.is_valid_ && MatchRegexAnywhere(re.pattern_, str); 389fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt} 390fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt 391fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt// Initializes an RE from its string representation. 392fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholtvoid RE::Init(const char* regex) { 393fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt pattern_ = full_pattern_ = NULL; 394fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt if (regex != NULL) { 395fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt pattern_ = posix::StrDup(regex); 396fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt } 397fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt 398fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt is_valid_ = ValidateRegex(regex); 399fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt if (!is_valid_) { 400fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt // No need to calculate the full pattern when the regex is invalid. 401fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt return; 402fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt } 403fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt 404fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt const size_t len = strlen(regex); 405fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt // Reserves enough bytes to hold the regular expression used for a 406fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt // full match: we need space to prepend a '^', append a '$', and 407fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt // terminate the string with '\0'. 408fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt char* buffer = static_cast<char*>(malloc(len + 3)); 409fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt full_pattern_ = buffer; 410fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt 411fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt if (*regex != '^') 412fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt *buffer++ = '^'; // Makes sure full_pattern_ starts with '^'. 413fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt 414fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt // We don't use snprintf or strncpy, as they trigger a warning when 415fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt // compiled with VC++ 8.0. 416fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt memcpy(buffer, regex, len); 417fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt buffer += len; 418fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt 419fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt if (len == 0 || regex[len - 1] != '$') 420fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt *buffer++ = '$'; // Makes sure full_pattern_ ends with '$'. 421fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt 422fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt *buffer = '\0'; 423fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt} 424fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt 425fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt#endif // GTEST_USES_POSIX_RE 426fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt 427fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholtconst char kUnknownFile[] = "unknown file"; 428fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt 429fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt// Formats a source file path and a line number as they would appear 430fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt// in an error message from the compiler used to compile this code. 431fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric AnholtGTEST_API_ ::std::string FormatFileLocation(const char* file, int line) { 432fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt const char* const file_name = file == NULL ? kUnknownFile : file; 433fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt 434fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt if (line < 0) { 435fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt return String::Format("%s:", file_name).c_str(); 436fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt } 437fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt#ifdef _MSC_VER 438fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt return String::Format("%s(%d):", file_name, line).c_str(); 439fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt#else 440fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt return String::Format("%s:%d:", file_name, line).c_str(); 441fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt#endif // _MSC_VER 442fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt} 443fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt 444fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt// Formats a file location for compiler-independent XML output. 445fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt// Although this function is not platform dependent, we put it next to 446fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt// FormatFileLocation in order to contrast the two functions. 447fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt// Note that FormatCompilerIndependentFileLocation() does NOT append colon 448fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt// to the file location it produces, unlike FormatFileLocation(). 449fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric AnholtGTEST_API_ ::std::string FormatCompilerIndependentFileLocation( 450fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt const char* file, int line) { 451fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt const char* const file_name = file == NULL ? kUnknownFile : file; 452fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt 453fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt if (line < 0) 454fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt return file_name; 455fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt else 456fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt return String::Format("%s:%d", file_name, line).c_str(); 457fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt} 458fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt 459fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt 460fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric AnholtGTestLog::GTestLog(GTestLogSeverity severity, const char* file, int line) 461fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt : severity_(severity) { 462fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt const char* const marker = 463fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt severity == GTEST_INFO ? "[ INFO ]" : 464fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt severity == GTEST_WARNING ? "[WARNING]" : 465fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt severity == GTEST_ERROR ? "[ ERROR ]" : "[ FATAL ]"; 466fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt GetStream() << ::std::endl << marker << " " 467fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt << FormatFileLocation(file, line).c_str() << ": "; 468fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt} 469fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt 470fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt// Flushes the buffers and, if severity is GTEST_FATAL, aborts the program. 471fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric AnholtGTestLog::~GTestLog() { 472fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt GetStream() << ::std::endl; 473fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt if (severity_ == GTEST_FATAL) { 474fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt fflush(stderr); 475fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt posix::Abort(); 476fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt } 477fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt} 478fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt// Disable Microsoft deprecation warnings for POSIX functions called from 479fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt// this class (creat, dup, dup2, and close) 480fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt#ifdef _MSC_VER 481fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt# pragma warning(push) 482fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt# pragma warning(disable: 4996) 483fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt#endif // _MSC_VER 484fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt 485fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt#if GTEST_HAS_STREAM_REDIRECTION 486fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt 487fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt// Object that captures an output stream (stdout/stderr). 488fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholtclass CapturedStream { 489fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt public: 490fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt // The ctor redirects the stream to a temporary file. 491fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt CapturedStream(int fd) : fd_(fd), uncaptured_fd_(dup(fd)) { 492fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt 493fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt# if GTEST_OS_WINDOWS 494fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt char temp_dir_path[MAX_PATH + 1] = { '\0' }; // NOLINT 495fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt char temp_file_path[MAX_PATH + 1] = { '\0' }; // NOLINT 496fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt 497fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt ::GetTempPathA(sizeof(temp_dir_path), temp_dir_path); 498fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt const UINT success = ::GetTempFileNameA(temp_dir_path, 499fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt "gtest_redir", 500fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt 0, // Generate unique file name. 501fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt temp_file_path); 502fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt GTEST_CHECK_(success != 0) 503fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt << "Unable to create a temporary file in " << temp_dir_path; 504fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt const int captured_fd = creat(temp_file_path, _S_IREAD | _S_IWRITE); 505fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt GTEST_CHECK_(captured_fd != -1) << "Unable to open temporary file " 506fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt << temp_file_path; 507fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt filename_ = temp_file_path; 508fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt# else 509fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt // There's no guarantee that a test has write access to the 510fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt // current directory, so we create the temporary file in the /tmp 511fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt // directory instead. 512fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt char name_template[] = "/tmp/captured_stream.XXXXXX"; 513fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt const int captured_fd = mkstemp(name_template); 514fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt filename_ = name_template; 515fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt# endif // GTEST_OS_WINDOWS 516fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt fflush(NULL); 517fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt dup2(captured_fd, fd_); 518fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt close(captured_fd); 519fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt } 520fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt 521fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt ~CapturedStream() { 522fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt remove(filename_.c_str()); 523fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt } 524fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt 525fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt String GetCapturedString() { 526fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt if (uncaptured_fd_ != -1) { 527fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt // Restores the original stream. 528fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt fflush(NULL); 529fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt dup2(uncaptured_fd_, fd_); 530fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt close(uncaptured_fd_); 531fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt uncaptured_fd_ = -1; 532fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt } 533fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt 534fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt FILE* const file = posix::FOpen(filename_.c_str(), "r"); 535fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt const String content = ReadEntireFile(file); 536fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt posix::FClose(file); 537fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt return content; 538fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt } 539fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt 540fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt private: 541fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt // Reads the entire content of a file as a String. 542fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt static String ReadEntireFile(FILE* file); 543fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt 544fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt // Returns the size (in bytes) of a file. 545fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt static size_t GetFileSize(FILE* file); 546fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt 547fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt const int fd_; // A stream to capture. 548fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt int uncaptured_fd_; 549fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt // Name of the temporary file holding the stderr output. 550fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt ::std::string filename_; 551fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt 552fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt GTEST_DISALLOW_COPY_AND_ASSIGN_(CapturedStream); 553fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt}; 554fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt 555fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt// Returns the size (in bytes) of a file. 556fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholtsize_t CapturedStream::GetFileSize(FILE* file) { 557fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt fseek(file, 0, SEEK_END); 558fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt return static_cast<size_t>(ftell(file)); 559fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt} 560fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt 561fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt// Reads the entire content of a file as a string. 562fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric AnholtString CapturedStream::ReadEntireFile(FILE* file) { 563fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt const size_t file_size = GetFileSize(file); 564fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt char* const buffer = new char[file_size]; 565fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt 566fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt size_t bytes_last_read = 0; // # of bytes read in the last fread() 567fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt size_t bytes_read = 0; // # of bytes read so far 568fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt 569fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt fseek(file, 0, SEEK_SET); 570fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt 571fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt // Keeps reading the file until we cannot read further or the 572fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt // pre-determined file size is reached. 573fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt do { 574fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt bytes_last_read = fread(buffer+bytes_read, 1, file_size-bytes_read, file); 575fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt bytes_read += bytes_last_read; 576fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt } while (bytes_last_read > 0 && bytes_read < file_size); 577fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt 578fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt const String content(buffer, bytes_read); 579fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt delete[] buffer; 580fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt 581fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt return content; 582fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt} 583fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt 584fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt# ifdef _MSC_VER 585fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt# pragma warning(pop) 586fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt# endif // _MSC_VER 587fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt 588fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholtstatic CapturedStream* g_captured_stderr = NULL; 589fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholtstatic CapturedStream* g_captured_stdout = NULL; 590fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt 591fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt// Starts capturing an output stream (stdout/stderr). 592fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholtvoid CaptureStream(int fd, const char* stream_name, CapturedStream** stream) { 593fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt if (*stream != NULL) { 594fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt GTEST_LOG_(FATAL) << "Only one " << stream_name 595fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt << " capturer can exist at a time."; 596fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt } 597fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt *stream = new CapturedStream(fd); 598fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt} 599fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt 600fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt// Stops capturing the output stream and returns the captured string. 601fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric AnholtString GetCapturedStream(CapturedStream** captured_stream) { 602fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt const String content = (*captured_stream)->GetCapturedString(); 603fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt 604fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt delete *captured_stream; 605fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt *captured_stream = NULL; 606fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt 607fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt return content; 608fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt} 609fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt 610fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt// Starts capturing stdout. 611fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholtvoid CaptureStdout() { 612fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt CaptureStream(kStdOutFileno, "stdout", &g_captured_stdout); 613fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt} 614fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt 615fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt// Starts capturing stderr. 616fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholtvoid CaptureStderr() { 617fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt CaptureStream(kStdErrFileno, "stderr", &g_captured_stderr); 618fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt} 619fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt 620fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt// Stops capturing stdout and returns the captured string. 621fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric AnholtString GetCapturedStdout() { return GetCapturedStream(&g_captured_stdout); } 622fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt 623fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt// Stops capturing stderr and returns the captured string. 624fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric AnholtString GetCapturedStderr() { return GetCapturedStream(&g_captured_stderr); } 625fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt 626fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt#endif // GTEST_HAS_STREAM_REDIRECTION 627fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt 628fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt#if GTEST_HAS_DEATH_TEST 629fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt 630fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt// A copy of all command line arguments. Set by InitGoogleTest(). 631fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt::std::vector<String> g_argvs; 632fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt 633fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt// Returns the command line as a vector of strings. 634fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholtconst ::std::vector<String>& GetArgvs() { return g_argvs; } 635fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt 636fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt#endif // GTEST_HAS_DEATH_TEST 637fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt 638fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt#if GTEST_OS_WINDOWS_MOBILE 639fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholtnamespace posix { 640fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholtvoid Abort() { 641fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt DebugBreak(); 642fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt TerminateProcess(GetCurrentProcess(), 1); 643fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt} 644fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt} // namespace posix 645fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt#endif // GTEST_OS_WINDOWS_MOBILE 646fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt 647fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt// Returns the name of the environment variable corresponding to the 648fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt// given flag. For example, FlagToEnvVar("foo") will return 649fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt// "GTEST_FOO" in the open-source version. 650fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholtstatic String FlagToEnvVar(const char* flag) { 651fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt const String full_flag = 652fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt (Message() << GTEST_FLAG_PREFIX_ << flag).GetString(); 653fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt 654fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt Message env_var; 655fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt for (size_t i = 0; i != full_flag.length(); i++) { 656fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt env_var << ToUpper(full_flag.c_str()[i]); 657fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt } 658fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt 659fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt return env_var.GetString(); 660fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt} 661fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt 662fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt// Parses 'str' for a 32-bit signed integer. If successful, writes 663fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt// the result to *value and returns true; otherwise leaves *value 664fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt// unchanged and returns false. 665fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholtbool ParseInt32(const Message& src_text, const char* str, Int32* value) { 666fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt // Parses the environment variable as a decimal integer. 667fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt char* end = NULL; 668fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt const long long_value = strtol(str, &end, 10); // NOLINT 669fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt 670fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt // Has strtol() consumed all characters in the string? 671fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt if (*end != '\0') { 672fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt // No - an invalid character was encountered. 673fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt Message msg; 674fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt msg << "WARNING: " << src_text 675fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt << " is expected to be a 32-bit integer, but actually" 676fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt << " has value \"" << str << "\".\n"; 677fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt printf("%s", msg.GetString().c_str()); 678fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt fflush(stdout); 679fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt return false; 680fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt } 681fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt 682fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt // Is the parsed value in the range of an Int32? 683fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt const Int32 result = static_cast<Int32>(long_value); 684fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt if (long_value == LONG_MAX || long_value == LONG_MIN || 685fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt // The parsed value overflows as a long. (strtol() returns 686fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt // LONG_MAX or LONG_MIN when the input overflows.) 687fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt result != long_value 688fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt // The parsed value overflows as an Int32. 689fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt ) { 690fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt Message msg; 691fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt msg << "WARNING: " << src_text 692fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt << " is expected to be a 32-bit integer, but actually" 693fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt << " has value " << str << ", which overflows.\n"; 694fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt printf("%s", msg.GetString().c_str()); 695fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt fflush(stdout); 696fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt return false; 697fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt } 698fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt 699fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt *value = result; 700fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt return true; 701fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt} 702fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt 703fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt// Reads and returns the Boolean environment variable corresponding to 704fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt// the given flag; if it's not set, returns default_value. 705fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt// 706fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt// The value is considered true iff it's not "0". 707fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholtbool BoolFromGTestEnv(const char* flag, bool default_value) { 708fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt const String env_var = FlagToEnvVar(flag); 709fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt const char* const string_value = posix::GetEnv(env_var.c_str()); 710fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt return string_value == NULL ? 711fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt default_value : strcmp(string_value, "0") != 0; 712fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt} 713fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt 714fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt// Reads and returns a 32-bit integer stored in the environment 715fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt// variable corresponding to the given flag; if it isn't set or 716fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt// doesn't represent a valid 32-bit integer, returns default_value. 717fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric AnholtInt32 Int32FromGTestEnv(const char* flag, Int32 default_value) { 718fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt const String env_var = FlagToEnvVar(flag); 719fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt const char* const string_value = posix::GetEnv(env_var.c_str()); 720fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt if (string_value == NULL) { 721fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt // The environment variable is not set. 722fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt return default_value; 723fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt } 724fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt 725fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt Int32 result = default_value; 726fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt if (!ParseInt32(Message() << "Environment variable " << env_var, 727fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt string_value, &result)) { 728fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt printf("The default value %s is used.\n", 729fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt (Message() << default_value).GetString().c_str()); 730fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt fflush(stdout); 731fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt return default_value; 732fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt } 733fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt 734fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt return result; 735fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt} 736fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt 737fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt// Reads and returns the string environment variable corresponding to 738fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt// the given flag; if it's not set, returns default_value. 739fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholtconst char* StringFromGTestEnv(const char* flag, const char* default_value) { 740fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt const String env_var = FlagToEnvVar(flag); 741fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt const char* const value = posix::GetEnv(env_var.c_str()); 742fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt return value == NULL ? default_value : value; 743fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt} 744fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt 745fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt} // namespace internal 746fe358c0ffa4acb7ecab10fda68ba9740497d2e7fEric Anholt} // namespace testing 747