chore: apply clang-format
This commit is contained in:
parent
e3f5398aa1
commit
93549f3600
@ -58,7 +58,7 @@ ConstructorInitializerIndentWidth: 4
|
|||||||
ContinuationIndentWidth: 4
|
ContinuationIndentWidth: 4
|
||||||
Cpp11BracedListStyle: true
|
Cpp11BracedListStyle: true
|
||||||
DeriveLineEnding: true
|
DeriveLineEnding: true
|
||||||
DerivePointerAlignment: true
|
DerivePointerAlignment: false
|
||||||
DisableFormat: false
|
DisableFormat: false
|
||||||
ExperimentalAutoDetectBinPacking: false
|
ExperimentalAutoDetectBinPacking: false
|
||||||
FixNamespaceComments: true
|
FixNamespaceComments: true
|
||||||
@ -84,7 +84,7 @@ IncludeIsMainRegex: '([-_](test|unittest))?$'
|
|||||||
IncludeIsMainSourceRegex: ''
|
IncludeIsMainSourceRegex: ''
|
||||||
IndentCaseLabels: true
|
IndentCaseLabels: true
|
||||||
IndentGotoLabels: true
|
IndentGotoLabels: true
|
||||||
IndentPPDirectives: None
|
IndentPPDirectives: AfterHash
|
||||||
IndentWidth: 2
|
IndentWidth: 2
|
||||||
IndentWrappedFunctionNames: false
|
IndentWrappedFunctionNames: false
|
||||||
JavaScriptQuotes: Leave
|
JavaScriptQuotes: Leave
|
||||||
|
|||||||
@ -48,11 +48,12 @@
|
|||||||
#ifndef BASE_COMMANDLINEFLAGS_H__
|
#ifndef BASE_COMMANDLINEFLAGS_H__
|
||||||
#define BASE_COMMANDLINEFLAGS_H__
|
#define BASE_COMMANDLINEFLAGS_H__
|
||||||
|
|
||||||
#include "config.h"
|
|
||||||
#include <cstdlib> // for getenv
|
#include <cstdlib> // for getenv
|
||||||
#include <cstring> // for memchr
|
#include <cstring> // for memchr
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
|
#include "config.h"
|
||||||
|
|
||||||
#ifdef GLOG_USE_GFLAGS
|
#ifdef GLOG_USE_GFLAGS
|
||||||
|
|
||||||
# include <gflags/gflags.h>
|
# include <gflags/gflags.h>
|
||||||
@ -74,8 +75,7 @@
|
|||||||
using fL##shorttype::FLAGS_##name
|
using fL##shorttype::FLAGS_##name
|
||||||
|
|
||||||
// bool specialization
|
// bool specialization
|
||||||
#define DECLARE_bool(name) \
|
# define DECLARE_bool(name) DECLARE_VARIABLE(bool, B, name, bool)
|
||||||
DECLARE_VARIABLE(bool, B, name, bool)
|
|
||||||
# define DEFINE_bool(name, value, meaning) \
|
# define DEFINE_bool(name, value, meaning) \
|
||||||
DEFINE_VARIABLE(bool, B, name, value, meaning, bool)
|
DEFINE_VARIABLE(bool, B, name, value, meaning, bool)
|
||||||
|
|
||||||
@ -86,7 +86,8 @@
|
|||||||
|
|
||||||
// uint32 specialization
|
// uint32 specialization
|
||||||
# ifndef DECLARE_uint32
|
# ifndef DECLARE_uint32
|
||||||
#define DECLARE_uint32(name) DECLARE_VARIABLE(google::uint32, U, name, uint32)
|
# define DECLARE_uint32(name) \
|
||||||
|
DECLARE_VARIABLE(google::uint32, U, name, uint32)
|
||||||
# endif // DECLARE_uint64
|
# endif // DECLARE_uint64
|
||||||
# define DEFINE_uint32(name, value, meaning) \
|
# define DEFINE_uint32(name, value, meaning) \
|
||||||
DEFINE_VARIABLE(google::uint32, U, name, value, meaning, uint32)
|
DEFINE_VARIABLE(google::uint32, U, name, value, meaning, uint32)
|
||||||
@ -130,8 +131,7 @@
|
|||||||
// These macros (could be functions, but I don't want to bother with a .cc
|
// These macros (could be functions, but I don't want to bother with a .cc
|
||||||
// file), make it easier to initialize flags from the environment.
|
// file), make it easier to initialize flags from the environment.
|
||||||
|
|
||||||
#define EnvToString(envname, dflt) \
|
#define EnvToString(envname, dflt) (!getenv(envname) ? (dflt) : getenv(envname))
|
||||||
(!getenv(envname) ? (dflt) : getenv(envname))
|
|
||||||
|
|
||||||
#define EnvToBool(envname, dflt) \
|
#define EnvToBool(envname, dflt) \
|
||||||
(!getenv(envname) ? (dflt) \
|
(!getenv(envname) ? (dflt) \
|
||||||
|
|||||||
@ -36,16 +36,14 @@
|
|||||||
class GoogleInitializer {
|
class GoogleInitializer {
|
||||||
public:
|
public:
|
||||||
using void_function = void (*)();
|
using void_function = void (*)();
|
||||||
GoogleInitializer(const char*, void_function f) {
|
GoogleInitializer(const char*, void_function f) { f(); }
|
||||||
f();
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#define REGISTER_MODULE_INITIALIZER(name, body) \
|
#define REGISTER_MODULE_INITIALIZER(name, body) \
|
||||||
namespace { \
|
namespace { \
|
||||||
static void google_init_module_##name() { body; } \
|
static void google_init_module_##name() { body; } \
|
||||||
GoogleInitializer google_initializer_module_##name(#name, \
|
GoogleInitializer google_initializer_module_##name( \
|
||||||
google_init_module_##name); \
|
#name, google_init_module_##name); \
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif /* _GOOGLEINIT_H */
|
#endif /* _GOOGLEINIT_H */
|
||||||
|
|||||||
@ -134,7 +134,8 @@
|
|||||||
// *does* cause problems for FreeBSD, or MacOSX, but isn't needed
|
// *does* cause problems for FreeBSD, or MacOSX, but isn't needed
|
||||||
// for locking there.)
|
// for locking there.)
|
||||||
# ifdef __linux__
|
# ifdef __linux__
|
||||||
# ifndef _XOPEN_SOURCE // Some other header might have already set it for us.
|
# ifndef _XOPEN_SOURCE // Some other header might have already set it for
|
||||||
|
// us.
|
||||||
# define _XOPEN_SOURCE 500 // may be needed to get the rwlock calls
|
# define _XOPEN_SOURCE 500 // may be needed to get the rwlock calls
|
||||||
# endif
|
# endif
|
||||||
# endif
|
# endif
|
||||||
@ -218,27 +219,40 @@ Mutex::~Mutex() { assert(mutex_ == 0); }
|
|||||||
void Mutex::Lock() { assert(--mutex_ == -1); }
|
void Mutex::Lock() { assert(--mutex_ == -1); }
|
||||||
void Mutex::Unlock() { assert(mutex_++ == -1); }
|
void Mutex::Unlock() { assert(mutex_++ == -1); }
|
||||||
# ifdef GMUTEX_TRYLOCK
|
# ifdef GMUTEX_TRYLOCK
|
||||||
bool Mutex::TryLock() { if (mutex_) return false; Lock(); return true; }
|
bool Mutex::TryLock() {
|
||||||
|
if (mutex_) return false;
|
||||||
|
Lock();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
# endif
|
# endif
|
||||||
void Mutex::ReaderLock() { assert(++mutex_ > 0); }
|
void Mutex::ReaderLock() { assert(++mutex_ > 0); }
|
||||||
void Mutex::ReaderUnlock() { assert(mutex_-- > 0); }
|
void Mutex::ReaderUnlock() { assert(mutex_-- > 0); }
|
||||||
|
|
||||||
#elif defined(_WIN32) || defined(__CYGWIN__)
|
#elif defined(_WIN32) || defined(__CYGWIN__)
|
||||||
|
|
||||||
Mutex::Mutex() { InitializeCriticalSection(&mutex_); SetIsSafe(); }
|
Mutex::Mutex() {
|
||||||
|
InitializeCriticalSection(&mutex_);
|
||||||
|
SetIsSafe();
|
||||||
|
}
|
||||||
Mutex::~Mutex() { DeleteCriticalSection(&mutex_); }
|
Mutex::~Mutex() { DeleteCriticalSection(&mutex_); }
|
||||||
void Mutex::Lock() { if (is_safe_) EnterCriticalSection(&mutex_); }
|
void Mutex::Lock() {
|
||||||
void Mutex::Unlock() { if (is_safe_) LeaveCriticalSection(&mutex_); }
|
if (is_safe_) EnterCriticalSection(&mutex_);
|
||||||
|
}
|
||||||
|
void Mutex::Unlock() {
|
||||||
|
if (is_safe_) LeaveCriticalSection(&mutex_);
|
||||||
|
}
|
||||||
# ifdef GMUTEX_TRYLOCK
|
# ifdef GMUTEX_TRYLOCK
|
||||||
bool Mutex::TryLock() { return is_safe_ ?
|
bool Mutex::TryLock() {
|
||||||
TryEnterCriticalSection(&mutex_) != 0 : true; }
|
return is_safe_ ? TryEnterCriticalSection(&mutex_) != 0 : true;
|
||||||
|
}
|
||||||
# endif
|
# endif
|
||||||
void Mutex::ReaderLock() { Lock(); } // we don't have read-write locks
|
void Mutex::ReaderLock() { Lock(); } // we don't have read-write locks
|
||||||
void Mutex::ReaderUnlock() { Unlock(); }
|
void Mutex::ReaderUnlock() { Unlock(); }
|
||||||
|
|
||||||
#elif defined(HAVE_PTHREAD) && defined(HAVE_RWLOCK)
|
#elif defined(HAVE_PTHREAD) && defined(HAVE_RWLOCK)
|
||||||
|
|
||||||
#define SAFE_PTHREAD(fncall) do { /* run fncall if is_safe_ is true */ \
|
# define SAFE_PTHREAD(fncall) \
|
||||||
|
do { /* run fncall if is_safe_ is true */ \
|
||||||
if (is_safe_ && fncall(&mutex_) != 0) abort(); \
|
if (is_safe_ && fncall(&mutex_) != 0) abort(); \
|
||||||
} while (0)
|
} while (0)
|
||||||
|
|
||||||
@ -250,9 +264,9 @@ Mutex::~Mutex() { SAFE_PTHREAD(pthread_rwlock_destroy); }
|
|||||||
void Mutex::Lock() { SAFE_PTHREAD(pthread_rwlock_wrlock); }
|
void Mutex::Lock() { SAFE_PTHREAD(pthread_rwlock_wrlock); }
|
||||||
void Mutex::Unlock() { SAFE_PTHREAD(pthread_rwlock_unlock); }
|
void Mutex::Unlock() { SAFE_PTHREAD(pthread_rwlock_unlock); }
|
||||||
# ifdef GMUTEX_TRYLOCK
|
# ifdef GMUTEX_TRYLOCK
|
||||||
bool Mutex::TryLock() { return is_safe_ ?
|
bool Mutex::TryLock() {
|
||||||
pthread_rwlock_trywrlock(&mutex_) == 0 :
|
return is_safe_ ? pthread_rwlock_trywrlock(&mutex_) == 0 : true;
|
||||||
true; }
|
}
|
||||||
# endif
|
# endif
|
||||||
void Mutex::ReaderLock() { SAFE_PTHREAD(pthread_rwlock_rdlock); }
|
void Mutex::ReaderLock() { SAFE_PTHREAD(pthread_rwlock_rdlock); }
|
||||||
void Mutex::ReaderUnlock() { SAFE_PTHREAD(pthread_rwlock_unlock); }
|
void Mutex::ReaderUnlock() { SAFE_PTHREAD(pthread_rwlock_unlock); }
|
||||||
@ -260,7 +274,8 @@ void Mutex::ReaderUnlock() { SAFE_PTHREAD(pthread_rwlock_unlock); }
|
|||||||
|
|
||||||
#elif defined(HAVE_PTHREAD)
|
#elif defined(HAVE_PTHREAD)
|
||||||
|
|
||||||
#define SAFE_PTHREAD(fncall) do { /* run fncall if is_safe_ is true */ \
|
# define SAFE_PTHREAD(fncall) \
|
||||||
|
do { /* run fncall if is_safe_ is true */ \
|
||||||
if (is_safe_ && fncall(&mutex_) != 0) abort(); \
|
if (is_safe_ && fncall(&mutex_) != 0) abort(); \
|
||||||
} while (0)
|
} while (0)
|
||||||
|
|
||||||
@ -272,8 +287,9 @@ Mutex::~Mutex() { SAFE_PTHREAD(pthread_mutex_destroy); }
|
|||||||
void Mutex::Lock() { SAFE_PTHREAD(pthread_mutex_lock); }
|
void Mutex::Lock() { SAFE_PTHREAD(pthread_mutex_lock); }
|
||||||
void Mutex::Unlock() { SAFE_PTHREAD(pthread_mutex_unlock); }
|
void Mutex::Unlock() { SAFE_PTHREAD(pthread_mutex_unlock); }
|
||||||
# ifdef GMUTEX_TRYLOCK
|
# ifdef GMUTEX_TRYLOCK
|
||||||
bool Mutex::TryLock() { return is_safe_ ?
|
bool Mutex::TryLock() {
|
||||||
pthread_mutex_trylock(&mutex_) == 0 : true; }
|
return is_safe_ ? pthread_mutex_trylock(&mutex_) == 0 : true;
|
||||||
|
}
|
||||||
# endif
|
# endif
|
||||||
void Mutex::ReaderLock() { Lock(); }
|
void Mutex::ReaderLock() { Lock(); }
|
||||||
void Mutex::ReaderUnlock() { Unlock(); }
|
void Mutex::ReaderUnlock() { Unlock(); }
|
||||||
@ -289,6 +305,7 @@ class MutexLock {
|
|||||||
public:
|
public:
|
||||||
explicit MutexLock(Mutex* mu) : mu_(mu) { mu_->Lock(); }
|
explicit MutexLock(Mutex* mu) : mu_(mu) { mu_->Lock(); }
|
||||||
~MutexLock() { mu_->Unlock(); }
|
~MutexLock() { mu_->Unlock(); }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Mutex* const mu_;
|
Mutex* const mu_;
|
||||||
// Disallow "evil" constructors
|
// Disallow "evil" constructors
|
||||||
@ -301,6 +318,7 @@ class ReaderMutexLock {
|
|||||||
public:
|
public:
|
||||||
explicit ReaderMutexLock(Mutex* mu) : mu_(mu) { mu_->ReaderLock(); }
|
explicit ReaderMutexLock(Mutex* mu) : mu_(mu) { mu_->ReaderLock(); }
|
||||||
~ReaderMutexLock() { mu_->ReaderUnlock(); }
|
~ReaderMutexLock() { mu_->ReaderUnlock(); }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Mutex* const mu_;
|
Mutex* const mu_;
|
||||||
// Disallow "evil" constructors
|
// Disallow "evil" constructors
|
||||||
@ -312,6 +330,7 @@ class WriterMutexLock {
|
|||||||
public:
|
public:
|
||||||
explicit WriterMutexLock(Mutex* mu) : mu_(mu) { mu_->WriterLock(); }
|
explicit WriterMutexLock(Mutex* mu) : mu_(mu) { mu_->WriterLock(); }
|
||||||
~WriterMutexLock() { mu_->WriterUnlock(); }
|
~WriterMutexLock() { mu_->WriterUnlock(); }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Mutex* const mu_;
|
Mutex* const mu_;
|
||||||
// Disallow "evil" constructors
|
// Disallow "evil" constructors
|
||||||
|
|||||||
133
src/demangle.cc
133
src/demangle.cc
@ -140,15 +140,14 @@ static bool AtLeastNumCharsRemaining(const char *str, ssize_t n) {
|
|||||||
// Returns true if "str" has "prefix" as a prefix.
|
// Returns true if "str" has "prefix" as a prefix.
|
||||||
static bool StrPrefix(const char* str, const char* prefix) {
|
static bool StrPrefix(const char* str, const char* prefix) {
|
||||||
size_t i = 0;
|
size_t i = 0;
|
||||||
while (str[i] != '\0' && prefix[i] != '\0' &&
|
while (str[i] != '\0' && prefix[i] != '\0' && str[i] == prefix[i]) {
|
||||||
str[i] == prefix[i]) {
|
|
||||||
++i;
|
++i;
|
||||||
}
|
}
|
||||||
return prefix[i] == '\0'; // Consumed everything in "prefix".
|
return prefix[i] == '\0'; // Consumed everything in "prefix".
|
||||||
}
|
}
|
||||||
|
|
||||||
static void InitState(State *state, const char *mangled,
|
static void InitState(State* state, const char* mangled, char* out,
|
||||||
char *out, size_t out_size) {
|
size_t out_size) {
|
||||||
state->mangled_cur = mangled;
|
state->mangled_cur = mangled;
|
||||||
state->out_cur = out;
|
state->out_cur = out;
|
||||||
state->out_begin = out;
|
state->out_begin = out;
|
||||||
@ -200,9 +199,7 @@ static bool ParseCharClass(State *state, const char *char_class) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// This function is used for handling an optional non-terminal.
|
// This function is used for handling an optional non-terminal.
|
||||||
static bool Optional(bool) {
|
static bool Optional(bool) { return true; }
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// This function is used for handling <non-terminal>+ syntax.
|
// This function is used for handling <non-terminal>+ syntax.
|
||||||
using ParseFunc = bool (*)(State*);
|
using ParseFunc = bool (*)(State*);
|
||||||
@ -248,17 +245,13 @@ static void Append(State *state, const char * const str, ssize_t length) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// We don't use equivalents in libc to avoid locale issues.
|
// We don't use equivalents in libc to avoid locale issues.
|
||||||
static bool IsLower(char c) {
|
static bool IsLower(char c) { return c >= 'a' && c <= 'z'; }
|
||||||
return c >= 'a' && c <= 'z';
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool IsAlpha(char c) {
|
static bool IsAlpha(char c) {
|
||||||
return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z');
|
return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z');
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool IsDigit(char c) {
|
static bool IsDigit(char c) { return c >= '0' && c <= '9'; }
|
||||||
return c >= '0' && c <= '9';
|
|
||||||
}
|
|
||||||
|
|
||||||
// Returns true if "str" is a function clone suffix. These suffixes are used
|
// Returns true if "str" is a function clone suffix. These suffixes are used
|
||||||
// by GCC 4.5.x and later versions to indicate functions which have been
|
// by GCC 4.5.x and later versions to indicate functions which have been
|
||||||
@ -473,8 +466,7 @@ static bool ParseName(State *state) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
State copy = *state;
|
State copy = *state;
|
||||||
if (ParseUnscopedTemplateName(state) &&
|
if (ParseUnscopedTemplateName(state) && ParseTemplateArgs(state)) {
|
||||||
ParseTemplateArgs(state)) {
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
*state = copy;
|
*state = copy;
|
||||||
@ -494,8 +486,7 @@ static bool ParseUnscopedName(State *state) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
State copy = *state;
|
State copy = *state;
|
||||||
if (ParseTwoCharToken(state, "St") &&
|
if (ParseTwoCharToken(state, "St") && MaybeAppend(state, "std::") &&
|
||||||
MaybeAppend(state, "std::") &&
|
|
||||||
ParseUnqualifiedName(state)) {
|
ParseUnqualifiedName(state)) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -513,10 +504,8 @@ static bool ParseUnscopedTemplateName(State *state) {
|
|||||||
// ::= N [<CV-qualifiers>] <template-prefix> <template-args> E
|
// ::= N [<CV-qualifiers>] <template-prefix> <template-args> E
|
||||||
static bool ParseNestedName(State* state) {
|
static bool ParseNestedName(State* state) {
|
||||||
State copy = *state;
|
State copy = *state;
|
||||||
if (ParseOneCharToken(state, 'N') &&
|
if (ParseOneCharToken(state, 'N') && EnterNestedName(state) &&
|
||||||
EnterNestedName(state) &&
|
Optional(ParseCVQualifiers(state)) && ParsePrefix(state) &&
|
||||||
Optional(ParseCVQualifiers(state)) &&
|
|
||||||
ParsePrefix(state) &&
|
|
||||||
LeaveNestedName(state, copy.nest_level) &&
|
LeaveNestedName(state, copy.nest_level) &&
|
||||||
ParseOneCharToken(state, 'E')) {
|
ParseOneCharToken(state, 'E')) {
|
||||||
return true;
|
return true;
|
||||||
@ -540,8 +529,7 @@ static bool ParsePrefix(State *state) {
|
|||||||
bool has_something = false;
|
bool has_something = false;
|
||||||
while (true) {
|
while (true) {
|
||||||
MaybeAppendSeparator(state);
|
MaybeAppendSeparator(state);
|
||||||
if (ParseTemplateParam(state) ||
|
if (ParseTemplateParam(state) || ParseSubstitution(state) ||
|
||||||
ParseSubstitution(state) ||
|
|
||||||
ParseUnscopedName(state)) {
|
ParseUnscopedName(state)) {
|
||||||
has_something = true;
|
has_something = true;
|
||||||
MaybeIncreaseNestLevel(state);
|
MaybeIncreaseNestLevel(state);
|
||||||
@ -562,8 +550,7 @@ static bool ParsePrefix(State *state) {
|
|||||||
// ::= <source-name> [<abi-tags>]
|
// ::= <source-name> [<abi-tags>]
|
||||||
// ::= <local-source-name> [<abi-tags>]
|
// ::= <local-source-name> [<abi-tags>]
|
||||||
static bool ParseUnqualifiedName(State* state) {
|
static bool ParseUnqualifiedName(State* state) {
|
||||||
return (ParseOperatorName(state) ||
|
return (ParseOperatorName(state) || ParseCtorDtorName(state) ||
|
||||||
ParseCtorDtorName(state) ||
|
|
||||||
(ParseSourceName(state) && Optional(ParseAbiTags(state))) ||
|
(ParseSourceName(state) && Optional(ParseAbiTags(state))) ||
|
||||||
(ParseLocalSourceName(state) && Optional(ParseAbiTags(state))));
|
(ParseLocalSourceName(state) && Optional(ParseAbiTags(state))));
|
||||||
}
|
}
|
||||||
@ -669,8 +656,7 @@ static bool ParseSeqId(State *state) {
|
|||||||
|
|
||||||
// <identifier> ::= <unqualified source code identifier> (of given length)
|
// <identifier> ::= <unqualified source code identifier> (of given length)
|
||||||
static bool ParseIdentifier(State* state, ssize_t length) {
|
static bool ParseIdentifier(State* state, ssize_t length) {
|
||||||
if (length == -1 ||
|
if (length == -1 || !AtLeastNumCharsRemaining(state->mangled_cur, length)) {
|
||||||
!AtLeastNumCharsRemaining(state->mangled_cur, length)) {
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (IdentifierIsAnonymousNamespace(state, length)) {
|
if (IdentifierIsAnonymousNamespace(state, length)) {
|
||||||
@ -712,10 +698,8 @@ static bool ParseOperatorName(State *state) {
|
|||||||
}
|
}
|
||||||
// First check with "cv" (cast) case.
|
// First check with "cv" (cast) case.
|
||||||
State copy = *state;
|
State copy = *state;
|
||||||
if (ParseTwoCharToken(state, "cv") &&
|
if (ParseTwoCharToken(state, "cv") && MaybeAppend(state, "operator ") &&
|
||||||
MaybeAppend(state, "operator ") &&
|
EnterNestedName(state) && ParseType(state) &&
|
||||||
EnterNestedName(state) &&
|
|
||||||
ParseType(state) &&
|
|
||||||
LeaveNestedName(state, copy.nest_level)) {
|
LeaveNestedName(state, copy.nest_level)) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -730,8 +714,7 @@ static bool ParseOperatorName(State *state) {
|
|||||||
|
|
||||||
// Other operator names should start with a lower alphabet followed
|
// Other operator names should start with a lower alphabet followed
|
||||||
// by a lower/upper alphabet.
|
// by a lower/upper alphabet.
|
||||||
if (!(IsLower(state->mangled_cur[0]) &&
|
if (!(IsLower(state->mangled_cur[0]) && IsAlpha(state->mangled_cur[1]))) {
|
||||||
IsAlpha(state->mangled_cur[1]))) {
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
// We may want to perform a binary search if we really need speed.
|
// We may want to perform a binary search if we really need speed.
|
||||||
@ -771,8 +754,7 @@ static bool ParseOperatorName(State *state) {
|
|||||||
// stack traces. The are special data.
|
// stack traces. The are special data.
|
||||||
static bool ParseSpecialName(State* state) {
|
static bool ParseSpecialName(State* state) {
|
||||||
State copy = *state;
|
State copy = *state;
|
||||||
if (ParseOneCharToken(state, 'T') &&
|
if (ParseOneCharToken(state, 'T') && ParseCharClass(state, "VTIS") &&
|
||||||
ParseCharClass(state, "VTIS") &&
|
|
||||||
ParseType(state)) {
|
ParseType(state)) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -784,8 +766,7 @@ static bool ParseSpecialName(State *state) {
|
|||||||
}
|
}
|
||||||
*state = copy;
|
*state = copy;
|
||||||
|
|
||||||
if (ParseTwoCharToken(state, "GV") &&
|
if (ParseTwoCharToken(state, "GV") && ParseName(state)) {
|
||||||
ParseName(state)) {
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
*state = copy;
|
*state = copy;
|
||||||
@ -833,14 +814,14 @@ static bool ParseSpecialName(State *state) {
|
|||||||
// ::= v <v-offset> _
|
// ::= v <v-offset> _
|
||||||
static bool ParseCallOffset(State* state) {
|
static bool ParseCallOffset(State* state) {
|
||||||
State copy = *state;
|
State copy = *state;
|
||||||
if (ParseOneCharToken(state, 'h') &&
|
if (ParseOneCharToken(state, 'h') && ParseNVOffset(state) &&
|
||||||
ParseNVOffset(state) && ParseOneCharToken(state, '_')) {
|
ParseOneCharToken(state, '_')) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
*state = copy;
|
*state = copy;
|
||||||
|
|
||||||
if (ParseOneCharToken(state, 'v') &&
|
if (ParseOneCharToken(state, 'v') && ParseVOffset(state) &&
|
||||||
ParseVOffset(state) && ParseOneCharToken(state, '_')) {
|
ParseOneCharToken(state, '_')) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
*state = copy;
|
*state = copy;
|
||||||
@ -866,8 +847,7 @@ static bool ParseVOffset(State *state) {
|
|||||||
// ::= D0 | D1 | D2
|
// ::= D0 | D1 | D2
|
||||||
static bool ParseCtorDtorName(State* state) {
|
static bool ParseCtorDtorName(State* state) {
|
||||||
State copy = *state;
|
State copy = *state;
|
||||||
if (ParseOneCharToken(state, 'C') &&
|
if (ParseOneCharToken(state, 'C') && ParseCharClass(state, "123")) {
|
||||||
ParseCharClass(state, "123")) {
|
|
||||||
const char* const prev_name = state->prev_name;
|
const char* const prev_name = state->prev_name;
|
||||||
const ssize_t prev_name_length = state->prev_name_length;
|
const ssize_t prev_name_length = state->prev_name_length;
|
||||||
MaybeAppendWithLength(state, prev_name, prev_name_length);
|
MaybeAppendWithLength(state, prev_name, prev_name_length);
|
||||||
@ -875,8 +855,7 @@ static bool ParseCtorDtorName(State *state) {
|
|||||||
}
|
}
|
||||||
*state = copy;
|
*state = copy;
|
||||||
|
|
||||||
if (ParseOneCharToken(state, 'D') &&
|
if (ParseOneCharToken(state, 'D') && ParseCharClass(state, "012")) {
|
||||||
ParseCharClass(state, "012")) {
|
|
||||||
const char* const prev_name = state->prev_name;
|
const char* const prev_name = state->prev_name;
|
||||||
const ssize_t prev_name_length = state->prev_name_length;
|
const ssize_t prev_name_length = state->prev_name_length;
|
||||||
MaybeAppend(state, "~");
|
MaybeAppend(state, "~");
|
||||||
@ -937,17 +916,13 @@ static bool ParseType(State *state) {
|
|||||||
}
|
}
|
||||||
*state = copy;
|
*state = copy;
|
||||||
|
|
||||||
if (ParseBuiltinType(state) ||
|
if (ParseBuiltinType(state) || ParseFunctionType(state) ||
|
||||||
ParseFunctionType(state) ||
|
ParseClassEnumType(state) || ParseArrayType(state) ||
|
||||||
ParseClassEnumType(state) ||
|
ParsePointerToMemberType(state) || ParseSubstitution(state)) {
|
||||||
ParseArrayType(state) ||
|
|
||||||
ParsePointerToMemberType(state) ||
|
|
||||||
ParseSubstitution(state)) {
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ParseTemplateTemplateParam(state) &&
|
if (ParseTemplateTemplateParam(state) && ParseTemplateArgs(state)) {
|
||||||
ParseTemplateArgs(state)) {
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
*state = copy;
|
*state = copy;
|
||||||
@ -995,8 +970,8 @@ static bool ParseBuiltinType(State *state) {
|
|||||||
static bool ParseFunctionType(State* state) {
|
static bool ParseFunctionType(State* state) {
|
||||||
State copy = *state;
|
State copy = *state;
|
||||||
if (ParseOneCharToken(state, 'F') &&
|
if (ParseOneCharToken(state, 'F') &&
|
||||||
Optional(ParseOneCharToken(state, 'Y')) &&
|
Optional(ParseOneCharToken(state, 'Y')) && ParseBareFunctionType(state) &&
|
||||||
ParseBareFunctionType(state) && ParseOneCharToken(state, 'E')) {
|
ParseOneCharToken(state, 'E')) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
*state = copy;
|
*state = copy;
|
||||||
@ -1017,9 +992,7 @@ static bool ParseBareFunctionType(State *state) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// <class-enum-type> ::= <name>
|
// <class-enum-type> ::= <name>
|
||||||
static bool ParseClassEnumType(State *state) {
|
static bool ParseClassEnumType(State* state) { return ParseName(state); }
|
||||||
return ParseName(state);
|
|
||||||
}
|
|
||||||
|
|
||||||
// <array-type> ::= A <(positive dimension) number> _ <(element) type>
|
// <array-type> ::= A <(positive dimension) number> _ <(element) type>
|
||||||
// ::= A [<(dimension) expression>] _ <(element) type>
|
// ::= A [<(dimension) expression>] _ <(element) type>
|
||||||
@ -1042,8 +1015,7 @@ static bool ParseArrayType(State *state) {
|
|||||||
// <pointer-to-member-type> ::= M <(class) type> <(member) type>
|
// <pointer-to-member-type> ::= M <(class) type> <(member) type>
|
||||||
static bool ParsePointerToMemberType(State* state) {
|
static bool ParsePointerToMemberType(State* state) {
|
||||||
State copy = *state;
|
State copy = *state;
|
||||||
if (ParseOneCharToken(state, 'M') && ParseType(state) &&
|
if (ParseOneCharToken(state, 'M') && ParseType(state) && ParseType(state)) {
|
||||||
ParseType(state)) {
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
*state = copy;
|
*state = copy;
|
||||||
@ -1068,20 +1040,17 @@ static bool ParseTemplateParam(State *state) {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// <template-template-param> ::= <template-param>
|
// <template-template-param> ::= <template-param>
|
||||||
// ::= <substitution>
|
// ::= <substitution>
|
||||||
static bool ParseTemplateTemplateParam(State* state) {
|
static bool ParseTemplateTemplateParam(State* state) {
|
||||||
return (ParseTemplateParam(state) ||
|
return (ParseTemplateParam(state) || ParseSubstitution(state));
|
||||||
ParseSubstitution(state));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// <template-args> ::= I <template-arg>+ E
|
// <template-args> ::= I <template-arg>+ E
|
||||||
static bool ParseTemplateArgs(State* state) {
|
static bool ParseTemplateArgs(State* state) {
|
||||||
State copy = *state;
|
State copy = *state;
|
||||||
DisableAppend(state);
|
DisableAppend(state);
|
||||||
if (ParseOneCharToken(state, 'I') &&
|
if (ParseOneCharToken(state, 'I') && OneOrMore(ParseTemplateArg, state) &&
|
||||||
OneOrMore(ParseTemplateArg, state) &&
|
|
||||||
ParseOneCharToken(state, 'E')) {
|
ParseOneCharToken(state, 'E')) {
|
||||||
RestoreAppend(state, copy.append);
|
RestoreAppend(state, copy.append);
|
||||||
MaybeAppend(state, "<>");
|
MaybeAppend(state, "<>");
|
||||||
@ -1107,15 +1076,13 @@ static bool ParseTemplateArg(State *state) {
|
|||||||
|
|
||||||
State copy = *state;
|
State copy = *state;
|
||||||
if ((ParseOneCharToken(state, 'I') || ParseOneCharToken(state, 'J')) &&
|
if ((ParseOneCharToken(state, 'I') || ParseOneCharToken(state, 'J')) &&
|
||||||
ZeroOrMore(ParseTemplateArg, state) &&
|
ZeroOrMore(ParseTemplateArg, state) && ParseOneCharToken(state, 'E')) {
|
||||||
ParseOneCharToken(state, 'E')) {
|
|
||||||
--state->arg_level;
|
--state->arg_level;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
*state = copy;
|
*state = copy;
|
||||||
|
|
||||||
if (ParseType(state) ||
|
if (ParseType(state) || ParseExprPrimary(state)) {
|
||||||
ParseExprPrimary(state)) {
|
|
||||||
--state->arg_level;
|
--state->arg_level;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -1153,25 +1120,21 @@ static bool ParseExpression(State *state) {
|
|||||||
++state->expr_level;
|
++state->expr_level;
|
||||||
|
|
||||||
State copy = *state;
|
State copy = *state;
|
||||||
if (ParseOperatorName(state) &&
|
if (ParseOperatorName(state) && ParseExpression(state) &&
|
||||||
ParseExpression(state) &&
|
ParseExpression(state) && ParseExpression(state)) {
|
||||||
ParseExpression(state) &&
|
--state->expr_level;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
*state = copy;
|
||||||
|
|
||||||
|
if (ParseOperatorName(state) && ParseExpression(state) &&
|
||||||
ParseExpression(state)) {
|
ParseExpression(state)) {
|
||||||
--state->expr_level;
|
--state->expr_level;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
*state = copy;
|
*state = copy;
|
||||||
|
|
||||||
if (ParseOperatorName(state) &&
|
if (ParseOperatorName(state) && ParseExpression(state)) {
|
||||||
ParseExpression(state) &&
|
|
||||||
ParseExpression(state)) {
|
|
||||||
--state->expr_level;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
*state = copy;
|
|
||||||
|
|
||||||
if (ParseOperatorName(state) &&
|
|
||||||
ParseExpression(state)) {
|
|
||||||
--state->expr_level;
|
--state->expr_level;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -1184,8 +1147,7 @@ static bool ParseExpression(State *state) {
|
|||||||
*state = copy;
|
*state = copy;
|
||||||
|
|
||||||
if (ParseTwoCharToken(state, "sr") && ParseType(state) &&
|
if (ParseTwoCharToken(state, "sr") && ParseType(state) &&
|
||||||
ParseUnqualifiedName(state) &&
|
ParseUnqualifiedName(state) && ParseTemplateArgs(state)) {
|
||||||
ParseTemplateArgs(state)) {
|
|
||||||
--state->expr_level;
|
--state->expr_level;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -1214,8 +1176,7 @@ static bool ParseExprPrimary(State *state) {
|
|||||||
*state = copy;
|
*state = copy;
|
||||||
|
|
||||||
if (ParseOneCharToken(state, 'L') && ParseType(state) &&
|
if (ParseOneCharToken(state, 'L') && ParseType(state) &&
|
||||||
ParseFloatNumber(state) &&
|
ParseFloatNumber(state) && ParseOneCharToken(state, 'E')) {
|
||||||
ParseOneCharToken(state, 'E')) {
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
*state = copy;
|
*state = copy;
|
||||||
|
|||||||
@ -67,14 +67,11 @@ static const char *DemangleIt(const char * const mangled) {
|
|||||||
|
|
||||||
# if defined(HAVE_DBGHELP) && !defined(NDEBUG)
|
# if defined(HAVE_DBGHELP) && !defined(NDEBUG)
|
||||||
TEST(Demangle, Windows) {
|
TEST(Demangle, Windows) {
|
||||||
EXPECT_STREQ(
|
EXPECT_STREQ("public: static void __cdecl Foo::func(int)",
|
||||||
"public: static void __cdecl Foo::func(int)",
|
|
||||||
DemangleIt("?func@Foo@@SAXH@Z"));
|
DemangleIt("?func@Foo@@SAXH@Z"));
|
||||||
EXPECT_STREQ(
|
EXPECT_STREQ("public: static void __cdecl Foo::func(int)",
|
||||||
"public: static void __cdecl Foo::func(int)",
|
|
||||||
DemangleIt("@ILT+1105(?func@Foo@@SAXH@Z)"));
|
DemangleIt("@ILT+1105(?func@Foo@@SAXH@Z)"));
|
||||||
EXPECT_STREQ(
|
EXPECT_STREQ("int __cdecl foobarArray(int * const)",
|
||||||
"int __cdecl foobarArray(int * const)",
|
|
||||||
DemangleIt("?foobarArray@@YAHQAH@Z"));
|
DemangleIt("?foobarArray@@YAHQAH@Z"));
|
||||||
}
|
}
|
||||||
# endif
|
# endif
|
||||||
|
|||||||
@ -56,8 +56,8 @@ const int GLOG_INFO = 0, GLOG_WARNING = 1, GLOG_ERROR = 2, GLOG_FATAL = 3,
|
|||||||
# ifdef ERROR
|
# ifdef ERROR
|
||||||
# error ERROR macro is defined. Define GLOG_NO_ABBREVIATED_SEVERITIES before including logging.h. See the document for detail.
|
# error ERROR macro is defined. Define GLOG_NO_ABBREVIATED_SEVERITIES before including logging.h. See the document for detail.
|
||||||
# endif
|
# endif
|
||||||
const int INFO = GLOG_INFO, WARNING = GLOG_WARNING,
|
const int INFO = GLOG_INFO, WARNING = GLOG_WARNING, ERROR = GLOG_ERROR,
|
||||||
ERROR = GLOG_ERROR, FATAL = GLOG_FATAL;
|
FATAL = GLOG_FATAL;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// DFATAL is FATAL in debug mode, ERROR in normal mode
|
// DFATAL is FATAL in debug mode, ERROR in normal mode
|
||||||
|
|||||||
@ -404,7 +404,8 @@ typedef void (*CustomPrefixCallback)(std::ostream& s, const LogMessageInfo& l,
|
|||||||
|
|
||||||
# if !defined(DECLARE_uint32)
|
# if !defined(DECLARE_uint32)
|
||||||
// uint32 specialization
|
// uint32 specialization
|
||||||
#define DECLARE_uint32(name) DECLARE_VARIABLE(google::uint32, U, name, uint32)
|
# define DECLARE_uint32(name) \
|
||||||
|
DECLARE_VARIABLE(google::uint32, U, name, uint32)
|
||||||
# endif // !defined(DECLARE_uint32) && !defined(GLOG_USE_GFLAGS)
|
# endif // !defined(DECLARE_uint32) && !defined(GLOG_USE_GFLAGS)
|
||||||
|
|
||||||
// Special case for string, because we have to specify the namespace
|
// Special case for string, because we have to specify the namespace
|
||||||
|
|||||||
@ -79,7 +79,8 @@
|
|||||||
__FILE__, __LINE__, &vlocal__, sizeof(google::SiteFlag), "")); \
|
__FILE__, __LINE__, &vlocal__, sizeof(google::SiteFlag), "")); \
|
||||||
google::int32 verbose_level__ = (verboselevel); \
|
google::int32 verbose_level__ = (verboselevel); \
|
||||||
(vlocal__.level == nullptr \
|
(vlocal__.level == nullptr \
|
||||||
? google::InitVLOG3__(&vlocal__, &FLAGS_v, __FILE__, verbose_level__) \
|
? google::InitVLOG3__(&vlocal__, &FLAGS_v, __FILE__, \
|
||||||
|
verbose_level__) \
|
||||||
: *vlocal__.level >= verbose_level__); \
|
: *vlocal__.level >= verbose_level__); \
|
||||||
})
|
})
|
||||||
#else
|
#else
|
||||||
|
|||||||
@ -130,8 +130,8 @@ void InitGoogleTest(int*, char**) {}
|
|||||||
# define EXPECT_NEAR(val1, val2, abs_error) \
|
# define EXPECT_NEAR(val1, val2, abs_error) \
|
||||||
do { \
|
do { \
|
||||||
if (abs(val1 - val2) > abs_error) { \
|
if (abs(val1 - val2) > abs_error) { \
|
||||||
fprintf(stderr, "Check failed: %s within %s of %s\n", #val1, #abs_error, \
|
fprintf(stderr, "Check failed: %s within %s of %s\n", #val1, \
|
||||||
#val2); \
|
#abs_error, #val2); \
|
||||||
exit(EXIT_FAILURE); \
|
exit(EXIT_FAILURE); \
|
||||||
} \
|
} \
|
||||||
} while (0)
|
} while (0)
|
||||||
@ -196,13 +196,15 @@ vector<void (*)()> g_testlist; // the tests to run
|
|||||||
# define TEST(a, b) \
|
# define TEST(a, b) \
|
||||||
struct Test_##a##_##b { \
|
struct Test_##a##_##b { \
|
||||||
Test_##a##_##b() { g_testlist.push_back(&Run); } \
|
Test_##a##_##b() { g_testlist.push_back(&Run); } \
|
||||||
static void Run() { FlagSaver fs; RunTest(); } \
|
static void Run() { \
|
||||||
|
FlagSaver fs; \
|
||||||
|
RunTest(); \
|
||||||
|
} \
|
||||||
static void RunTest(); \
|
static void RunTest(); \
|
||||||
}; \
|
}; \
|
||||||
static Test_##a##_##b g_test_##a##_##b; \
|
static Test_##a##_##b g_test_##a##_##b; \
|
||||||
void Test_##a##_##b::RunTest()
|
void Test_##a##_##b::RunTest()
|
||||||
|
|
||||||
|
|
||||||
static inline int RUN_ALL_TESTS() {
|
static inline int RUN_ALL_TESTS() {
|
||||||
vector<void (*)()>::const_iterator it;
|
vector<void (*)()>::const_iterator it;
|
||||||
for (it = g_testlist.begin(); it != g_testlist.end(); ++it) {
|
for (it = g_testlist.begin(); it != g_testlist.end(); ++it) {
|
||||||
@ -317,8 +319,7 @@ class CapturedStream {
|
|||||||
CHECK(uncaptured_fd_ != -1);
|
CHECK(uncaptured_fd_ != -1);
|
||||||
|
|
||||||
// Open file to save stream to
|
// Open file to save stream to
|
||||||
int cap_fd = open(filename_.c_str(),
|
int cap_fd = open(filename_.c_str(), O_CREAT | O_TRUNC | O_WRONLY,
|
||||||
O_CREAT | O_TRUNC | O_WRONLY,
|
|
||||||
S_IRUSR | S_IWUSR);
|
S_IRUSR | S_IWUSR);
|
||||||
CHECK(cap_fd != -1);
|
CHECK(cap_fd != -1);
|
||||||
|
|
||||||
@ -377,7 +378,8 @@ static inline string ReadEntireFile(FILE * file) {
|
|||||||
// Keep reading the file until we cannot read further or the
|
// Keep reading the file until we cannot read further or the
|
||||||
// pre-determined file size is reached.
|
// pre-determined file size is reached.
|
||||||
do {
|
do {
|
||||||
bytes_last_read = fread(buffer+bytes_read, 1, file_size-bytes_read, file);
|
bytes_last_read =
|
||||||
|
fread(buffer + bytes_read, 1, file_size - bytes_read, file);
|
||||||
bytes_read += bytes_last_read;
|
bytes_read += bytes_last_read;
|
||||||
} while (bytes_last_read > 0 && bytes_read < file_size);
|
} while (bytes_last_read > 0 && bytes_read < file_size);
|
||||||
|
|
||||||
@ -391,8 +393,7 @@ static inline string ReadEntireFile(FILE * file) {
|
|||||||
static inline string GetCapturedTestOutput(int fd) {
|
static inline string GetCapturedTestOutput(int fd) {
|
||||||
CHECK(fd == STDOUT_FILENO || fd == STDERR_FILENO);
|
CHECK(fd == STDOUT_FILENO || fd == STDERR_FILENO);
|
||||||
CapturedStream* const cap = s_captured_streams[fd];
|
CapturedStream* const cap = s_captured_streams[fd];
|
||||||
CHECK(cap)
|
CHECK(cap) << ": did you forget CaptureTestStdout() or CaptureTestStderr()?";
|
||||||
<< ": did you forget CaptureTestStdout() or CaptureTestStderr()?";
|
|
||||||
|
|
||||||
// Make sure everything is flushed.
|
// Make sure everything is flushed.
|
||||||
cap->StopCapture();
|
cap->StopCapture();
|
||||||
@ -468,8 +469,7 @@ static inline string MungeLine(const string& line) {
|
|||||||
MungeLine(rest));
|
MungeLine(rest));
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void StringReplace(string* str,
|
static inline void StringReplace(string* str, const string& oldsub,
|
||||||
const string& oldsub,
|
|
||||||
const string& newsub) {
|
const string& newsub) {
|
||||||
size_t pos = str->find(oldsub);
|
size_t pos = str->find(oldsub);
|
||||||
if (pos != string::npos) {
|
if (pos != string::npos) {
|
||||||
@ -589,9 +589,7 @@ class Thread {
|
|||||||
handle_ = CreateThread(nullptr, 0, &Thread::InvokeThreadW, this, 0, &th_);
|
handle_ = CreateThread(nullptr, 0, &Thread::InvokeThreadW, this, 0, &th_);
|
||||||
CHECK(handle_) << "CreateThread";
|
CHECK(handle_) << "CreateThread";
|
||||||
}
|
}
|
||||||
void Join() {
|
void Join() { WaitForSingleObject(handle_, INFINITE); }
|
||||||
WaitForSingleObject(handle_, INFINITE);
|
|
||||||
}
|
|
||||||
#elif defined(HAVE_PTHREAD)
|
#elif defined(HAVE_PTHREAD)
|
||||||
void Start() { pthread_create(&th_, nullptr, &Thread::InvokeThread, this); }
|
void Start() { pthread_create(&th_, nullptr, &Thread::InvokeThread, this); }
|
||||||
void Join() { pthread_join(th_, nullptr); }
|
void Join() { pthread_join(th_, nullptr); }
|
||||||
|
|||||||
432
src/logging.cc
432
src/logging.cc
@ -97,21 +97,21 @@
|
|||||||
typedef int mode_t;
|
typedef int mode_t;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
using std::string;
|
|
||||||
using std::vector;
|
|
||||||
using std::setw;
|
|
||||||
using std::setfill;
|
|
||||||
using std::hex;
|
|
||||||
using std::dec;
|
using std::dec;
|
||||||
|
using std::hex;
|
||||||
using std::min;
|
using std::min;
|
||||||
using std::ostream;
|
using std::ostream;
|
||||||
using std::ostringstream;
|
using std::ostringstream;
|
||||||
|
using std::setfill;
|
||||||
|
using std::setw;
|
||||||
|
using std::string;
|
||||||
|
using std::vector;
|
||||||
|
|
||||||
using std::FILE;
|
|
||||||
using std::fwrite;
|
|
||||||
using std::fclose;
|
using std::fclose;
|
||||||
using std::fflush;
|
using std::fflush;
|
||||||
|
using std::FILE;
|
||||||
using std::fprintf;
|
using std::fprintf;
|
||||||
|
using std::fwrite;
|
||||||
using std::perror;
|
using std::perror;
|
||||||
|
|
||||||
#ifdef __QNX__
|
#ifdef __QNX__
|
||||||
@ -147,7 +147,9 @@ GLOG_DEFINE_bool(colorlogtostdout, false,
|
|||||||
GLOG_DEFINE_bool(logtostdout, BoolFromEnv("GOOGLE_LOGTOSTDOUT", false),
|
GLOG_DEFINE_bool(logtostdout, BoolFromEnv("GOOGLE_LOGTOSTDOUT", false),
|
||||||
"log messages go to stdout instead of logfiles");
|
"log messages go to stdout instead of logfiles");
|
||||||
#ifdef GLOG_OS_LINUX
|
#ifdef GLOG_OS_LINUX
|
||||||
GLOG_DEFINE_bool(drop_log_memory, true, "Drop in-memory buffers of log contents. "
|
GLOG_DEFINE_bool(
|
||||||
|
drop_log_memory, true,
|
||||||
|
"Drop in-memory buffers of log contents. "
|
||||||
"Logs can grow very quickly and they are rarely read before they "
|
"Logs can grow very quickly and they are rarely read before they "
|
||||||
"need to be evicted from memory. Instead, drop them from memory "
|
"need to be evicted from memory. Instead, drop them from memory "
|
||||||
"as soon as they are flushed to disk.");
|
"as soon as they are flushed to disk.");
|
||||||
@ -171,7 +173,8 @@ GLOG_DEFINE_bool(log_prefix, true,
|
|||||||
"Prepend the log prefix to the start of each log line");
|
"Prepend the log prefix to the start of each log line");
|
||||||
GLOG_DEFINE_bool(log_year_in_prefix, true,
|
GLOG_DEFINE_bool(log_year_in_prefix, true,
|
||||||
"Include the year in the log prefix");
|
"Include the year in the log prefix");
|
||||||
GLOG_DEFINE_int32(minloglevel, 0, "Messages logged at a lower level than this don't "
|
GLOG_DEFINE_int32(minloglevel, 0,
|
||||||
|
"Messages logged at a lower level than this don't "
|
||||||
"actually get logged anywhere");
|
"actually get logged anywhere");
|
||||||
GLOG_DEFINE_int32(logbuflevel, 0,
|
GLOG_DEFINE_int32(logbuflevel, 0,
|
||||||
"Buffer log messages logged at this level or lower"
|
"Buffer log messages logged at this level or lower"
|
||||||
@ -187,8 +190,7 @@ GLOG_DEFINE_int32(logemaillevel, 999,
|
|||||||
"Email log messages logged at this level or higher"
|
"Email log messages logged at this level or higher"
|
||||||
" (0 means email all; 3 means email FATAL only;"
|
" (0 means email all; 3 means email FATAL only;"
|
||||||
" ...)");
|
" ...)");
|
||||||
GLOG_DEFINE_string(logmailer, "",
|
GLOG_DEFINE_string(logmailer, "", "Mailer used to send logging email");
|
||||||
"Mailer used to send logging email");
|
|
||||||
|
|
||||||
// Compute the default value for --log_dir
|
// Compute the default value for --log_dir
|
||||||
static const char* DefaultLogDir() {
|
static const char* DefaultLogDir() {
|
||||||
@ -206,10 +208,12 @@ static const char* DefaultLogDir() {
|
|||||||
|
|
||||||
GLOG_DEFINE_int32(logfile_mode, 0664, "Log file mode/permissions.");
|
GLOG_DEFINE_int32(logfile_mode, 0664, "Log file mode/permissions.");
|
||||||
|
|
||||||
GLOG_DEFINE_string(log_dir, DefaultLogDir(),
|
GLOG_DEFINE_string(
|
||||||
|
log_dir, DefaultLogDir(),
|
||||||
"If specified, logfiles are written into this directory instead "
|
"If specified, logfiles are written into this directory instead "
|
||||||
"of the default logging directory.");
|
"of the default logging directory.");
|
||||||
GLOG_DEFINE_string(log_link, "", "Put additional links to the log "
|
GLOG_DEFINE_string(log_link, "",
|
||||||
|
"Put additional links to the log "
|
||||||
"files in this directory");
|
"files in this directory");
|
||||||
|
|
||||||
GLOG_DEFINE_uint32(max_log_size, 1800,
|
GLOG_DEFINE_uint32(max_log_size, 1800,
|
||||||
@ -222,8 +226,7 @@ GLOG_DEFINE_bool(stop_logging_if_full_disk, false,
|
|||||||
GLOG_DEFINE_string(log_backtrace_at, "",
|
GLOG_DEFINE_string(log_backtrace_at, "",
|
||||||
"Emit a backtrace when logging at file:linenum.");
|
"Emit a backtrace when logging at file:linenum.");
|
||||||
|
|
||||||
GLOG_DEFINE_bool(log_utc_time, false,
|
GLOG_DEFINE_bool(log_utc_time, false, "Use UTC time for logging.");
|
||||||
"Use UTC time for logging.");
|
|
||||||
|
|
||||||
// TODO(hamaji): consider windows
|
// TODO(hamaji): consider windows
|
||||||
enum { PATH_SEPARATOR = '/' };
|
enum { PATH_SEPARATOR = '/' };
|
||||||
@ -231,15 +234,11 @@ enum { PATH_SEPARATOR = '/' };
|
|||||||
#ifndef HAVE_PREAD
|
#ifndef HAVE_PREAD
|
||||||
static ssize_t pread(int fd, void* buf, size_t count, off_t offset) {
|
static ssize_t pread(int fd, void* buf, size_t count, off_t offset) {
|
||||||
off_t orig_offset = lseek(fd, 0, SEEK_CUR);
|
off_t orig_offset = lseek(fd, 0, SEEK_CUR);
|
||||||
if (orig_offset == (off_t)-1)
|
if (orig_offset == (off_t)-1) return -1;
|
||||||
return -1;
|
if (lseek(fd, offset, SEEK_CUR) == (off_t)-1) return -1;
|
||||||
if (lseek(fd, offset, SEEK_CUR) == (off_t)-1)
|
|
||||||
return -1;
|
|
||||||
ssize_t len = read(fd, buf, count);
|
ssize_t len = read(fd, buf, count);
|
||||||
if (len < 0)
|
if (len < 0) return len;
|
||||||
return len;
|
if (lseek(fd, orig_offset, SEEK_SET) == (off_t)-1) return -1;
|
||||||
if (lseek(fd, orig_offset, SEEK_SET) == (off_t)-1)
|
|
||||||
return -1;
|
|
||||||
return len;
|
return len;
|
||||||
}
|
}
|
||||||
#endif // !HAVE_PREAD
|
#endif // !HAVE_PREAD
|
||||||
@ -247,15 +246,11 @@ static ssize_t pread(int fd, void* buf, size_t count, off_t offset) {
|
|||||||
#ifndef HAVE_PWRITE
|
#ifndef HAVE_PWRITE
|
||||||
static ssize_t pwrite(int fd, void* buf, size_t count, off_t offset) {
|
static ssize_t pwrite(int fd, void* buf, size_t count, off_t offset) {
|
||||||
off_t orig_offset = lseek(fd, 0, SEEK_CUR);
|
off_t orig_offset = lseek(fd, 0, SEEK_CUR);
|
||||||
if (orig_offset == (off_t)-1)
|
if (orig_offset == (off_t)-1) return -1;
|
||||||
return -1;
|
if (lseek(fd, offset, SEEK_CUR) == (off_t)-1) return -1;
|
||||||
if (lseek(fd, offset, SEEK_CUR) == (off_t)-1)
|
|
||||||
return -1;
|
|
||||||
ssize_t len = write(fd, buf, count);
|
ssize_t len = write(fd, buf, count);
|
||||||
if (len < 0)
|
if (len < 0) return len;
|
||||||
return len;
|
if (lseek(fd, orig_offset, SEEK_SET) == (off_t)-1) return -1;
|
||||||
if (lseek(fd, orig_offset, SEEK_SET) == (off_t)-1)
|
|
||||||
return -1;
|
|
||||||
return len;
|
return len;
|
||||||
}
|
}
|
||||||
#endif // !HAVE_PWRITE
|
#endif // !HAVE_PWRITE
|
||||||
@ -294,16 +289,11 @@ static bool TerminalSupportsColor() {
|
|||||||
const char* const term = getenv("TERM");
|
const char* const term = getenv("TERM");
|
||||||
if (term != nullptr && term[0] != '\0') {
|
if (term != nullptr && term[0] != '\0') {
|
||||||
term_supports_color =
|
term_supports_color =
|
||||||
!strcmp(term, "xterm") ||
|
!strcmp(term, "xterm") || !strcmp(term, "xterm-color") ||
|
||||||
!strcmp(term, "xterm-color") ||
|
!strcmp(term, "xterm-256color") || !strcmp(term, "screen-256color") ||
|
||||||
!strcmp(term, "xterm-256color") ||
|
!strcmp(term, "konsole") || !strcmp(term, "konsole-16color") ||
|
||||||
!strcmp(term, "screen-256color") ||
|
!strcmp(term, "konsole-256color") || !strcmp(term, "screen") ||
|
||||||
!strcmp(term, "konsole") ||
|
!strcmp(term, "linux") || !strcmp(term, "cygwin");
|
||||||
!strcmp(term, "konsole-16color") ||
|
|
||||||
!strcmp(term, "konsole-256color") ||
|
|
||||||
!strcmp(term, "screen") ||
|
|
||||||
!strcmp(term, "linux") ||
|
|
||||||
!strcmp(term, "cygwin");
|
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
return term_supports_color;
|
return term_supports_color;
|
||||||
@ -311,12 +301,7 @@ static bool TerminalSupportsColor() {
|
|||||||
|
|
||||||
namespace google {
|
namespace google {
|
||||||
|
|
||||||
enum GLogColor {
|
enum GLogColor { COLOR_DEFAULT, COLOR_RED, COLOR_GREEN, COLOR_YELLOW };
|
||||||
COLOR_DEFAULT,
|
|
||||||
COLOR_RED,
|
|
||||||
COLOR_GREEN,
|
|
||||||
COLOR_YELLOW
|
|
||||||
};
|
|
||||||
|
|
||||||
static GLogColor SeverityToColor(LogSeverity severity) {
|
static GLogColor SeverityToColor(LogSeverity severity) {
|
||||||
assert(severity >= 0 && severity < NUM_SEVERITIES);
|
assert(severity >= 0 && severity < NUM_SEVERITIES);
|
||||||
@ -344,10 +329,14 @@ static GLogColor SeverityToColor(LogSeverity severity) {
|
|||||||
// Returns the character attribute for the given color.
|
// Returns the character attribute for the given color.
|
||||||
static WORD GetColorAttribute(GLogColor color) {
|
static WORD GetColorAttribute(GLogColor color) {
|
||||||
switch (color) {
|
switch (color) {
|
||||||
case COLOR_RED: return FOREGROUND_RED;
|
case COLOR_RED:
|
||||||
case COLOR_GREEN: return FOREGROUND_GREEN;
|
return FOREGROUND_RED;
|
||||||
case COLOR_YELLOW: return FOREGROUND_RED | FOREGROUND_GREEN;
|
case COLOR_GREEN:
|
||||||
default: return 0;
|
return FOREGROUND_GREEN;
|
||||||
|
case COLOR_YELLOW:
|
||||||
|
return FOREGROUND_RED | FOREGROUND_GREEN;
|
||||||
|
default:
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -356,10 +345,14 @@ static WORD GetColorAttribute(GLogColor color) {
|
|||||||
// Returns the ANSI color code for the given color.
|
// Returns the ANSI color code for the given color.
|
||||||
static const char* GetAnsiColorCode(GLogColor color) {
|
static const char* GetAnsiColorCode(GLogColor color) {
|
||||||
switch (color) {
|
switch (color) {
|
||||||
case COLOR_RED: return "1";
|
case COLOR_RED:
|
||||||
case COLOR_GREEN: return "2";
|
return "1";
|
||||||
case COLOR_YELLOW: return "3";
|
case COLOR_GREEN:
|
||||||
case COLOR_DEFAULT: return "";
|
return "2";
|
||||||
|
case COLOR_YELLOW:
|
||||||
|
return "3";
|
||||||
|
case COLOR_DEFAULT:
|
||||||
|
return "";
|
||||||
};
|
};
|
||||||
return nullptr; // stop warning about return type.
|
return nullptr; // stop warning about return type.
|
||||||
}
|
}
|
||||||
@ -419,9 +412,8 @@ int64 LogMessage::num_messages_[NUM_SEVERITIES] = {0, 0, 0, 0};
|
|||||||
// Globally disable log writing (if disk is full)
|
// Globally disable log writing (if disk is full)
|
||||||
static bool stop_writing = false;
|
static bool stop_writing = false;
|
||||||
|
|
||||||
const char*const LogSeverityNames[NUM_SEVERITIES] = {
|
const char* const LogSeverityNames[NUM_SEVERITIES] = {"INFO", "WARNING",
|
||||||
"INFO", "WARNING", "ERROR", "FATAL"
|
"ERROR", "FATAL"};
|
||||||
};
|
|
||||||
|
|
||||||
// Has the user called SetExitOnDFatal(true)?
|
// Has the user called SetExitOnDFatal(true)?
|
||||||
static bool exit_on_dfatal = true;
|
static bool exit_on_dfatal = true;
|
||||||
@ -440,7 +432,7 @@ namespace {
|
|||||||
CustomPrefixCallback custom_prefix_callback = nullptr;
|
CustomPrefixCallback custom_prefix_callback = nullptr;
|
||||||
// User-provided data to pass to the callback:
|
// User-provided data to pass to the callback:
|
||||||
void* custom_prefix_callback_data = nullptr;
|
void* custom_prefix_callback_data = nullptr;
|
||||||
}
|
} // namespace
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
@ -509,8 +501,7 @@ class LogCleaner {
|
|||||||
// update next_cleanup_time_
|
// update next_cleanup_time_
|
||||||
void UpdateCleanUpTime();
|
void UpdateCleanUpTime();
|
||||||
|
|
||||||
void Run(bool base_filename_selected,
|
void Run(bool base_filename_selected, const string& base_filename,
|
||||||
const string& base_filename,
|
|
||||||
const string& filename_extension);
|
const string& filename_extension);
|
||||||
|
|
||||||
bool enabled() const { return enabled_; }
|
bool enabled() const { return enabled_; }
|
||||||
@ -545,8 +536,7 @@ class LogDestination {
|
|||||||
// These methods are just forwarded to by their global versions.
|
// These methods are just forwarded to by their global versions.
|
||||||
static void SetLogDestination(LogSeverity severity,
|
static void SetLogDestination(LogSeverity severity,
|
||||||
const char* base_filename);
|
const char* base_filename);
|
||||||
static void SetLogSymlink(LogSeverity severity,
|
static void SetLogSymlink(LogSeverity severity, const char* symlink_basename);
|
||||||
const char* symlink_basename);
|
|
||||||
static void AddLogSink(LogSink* destination);
|
static void AddLogSink(LogSink* destination);
|
||||||
static void RemoveLogSink(LogSink* destination);
|
static void RemoveLogSink(LogSink* destination);
|
||||||
static void SetLogFilenameExtension(const char* filename_extension);
|
static void SetLogFilenameExtension(const char* filename_extension);
|
||||||
@ -584,14 +574,12 @@ class LogDestination {
|
|||||||
size_t len);
|
size_t len);
|
||||||
// Take a log message of a particular severity and log it to a file
|
// Take a log message of a particular severity and log it to a file
|
||||||
// iff the base filename is not "" (which means "don't log to me")
|
// iff the base filename is not "" (which means "don't log to me")
|
||||||
static void MaybeLogToLogfile(LogSeverity severity,
|
static void MaybeLogToLogfile(LogSeverity severity, time_t timestamp,
|
||||||
time_t timestamp,
|
|
||||||
const char* message, size_t len);
|
const char* message, size_t len);
|
||||||
// Take a log message of a particular severity and log it to the file
|
// Take a log message of a particular severity and log it to the file
|
||||||
// for that severity and also for all files with severity less than
|
// for that severity and also for all files with severity less than
|
||||||
// this severity.
|
// this severity.
|
||||||
static void LogToAllLogfiles(LogSeverity severity,
|
static void LogToAllLogfiles(LogSeverity severity, time_t timestamp,
|
||||||
time_t timestamp,
|
|
||||||
const char* message, size_t len);
|
const char* message, size_t len);
|
||||||
|
|
||||||
// Send logging info to all registered sinks.
|
// Send logging info to all registered sinks.
|
||||||
@ -652,15 +640,10 @@ const string& LogDestination::hostname() {
|
|||||||
return hostname_;
|
return hostname_;
|
||||||
}
|
}
|
||||||
|
|
||||||
LogDestination::LogDestination(LogSeverity severity,
|
LogDestination::LogDestination(LogSeverity severity, const char* base_filename)
|
||||||
const char* base_filename)
|
: fileobject_(severity, base_filename), logger_(&fileobject_) {}
|
||||||
: fileobject_(severity, base_filename),
|
|
||||||
logger_(&fileobject_) {
|
|
||||||
}
|
|
||||||
|
|
||||||
LogDestination::~LogDestination() {
|
LogDestination::~LogDestination() { ResetLoggerImpl(); }
|
||||||
ResetLoggerImpl();
|
|
||||||
}
|
|
||||||
|
|
||||||
void LogDestination::SetLoggerImpl(base::Logger* logger) {
|
void LogDestination::SetLoggerImpl(base::Logger* logger) {
|
||||||
if (logger_ == logger) {
|
if (logger_ == logger) {
|
||||||
@ -731,7 +714,8 @@ inline void LogDestination::RemoveLogSink(LogSink *destination) {
|
|||||||
MutexLock l(&sink_mutex_);
|
MutexLock l(&sink_mutex_);
|
||||||
// This doesn't keep the sinks in order, but who cares?
|
// This doesn't keep the sinks in order, but who cares?
|
||||||
if (sinks_) {
|
if (sinks_) {
|
||||||
sinks_->erase(std::remove(sinks_->begin(), sinks_->end(), destination), sinks_->end());
|
sinks_->erase(std::remove(sinks_->begin(), sinks_->end(), destination),
|
||||||
|
sinks_->end());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -835,7 +819,9 @@ static void WriteToStderr(const char* message, size_t len) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
inline void LogDestination::MaybeLogToStderr(LogSeverity severity,
|
inline void LogDestination::MaybeLogToStderr(LogSeverity severity,
|
||||||
const char* message, size_t message_len, size_t prefix_len) {
|
const char* message,
|
||||||
|
size_t message_len,
|
||||||
|
size_t prefix_len) {
|
||||||
if ((severity >= FLAGS_stderrthreshold) || FLAGS_alsologtostderr) {
|
if ((severity >= FLAGS_stderrthreshold) || FLAGS_alsologtostderr) {
|
||||||
ColoredWriteToStderr(severity, message, message_len);
|
ColoredWriteToStderr(severity, message, message_len);
|
||||||
#ifdef GLOG_OS_WINDOWS
|
#ifdef GLOG_OS_WINDOWS
|
||||||
@ -859,11 +845,9 @@ inline void LogDestination::MaybeLogToStderr(LogSeverity severity,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
inline void LogDestination::MaybeLogToEmail(LogSeverity severity,
|
inline void LogDestination::MaybeLogToEmail(LogSeverity severity,
|
||||||
const char* message, size_t len) {
|
const char* message, size_t len) {
|
||||||
if (severity >= email_logging_severity_ ||
|
if (severity >= email_logging_severity_ || severity >= FLAGS_logemaillevel) {
|
||||||
severity >= FLAGS_logemaillevel) {
|
|
||||||
string to(FLAGS_alsologtoemail);
|
string to(FLAGS_alsologtoemail);
|
||||||
if (!addresses_.empty()) {
|
if (!addresses_.empty()) {
|
||||||
if (!to.empty()) {
|
if (!to.empty()) {
|
||||||
@ -871,7 +855,8 @@ inline void LogDestination::MaybeLogToEmail(LogSeverity severity,
|
|||||||
}
|
}
|
||||||
to += addresses_;
|
to += addresses_;
|
||||||
}
|
}
|
||||||
const string subject(string("[LOG] ") + LogSeverityNames[severity] + ": " +
|
const string subject(
|
||||||
|
string("[LOG] ") + LogSeverityNames[severity] + ": " +
|
||||||
glog_internal_namespace_::ProgramInvocationShortName());
|
glog_internal_namespace_::ProgramInvocationShortName());
|
||||||
string body(hostname());
|
string body(hostname());
|
||||||
body += "\n\n";
|
body += "\n\n";
|
||||||
@ -885,11 +870,9 @@ inline void LogDestination::MaybeLogToEmail(LogSeverity severity,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
inline void LogDestination::MaybeLogToLogfile(LogSeverity severity,
|
inline void LogDestination::MaybeLogToLogfile(LogSeverity severity,
|
||||||
time_t timestamp,
|
time_t timestamp,
|
||||||
const char* message,
|
const char* message, size_t len) {
|
||||||
size_t len) {
|
|
||||||
const bool should_flush = severity > FLAGS_logbuflevel;
|
const bool should_flush = severity > FLAGS_logbuflevel;
|
||||||
LogDestination* destination = log_destination(severity);
|
LogDestination* destination = log_destination(severity);
|
||||||
destination->logger_->Write(should_flush, timestamp, message, len);
|
destination->logger_->Write(should_flush, timestamp, message, len);
|
||||||
@ -897,8 +880,7 @@ inline void LogDestination::MaybeLogToLogfile(LogSeverity severity,
|
|||||||
|
|
||||||
inline void LogDestination::LogToAllLogfiles(LogSeverity severity,
|
inline void LogDestination::LogToAllLogfiles(LogSeverity severity,
|
||||||
time_t timestamp,
|
time_t timestamp,
|
||||||
const char* message,
|
const char* message, size_t len) {
|
||||||
size_t len) {
|
|
||||||
if (FLAGS_logtostdout) { // global flag: never log to file
|
if (FLAGS_logtostdout) { // global flag: never log to file
|
||||||
ColoredWriteToStdout(severity, message, len);
|
ColoredWriteToStdout(severity, message, len);
|
||||||
} else if (FLAGS_logtostderr) { // global flag: never log to file
|
} else if (FLAGS_logtostderr) { // global flag: never log to file
|
||||||
@ -919,8 +901,8 @@ inline void LogDestination::LogToSinks(LogSeverity severity,
|
|||||||
ReaderMutexLock l(&sink_mutex_);
|
ReaderMutexLock l(&sink_mutex_);
|
||||||
if (sinks_) {
|
if (sinks_) {
|
||||||
for (size_t i = sinks_->size(); i-- > 0;) {
|
for (size_t i = sinks_->size(); i-- > 0;) {
|
||||||
(*sinks_)[i]->send(severity, full_filename, base_filename,
|
(*sinks_)[i]->send(severity, full_filename, base_filename, line,
|
||||||
line, logmsgtime, message, message_len);
|
logmsgtime, message, message_len);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1056,8 +1038,8 @@ void LogFileObject::FlushUnlocked(){
|
|||||||
bytes_since_flush_ = 0;
|
bytes_since_flush_ = 0;
|
||||||
}
|
}
|
||||||
// Figure out when we are due for another flush.
|
// Figure out when we are due for another flush.
|
||||||
const int64 next = (FLAGS_logbufsecs
|
const int64 next =
|
||||||
* static_cast<int64>(1000000)); // in usec
|
(FLAGS_logbufsecs * static_cast<int64>(1000000)); // in usec
|
||||||
next_flush_time_ = CycleClock_Now() + UsecToCycles(next);
|
next_flush_time_ = CycleClock_Now() + UsecToCycles(next);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1109,13 +1091,14 @@ bool LogFileObject::CreateLogfile(const string& time_pid_string) {
|
|||||||
if (file_ == nullptr) { // Man, we're screwed!
|
if (file_ == nullptr) { // Man, we're screwed!
|
||||||
close(fd);
|
close(fd);
|
||||||
if (FLAGS_timestamp_in_logfile_name) {
|
if (FLAGS_timestamp_in_logfile_name) {
|
||||||
unlink(filename); // Erase the half-baked evidence: an unusable log file, only if we just created it.
|
unlink(filename); // Erase the half-baked evidence: an unusable log file,
|
||||||
|
// only if we just created it.
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
#ifdef GLOG_OS_WINDOWS
|
#ifdef GLOG_OS_WINDOWS
|
||||||
// https://github.com/golang/go/issues/27638 - make sure we seek to the end to append
|
// https://github.com/golang/go/issues/27638 - make sure we seek to the end to
|
||||||
// empirically replicated with wine over mingw build
|
// append empirically replicated with wine over mingw build
|
||||||
if (!FLAGS_timestamp_in_logfile_name) {
|
if (!FLAGS_timestamp_in_logfile_name) {
|
||||||
if (fseek(file_, 0, SEEK_END) != 0) {
|
if (fseek(file_, 0, SEEK_END) != 0) {
|
||||||
return false;
|
return false;
|
||||||
@ -1133,7 +1116,9 @@ bool LogFileObject::CreateLogfile(const string& time_pid_string) {
|
|||||||
const string linkname =
|
const string linkname =
|
||||||
symlink_basename_ + '.' + LogSeverityNames[severity_];
|
symlink_basename_ + '.' + LogSeverityNames[severity_];
|
||||||
string linkpath;
|
string linkpath;
|
||||||
if ( slash ) linkpath = string(filename, static_cast<size_t>(slash-filename+1)); // get dirname
|
if (slash)
|
||||||
|
linkpath = string(
|
||||||
|
filename, static_cast<size_t>(slash - filename + 1)); // get dirname
|
||||||
linkpath += linkname;
|
linkpath += linkname;
|
||||||
unlink(linkpath.c_str()); // delete old one if it exists
|
unlink(linkpath.c_str()); // delete old one if it exists
|
||||||
|
|
||||||
@ -1163,10 +1148,8 @@ bool LogFileObject::CreateLogfile(const string& time_pid_string) {
|
|||||||
return true; // Everything worked
|
return true; // Everything worked
|
||||||
}
|
}
|
||||||
|
|
||||||
void LogFileObject::Write(bool force_flush,
|
void LogFileObject::Write(bool force_flush, time_t timestamp,
|
||||||
time_t timestamp,
|
const char* message, size_t message_len) {
|
||||||
const char* message,
|
|
||||||
size_t message_len) {
|
|
||||||
MutexLock l(&lock_);
|
MutexLock l(&lock_);
|
||||||
|
|
||||||
// We don't log if the base_name_ is "" (which means "don't write")
|
// We don't log if the base_name_ is "" (which means "don't write")
|
||||||
@ -1199,15 +1182,10 @@ void LogFileObject::Write(bool force_flush,
|
|||||||
// The logfile's filename will have the date/time & pid in it
|
// The logfile's filename will have the date/time & pid in it
|
||||||
ostringstream time_pid_stream;
|
ostringstream time_pid_stream;
|
||||||
time_pid_stream.fill('0');
|
time_pid_stream.fill('0');
|
||||||
time_pid_stream << 1900+tm_time.tm_year
|
time_pid_stream << 1900 + tm_time.tm_year << setw(2) << 1 + tm_time.tm_mon
|
||||||
<< setw(2) << 1+tm_time.tm_mon
|
<< setw(2) << tm_time.tm_mday << '-' << setw(2)
|
||||||
<< setw(2) << tm_time.tm_mday
|
<< tm_time.tm_hour << setw(2) << tm_time.tm_min << setw(2)
|
||||||
<< '-'
|
<< tm_time.tm_sec << '.' << GetMainThreadPid();
|
||||||
<< setw(2) << tm_time.tm_hour
|
|
||||||
<< setw(2) << tm_time.tm_min
|
|
||||||
<< setw(2) << tm_time.tm_sec
|
|
||||||
<< '.'
|
|
||||||
<< GetMainThreadPid();
|
|
||||||
const string& time_pid_string = time_pid_stream.str();
|
const string& time_pid_string = time_pid_stream.str();
|
||||||
|
|
||||||
if (base_filename_selected_) {
|
if (base_filename_selected_) {
|
||||||
@ -1241,9 +1219,8 @@ void LogFileObject::Write(bool force_flush,
|
|||||||
// deadlock. Simply use a name like invalid-user.
|
// deadlock. Simply use a name like invalid-user.
|
||||||
if (uidname.empty()) uidname = "invalid-user";
|
if (uidname.empty()) uidname = "invalid-user";
|
||||||
|
|
||||||
stripped_filename = stripped_filename+'.'+hostname+'.'
|
stripped_filename = stripped_filename + '.' + hostname + '.' + uidname +
|
||||||
+uidname+".log."
|
".log." + LogSeverityNames[severity_] + '.';
|
||||||
+LogSeverityNames[severity_]+'.';
|
|
||||||
// We're going to (potentially) try to put logs in several different dirs
|
// We're going to (potentially) try to put logs in several different dirs
|
||||||
const vector<string>& log_dirs = GetLoggingDirectories();
|
const vector<string>& log_dirs = GetLoggingDirectories();
|
||||||
|
|
||||||
@ -1270,25 +1247,26 @@ void LogFileObject::Write(bool force_flush,
|
|||||||
if (FLAGS_log_file_header) {
|
if (FLAGS_log_file_header) {
|
||||||
ostringstream file_header_stream;
|
ostringstream file_header_stream;
|
||||||
file_header_stream.fill('0');
|
file_header_stream.fill('0');
|
||||||
file_header_stream << "Log file created at: "
|
file_header_stream << "Log file created at: " << 1900 + tm_time.tm_year
|
||||||
<< 1900+tm_time.tm_year << '/'
|
<< '/' << setw(2) << 1 + tm_time.tm_mon << '/'
|
||||||
<< setw(2) << 1+tm_time.tm_mon << '/'
|
<< setw(2) << tm_time.tm_mday << ' ' << setw(2)
|
||||||
<< setw(2) << tm_time.tm_mday
|
<< tm_time.tm_hour << ':' << setw(2) << tm_time.tm_min
|
||||||
<< ' '
|
<< ':' << setw(2) << tm_time.tm_sec
|
||||||
<< setw(2) << tm_time.tm_hour << ':'
|
<< (FLAGS_log_utc_time ? " UTC\n" : "\n")
|
||||||
<< setw(2) << tm_time.tm_min << ':'
|
<< "Running on machine: " << LogDestination::hostname()
|
||||||
<< setw(2) << tm_time.tm_sec << (FLAGS_log_utc_time ? " UTC\n" : "\n")
|
<< '\n';
|
||||||
<< "Running on machine: "
|
|
||||||
<< LogDestination::hostname() << '\n';
|
|
||||||
|
|
||||||
if (!g_application_fingerprint.empty()) {
|
if (!g_application_fingerprint.empty()) {
|
||||||
file_header_stream << "Application fingerprint: " << g_application_fingerprint << '\n';
|
file_header_stream << "Application fingerprint: "
|
||||||
|
<< g_application_fingerprint << '\n';
|
||||||
}
|
}
|
||||||
const char* const date_time_format = FLAGS_log_year_in_prefix
|
const char* const date_time_format = FLAGS_log_year_in_prefix
|
||||||
? "yyyymmdd hh:mm:ss.uuuuuu"
|
? "yyyymmdd hh:mm:ss.uuuuuu"
|
||||||
: "mmdd hh:mm:ss.uuuuuu";
|
: "mmdd hh:mm:ss.uuuuuu";
|
||||||
file_header_stream << "Running duration (h:mm:ss): "
|
file_header_stream << "Running duration (h:mm:ss): "
|
||||||
<< PrettyDuration(static_cast<int>(WallTime_Now() - start_time_)) << '\n'
|
<< PrettyDuration(
|
||||||
|
static_cast<int>(WallTime_Now() - start_time_))
|
||||||
|
<< '\n'
|
||||||
<< "Log line format: [IWEF]" << date_time_format << " "
|
<< "Log line format: [IWEF]" << date_time_format << " "
|
||||||
<< "threadid file:line] msg" << '\n';
|
<< "threadid file:line] msg" << '\n';
|
||||||
const string& file_header_string = file_header_stream.str();
|
const string& file_header_string = file_header_stream.str();
|
||||||
@ -1326,8 +1304,7 @@ void LogFileObject::Write(bool force_flush,
|
|||||||
|
|
||||||
// See important msgs *now*. Also, flush logs at least every 10^6 chars,
|
// See important msgs *now*. Also, flush logs at least every 10^6 chars,
|
||||||
// or every "FLAGS_logbufsecs" seconds.
|
// or every "FLAGS_logbufsecs" seconds.
|
||||||
if ( force_flush ||
|
if (force_flush || (bytes_since_flush_ >= 1000000) ||
|
||||||
(bytes_since_flush_ >= 1000000) ||
|
|
||||||
(CycleClock_Now() >= next_flush_time_)) {
|
(CycleClock_Now() >= next_flush_time_)) {
|
||||||
FlushUnlocked();
|
FlushUnlocked();
|
||||||
#ifdef GLOG_OS_LINUX
|
#ifdef GLOG_OS_LINUX
|
||||||
@ -1355,8 +1332,7 @@ void LogFileObject::Write(bool force_flush,
|
|||||||
|
|
||||||
// Remove old logs
|
// Remove old logs
|
||||||
if (log_cleaner.enabled()) {
|
if (log_cleaner.enabled()) {
|
||||||
log_cleaner.Run(base_filename_selected_,
|
log_cleaner.Run(base_filename_selected_, base_filename_,
|
||||||
base_filename_,
|
|
||||||
filename_extension_);
|
filename_extension_);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1369,18 +1345,14 @@ void LogCleaner::Enable(unsigned int overdue_days) {
|
|||||||
overdue_days_ = overdue_days;
|
overdue_days_ = overdue_days;
|
||||||
}
|
}
|
||||||
|
|
||||||
void LogCleaner::Disable() {
|
void LogCleaner::Disable() { enabled_ = false; }
|
||||||
enabled_ = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
void LogCleaner::UpdateCleanUpTime() {
|
void LogCleaner::UpdateCleanUpTime() {
|
||||||
const int64 next = (FLAGS_logcleansecs
|
const int64 next = (FLAGS_logcleansecs * 1000000); // in usec
|
||||||
* 1000000); // in usec
|
|
||||||
next_cleanup_time_ = CycleClock_Now() + UsecToCycles(next);
|
next_cleanup_time_ = CycleClock_Now() + UsecToCycles(next);
|
||||||
}
|
}
|
||||||
|
|
||||||
void LogCleaner::Run(bool base_filename_selected,
|
void LogCleaner::Run(bool base_filename_selected, const string& base_filename,
|
||||||
const string& base_filename,
|
|
||||||
const string& filename_extension) {
|
const string& filename_extension) {
|
||||||
assert(enabled_);
|
assert(enabled_);
|
||||||
assert(!base_filename_selected || !base_filename.empty());
|
assert(!base_filename_selected || !base_filename.empty());
|
||||||
@ -1441,7 +1413,8 @@ vector<string> LogCleaner::GetOverdueLogNames(
|
|||||||
filepath = log_directory + filepath;
|
filepath = log_directory + filepath;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (IsLogFromCurrentProject(filepath, base_filename, filename_extension) &&
|
if (IsLogFromCurrentProject(filepath, base_filename,
|
||||||
|
filename_extension) &&
|
||||||
IsLogLastModifiedOver(filepath, days)) {
|
IsLogLastModifiedOver(filepath, days)) {
|
||||||
overdue_log_names.push_back(filepath);
|
overdue_log_names.push_back(filepath);
|
||||||
}
|
}
|
||||||
@ -1452,8 +1425,8 @@ vector<string> LogCleaner::GetOverdueLogNames(
|
|||||||
return overdue_log_names;
|
return overdue_log_names;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool LogCleaner::IsLogFromCurrentProject(const string& filepath,
|
bool LogCleaner::IsLogFromCurrentProject(
|
||||||
const string& base_filename,
|
const string& filepath, const string& base_filename,
|
||||||
const string& filename_extension) const {
|
const string& filename_extension) const {
|
||||||
// We should remove duplicated delimiters from `base_filename`, e.g.,
|
// We should remove duplicated delimiters from `base_filename`, e.g.,
|
||||||
// before: "/tmp//<base_filename>.<create_time>.<pid>"
|
// before: "/tmp//<base_filename>.<create_time>.<pid>"
|
||||||
@ -1488,11 +1461,11 @@ bool LogCleaner::IsLogFromCurrentProject(const string& filepath,
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
// for origin version, `filename_extension` is middle of the `filepath`.
|
// for origin version, `filename_extension` is middle of the `filepath`.
|
||||||
string ext = filepath.substr(cleaned_base_filename.size(), filename_extension.size());
|
string ext = filepath.substr(cleaned_base_filename.size(),
|
||||||
|
filename_extension.size());
|
||||||
if (ext == filename_extension) {
|
if (ext == filename_extension) {
|
||||||
cleaned_base_filename += filename_extension;
|
cleaned_base_filename += filename_extension;
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
// for new version, `filename_extension` is right of the `filepath`.
|
// for new version, `filename_extension` is right of the `filepath`.
|
||||||
if (filename_extension.size() >= real_filepath_size) {
|
if (filename_extension.size() >= real_filepath_size) {
|
||||||
return false;
|
return false;
|
||||||
@ -1510,19 +1483,29 @@ bool LogCleaner::IsLogFromCurrentProject(const string& filepath,
|
|||||||
const char& c = filepath[i];
|
const char& c = filepath[i];
|
||||||
|
|
||||||
if (i <= cleaned_base_filename.size() + 7) { // 0 ~ 7 : YYYYMMDD
|
if (i <= cleaned_base_filename.size() + 7) { // 0 ~ 7 : YYYYMMDD
|
||||||
if (c < '0' || c > '9') { return false; }
|
if (c < '0' || c > '9') {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
} else if (i == cleaned_base_filename.size() + 8) { // 8: -
|
} else if (i == cleaned_base_filename.size() + 8) { // 8: -
|
||||||
if (c != '-') { return false; }
|
if (c != '-') {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
} else if (i <= cleaned_base_filename.size() + 14) { // 9 ~ 14: HHMMSS
|
} else if (i <= cleaned_base_filename.size() + 14) { // 9 ~ 14: HHMMSS
|
||||||
if (c < '0' || c > '9') { return false; }
|
if (c < '0' || c > '9') {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
} else if (i == cleaned_base_filename.size() + 15) { // 15: .
|
} else if (i == cleaned_base_filename.size() + 15) { // 15: .
|
||||||
if (c != '.') { return false; }
|
if (c != '.') {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
} else if (i >= cleaned_base_filename.size() + 16) { // 16+: pid
|
} else if (i >= cleaned_base_filename.size() + 16) { // 16+: pid
|
||||||
if (c < '0' || c > '9') { return false; }
|
if (c < '0' || c > '9') {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1577,8 +1560,7 @@ static thread_local std::aligned_storage<
|
|||||||
#endif // defined(GLOG_THREAD_LOCAL_STORAGE)
|
#endif // defined(GLOG_THREAD_LOCAL_STORAGE)
|
||||||
|
|
||||||
LogMessage::LogMessageData::LogMessageData()
|
LogMessage::LogMessageData::LogMessageData()
|
||||||
: stream_(message_text_, LogMessage::kMaxLogMessageLen, 0) {
|
: stream_(message_text_, LogMessage::kMaxLogMessageLen, 0) {}
|
||||||
}
|
|
||||||
|
|
||||||
LogMessage::LogMessage(const char* file, int line, LogSeverity severity,
|
LogMessage::LogMessage(const char* file, int line, LogSeverity severity,
|
||||||
int64 ctr, void (LogMessage::*send_method)())
|
int64 ctr, void (LogMessage::*send_method)())
|
||||||
@ -1605,8 +1587,9 @@ LogMessage::LogMessage(const char* file, int line, LogSeverity severity)
|
|||||||
LogMessage::LogMessage(const char* file, int line, LogSeverity severity,
|
LogMessage::LogMessage(const char* file, int line, LogSeverity severity,
|
||||||
LogSink* sink, bool also_send_to_log)
|
LogSink* sink, bool also_send_to_log)
|
||||||
: allocated_(nullptr) {
|
: allocated_(nullptr) {
|
||||||
Init(file, line, severity, also_send_to_log ? &LogMessage::SendToSinkAndLog :
|
Init(file, line, severity,
|
||||||
&LogMessage::SendToSink);
|
also_send_to_log ? &LogMessage::SendToSinkAndLog
|
||||||
|
: &LogMessage::SendToSink);
|
||||||
data_->sink_ = sink; // override Init()'s setting to nullptr
|
data_->sink_ = sink; // override Init()'s setting to nullptr
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1624,9 +1607,7 @@ LogMessage::LogMessage(const char* file, int line, LogSeverity severity,
|
|||||||
data_->message_ = message; // override Init()'s setting to nullptr
|
data_->message_ = message; // override Init()'s setting to nullptr
|
||||||
}
|
}
|
||||||
|
|
||||||
void LogMessage::Init(const char* file,
|
void LogMessage::Init(const char* file, int line, LogSeverity severity,
|
||||||
int line,
|
|
||||||
LogSeverity severity,
|
|
||||||
void (LogMessage::*send_method)()) {
|
void (LogMessage::*send_method)()) {
|
||||||
allocated_ = nullptr;
|
allocated_ = nullptr;
|
||||||
if (severity != GLOG_FATAL || !exit_on_dfatal) {
|
if (severity != GLOG_FATAL || !exit_on_dfatal) {
|
||||||
@ -1727,8 +1708,7 @@ LogMessage::~LogMessage() {
|
|||||||
if (data_ == static_cast<void*>(&thread_msg_data)) {
|
if (data_ == static_cast<void*>(&thread_msg_data)) {
|
||||||
data_->~LogMessageData();
|
data_->~LogMessageData();
|
||||||
thread_data_available = true;
|
thread_data_available = true;
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
delete allocated_;
|
delete allocated_;
|
||||||
}
|
}
|
||||||
#else // !defined(GLOG_THREAD_LOCAL_STORAGE)
|
#else // !defined(GLOG_THREAD_LOCAL_STORAGE)
|
||||||
@ -1736,13 +1716,9 @@ LogMessage::~LogMessage() {
|
|||||||
#endif // defined(GLOG_THREAD_LOCAL_STORAGE)
|
#endif // defined(GLOG_THREAD_LOCAL_STORAGE)
|
||||||
}
|
}
|
||||||
|
|
||||||
int LogMessage::preserved_errno() const {
|
int LogMessage::preserved_errno() const { return data_->preserved_errno_; }
|
||||||
return data_->preserved_errno_;
|
|
||||||
}
|
|
||||||
|
|
||||||
ostream& LogMessage::stream() {
|
ostream& LogMessage::stream() { return data_->stream_; }
|
||||||
return data_->stream_;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Flush buffered message, called by the destructor, or any other function
|
// Flush buffered message, called by the destructor, or any other function
|
||||||
// that needs to synchronize the log.
|
// that needs to synchronize the log.
|
||||||
@ -1824,12 +1800,14 @@ void LogMessage::SendToLog() EXCLUSIVE_LOCKS_REQUIRED(log_mutex) {
|
|||||||
log_mutex.AssertHeld();
|
log_mutex.AssertHeld();
|
||||||
|
|
||||||
RAW_DCHECK(data_->num_chars_to_log_ > 0 &&
|
RAW_DCHECK(data_->num_chars_to_log_ > 0 &&
|
||||||
data_->message_text_[data_->num_chars_to_log_-1] == '\n', "");
|
data_->message_text_[data_->num_chars_to_log_ - 1] == '\n',
|
||||||
|
"");
|
||||||
|
|
||||||
// Messages of a given severity get logged to lower severity logs, too
|
// Messages of a given severity get logged to lower severity logs, too
|
||||||
|
|
||||||
if (!already_warned_before_initgoogle && !IsGoogleLoggingInitialized()) {
|
if (!already_warned_before_initgoogle && !IsGoogleLoggingInitialized()) {
|
||||||
const char w[] = "WARNING: Logging before InitGoogleLogging() is "
|
const char w[] =
|
||||||
|
"WARNING: Logging before InitGoogleLogging() is "
|
||||||
"written to STDERR\n";
|
"written to STDERR\n";
|
||||||
WriteToStderr(w, strlen(w));
|
WriteToStderr(w, strlen(w));
|
||||||
already_warned_before_initgoogle = true;
|
already_warned_before_initgoogle = true;
|
||||||
@ -1848,12 +1826,10 @@ void LogMessage::SendToLog() EXCLUSIVE_LOCKS_REQUIRED(log_mutex) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// this could be protected by a flag if necessary.
|
// this could be protected by a flag if necessary.
|
||||||
LogDestination::LogToSinks(data_->severity_,
|
LogDestination::LogToSinks(
|
||||||
data_->fullname_, data_->basename_,
|
data_->severity_, data_->fullname_, data_->basename_, data_->line_,
|
||||||
data_->line_, logmsgtime_,
|
logmsgtime_, data_->message_text_ + data_->num_prefix_chars_,
|
||||||
data_->message_text_ + data_->num_prefix_chars_,
|
(data_->num_chars_to_log_ - data_->num_prefix_chars_ - 1));
|
||||||
(data_->num_chars_to_log_ -
|
|
||||||
data_->num_prefix_chars_ - 1) );
|
|
||||||
} else {
|
} else {
|
||||||
// log this message to all log files of severity <= severity_
|
// log this message to all log files of severity <= severity_
|
||||||
LogDestination::LogToAllLogfiles(data_->severity_, logmsgtime_.timestamp(),
|
LogDestination::LogToAllLogfiles(data_->severity_, logmsgtime_.timestamp(),
|
||||||
@ -1865,12 +1841,10 @@ void LogMessage::SendToLog() EXCLUSIVE_LOCKS_REQUIRED(log_mutex) {
|
|||||||
data_->num_prefix_chars_);
|
data_->num_prefix_chars_);
|
||||||
LogDestination::MaybeLogToEmail(data_->severity_, data_->message_text_,
|
LogDestination::MaybeLogToEmail(data_->severity_, data_->message_text_,
|
||||||
data_->num_chars_to_log_);
|
data_->num_chars_to_log_);
|
||||||
LogDestination::LogToSinks(data_->severity_,
|
LogDestination::LogToSinks(
|
||||||
data_->fullname_, data_->basename_,
|
data_->severity_, data_->fullname_, data_->basename_, data_->line_,
|
||||||
data_->line_, logmsgtime_,
|
logmsgtime_, data_->message_text_ + data_->num_prefix_chars_,
|
||||||
data_->message_text_ + data_->num_prefix_chars_,
|
(data_->num_chars_to_log_ - data_->num_prefix_chars_ - 1));
|
||||||
(data_->num_chars_to_log_
|
|
||||||
- data_->num_prefix_chars_ - 1) );
|
|
||||||
// NOTE: -1 removes trailing \n
|
// NOTE: -1 removes trailing \n
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1885,8 +1859,8 @@ void LogMessage::SendToLog() EXCLUSIVE_LOCKS_REQUIRED(log_mutex) {
|
|||||||
SetCrashReason(&crash_reason);
|
SetCrashReason(&crash_reason);
|
||||||
|
|
||||||
// Store shortened fatal message for other logs and GWQ status
|
// Store shortened fatal message for other logs and GWQ status
|
||||||
const size_t copy = min(data_->num_chars_to_log_,
|
const size_t copy =
|
||||||
sizeof(fatal_message)-1);
|
min(data_->num_chars_to_log_, sizeof(fatal_message) - 1);
|
||||||
memcpy(fatal_message, data_->message_text_, copy);
|
memcpy(fatal_message, data_->message_text_, copy);
|
||||||
fatal_message[copy] = '\0';
|
fatal_message[copy] = '\0';
|
||||||
fatal_time = logmsgtime_.timestamp();
|
fatal_time = logmsgtime_.timestamp();
|
||||||
@ -1955,20 +1929,18 @@ void InstallFailureFunction(logging_fail_func_t fail_func) {
|
|||||||
g_logging_fail_func = fail_func;
|
g_logging_fail_func = fail_func;
|
||||||
}
|
}
|
||||||
|
|
||||||
void LogMessage::Fail() {
|
void LogMessage::Fail() { g_logging_fail_func(); }
|
||||||
g_logging_fail_func();
|
|
||||||
}
|
|
||||||
|
|
||||||
// L >= log_mutex (callers must hold the log_mutex).
|
// L >= log_mutex (callers must hold the log_mutex).
|
||||||
void LogMessage::SendToSink() EXCLUSIVE_LOCKS_REQUIRED(log_mutex) {
|
void LogMessage::SendToSink() EXCLUSIVE_LOCKS_REQUIRED(log_mutex) {
|
||||||
if (data_->sink_ != nullptr) {
|
if (data_->sink_ != nullptr) {
|
||||||
RAW_DCHECK(data_->num_chars_to_log_ > 0 &&
|
RAW_DCHECK(data_->num_chars_to_log_ > 0 &&
|
||||||
data_->message_text_[data_->num_chars_to_log_-1] == '\n', "");
|
data_->message_text_[data_->num_chars_to_log_ - 1] == '\n',
|
||||||
data_->sink_->send(data_->severity_, data_->fullname_, data_->basename_,
|
"");
|
||||||
data_->line_, logmsgtime_,
|
data_->sink_->send(
|
||||||
data_->message_text_ + data_->num_prefix_chars_,
|
data_->severity_, data_->fullname_, data_->basename_, data_->line_,
|
||||||
(data_->num_chars_to_log_ -
|
logmsgtime_, data_->message_text_ + data_->num_prefix_chars_,
|
||||||
data_->num_prefix_chars_ - 1) );
|
(data_->num_chars_to_log_ - data_->num_prefix_chars_ - 1));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1982,7 +1954,8 @@ void LogMessage::SendToSinkAndLog() EXCLUSIVE_LOCKS_REQUIRED(log_mutex) {
|
|||||||
void LogMessage::SaveOrSendToLog() EXCLUSIVE_LOCKS_REQUIRED(log_mutex) {
|
void LogMessage::SaveOrSendToLog() EXCLUSIVE_LOCKS_REQUIRED(log_mutex) {
|
||||||
if (data_->outvec_ != nullptr) {
|
if (data_->outvec_ != nullptr) {
|
||||||
RAW_DCHECK(data_->num_chars_to_log_ > 0 &&
|
RAW_DCHECK(data_->num_chars_to_log_ > 0 &&
|
||||||
data_->message_text_[data_->num_chars_to_log_-1] == '\n', "");
|
data_->message_text_[data_->num_chars_to_log_ - 1] == '\n',
|
||||||
|
"");
|
||||||
// Omit prefix of message and trailing newline when recording in outvec_.
|
// Omit prefix of message and trailing newline when recording in outvec_.
|
||||||
const char* start = data_->message_text_ + data_->num_prefix_chars_;
|
const char* start = data_->message_text_ + data_->num_prefix_chars_;
|
||||||
size_t len = data_->num_chars_to_log_ - data_->num_prefix_chars_ - 1;
|
size_t len = data_->num_chars_to_log_ - data_->num_prefix_chars_ - 1;
|
||||||
@ -1995,7 +1968,8 @@ void LogMessage::SaveOrSendToLog() EXCLUSIVE_LOCKS_REQUIRED(log_mutex) {
|
|||||||
void LogMessage::WriteToStringAndLog() EXCLUSIVE_LOCKS_REQUIRED(log_mutex) {
|
void LogMessage::WriteToStringAndLog() EXCLUSIVE_LOCKS_REQUIRED(log_mutex) {
|
||||||
if (data_->message_ != nullptr) {
|
if (data_->message_ != nullptr) {
|
||||||
RAW_DCHECK(data_->num_chars_to_log_ > 0 &&
|
RAW_DCHECK(data_->num_chars_to_log_ > 0 &&
|
||||||
data_->message_text_[data_->num_chars_to_log_-1] == '\n', "");
|
data_->message_text_[data_->num_chars_to_log_ - 1] == '\n',
|
||||||
|
"");
|
||||||
// Omit prefix of message and trailing newline when writing to message_.
|
// Omit prefix of message and trailing newline when writing to message_.
|
||||||
const char* start = data_->message_text_ + data_->num_prefix_chars_;
|
const char* start = data_->message_text_ + data_->num_prefix_chars_;
|
||||||
size_t len = data_->num_chars_to_log_ - data_->num_prefix_chars_ - 1;
|
size_t len = data_->num_chars_to_log_ - data_->num_prefix_chars_ - 1;
|
||||||
@ -2011,8 +1985,7 @@ void LogMessage::SendToSyslogAndLog() {
|
|||||||
static bool openlog_already_called = false;
|
static bool openlog_already_called = false;
|
||||||
if (!openlog_already_called) {
|
if (!openlog_already_called) {
|
||||||
openlog(glog_internal_namespace_::ProgramInvocationShortName(),
|
openlog(glog_internal_namespace_::ProgramInvocationShortName(),
|
||||||
LOG_CONS | LOG_NDELAY | LOG_PID,
|
LOG_CONS | LOG_NDELAY | LOG_PID, LOG_USER);
|
||||||
LOG_USER);
|
|
||||||
openlog_already_called = true;
|
openlog_already_called = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2065,8 +2038,8 @@ ErrnoLogMessage::ErrnoLogMessage(const char* file, int line,
|
|||||||
ErrnoLogMessage::~ErrnoLogMessage() {
|
ErrnoLogMessage::~ErrnoLogMessage() {
|
||||||
// Don't access errno directly because it may have been altered
|
// Don't access errno directly because it may have been altered
|
||||||
// while streaming the message.
|
// while streaming the message.
|
||||||
stream() << ": " << StrError(preserved_errno()) << " ["
|
stream() << ": " << StrError(preserved_errno()) << " [" << preserved_errno()
|
||||||
<< preserved_errno() << "]";
|
<< "]";
|
||||||
}
|
}
|
||||||
|
|
||||||
void FlushLogFiles(LogSeverity min_severity) {
|
void FlushLogFiles(LogSeverity min_severity) {
|
||||||
@ -2133,17 +2106,11 @@ string LogSink::ToString(LogSeverity severity, const char* file, int line,
|
|||||||
if (FLAGS_log_year_in_prefix) {
|
if (FLAGS_log_year_in_prefix) {
|
||||||
stream << setw(4) << 1900 + logmsgtime.year();
|
stream << setw(4) << 1900 + logmsgtime.year();
|
||||||
}
|
}
|
||||||
stream << setw(2) << 1 + logmsgtime.month()
|
stream << setw(2) << 1 + logmsgtime.month() << setw(2) << logmsgtime.day()
|
||||||
<< setw(2) << logmsgtime.day()
|
<< ' ' << setw(2) << logmsgtime.hour() << ':' << setw(2)
|
||||||
<< ' '
|
<< logmsgtime.min() << ':' << setw(2) << logmsgtime.sec() << '.'
|
||||||
<< setw(2) << logmsgtime.hour() << ':'
|
<< setw(6) << logmsgtime.usec() << ' ' << setfill(' ') << setw(5)
|
||||||
<< setw(2) << logmsgtime.min() << ':'
|
<< GetTID() << setfill('0') << ' ' << file << ':' << line << "] ";
|
||||||
<< setw(2) << logmsgtime.sec() << '.'
|
|
||||||
<< setw(6) << logmsgtime.usec()
|
|
||||||
<< ' '
|
|
||||||
<< setfill(' ') << setw(5) << GetTID() << setfill('0')
|
|
||||||
<< ' '
|
|
||||||
<< file << ':' << line << "] ";
|
|
||||||
|
|
||||||
// A call to `write' is enclosed in parenthneses to prevent possible macro
|
// A call to `write' is enclosed in parenthneses to prevent possible macro
|
||||||
// expansion. On Windows, `write' could be a macro defined for portability.
|
// expansion. On Windows, `write' could be a macro defined for portability.
|
||||||
@ -2171,9 +2138,7 @@ void SetEmailLogging(LogSeverity min_severity, const char* addresses) {
|
|||||||
LogDestination::SetEmailLogging(min_severity, addresses);
|
LogDestination::SetEmailLogging(min_severity, addresses);
|
||||||
}
|
}
|
||||||
|
|
||||||
void LogToStderr() {
|
void LogToStderr() { LogDestination::LogToStderr(); }
|
||||||
LogDestination::LogToStderr();
|
|
||||||
}
|
|
||||||
|
|
||||||
namespace base {
|
namespace base {
|
||||||
namespace internal {
|
namespace internal {
|
||||||
@ -2270,7 +2235,8 @@ static bool SendEmailInternal(const char*dest, const char *subject,
|
|||||||
// allow email addresses that start with a special character, such as a
|
// allow email addresses that start with a special character, such as a
|
||||||
// pipe or dash, which could be misunderstood as a command-line flag by
|
// pipe or dash, which could be misunderstood as a command-line flag by
|
||||||
// certain versions of `mail` that are vulnerable to command injection.[2]
|
// certain versions of `mail` that are vulnerable to command injection.[2]
|
||||||
// [1] https://html.spec.whatwg.org/multipage/input.html#valid-e-mail-address
|
// [1]
|
||||||
|
// https://html.spec.whatwg.org/multipage/input.html#valid-e-mail-address
|
||||||
// [2] e.g. https://nvd.nist.gov/vuln/detail/CVE-2004-2771
|
// [2] e.g. https://nvd.nist.gov/vuln/detail/CVE-2004-2771
|
||||||
if (!std::regex_match(
|
if (!std::regex_match(
|
||||||
s,
|
s,
|
||||||
@ -2281,8 +2247,7 @@ static bool SendEmailInternal(const char*dest, const char *subject,
|
|||||||
if (use_logging) {
|
if (use_logging) {
|
||||||
VLOG(1) << "Invalid destination email address:" << s;
|
VLOG(1) << "Invalid destination email address:" << s;
|
||||||
} else {
|
} else {
|
||||||
fprintf(stderr, "Invalid destination email address: %s\n",
|
fprintf(stderr, "Invalid destination email address: %s\n", s.c_str());
|
||||||
s.c_str());
|
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -2296,11 +2261,11 @@ static bool SendEmailInternal(const char*dest, const char *subject,
|
|||||||
dest = tmp.c_str();
|
dest = tmp.c_str();
|
||||||
|
|
||||||
if (use_logging) {
|
if (use_logging) {
|
||||||
VLOG(1) << "Trying to send TITLE:" << subject
|
VLOG(1) << "Trying to send TITLE:" << subject << " BODY:" << body
|
||||||
<< " BODY:" << body << " to " << dest;
|
<< " to " << dest;
|
||||||
} else {
|
} else {
|
||||||
fprintf(stderr, "Trying to send TITLE: %s BODY: %s to %s\n",
|
fprintf(stderr, "Trying to send TITLE: %s BODY: %s to %s\n", subject,
|
||||||
subject, body, dest);
|
body, dest);
|
||||||
}
|
}
|
||||||
|
|
||||||
string logmailer;
|
string logmailer;
|
||||||
@ -2330,8 +2295,8 @@ static bool SendEmailInternal(const char*dest, const char *subject,
|
|||||||
LOG(ERROR) << "Problems sending mail to " << dest << ": "
|
LOG(ERROR) << "Problems sending mail to " << dest << ": "
|
||||||
<< StrError(errno);
|
<< StrError(errno);
|
||||||
} else {
|
} else {
|
||||||
fprintf(stderr, "Problems sending mail to %s: %s\n",
|
fprintf(stderr, "Problems sending mail to %s: %s\n", dest,
|
||||||
dest, StrError(errno).c_str());
|
StrError(errno).c_str());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return ok;
|
return ok;
|
||||||
@ -2367,8 +2332,7 @@ static void GetTempDirectories(vector<string>* list) {
|
|||||||
// C:/WINDOWS/ or C:/WINNT/
|
// C:/WINDOWS/ or C:/WINNT/
|
||||||
// .
|
// .
|
||||||
char tmp[MAX_PATH];
|
char tmp[MAX_PATH];
|
||||||
if (GetTempPathA(MAX_PATH, tmp))
|
if (GetTempPathA(MAX_PATH, tmp)) list->push_back(tmp);
|
||||||
list->push_back(tmp);
|
|
||||||
list->push_back("C:\\tmp\\");
|
list->push_back("C:\\tmp\\");
|
||||||
list->push_back("C:\\temp\\");
|
list->push_back("C:\\temp\\");
|
||||||
#else
|
#else
|
||||||
@ -2379,7 +2343,8 @@ static void GetTempDirectories(vector<string>* list) {
|
|||||||
getenv("TEST_TMPDIR"),
|
getenv("TEST_TMPDIR"),
|
||||||
|
|
||||||
// Explicitly-supplied temp dirs
|
// Explicitly-supplied temp dirs
|
||||||
getenv("TMPDIR"), getenv("TMP"),
|
getenv("TMPDIR"),
|
||||||
|
getenv("TMP"),
|
||||||
|
|
||||||
// If all else fails
|
// If all else fails
|
||||||
"/tmp",
|
"/tmp",
|
||||||
@ -2414,7 +2379,8 @@ const vector<string>& GetLoggingDirectories() {
|
|||||||
|
|
||||||
if (!FLAGS_log_dir.empty()) {
|
if (!FLAGS_log_dir.empty()) {
|
||||||
// Ensure the specified path ends with a directory delimiter.
|
// Ensure the specified path ends with a directory delimiter.
|
||||||
if (std::find(std::begin(possible_dir_delim), std::end(possible_dir_delim),
|
if (std::find(std::begin(possible_dir_delim),
|
||||||
|
std::end(possible_dir_delim),
|
||||||
FLAGS_log_dir.back()) == std::end(possible_dir_delim)) {
|
FLAGS_log_dir.back()) == std::end(possible_dir_delim)) {
|
||||||
logging_directories_list->push_back(FLAGS_log_dir + "/");
|
logging_directories_list->push_back(FLAGS_log_dir + "/");
|
||||||
} else {
|
} else {
|
||||||
@ -2436,7 +2402,8 @@ const vector<string>& GetLoggingDirectories() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void TestOnly_ClearLoggingDirectoriesList() {
|
void TestOnly_ClearLoggingDirectoriesList() {
|
||||||
fprintf(stderr, "TestOnly_ClearLoggingDirectoriesList should only be "
|
fprintf(stderr,
|
||||||
|
"TestOnly_ClearLoggingDirectoriesList should only be "
|
||||||
"called from test code.\n");
|
"called from test code.\n");
|
||||||
delete logging_directories_list;
|
delete logging_directories_list;
|
||||||
logging_directories_list = nullptr;
|
logging_directories_list = nullptr;
|
||||||
@ -2553,7 +2520,6 @@ void TruncateStdoutStderr() {
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// Helper functions for string comparisons.
|
// Helper functions for string comparisons.
|
||||||
#define DEFINE_CHECK_STROP_IMPL(name, func, expected) \
|
#define DEFINE_CHECK_STROP_IMPL(name, func, expected) \
|
||||||
string* Check##func##expected##Impl(const char* s1, const char* s2, \
|
string* Check##func##expected##Impl(const char* s1, const char* s2, \
|
||||||
@ -2613,7 +2579,8 @@ int posix_strerror_r(int err, char *buf, size_t len) {
|
|||||||
return 0;
|
return 0;
|
||||||
} else {
|
} else {
|
||||||
buf[0] = '\000';
|
buf[0] = '\000';
|
||||||
#if defined(GLOG_OS_MACOSX) || defined(GLOG_OS_FREEBSD) || defined(GLOG_OS_OPENBSD)
|
#if defined(GLOG_OS_MACOSX) || defined(GLOG_OS_FREEBSD) || \
|
||||||
|
defined(GLOG_OS_OPENBSD)
|
||||||
if (reinterpret_cast<intptr_t>(rc) < sys_nerr) {
|
if (reinterpret_cast<intptr_t>(rc) < sys_nerr) {
|
||||||
// This means an error on MacOSX or FreeBSD.
|
// This means an error on MacOSX or FreeBSD.
|
||||||
return -1;
|
return -1;
|
||||||
@ -2634,12 +2601,12 @@ string StrError(int err) {
|
|||||||
return buf;
|
return buf;
|
||||||
}
|
}
|
||||||
|
|
||||||
LogMessageFatal::LogMessageFatal(const char* file, int line) :
|
LogMessageFatal::LogMessageFatal(const char* file, int line)
|
||||||
LogMessage(file, line, GLOG_FATAL) {}
|
: LogMessage(file, line, GLOG_FATAL) {}
|
||||||
|
|
||||||
LogMessageFatal::LogMessageFatal(const char* file, int line,
|
LogMessageFatal::LogMessageFatal(const char* file, int line,
|
||||||
const CheckOpString& result) :
|
const CheckOpString& result)
|
||||||
LogMessage(file, line, result) {}
|
: LogMessage(file, line, result) {}
|
||||||
|
|
||||||
LogMessageFatal::~LogMessageFatal() {
|
LogMessageFatal::~LogMessageFatal() {
|
||||||
Flush();
|
Flush();
|
||||||
@ -2653,9 +2620,7 @@ CheckOpMessageBuilder::CheckOpMessageBuilder(const char *exprtext)
|
|||||||
*stream_ << exprtext << " (";
|
*stream_ << exprtext << " (";
|
||||||
}
|
}
|
||||||
|
|
||||||
CheckOpMessageBuilder::~CheckOpMessageBuilder() {
|
CheckOpMessageBuilder::~CheckOpMessageBuilder() { delete stream_; }
|
||||||
delete stream_;
|
|
||||||
}
|
|
||||||
|
|
||||||
ostream* CheckOpMessageBuilder::ForVar2() {
|
ostream* CheckOpMessageBuilder::ForVar2() {
|
||||||
*stream_ << " vs. ";
|
*stream_ << " vs. ";
|
||||||
@ -2705,8 +2670,7 @@ void InitGoogleLogging(const char* argv0) {
|
|||||||
glog_internal_namespace_::InitGoogleLoggingUtilities(argv0);
|
glog_internal_namespace_::InitGoogleLoggingUtilities(argv0);
|
||||||
}
|
}
|
||||||
|
|
||||||
void InitGoogleLogging(const char* argv0,
|
void InitGoogleLogging(const char* argv0, CustomPrefixCallback prefix_callback,
|
||||||
CustomPrefixCallback prefix_callback,
|
|
||||||
void* prefix_callback_data) {
|
void* prefix_callback_data) {
|
||||||
custom_prefix_callback = prefix_callback;
|
custom_prefix_callback = prefix_callback;
|
||||||
custom_prefix_callback_data = prefix_callback_data;
|
custom_prefix_callback_data = prefix_callback_data;
|
||||||
@ -2724,9 +2688,7 @@ void EnableLogCleaner(unsigned int overdue_days) {
|
|||||||
log_cleaner.Enable(overdue_days);
|
log_cleaner.Enable(overdue_days);
|
||||||
}
|
}
|
||||||
|
|
||||||
void DisableLogCleaner() {
|
void DisableLogCleaner() { log_cleaner.Disable(); }
|
||||||
log_cleaner.Disable();
|
|
||||||
}
|
|
||||||
|
|
||||||
LogMessageTime::LogMessageTime()
|
LogMessageTime::LogMessageTime()
|
||||||
: time_struct_(), timestamp_(0), usecs_(0), gmtoffset_(0) {}
|
: time_struct_(), timestamp_(0), usecs_(0), gmtoffset_(0) {}
|
||||||
@ -2769,8 +2731,10 @@ void LogMessageTime::CalcGmtOffset() {
|
|||||||
|
|
||||||
time_t gmt_sec = mktime(&gmt_struct);
|
time_t gmt_sec = mktime(&gmt_struct);
|
||||||
const long hour_secs = 3600;
|
const long hour_secs = 3600;
|
||||||
// If the Daylight Saving Time(isDst) is active subtract an hour from the current timestamp.
|
// If the Daylight Saving Time(isDst) is active subtract an hour from the
|
||||||
gmtoffset_ = static_cast<long int>(timestamp_ - gmt_sec + (isDst ? hour_secs : 0) ) ;
|
// current timestamp.
|
||||||
|
gmtoffset_ =
|
||||||
|
static_cast<long int>(timestamp_ - gmt_sec + (isDst ? hour_secs : 0));
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace google
|
} // namespace google
|
||||||
|
|||||||
@ -29,10 +29,10 @@
|
|||||||
//
|
//
|
||||||
// Author: Ray Sidney
|
// Author: Ray Sidney
|
||||||
|
|
||||||
|
#include <fcntl.h>
|
||||||
|
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
#include "utilities.h"
|
#include "utilities.h"
|
||||||
|
|
||||||
#include <fcntl.h>
|
|
||||||
#ifdef HAVE_GLOB_H
|
#ifdef HAVE_GLOB_H
|
||||||
# include <glob.h>
|
# include <glob.h>
|
||||||
#endif
|
#endif
|
||||||
@ -69,6 +69,7 @@ using namespace GFLAGS_NAMESPACE;
|
|||||||
|
|
||||||
#ifdef HAVE_LIB_GMOCK
|
#ifdef HAVE_LIB_GMOCK
|
||||||
# include <gmock/gmock.h>
|
# include <gmock/gmock.h>
|
||||||
|
|
||||||
# include "mock-log.h"
|
# include "mock-log.h"
|
||||||
// Introduce several symbols from gmock.
|
// Introduce several symbols from gmock.
|
||||||
using google::glog_testing::ScopedMockLog;
|
using google::glog_testing::ScopedMockLog;
|
||||||
@ -132,7 +133,8 @@ static void BM_Check1(int n) {
|
|||||||
}
|
}
|
||||||
BENCHMARK(BM_Check1)
|
BENCHMARK(BM_Check1)
|
||||||
|
|
||||||
static void CheckFailure(int a, int b, const char* file, int line, const char* msg);
|
static void CheckFailure(int a, int b, const char* file, int line,
|
||||||
|
const char* msg);
|
||||||
static void BM_Check3(int n) {
|
static void BM_Check3(int n) {
|
||||||
while (n-- > 0) {
|
while (n-- > 0) {
|
||||||
if (n < x) CheckFailure(n, x, __FILE__, __LINE__, "n < x");
|
if (n < x) CheckFailure(n, x, __FILE__, __LINE__, "n < x");
|
||||||
@ -165,8 +167,7 @@ static void BM_Check2(int n) {
|
|||||||
BENCHMARK(BM_Check2)
|
BENCHMARK(BM_Check2)
|
||||||
|
|
||||||
static void CheckFailure(int, int, const char* /* file */, int /* line */,
|
static void CheckFailure(int, int, const char* /* file */, int /* line */,
|
||||||
const char* /* msg */) {
|
const char* /* msg */) {}
|
||||||
}
|
|
||||||
|
|
||||||
static void BM_logspeed(int n) {
|
static void BM_logspeed(int n) {
|
||||||
while (n-- > 0) {
|
while (n-- > 0) {
|
||||||
@ -182,7 +183,8 @@ static void BM_vlog(int n) {
|
|||||||
}
|
}
|
||||||
BENCHMARK(BM_vlog)
|
BENCHMARK(BM_vlog)
|
||||||
|
|
||||||
// Dynamically generate a prefix using the default format and write it to the stream.
|
// Dynamically generate a prefix using the default format and write it to the
|
||||||
|
// stream.
|
||||||
void PrefixAttacher(std::ostream& s, const LogMessageInfo& l, void* data) {
|
void PrefixAttacher(std::ostream& s, const LogMessageInfo& l, void* data) {
|
||||||
// Assert that `data` contains the expected contents before producing the
|
// Assert that `data` contains the expected contents before producing the
|
||||||
// prefix (otherwise causing the tests to fail):
|
// prefix (otherwise causing the tests to fail):
|
||||||
@ -190,20 +192,12 @@ void PrefixAttacher(std::ostream &s, const LogMessageInfo &l, void* data) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
s << l.severity[0]
|
s << l.severity[0] << setw(4) << 1900 + l.time.year() << setw(2)
|
||||||
<< setw(4) << 1900 + l.time.year()
|
<< 1 + l.time.month() << setw(2) << l.time.day() << ' ' << setw(2)
|
||||||
<< setw(2) << 1 + l.time.month()
|
<< l.time.hour() << ':' << setw(2) << l.time.min() << ':' << setw(2)
|
||||||
<< setw(2) << l.time.day()
|
<< l.time.sec() << "." << setw(6) << l.time.usec() << ' ' << setfill(' ')
|
||||||
<< ' '
|
<< setw(5) << l.thread_id << setfill('0') << ' ' << l.filename << ':'
|
||||||
<< setw(2) << l.time.hour() << ':'
|
<< l.line_number << "]";
|
||||||
<< setw(2) << l.time.min() << ':'
|
|
||||||
<< setw(2) << l.time.sec() << "."
|
|
||||||
<< setw(6) << l.time.usec()
|
|
||||||
<< ' '
|
|
||||||
<< setfill(' ') << setw(5)
|
|
||||||
<< l.thread_id << setfill('0')
|
|
||||||
<< ' '
|
|
||||||
<< l.filename << ':' << l.line_number << "]";
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int main(int argc, char** argv) {
|
int main(int argc, char** argv) {
|
||||||
@ -216,8 +210,8 @@ int main(int argc, char **argv) {
|
|||||||
|
|
||||||
// Test some basics before InitGoogleLogging:
|
// Test some basics before InitGoogleLogging:
|
||||||
CaptureTestStderr();
|
CaptureTestStderr();
|
||||||
LogWithLevels(FLAGS_v, FLAGS_stderrthreshold,
|
LogWithLevels(FLAGS_v, FLAGS_stderrthreshold, FLAGS_logtostderr,
|
||||||
FLAGS_logtostderr, FLAGS_alsologtostderr);
|
FLAGS_alsologtostderr);
|
||||||
LogWithLevels(0, 0, false, false); // simulate "before global c-tors"
|
LogWithLevels(0, 0, false, false); // simulate "before global c-tors"
|
||||||
const string early_stderr = GetCapturedTestStderr();
|
const string early_stderr = GetCapturedTestStderr();
|
||||||
|
|
||||||
@ -226,7 +220,8 @@ int main(int argc, char **argv) {
|
|||||||
// Setting a custom prefix generator (it will use the default format so that
|
// Setting a custom prefix generator (it will use the default format so that
|
||||||
// the golden outputs can be reused):
|
// the golden outputs can be reused):
|
||||||
string prefix_attacher_data = "good data";
|
string prefix_attacher_data = "good data";
|
||||||
InitGoogleLogging(argv[0], &PrefixAttacher, static_cast<void*>(&prefix_attacher_data));
|
InitGoogleLogging(argv[0], &PrefixAttacher,
|
||||||
|
static_cast<void*>(&prefix_attacher_data));
|
||||||
|
|
||||||
EXPECT_TRUE(IsGoogleLoggingInitialized());
|
EXPECT_TRUE(IsGoogleLoggingInitialized());
|
||||||
|
|
||||||
@ -249,7 +244,8 @@ int main(int argc, char **argv) {
|
|||||||
CaptureTestStderr();
|
CaptureTestStderr();
|
||||||
|
|
||||||
// re-emit early_stderr
|
// re-emit early_stderr
|
||||||
LogMessage("dummy", LogMessage::kNoLogPrefix, GLOG_INFO).stream() << early_stderr;
|
LogMessage("dummy", LogMessage::kNoLogPrefix, GLOG_INFO).stream()
|
||||||
|
<< early_stderr;
|
||||||
|
|
||||||
TestLogging(true);
|
TestLogging(true);
|
||||||
TestRawLogging();
|
TestRawLogging();
|
||||||
@ -341,7 +337,8 @@ void TestLogging(bool check_counts) {
|
|||||||
LOG(ERROR) << "inner";
|
LOG(ERROR) << "inner";
|
||||||
}
|
}
|
||||||
|
|
||||||
LogMessage("foo", LogMessage::kNoLogPrefix, GLOG_INFO).stream() << "no prefix";
|
LogMessage("foo", LogMessage::kNoLogPrefix, GLOG_INFO).stream()
|
||||||
|
<< "no prefix";
|
||||||
|
|
||||||
if (check_counts) {
|
if (check_counts) {
|
||||||
CHECK_EQ(base_num_infos + 15, LogMessage::num_messages(GLOG_INFO));
|
CHECK_EQ(base_num_infos + 15, LogMessage::num_messages(GLOG_INFO));
|
||||||
@ -350,23 +347,17 @@ void TestLogging(bool check_counts) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void NoAllocNewHook() {
|
static void NoAllocNewHook() { LOG(FATAL) << "unexpected new"; }
|
||||||
LOG(FATAL) << "unexpected new";
|
|
||||||
}
|
|
||||||
|
|
||||||
struct NewHook {
|
struct NewHook {
|
||||||
NewHook() {
|
NewHook() { g_new_hook = &NoAllocNewHook; }
|
||||||
g_new_hook = &NoAllocNewHook;
|
|
||||||
}
|
|
||||||
~NewHook() { g_new_hook = nullptr; }
|
~NewHook() { g_new_hook = nullptr; }
|
||||||
};
|
};
|
||||||
|
|
||||||
TEST(DeathNoAllocNewHook, logging) {
|
TEST(DeathNoAllocNewHook, logging) {
|
||||||
// tests that NewHook used below works
|
// tests that NewHook used below works
|
||||||
NewHook new_hook;
|
NewHook new_hook;
|
||||||
ASSERT_DEATH({
|
ASSERT_DEATH({ new int; }, "unexpected new");
|
||||||
new int;
|
|
||||||
}, "unexpected new");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void TestRawLogging() {
|
void TestRawLogging() {
|
||||||
@ -425,8 +416,8 @@ void TestRawLogging() {
|
|||||||
|
|
||||||
void LogWithLevels(int v, int severity, bool err, bool alsoerr) {
|
void LogWithLevels(int v, int severity, bool err, bool alsoerr) {
|
||||||
RAW_LOG(INFO,
|
RAW_LOG(INFO,
|
||||||
"Test: v=%d stderrthreshold=%d logtostderr=%d alsologtostderr=%d",
|
"Test: v=%d stderrthreshold=%d logtostderr=%d alsologtostderr=%d", v,
|
||||||
v, severity, err, alsoerr);
|
severity, err, alsoerr);
|
||||||
|
|
||||||
FlagSaver saver;
|
FlagSaver saver;
|
||||||
|
|
||||||
@ -463,28 +454,48 @@ void LogWithLevels(int v, int severity, bool err, bool alsoerr) {
|
|||||||
LOG_IF(ERROR, false) << "don't log_if error";
|
LOG_IF(ERROR, false) << "don't log_if error";
|
||||||
|
|
||||||
int c;
|
int c;
|
||||||
c = 1; VLOG_IF(100, c -= 2) << "vlog_if 100 expr"; EXPECT_EQ(c, -1);
|
c = 1;
|
||||||
c = 1; VLOG_IF(0, c -= 2) << "vlog_if 0 expr"; EXPECT_EQ(c, -1);
|
VLOG_IF(100, c -= 2) << "vlog_if 100 expr";
|
||||||
c = 1; LOG_IF(INFO, c -= 2) << "log_if info expr"; EXPECT_EQ(c, -1);
|
EXPECT_EQ(c, -1);
|
||||||
c = 1; LOG_IF(ERROR, c -= 2) << "log_if error expr"; EXPECT_EQ(c, -1);
|
c = 1;
|
||||||
c = 2; VLOG_IF(0, c -= 2) << "don't vlog_if 0 expr"; EXPECT_EQ(c, 0);
|
VLOG_IF(0, c -= 2) << "vlog_if 0 expr";
|
||||||
c = 2; LOG_IF(ERROR, c -= 2) << "don't log_if error expr"; EXPECT_EQ(c, 0);
|
EXPECT_EQ(c, -1);
|
||||||
|
c = 1;
|
||||||
|
LOG_IF(INFO, c -= 2) << "log_if info expr";
|
||||||
|
EXPECT_EQ(c, -1);
|
||||||
|
c = 1;
|
||||||
|
LOG_IF(ERROR, c -= 2) << "log_if error expr";
|
||||||
|
EXPECT_EQ(c, -1);
|
||||||
|
c = 2;
|
||||||
|
VLOG_IF(0, c -= 2) << "don't vlog_if 0 expr";
|
||||||
|
EXPECT_EQ(c, 0);
|
||||||
|
c = 2;
|
||||||
|
LOG_IF(ERROR, c -= 2) << "don't log_if error expr";
|
||||||
|
EXPECT_EQ(c, 0);
|
||||||
|
|
||||||
c = 3; LOG_IF_EVERY_N(INFO, c -= 4, 1) << "log_if info every 1 expr";
|
c = 3;
|
||||||
|
LOG_IF_EVERY_N(INFO, c -= 4, 1) << "log_if info every 1 expr";
|
||||||
EXPECT_EQ(c, -1);
|
EXPECT_EQ(c, -1);
|
||||||
c = 3; LOG_IF_EVERY_N(ERROR, c -= 4, 1) << "log_if error every 1 expr";
|
c = 3;
|
||||||
|
LOG_IF_EVERY_N(ERROR, c -= 4, 1) << "log_if error every 1 expr";
|
||||||
EXPECT_EQ(c, -1);
|
EXPECT_EQ(c, -1);
|
||||||
c = 4; LOG_IF_EVERY_N(ERROR, c -= 4, 3) << "don't log_if info every 3 expr";
|
c = 4;
|
||||||
|
LOG_IF_EVERY_N(ERROR, c -= 4, 3) << "don't log_if info every 3 expr";
|
||||||
EXPECT_EQ(c, 0);
|
EXPECT_EQ(c, 0);
|
||||||
c = 4; LOG_IF_EVERY_N(ERROR, c -= 4, 3) << "don't log_if error every 3 expr";
|
c = 4;
|
||||||
|
LOG_IF_EVERY_N(ERROR, c -= 4, 3) << "don't log_if error every 3 expr";
|
||||||
EXPECT_EQ(c, 0);
|
EXPECT_EQ(c, 0);
|
||||||
c = 5; VLOG_IF_EVERY_N(0, c -= 4, 1) << "vlog_if 0 every 1 expr";
|
c = 5;
|
||||||
|
VLOG_IF_EVERY_N(0, c -= 4, 1) << "vlog_if 0 every 1 expr";
|
||||||
EXPECT_EQ(c, 1);
|
EXPECT_EQ(c, 1);
|
||||||
c = 5; VLOG_IF_EVERY_N(100, c -= 4, 3) << "vlog_if 100 every 3 expr";
|
c = 5;
|
||||||
|
VLOG_IF_EVERY_N(100, c -= 4, 3) << "vlog_if 100 every 3 expr";
|
||||||
EXPECT_EQ(c, 1);
|
EXPECT_EQ(c, 1);
|
||||||
c = 6; VLOG_IF_EVERY_N(0, c -= 6, 1) << "don't vlog_if 0 every 1 expr";
|
c = 6;
|
||||||
|
VLOG_IF_EVERY_N(0, c -= 6, 1) << "don't vlog_if 0 every 1 expr";
|
||||||
EXPECT_EQ(c, 0);
|
EXPECT_EQ(c, 0);
|
||||||
c = 6; VLOG_IF_EVERY_N(100, c -= 6, 3) << "don't vlog_if 100 every 1 expr";
|
c = 6;
|
||||||
|
VLOG_IF_EVERY_N(100, c -= 6, 3) << "don't vlog_if 100 every 1 expr";
|
||||||
EXPECT_EQ(c, 0);
|
EXPECT_EQ(c, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -530,12 +541,17 @@ void TestLogString() {
|
|||||||
vector<string> errors;
|
vector<string> errors;
|
||||||
vector<string>* no_errors = nullptr;
|
vector<string>* no_errors = nullptr;
|
||||||
|
|
||||||
LOG_STRING(INFO, &errors) << "LOG_STRING: " << "collected info";
|
LOG_STRING(INFO, &errors) << "LOG_STRING: "
|
||||||
LOG_STRING(WARNING, &errors) << "LOG_STRING: " << "collected warning";
|
<< "collected info";
|
||||||
LOG_STRING(ERROR, &errors) << "LOG_STRING: " << "collected error";
|
LOG_STRING(WARNING, &errors) << "LOG_STRING: "
|
||||||
|
<< "collected warning";
|
||||||
|
LOG_STRING(ERROR, &errors) << "LOG_STRING: "
|
||||||
|
<< "collected error";
|
||||||
|
|
||||||
LOG_STRING(INFO, no_errors) << "LOG_STRING: " << "reported info";
|
LOG_STRING(INFO, no_errors) << "LOG_STRING: "
|
||||||
LOG_STRING(WARNING, no_errors) << "LOG_STRING: " << "reported warning";
|
<< "reported info";
|
||||||
|
LOG_STRING(WARNING, no_errors) << "LOG_STRING: "
|
||||||
|
<< "reported warning";
|
||||||
LOG_STRING(ERROR, nullptr) << "LOG_STRING: "
|
LOG_STRING(ERROR, nullptr) << "LOG_STRING: "
|
||||||
<< "reported error";
|
<< "reported error";
|
||||||
|
|
||||||
@ -548,15 +564,20 @@ void TestLogToString() {
|
|||||||
string error;
|
string error;
|
||||||
string* no_error = nullptr;
|
string* no_error = nullptr;
|
||||||
|
|
||||||
LOG_TO_STRING(INFO, &error) << "LOG_TO_STRING: " << "collected info";
|
LOG_TO_STRING(INFO, &error) << "LOG_TO_STRING: "
|
||||||
|
<< "collected info";
|
||||||
LOG(INFO) << "Captured by LOG_TO_STRING: " << error;
|
LOG(INFO) << "Captured by LOG_TO_STRING: " << error;
|
||||||
LOG_TO_STRING(WARNING, &error) << "LOG_TO_STRING: " << "collected warning";
|
LOG_TO_STRING(WARNING, &error) << "LOG_TO_STRING: "
|
||||||
|
<< "collected warning";
|
||||||
LOG(INFO) << "Captured by LOG_TO_STRING: " << error;
|
LOG(INFO) << "Captured by LOG_TO_STRING: " << error;
|
||||||
LOG_TO_STRING(ERROR, &error) << "LOG_TO_STRING: " << "collected error";
|
LOG_TO_STRING(ERROR, &error) << "LOG_TO_STRING: "
|
||||||
|
<< "collected error";
|
||||||
LOG(INFO) << "Captured by LOG_TO_STRING: " << error;
|
LOG(INFO) << "Captured by LOG_TO_STRING: " << error;
|
||||||
|
|
||||||
LOG_TO_STRING(INFO, no_error) << "LOG_TO_STRING: " << "reported info";
|
LOG_TO_STRING(INFO, no_error) << "LOG_TO_STRING: "
|
||||||
LOG_TO_STRING(WARNING, no_error) << "LOG_TO_STRING: " << "reported warning";
|
<< "reported info";
|
||||||
|
LOG_TO_STRING(WARNING, no_error) << "LOG_TO_STRING: "
|
||||||
|
<< "reported warning";
|
||||||
LOG_TO_STRING(ERROR, nullptr) << "LOG_TO_STRING: "
|
LOG_TO_STRING(ERROR, nullptr) << "LOG_TO_STRING: "
|
||||||
<< "reported error";
|
<< "reported error";
|
||||||
}
|
}
|
||||||
@ -568,8 +589,8 @@ class TestLogSinkImpl : public LogSink {
|
|||||||
const char* base_filename, int line,
|
const char* base_filename, int line,
|
||||||
const LogMessageTime& logmsgtime, const char* message,
|
const LogMessageTime& logmsgtime, const char* message,
|
||||||
size_t message_len) override {
|
size_t message_len) override {
|
||||||
errors.push_back(
|
errors.push_back(ToString(severity, base_filename, line, logmsgtime,
|
||||||
ToString(severity, base_filename, line, logmsgtime, message, message_len));
|
message, message_len));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -577,26 +598,36 @@ void TestLogSink() {
|
|||||||
TestLogSinkImpl sink;
|
TestLogSinkImpl sink;
|
||||||
LogSink* no_sink = nullptr;
|
LogSink* no_sink = nullptr;
|
||||||
|
|
||||||
LOG_TO_SINK(&sink, INFO) << "LOG_TO_SINK: " << "collected info";
|
LOG_TO_SINK(&sink, INFO) << "LOG_TO_SINK: "
|
||||||
LOG_TO_SINK(&sink, WARNING) << "LOG_TO_SINK: " << "collected warning";
|
<< "collected info";
|
||||||
LOG_TO_SINK(&sink, ERROR) << "LOG_TO_SINK: " << "collected error";
|
LOG_TO_SINK(&sink, WARNING) << "LOG_TO_SINK: "
|
||||||
|
<< "collected warning";
|
||||||
|
LOG_TO_SINK(&sink, ERROR) << "LOG_TO_SINK: "
|
||||||
|
<< "collected error";
|
||||||
|
|
||||||
LOG_TO_SINK(no_sink, INFO) << "LOG_TO_SINK: " << "reported info";
|
LOG_TO_SINK(no_sink, INFO) << "LOG_TO_SINK: "
|
||||||
LOG_TO_SINK(no_sink, WARNING) << "LOG_TO_SINK: " << "reported warning";
|
<< "reported info";
|
||||||
|
LOG_TO_SINK(no_sink, WARNING) << "LOG_TO_SINK: "
|
||||||
|
<< "reported warning";
|
||||||
LOG_TO_SINK(nullptr, ERROR) << "LOG_TO_SINK: "
|
LOG_TO_SINK(nullptr, ERROR) << "LOG_TO_SINK: "
|
||||||
<< "reported error";
|
<< "reported error";
|
||||||
|
|
||||||
LOG_TO_SINK_BUT_NOT_TO_LOGFILE(&sink, INFO)
|
LOG_TO_SINK_BUT_NOT_TO_LOGFILE(&sink, INFO)
|
||||||
<< "LOG_TO_SINK_BUT_NOT_TO_LOGFILE: " << "collected info";
|
<< "LOG_TO_SINK_BUT_NOT_TO_LOGFILE: "
|
||||||
|
<< "collected info";
|
||||||
LOG_TO_SINK_BUT_NOT_TO_LOGFILE(&sink, WARNING)
|
LOG_TO_SINK_BUT_NOT_TO_LOGFILE(&sink, WARNING)
|
||||||
<< "LOG_TO_SINK_BUT_NOT_TO_LOGFILE: " << "collected warning";
|
<< "LOG_TO_SINK_BUT_NOT_TO_LOGFILE: "
|
||||||
|
<< "collected warning";
|
||||||
LOG_TO_SINK_BUT_NOT_TO_LOGFILE(&sink, ERROR)
|
LOG_TO_SINK_BUT_NOT_TO_LOGFILE(&sink, ERROR)
|
||||||
<< "LOG_TO_SINK_BUT_NOT_TO_LOGFILE: " << "collected error";
|
<< "LOG_TO_SINK_BUT_NOT_TO_LOGFILE: "
|
||||||
|
<< "collected error";
|
||||||
|
|
||||||
LOG_TO_SINK_BUT_NOT_TO_LOGFILE(no_sink, INFO)
|
LOG_TO_SINK_BUT_NOT_TO_LOGFILE(no_sink, INFO)
|
||||||
<< "LOG_TO_SINK_BUT_NOT_TO_LOGFILE: " << "thrashed info";
|
<< "LOG_TO_SINK_BUT_NOT_TO_LOGFILE: "
|
||||||
|
<< "thrashed info";
|
||||||
LOG_TO_SINK_BUT_NOT_TO_LOGFILE(no_sink, WARNING)
|
LOG_TO_SINK_BUT_NOT_TO_LOGFILE(no_sink, WARNING)
|
||||||
<< "LOG_TO_SINK_BUT_NOT_TO_LOGFILE: " << "thrashed warning";
|
<< "LOG_TO_SINK_BUT_NOT_TO_LOGFILE: "
|
||||||
|
<< "thrashed warning";
|
||||||
LOG_TO_SINK_BUT_NOT_TO_LOGFILE(nullptr, ERROR)
|
LOG_TO_SINK_BUT_NOT_TO_LOGFILE(nullptr, ERROR)
|
||||||
<< "LOG_TO_SINK_BUT_NOT_TO_LOGFILE: "
|
<< "LOG_TO_SINK_BUT_NOT_TO_LOGFILE: "
|
||||||
<< "thrashed error";
|
<< "thrashed error";
|
||||||
@ -608,10 +639,7 @@ void TestLogSink() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// For testing using CHECK*() on anonymous enums.
|
// For testing using CHECK*() on anonymous enums.
|
||||||
enum {
|
enum { CASE_A, CASE_B };
|
||||||
CASE_A,
|
|
||||||
CASE_B
|
|
||||||
};
|
|
||||||
|
|
||||||
void TestCHECK() {
|
void TestCHECK() {
|
||||||
// Tests using CHECK*() on int values.
|
// Tests using CHECK*() on int values.
|
||||||
@ -669,8 +697,7 @@ void TestSTREQ() {
|
|||||||
CHECK_STRCASENE("this", "that");
|
CHECK_STRCASENE("this", "that");
|
||||||
CHECK_STRCASENE(nullptr, "that");
|
CHECK_STRCASENE(nullptr, "that");
|
||||||
CHECK_STREQ((string("a") + "b").c_str(), "ab");
|
CHECK_STREQ((string("a") + "b").c_str(), "ab");
|
||||||
CHECK_STREQ(string("test").c_str(),
|
CHECK_STREQ(string("test").c_str(), (string("te") + string("st")).c_str());
|
||||||
(string("te") + string("st")).c_str());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(DeathSTREQ, logging) {
|
TEST(DeathSTREQ, logging) {
|
||||||
@ -742,7 +769,8 @@ static void DeleteFiles(const string& pattern) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// check string is in file (or is *NOT*, depending on optional checkInFileOrNot)
|
// check string is in file (or is *NOT*, depending on optional checkInFileOrNot)
|
||||||
static void CheckFile(const string& name, const string& expected_string, const bool checkInFileOrNot = true) {
|
static void CheckFile(const string& name, const string& expected_string,
|
||||||
|
const bool checkInFileOrNot = true) {
|
||||||
vector<string> files;
|
vector<string> files;
|
||||||
GetFiles(name + "*", &files);
|
GetFiles(name + "*", &files);
|
||||||
CHECK_EQ(files.size(), 1UL);
|
CHECK_EQ(files.size(), 1UL);
|
||||||
@ -760,7 +788,8 @@ static void CheckFile(const string& name, const string& expected_string, const b
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
fclose(file);
|
fclose(file);
|
||||||
LOG(FATAL) << "Did " << (checkInFileOrNot? "not " : "") << "find " << expected_string << " in " << files[0];
|
LOG(FATAL) << "Did " << (checkInFileOrNot ? "not " : "") << "find "
|
||||||
|
<< expected_string << " in " << files[0];
|
||||||
}
|
}
|
||||||
|
|
||||||
static void TestBasename() {
|
static void TestBasename() {
|
||||||
@ -780,8 +809,11 @@ static void TestBasename() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void TestBasenameAppendWhenNoTimestamp() {
|
static void TestBasenameAppendWhenNoTimestamp() {
|
||||||
fprintf(stderr, "==== Test setting log file basename without timestamp and appending properly\n");
|
fprintf(stderr,
|
||||||
const string dest = FLAGS_test_tmpdir + "/logging_test_basename_append_when_no_timestamp";
|
"==== Test setting log file basename without timestamp and appending "
|
||||||
|
"properly\n");
|
||||||
|
const string dest =
|
||||||
|
FLAGS_test_tmpdir + "/logging_test_basename_append_when_no_timestamp";
|
||||||
DeleteFiles(dest + "*");
|
DeleteFiles(dest + "*");
|
||||||
|
|
||||||
ofstream out(dest.c_str());
|
ofstream out(dest.c_str());
|
||||||
@ -806,10 +838,14 @@ static void TestBasenameAppendWhenNoTimestamp() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void TestTwoProcessesWrite() {
|
static void TestTwoProcessesWrite() {
|
||||||
// test only implemented for platforms with fork & wait; the actual implementation relies on flock
|
// test only implemented for platforms with fork & wait; the actual
|
||||||
|
// implementation relies on flock
|
||||||
#if defined(HAVE_SYS_WAIT_H) && defined(HAVE_UNISTD_H) && defined(HAVE_FCNTL)
|
#if defined(HAVE_SYS_WAIT_H) && defined(HAVE_UNISTD_H) && defined(HAVE_FCNTL)
|
||||||
fprintf(stderr, "==== Test setting log file basename and two processes writing - second should fail\n");
|
fprintf(stderr,
|
||||||
const string dest = FLAGS_test_tmpdir + "/logging_test_basename_two_processes_writing";
|
"==== Test setting log file basename and two processes writing - "
|
||||||
|
"second should fail\n");
|
||||||
|
const string dest =
|
||||||
|
FLAGS_test_tmpdir + "/logging_test_basename_two_processes_writing";
|
||||||
DeleteFiles(dest + "*");
|
DeleteFiles(dest + "*");
|
||||||
|
|
||||||
// make both processes write into the same file (easier test)
|
// make both processes write into the same file (easier test)
|
||||||
@ -821,7 +857,8 @@ static void TestTwoProcessesWrite() {
|
|||||||
pid_t pid = fork();
|
pid_t pid = fork();
|
||||||
CHECK_ERR(pid);
|
CHECK_ERR(pid);
|
||||||
if (pid == 0) {
|
if (pid == 0) {
|
||||||
LOG(INFO) << "message to new base, child - should only appear on STDERR not on the file";
|
LOG(INFO) << "message to new base, child - should only appear on STDERR "
|
||||||
|
"not on the file";
|
||||||
ShutdownGoogleLogging(); // for children proc
|
ShutdownGoogleLogging(); // for children proc
|
||||||
exit(EXIT_SUCCESS);
|
exit(EXIT_SUCCESS);
|
||||||
} else if (pid > 0) {
|
} else if (pid > 0) {
|
||||||
@ -830,7 +867,10 @@ static void TestTwoProcessesWrite() {
|
|||||||
FLAGS_timestamp_in_logfile_name = true;
|
FLAGS_timestamp_in_logfile_name = true;
|
||||||
|
|
||||||
CheckFile(dest, "message to new base, parent");
|
CheckFile(dest, "message to new base, parent");
|
||||||
CheckFile(dest, "message to new base, child - should only appear on STDERR not on the file", false);
|
CheckFile(dest,
|
||||||
|
"message to new base, child - should only appear on STDERR not on "
|
||||||
|
"the file",
|
||||||
|
false);
|
||||||
|
|
||||||
// Release
|
// Release
|
||||||
LogToStderr();
|
LogToStderr();
|
||||||
@ -1014,11 +1054,9 @@ static void TestTruncate() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
struct RecordDeletionLogger : public base::Logger {
|
struct RecordDeletionLogger : public base::Logger {
|
||||||
RecordDeletionLogger(bool* set_on_destruction,
|
RecordDeletionLogger(bool* set_on_destruction, base::Logger* wrapped_logger)
|
||||||
base::Logger* wrapped_logger) :
|
: set_on_destruction_(set_on_destruction),
|
||||||
set_on_destruction_(set_on_destruction),
|
wrapped_logger_(wrapped_logger) {
|
||||||
wrapped_logger_(wrapped_logger)
|
|
||||||
{
|
|
||||||
*set_on_destruction_ = false;
|
*set_on_destruction_ = false;
|
||||||
}
|
}
|
||||||
~RecordDeletionLogger() override { *set_on_destruction_ = true; }
|
~RecordDeletionLogger() override { *set_on_destruction_ = true; }
|
||||||
@ -1095,8 +1133,8 @@ static void TestLogPeriodically() {
|
|||||||
// minimize error.
|
// minimize error.
|
||||||
int64 nsBetweenCalls[LogTimes::MAX_CALLS - 1];
|
int64 nsBetweenCalls[LogTimes::MAX_CALLS - 1];
|
||||||
for (size_t i = 1; i < LogTimes::MAX_CALLS; ++i) {
|
for (size_t i = 1; i < LogTimes::MAX_CALLS; ++i) {
|
||||||
nsBetweenCalls[i - 1] = elapsedTime_ns(
|
nsBetweenCalls[i - 1] = elapsedTime_ns(timeLogger.m_callTimes[i - 1],
|
||||||
timeLogger.m_callTimes[i - 1], timeLogger.m_callTimes[i]);
|
timeLogger.m_callTimes[i]);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (long time_ns : nsBetweenCalls) {
|
for (long time_ns : nsBetweenCalls) {
|
||||||
@ -1107,8 +1145,9 @@ static void TestLogPeriodically() {
|
|||||||
namespace google {
|
namespace google {
|
||||||
namespace glog_internal_namespace_ {
|
namespace glog_internal_namespace_ {
|
||||||
extern // in logging.cc
|
extern // in logging.cc
|
||||||
bool SafeFNMatch_(const char* pattern, size_t patt_len,
|
bool
|
||||||
const char* str, size_t str_len);
|
SafeFNMatch_(const char* pattern, size_t patt_len, const char* str,
|
||||||
|
size_t str_len);
|
||||||
} // namespace glog_internal_namespace_
|
} // namespace glog_internal_namespace_
|
||||||
using glog_internal_namespace_::SafeFNMatch_;
|
using glog_internal_namespace_::SafeFNMatch_;
|
||||||
} // namespace google
|
} // namespace google
|
||||||
@ -1116,8 +1155,8 @@ using glog_internal_namespace_::SafeFNMatch_;
|
|||||||
static bool WrapSafeFNMatch(string pattern, string str) {
|
static bool WrapSafeFNMatch(string pattern, string str) {
|
||||||
pattern += "abc";
|
pattern += "abc";
|
||||||
str += "defgh";
|
str += "defgh";
|
||||||
return SafeFNMatch_(pattern.data(), pattern.size() - 3,
|
return SafeFNMatch_(pattern.data(), pattern.size() - 3, str.data(),
|
||||||
str.data(), str.size() - 5);
|
str.size() - 5);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(SafeFNMatch, logging) {
|
TEST(SafeFNMatch, logging) {
|
||||||
@ -1184,7 +1223,6 @@ class TestLogSinkWriter : public Thread {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
// helpers ---------------
|
// helpers ---------------
|
||||||
|
|
||||||
// For creating a "Condition".
|
// For creating a "Condition".
|
||||||
@ -1239,7 +1277,6 @@ class TestLogSinkWriter : public Thread {
|
|||||||
// (that other thread can than use LOG() itself),
|
// (that other thread can than use LOG() itself),
|
||||||
class TestWaitingLogSink : public LogSink {
|
class TestWaitingLogSink : public LogSink {
|
||||||
public:
|
public:
|
||||||
|
|
||||||
TestWaitingLogSink() {
|
TestWaitingLogSink() {
|
||||||
tid_ = pthread_self(); // for thread-specific behavior
|
tid_ = pthread_self(); // for thread-specific behavior
|
||||||
AddLogSink(this);
|
AddLogSink(this);
|
||||||
@ -1260,8 +1297,8 @@ class TestWaitingLogSink : public LogSink {
|
|||||||
// Note: Something like ThreadLocalLogSink is a better choice
|
// Note: Something like ThreadLocalLogSink is a better choice
|
||||||
// to do thread-specific LogSink logic for real.
|
// to do thread-specific LogSink logic for real.
|
||||||
if (pthread_equal(tid_, pthread_self())) {
|
if (pthread_equal(tid_, pthread_self())) {
|
||||||
writer_.Buffer(ToString(severity, base_filename, line,
|
writer_.Buffer(ToString(severity, base_filename, line, logmsgtime,
|
||||||
logmsgtime, message, message_len));
|
message, message_len));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1271,7 +1308,6 @@ class TestWaitingLogSink : public LogSink {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
pthread_t tid_;
|
pthread_t tid_;
|
||||||
TestLogSinkWriter writer_;
|
TestLogSinkWriter writer_;
|
||||||
};
|
};
|
||||||
@ -1282,7 +1318,8 @@ static void TestLogSinkWaitTillSent() {
|
|||||||
// Clear global_messages here to make sure that this test case can be
|
// Clear global_messages here to make sure that this test case can be
|
||||||
// reentered
|
// reentered
|
||||||
global_messages.clear();
|
global_messages.clear();
|
||||||
{ TestWaitingLogSink sink;
|
{
|
||||||
|
TestWaitingLogSink sink;
|
||||||
// Sleeps give the sink threads time to do all their work,
|
// Sleeps give the sink threads time to do all their work,
|
||||||
// so that we get a reliable log capture to compare to the golden file.
|
// so that we get a reliable log capture to compare to the golden file.
|
||||||
LOG(INFO) << "Message 1";
|
LOG(INFO) << "Message 1";
|
||||||
@ -1308,7 +1345,8 @@ TEST(Strerror, logging) {
|
|||||||
CHECK_EQ(posix_strerror_r(errcode, buf, 0), -1);
|
CHECK_EQ(posix_strerror_r(errcode, buf, 0), -1);
|
||||||
CHECK_EQ(buf[0], 'A');
|
CHECK_EQ(buf[0], 'A');
|
||||||
CHECK_EQ(posix_strerror_r(errcode, nullptr, buf_size), -1);
|
CHECK_EQ(posix_strerror_r(errcode, nullptr, buf_size), -1);
|
||||||
#if defined(GLOG_OS_MACOSX) || defined(GLOG_OS_FREEBSD) || defined(GLOG_OS_OPENBSD)
|
#if defined(GLOG_OS_MACOSX) || defined(GLOG_OS_FREEBSD) || \
|
||||||
|
defined(GLOG_OS_OPENBSD)
|
||||||
// MacOSX or FreeBSD considers this case is an error since there is
|
// MacOSX or FreeBSD considers this case is an error since there is
|
||||||
// no enough space.
|
// no enough space.
|
||||||
CHECK_EQ(posix_strerror_r(errcode, buf, 1), -1);
|
CHECK_EQ(posix_strerror_r(errcode, buf, 1), -1);
|
||||||
@ -1404,9 +1442,8 @@ TEST(TestExitOnDFatal, ToBeOrNotToBe) {
|
|||||||
|
|
||||||
# ifdef GTEST_HAS_DEATH_TEST
|
# ifdef GTEST_HAS_DEATH_TEST
|
||||||
// Death comes on little cats' feet.
|
// Death comes on little cats' feet.
|
||||||
EXPECT_DEBUG_DEATH({
|
EXPECT_DEBUG_DEATH({ LOG(DFATAL) << "This should be fatal in debug mode"; },
|
||||||
LOG(DFATAL) << "This should be fatal in debug mode";
|
"This should be fatal in debug mode");
|
||||||
}, "This should be fatal in debug mode");
|
|
||||||
# endif
|
# endif
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1443,10 +1480,10 @@ TEST(LogBacktraceAt, DoesBacktraceAtRightLineWhenEnabled) {
|
|||||||
// the name of the containing function, followed by the log message.
|
// the name of the containing function, followed by the log message.
|
||||||
// We use HasSubstr()s instead of ContainsRegex() for environments
|
// We use HasSubstr()s instead of ContainsRegex() for environments
|
||||||
// which don't have regexp.
|
// which don't have regexp.
|
||||||
EXPECT_CALL(log, Log(_, _, AllOf(HasSubstr("stacktrace:"),
|
EXPECT_CALL(
|
||||||
HasSubstr("BacktraceAtHelper"),
|
log, Log(_, _,
|
||||||
HasSubstr("main"),
|
AllOf(HasSubstr("stacktrace:"), HasSubstr("BacktraceAtHelper"),
|
||||||
HasSubstr("Backtrace me"))));
|
HasSubstr("main"), HasSubstr("Backtrace me"))));
|
||||||
// Other LOGs should not include a backtrace.
|
// Other LOGs should not include a backtrace.
|
||||||
EXPECT_CALL(log, Log(_, _, "Not me"));
|
EXPECT_CALL(log, Log(_, _, "Not me"));
|
||||||
|
|
||||||
@ -1480,7 +1517,8 @@ TEST(UserDefinedClass, logging) {
|
|||||||
TEST(LogMsgTime, gmtoff) {
|
TEST(LogMsgTime, gmtoff) {
|
||||||
/*
|
/*
|
||||||
* Unit test for GMT offset API
|
* Unit test for GMT offset API
|
||||||
* TODO: To properly test this API, we need a platform independent way to set time-zone.
|
* TODO: To properly test this API, we need a platform independent way to set
|
||||||
|
* time-zone.
|
||||||
* */
|
* */
|
||||||
google::LogMessage log_obj(__FILE__, __LINE__);
|
google::LogMessage log_obj(__FILE__, __LINE__);
|
||||||
|
|
||||||
@ -1495,14 +1533,16 @@ TEST(EmailLogging, ValidAddress) {
|
|||||||
FlagSaver saver;
|
FlagSaver saver;
|
||||||
FLAGS_logmailer = "/usr/bin/true";
|
FLAGS_logmailer = "/usr/bin/true";
|
||||||
|
|
||||||
EXPECT_TRUE(SendEmail("example@example.com", "Example subject", "Example body"));
|
EXPECT_TRUE(
|
||||||
|
SendEmail("example@example.com", "Example subject", "Example body"));
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(EmailLogging, MultipleAddresses) {
|
TEST(EmailLogging, MultipleAddresses) {
|
||||||
FlagSaver saver;
|
FlagSaver saver;
|
||||||
FLAGS_logmailer = "/usr/bin/true";
|
FLAGS_logmailer = "/usr/bin/true";
|
||||||
|
|
||||||
EXPECT_TRUE(SendEmail("example@example.com,foo@bar.com", "Example subject", "Example body"));
|
EXPECT_TRUE(SendEmail("example@example.com,foo@bar.com", "Example subject",
|
||||||
|
"Example body"));
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(EmailLogging, InvalidAddress) {
|
TEST(EmailLogging, InvalidAddress) {
|
||||||
@ -1516,5 +1556,6 @@ TEST(EmailLogging, MaliciousAddress) {
|
|||||||
FlagSaver saver;
|
FlagSaver saver;
|
||||||
FLAGS_logmailer = "/usr/bin/true";
|
FLAGS_logmailer = "/usr/bin/true";
|
||||||
|
|
||||||
EXPECT_FALSE(SendEmail("!/bin/true@example.com", "Example subject", "Example body"));
|
EXPECT_FALSE(
|
||||||
|
SendEmail("!/bin/true@example.com", "Example subject", "Example body"));
|
||||||
}
|
}
|
||||||
|
|||||||
@ -33,11 +33,11 @@
|
|||||||
|
|
||||||
#include "mock-log.h"
|
#include "mock-log.h"
|
||||||
|
|
||||||
#include <string>
|
|
||||||
|
|
||||||
#include <gmock/gmock.h>
|
#include <gmock/gmock.h>
|
||||||
#include <gtest/gtest.h>
|
#include <gtest/gtest.h>
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
using google::GLOG_ERROR;
|
using google::GLOG_ERROR;
|
||||||
@ -57,8 +57,7 @@ TEST(ScopedMockLogTest, InterceptsLog) {
|
|||||||
InSequence s;
|
InSequence s;
|
||||||
EXPECT_CALL(log,
|
EXPECT_CALL(log,
|
||||||
Log(GLOG_WARNING, EndsWith("mock-log_unittest.cc"), "Fishy."));
|
Log(GLOG_WARNING, EndsWith("mock-log_unittest.cc"), "Fishy."));
|
||||||
EXPECT_CALL(log, Log(GLOG_INFO, _, "Working..."))
|
EXPECT_CALL(log, Log(GLOG_INFO, _, "Working...")).Times(2);
|
||||||
.Times(2);
|
|
||||||
EXPECT_CALL(log, Log(GLOG_ERROR, _, "Bad!!"));
|
EXPECT_CALL(log, Log(GLOG_ERROR, _, "Bad!!"));
|
||||||
|
|
||||||
LOG(WARNING) << "Fishy.";
|
LOG(WARNING) << "Fishy.";
|
||||||
@ -67,13 +66,9 @@ TEST(ScopedMockLogTest, InterceptsLog) {
|
|||||||
LOG(ERROR) << "Bad!!";
|
LOG(ERROR) << "Bad!!";
|
||||||
}
|
}
|
||||||
|
|
||||||
void LogBranch() {
|
void LogBranch() { LOG(INFO) << "Logging a branch..."; }
|
||||||
LOG(INFO) << "Logging a branch...";
|
|
||||||
}
|
|
||||||
|
|
||||||
void LogTree() {
|
void LogTree() { LOG(INFO) << "Logging the whole tree..."; }
|
||||||
LOG(INFO) << "Logging the whole tree...";
|
|
||||||
}
|
|
||||||
|
|
||||||
void LogForest() {
|
void LogForest() {
|
||||||
LOG(INFO) << "Logging the entire forest.";
|
LOG(INFO) << "Logging the entire forest.";
|
||||||
|
|||||||
@ -1,6 +1,3 @@
|
|||||||
#include "glog/logging.h"
|
#include "glog/logging.h"
|
||||||
|
|
||||||
int main(int /*argc*/, char** argv)
|
int main(int /*argc*/, char** argv) { google::InitGoogleLogging(argv[0]); }
|
||||||
{
|
|
||||||
google::InitGoogleLogging(argv[0]);
|
|
||||||
}
|
|
||||||
|
|||||||
@ -103,8 +103,8 @@ static bool DoRawLog(char** buf, size_t* size, const char* format, ...) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Helper for RawLog__ below.
|
// Helper for RawLog__ below.
|
||||||
inline static bool VADoRawLog(char** buf, size_t* size,
|
inline static bool VADoRawLog(char** buf, size_t* size, const char* format,
|
||||||
const char* format, va_list ap) {
|
va_list ap) {
|
||||||
#if defined(__GNUC__)
|
#if defined(__GNUC__)
|
||||||
# pragma GCC diagnostic push
|
# pragma GCC diagnostic push
|
||||||
# pragma GCC diagnostic ignored "-Wformat-nonliteral"
|
# pragma GCC diagnostic ignored "-Wformat-nonliteral"
|
||||||
@ -139,8 +139,7 @@ void RawLog__(LogSeverity severity, const char* file, int line,
|
|||||||
|
|
||||||
// NOTE: this format should match the specification in base/logging.h
|
// NOTE: this format should match the specification in base/logging.h
|
||||||
DoRawLog(&buf, &size, "%c00000000 00:00:00.000000 %5u %s:%d] RAW: ",
|
DoRawLog(&buf, &size, "%c00000000 00:00:00.000000 %5u %s:%d] RAW: ",
|
||||||
LogSeverityNames[severity][0],
|
LogSeverityNames[severity][0], static_cast<unsigned int>(GetTID()),
|
||||||
static_cast<unsigned int>(GetTID()),
|
|
||||||
const_basename(const_cast<char*>(file)), line);
|
const_basename(const_cast<char*>(file)), line);
|
||||||
|
|
||||||
// Record the position and size of the buffer after the prefix
|
// Record the position and size of the buffer after the prefix
|
||||||
|
|||||||
@ -63,10 +63,8 @@ const struct {
|
|||||||
int number;
|
int number;
|
||||||
const char* name;
|
const char* name;
|
||||||
} kFailureSignals[] = {
|
} kFailureSignals[] = {
|
||||||
{ SIGSEGV, "SIGSEGV" },
|
{SIGSEGV, "SIGSEGV"}, {SIGILL, "SIGILL"},
|
||||||
{ SIGILL, "SIGILL" },
|
{SIGFPE, "SIGFPE"}, {SIGABRT, "SIGABRT"},
|
||||||
{ SIGFPE, "SIGFPE" },
|
|
||||||
{ SIGABRT, "SIGABRT" },
|
|
||||||
#if !defined(GLOG_OS_WINDOWS)
|
#if !defined(GLOG_OS_WINDOWS)
|
||||||
{SIGBUS, "SIGBUS"},
|
{SIGBUS, "SIGBUS"},
|
||||||
#endif
|
#endif
|
||||||
@ -78,7 +76,8 @@ static bool kFailureSignalHandlerInstalled = false;
|
|||||||
#if !defined(GLOG_OS_WINDOWS)
|
#if !defined(GLOG_OS_WINDOWS)
|
||||||
// Returns the program counter from signal context, nullptr if unknown.
|
// Returns the program counter from signal context, nullptr if unknown.
|
||||||
void* GetPC(void* ucontext_in_void) {
|
void* GetPC(void* ucontext_in_void) {
|
||||||
#if (defined(HAVE_UCONTEXT_H) || defined(HAVE_SYS_UCONTEXT_H)) && defined(PC_FROM_UCONTEXT)
|
# if (defined(HAVE_UCONTEXT_H) || defined(HAVE_SYS_UCONTEXT_H)) && \
|
||||||
|
defined(PC_FROM_UCONTEXT)
|
||||||
if (ucontext_in_void != nullptr) {
|
if (ucontext_in_void != nullptr) {
|
||||||
ucontext_t* context = reinterpret_cast<ucontext_t*>(ucontext_in_void);
|
ucontext_t* context = reinterpret_cast<ucontext_t*>(ucontext_in_void);
|
||||||
return (void*)context->PC_FROM_UCONTEXT;
|
return (void*)context->PC_FROM_UCONTEXT;
|
||||||
@ -95,13 +94,12 @@ void* GetPC(void* ucontext_in_void) {
|
|||||||
class MinimalFormatter {
|
class MinimalFormatter {
|
||||||
public:
|
public:
|
||||||
MinimalFormatter(char* buffer, size_t size)
|
MinimalFormatter(char* buffer, size_t size)
|
||||||
: buffer_(buffer),
|
: buffer_(buffer), cursor_(buffer), end_(buffer + size) {}
|
||||||
cursor_(buffer),
|
|
||||||
end_(buffer + size) {
|
|
||||||
}
|
|
||||||
|
|
||||||
// Returns the number of bytes written in the buffer.
|
// Returns the number of bytes written in the buffer.
|
||||||
std::size_t num_bytes_written() const { return static_cast<std::size_t>(cursor_ - buffer_); }
|
std::size_t num_bytes_written() const {
|
||||||
|
return static_cast<std::size_t>(cursor_ - buffer_);
|
||||||
|
}
|
||||||
|
|
||||||
// Appends string from "str" and updates the internal cursor.
|
// Appends string from "str" and updates the internal cursor.
|
||||||
void AppendString(const char* str) {
|
void AppendString(const char* str) {
|
||||||
@ -235,8 +233,8 @@ void DumpStackFrameInfo(const char* prefix, void* pc) {
|
|||||||
char symbolized[1024]; // Big enough for a sane symbol.
|
char symbolized[1024]; // Big enough for a sane symbol.
|
||||||
// Symbolizes the previous address of pc because pc may be in the
|
// Symbolizes the previous address of pc because pc may be in the
|
||||||
// next function.
|
// next function.
|
||||||
if (Symbolize(reinterpret_cast<char *>(pc) - 1,
|
if (Symbolize(reinterpret_cast<char*>(pc) - 1, symbolized,
|
||||||
symbolized, sizeof(symbolized))) {
|
sizeof(symbolized))) {
|
||||||
symbol = symbolized;
|
symbol = symbolized;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -279,8 +277,7 @@ static pthread_t* g_entered_thread_id_pointer = nullptr;
|
|||||||
#if defined(GLOG_OS_WINDOWS)
|
#if defined(GLOG_OS_WINDOWS)
|
||||||
void FailureSignalHandler(int signal_number)
|
void FailureSignalHandler(int signal_number)
|
||||||
#else
|
#else
|
||||||
void FailureSignalHandler(int signal_number,
|
void FailureSignalHandler(int signal_number, siginfo_t* signal_info,
|
||||||
siginfo_t *signal_info,
|
|
||||||
void* ucontext)
|
void* ucontext)
|
||||||
#endif
|
#endif
|
||||||
{
|
{
|
||||||
@ -400,8 +397,7 @@ void InstallFailureSignalHandler() {
|
|||||||
kFailureSignalHandlerInstalled = true;
|
kFailureSignalHandlerInstalled = true;
|
||||||
#elif defined(GLOG_OS_WINDOWS)
|
#elif defined(GLOG_OS_WINDOWS)
|
||||||
for (size_t i = 0; i < ARRAYSIZE(kFailureSignals); ++i) {
|
for (size_t i = 0; i < ARRAYSIZE(kFailureSignals); ++i) {
|
||||||
CHECK_NE(signal(kFailureSignals[i].number, &FailureSignalHandler),
|
CHECK_NE(signal(kFailureSignals[i].number, &FailureSignalHandler), SIG_ERR);
|
||||||
SIG_ERR);
|
|
||||||
}
|
}
|
||||||
kFailureSignalHandlerInstalled = true;
|
kFailureSignalHandlerInstalled = true;
|
||||||
#endif // HAVE_SIGACTION
|
#endif // HAVE_SIGACTION
|
||||||
|
|||||||
@ -89,7 +89,8 @@ int main(int argc, char **argv) {
|
|||||||
*a = 0;
|
*a = 0;
|
||||||
} else if (command == "loop") {
|
} else if (command == "loop") {
|
||||||
fprintf(stderr, "looping\n");
|
fprintf(stderr, "looping\n");
|
||||||
while (true);
|
while (true)
|
||||||
|
;
|
||||||
} else if (command == "die_in_thread") {
|
} else if (command == "die_in_thread") {
|
||||||
# if defined(HAVE_PTHREAD)
|
# if defined(HAVE_PTHREAD)
|
||||||
pthread_t thread;
|
pthread_t thread;
|
||||||
|
|||||||
@ -114,7 +114,8 @@ int GetStackTrace(void** result, int max_depth, int skip_count) {
|
|||||||
result[n++] = *(sp + 2);
|
result[n++] = *(sp + 2);
|
||||||
#elif defined(_CALL_SYSV)
|
#elif defined(_CALL_SYSV)
|
||||||
result[n++] = *(sp + 1);
|
result[n++] = *(sp + 1);
|
||||||
#elif defined(__APPLE__) || ((defined(__linux) || defined(__linux__)) && defined(__PPC64__))
|
#elif defined(__APPLE__) || \
|
||||||
|
((defined(__linux) || defined(__linux__)) && defined(__PPC64__))
|
||||||
// This check is in case the compiler doesn't define _CALL_AIX/etc.
|
// This check is in case the compiler doesn't define _CALL_AIX/etc.
|
||||||
result[n++] = *(sp + 2);
|
result[n++] = *(sp + 2);
|
||||||
#elif defined(__linux) || defined(__OpenBSD__)
|
#elif defined(__linux) || defined(__OpenBSD__)
|
||||||
|
|||||||
@ -75,7 +75,10 @@ AddressRange expected_range[BACKTRACE_STEPS];
|
|||||||
// (4.3.1, 4.4.0) thinks it safe to assign &&end an address that is before
|
// (4.3.1, 4.4.0) thinks it safe to assign &&end an address that is before
|
||||||
// the recursive call.
|
// the recursive call.
|
||||||
# define DECLARE_ADDRESS_LABEL(a_label) \
|
# define DECLARE_ADDRESS_LABEL(a_label) \
|
||||||
a_label: do { __asm__ __volatile__(""); } while (0)
|
a_label: \
|
||||||
|
do { \
|
||||||
|
__asm__ __volatile__(""); \
|
||||||
|
} while (0)
|
||||||
// Gcc 4.4.0 may split function into multiple chunks, and the chunk
|
// Gcc 4.4.0 may split function into multiple chunks, and the chunk
|
||||||
// performing recursive call may end up later in the code then the return
|
// performing recursive call may end up later in the code then the return
|
||||||
// instruction (this actually happens with FDO).
|
// instruction (this actually happens with FDO).
|
||||||
@ -85,9 +88,8 @@ AddressRange expected_range[BACKTRACE_STEPS];
|
|||||||
void* ra = __builtin_return_address(0); \
|
void* ra = __builtin_return_address(0); \
|
||||||
CHECK_LT((prange)->start, ra); \
|
CHECK_LT((prange)->start, ra); \
|
||||||
if (ra > (prange)->end) { \
|
if (ra > (prange)->end) { \
|
||||||
printf("Adjusting range from %p..%p to %p..%p\n", \
|
printf("Adjusting range from %p..%p to %p..%p\n", (prange)->start, \
|
||||||
(prange)->start, (prange)->end, \
|
(prange)->end, (prange)->start, ra); \
|
||||||
(prange)->start, ra); \
|
|
||||||
(prange)->end = ra; \
|
(prange)->end = ra; \
|
||||||
} \
|
} \
|
||||||
} while (0)
|
} while (0)
|
||||||
@ -98,14 +100,18 @@ AddressRange expected_range[BACKTRACE_STEPS];
|
|||||||
(prange)->start = reinterpret_cast<const void*>(&fn); \
|
(prange)->start = reinterpret_cast<const void*>(&fn); \
|
||||||
(prange)->end = reinterpret_cast<const char*>(&fn) + 256; \
|
(prange)->end = reinterpret_cast<const char*>(&fn) + 256; \
|
||||||
} while (0)
|
} while (0)
|
||||||
#define DECLARE_ADDRESS_LABEL(a_label) do { } while (0)
|
# define DECLARE_ADDRESS_LABEL(a_label) \
|
||||||
#define ADJUST_ADDRESS_RANGE_FROM_RA(prange) do { } while (0)
|
do { \
|
||||||
|
} while (0)
|
||||||
|
# define ADJUST_ADDRESS_RANGE_FROM_RA(prange) \
|
||||||
|
do { \
|
||||||
|
} while (0)
|
||||||
# endif // __GNUC__
|
# endif // __GNUC__
|
||||||
|
|
||||||
//-----------------------------------------------------------------------//
|
//-----------------------------------------------------------------------//
|
||||||
|
|
||||||
static void CheckRetAddrIsInFunction(void *ret_addr, const AddressRange &range)
|
static void CheckRetAddrIsInFunction(void* ret_addr,
|
||||||
{
|
const AddressRange& range) {
|
||||||
CHECK_GE(ret_addr, range.start);
|
CHECK_GE(ret_addr, range.start);
|
||||||
CHECK_LE(ret_addr, range.end);
|
CHECK_LE(ret_addr, range.end);
|
||||||
}
|
}
|
||||||
@ -149,8 +155,8 @@ static void ATTRIBUTE_NOINLINE CheckStackTraceLeaf() {
|
|||||||
# endif
|
# endif
|
||||||
}
|
}
|
||||||
for (int i = 0; i < BACKTRACE_STEPS; i++) {
|
for (int i = 0; i < BACKTRACE_STEPS; i++) {
|
||||||
printf("Backtrace %d: expected: %p..%p actual: %p ... ",
|
printf("Backtrace %d: expected: %p..%p actual: %p ... ", i,
|
||||||
i, expected_range[i].start, expected_range[i].end, stack[i]);
|
expected_range[i].start, expected_range[i].end, stack[i]);
|
||||||
fflush(stdout);
|
fflush(stdout);
|
||||||
CheckRetAddrIsInFunction(stack[i], expected_range[i]);
|
CheckRetAddrIsInFunction(stack[i], expected_range[i]);
|
||||||
printf("OK\n");
|
printf("OK\n");
|
||||||
@ -207,7 +213,8 @@ static void ATTRIBUTE_NOINLINE CheckStackTrace1(int i) {
|
|||||||
// See https://github.com/google/glog/issues/421 for the detail.
|
// See https://github.com/google/glog/issues/421 for the detail.
|
||||||
static
|
static
|
||||||
# endif
|
# endif
|
||||||
void ATTRIBUTE_NOINLINE CheckStackTrace(int i) {
|
void ATTRIBUTE_NOINLINE
|
||||||
|
CheckStackTrace(int i) {
|
||||||
INIT_ADDRESS_RANGE(CheckStackTrace, start, end, &expected_range[5]);
|
INIT_ADDRESS_RANGE(CheckStackTrace, start, end, &expected_range[5]);
|
||||||
DECLARE_ADDRESS_LABEL(start);
|
DECLARE_ADDRESS_LABEL(start);
|
||||||
for (int j = i; j >= 0; j--) {
|
for (int j = i; j >= 0; j--) {
|
||||||
|
|||||||
@ -45,11 +45,11 @@ struct trace_arg_t {
|
|||||||
};
|
};
|
||||||
|
|
||||||
// Workaround for the malloc() in _Unwind_Backtrace() issue.
|
// Workaround for the malloc() in _Unwind_Backtrace() issue.
|
||||||
static _Unwind_Reason_Code nop_backtrace(struct _Unwind_Context */*uc*/, void */*opq*/) {
|
static _Unwind_Reason_Code nop_backtrace(struct _Unwind_Context* /*uc*/,
|
||||||
|
void* /*opq*/) {
|
||||||
return _URC_NO_REASON;
|
return _URC_NO_REASON;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// This code is not considered ready to run until
|
// This code is not considered ready to run until
|
||||||
// static initializers run so that we are guaranteed
|
// static initializers run so that we are guaranteed
|
||||||
// that any malloc-related initialization is done.
|
// that any malloc-related initialization is done.
|
||||||
|
|||||||
@ -31,10 +31,11 @@
|
|||||||
//
|
//
|
||||||
// Windows implementation - just use CaptureStackBackTrace
|
// Windows implementation - just use CaptureStackBackTrace
|
||||||
|
|
||||||
|
#include <dbghelp.h>
|
||||||
|
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
#include "port.h"
|
#include "port.h"
|
||||||
#include "stacktrace.h"
|
#include "stacktrace.h"
|
||||||
#include <dbghelp.h>
|
|
||||||
|
|
||||||
namespace google {
|
namespace google {
|
||||||
|
|
||||||
|
|||||||
@ -34,8 +34,8 @@
|
|||||||
#include "utilities.h" // for OS_* macros
|
#include "utilities.h" // for OS_* macros
|
||||||
|
|
||||||
#if !defined(GLOG_OS_WINDOWS)
|
#if !defined(GLOG_OS_WINDOWS)
|
||||||
#include <unistd.h>
|
|
||||||
# include <sys/mman.h>
|
# include <sys/mman.h>
|
||||||
|
# include <unistd.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include <cstdio> // for nullptr
|
#include <cstdio> // for nullptr
|
||||||
|
|||||||
114
src/symbolize.cc
114
src/symbolize.cc
@ -56,13 +56,12 @@
|
|||||||
|
|
||||||
#if defined(HAVE_SYMBOLIZE)
|
#if defined(HAVE_SYMBOLIZE)
|
||||||
|
|
||||||
#include <cstring>
|
|
||||||
|
|
||||||
# include <algorithm>
|
# include <algorithm>
|
||||||
|
# include <cstring>
|
||||||
# include <limits>
|
# include <limits>
|
||||||
|
|
||||||
#include "symbolize.h"
|
|
||||||
# include "demangle.h"
|
# include "demangle.h"
|
||||||
|
# include "symbolize.h"
|
||||||
|
|
||||||
namespace google {
|
namespace google {
|
||||||
|
|
||||||
@ -136,7 +135,9 @@ static ATTRIBUTE_NOINLINE void DemangleInplace(char *out, size_t out_size) {
|
|||||||
# include "symbolize.h"
|
# include "symbolize.h"
|
||||||
|
|
||||||
// Re-runs fn until it doesn't cause EINTR.
|
// Re-runs fn until it doesn't cause EINTR.
|
||||||
#define NO_INTR(fn) do {} while ((fn) < 0 && errno == EINTR)
|
# define NO_INTR(fn) \
|
||||||
|
do { \
|
||||||
|
} while ((fn) < 0 && errno == EINTR)
|
||||||
|
|
||||||
namespace google {
|
namespace google {
|
||||||
|
|
||||||
@ -147,7 +148,8 @@ namespace google {
|
|||||||
static ssize_t ReadFromOffset(const int fd, void* buf, const size_t count,
|
static ssize_t ReadFromOffset(const int fd, void* buf, const size_t count,
|
||||||
const size_t offset) {
|
const size_t offset) {
|
||||||
SAFE_ASSERT(fd >= 0);
|
SAFE_ASSERT(fd >= 0);
|
||||||
SAFE_ASSERT(count <= static_cast<size_t>(std::numeric_limits<ssize_t>::max()));
|
SAFE_ASSERT(count <=
|
||||||
|
static_cast<size_t>(std::numeric_limits<ssize_t>::max()));
|
||||||
char* buf0 = reinterpret_cast<char*>(buf);
|
char* buf0 = reinterpret_cast<char*>(buf);
|
||||||
size_t num_bytes = 0;
|
size_t num_bytes = 0;
|
||||||
while (num_bytes < count) {
|
while (num_bytes < count) {
|
||||||
@ -170,8 +172,8 @@ static ssize_t ReadFromOffset(const int fd, void *buf, const size_t count,
|
|||||||
// pointed by "fd" into the buffer starting at "buf" while handling
|
// pointed by "fd" into the buffer starting at "buf" while handling
|
||||||
// short reads and EINTR. On success, return true. Otherwise, return
|
// short reads and EINTR. On success, return true. Otherwise, return
|
||||||
// false.
|
// false.
|
||||||
static bool ReadFromOffsetExact(const int fd, void *buf,
|
static bool ReadFromOffsetExact(const int fd, void* buf, const size_t count,
|
||||||
const size_t count, const size_t offset) {
|
const size_t offset) {
|
||||||
ssize_t len = ReadFromOffset(fd, buf, count, offset);
|
ssize_t len = ReadFromOffset(fd, buf, count, offset);
|
||||||
return static_cast<size_t>(len) == count;
|
return static_cast<size_t>(len) == count;
|
||||||
}
|
}
|
||||||
@ -193,9 +195,11 @@ static int FileGetElfType(const int fd) {
|
|||||||
// and return true. Otherwise, return false.
|
// and return true. Otherwise, return false.
|
||||||
// To keep stack consumption low, we would like this function to not get
|
// To keep stack consumption low, we would like this function to not get
|
||||||
// inlined.
|
// inlined.
|
||||||
static ATTRIBUTE_NOINLINE bool
|
static ATTRIBUTE_NOINLINE bool GetSectionHeaderByType(const int fd,
|
||||||
GetSectionHeaderByType(const int fd, ElfW(Half) sh_num, const size_t sh_offset,
|
ElfW(Half) sh_num,
|
||||||
ElfW(Word) type, ElfW(Shdr) *out) {
|
const size_t sh_offset,
|
||||||
|
ElfW(Word) type,
|
||||||
|
ElfW(Shdr) * out) {
|
||||||
// Read at most 16 section headers at a time to save read calls.
|
// Read at most 16 section headers at a time to save read calls.
|
||||||
ElfW(Shdr) buf[16];
|
ElfW(Shdr) buf[16];
|
||||||
for (size_t i = 0; i < sh_num;) {
|
for (size_t i = 0; i < sh_num;) {
|
||||||
@ -242,8 +246,8 @@ bool GetSectionHeaderByName(int fd, const char *name, size_t name_len,
|
|||||||
}
|
}
|
||||||
|
|
||||||
for (size_t i = 0; i < elf_header.e_shnum; ++i) {
|
for (size_t i = 0; i < elf_header.e_shnum; ++i) {
|
||||||
size_t section_header_offset = (elf_header.e_shoff +
|
size_t section_header_offset =
|
||||||
elf_header.e_shentsize * i);
|
(elf_header.e_shoff + elf_header.e_shentsize * i);
|
||||||
if (!ReadFromOffsetExact(fd, out, sizeof(*out), section_header_offset)) {
|
if (!ReadFromOffsetExact(fd, out, sizeof(*out), section_header_offset)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -277,9 +281,10 @@ bool GetSectionHeaderByName(int fd, const char *name, size_t name_len,
|
|||||||
// to out. Otherwise, return false.
|
// to out. Otherwise, return false.
|
||||||
// To keep stack consumption low, we would like this function to not get
|
// To keep stack consumption low, we would like this function to not get
|
||||||
// inlined.
|
// inlined.
|
||||||
static ATTRIBUTE_NOINLINE bool
|
static ATTRIBUTE_NOINLINE bool FindSymbol(uint64_t pc, const int fd, char* out,
|
||||||
FindSymbol(uint64_t pc, const int fd, char *out, size_t out_size,
|
size_t out_size,
|
||||||
uint64_t symbol_offset, const ElfW(Shdr) *strtab,
|
uint64_t symbol_offset,
|
||||||
|
const ElfW(Shdr) * strtab,
|
||||||
const ElfW(Shdr) * symtab) {
|
const ElfW(Shdr) * symtab) {
|
||||||
if (symtab == nullptr) {
|
if (symtab == nullptr) {
|
||||||
return false;
|
return false;
|
||||||
@ -331,11 +336,8 @@ FindSymbol(uint64_t pc, const int fd, char *out, size_t out_size,
|
|||||||
// both regular and dynamic symbol tables if necessary. On success,
|
// both regular and dynamic symbol tables if necessary. On success,
|
||||||
// write the symbol name to "out" and return true. Otherwise, return
|
// write the symbol name to "out" and return true. Otherwise, return
|
||||||
// false.
|
// false.
|
||||||
static bool GetSymbolFromObjectFile(const int fd,
|
static bool GetSymbolFromObjectFile(const int fd, uint64_t pc, char* out,
|
||||||
uint64_t pc,
|
size_t out_size, uint64_t base_address) {
|
||||||
char* out,
|
|
||||||
size_t out_size,
|
|
||||||
uint64_t base_address) {
|
|
||||||
// Read the ELF header.
|
// Read the ELF header.
|
||||||
ElfW(Ehdr) elf_header;
|
ElfW(Ehdr) elf_header;
|
||||||
if (!ReadFromOffsetExact(fd, &elf_header, sizeof(elf_header), 0)) {
|
if (!ReadFromOffsetExact(fd, &elf_header, sizeof(elf_header), 0)) {
|
||||||
@ -347,8 +349,9 @@ static bool GetSymbolFromObjectFile(const int fd,
|
|||||||
// Consult a regular symbol table first.
|
// Consult a regular symbol table first.
|
||||||
if (GetSectionHeaderByType(fd, elf_header.e_shnum, elf_header.e_shoff,
|
if (GetSectionHeaderByType(fd, elf_header.e_shnum, elf_header.e_shoff,
|
||||||
SHT_SYMTAB, &symtab)) {
|
SHT_SYMTAB, &symtab)) {
|
||||||
if (!ReadFromOffsetExact(fd, &strtab, sizeof(strtab), elf_header.e_shoff +
|
if (!ReadFromOffsetExact(
|
||||||
symtab.sh_link * sizeof(symtab))) {
|
fd, &strtab, sizeof(strtab),
|
||||||
|
elf_header.e_shoff + symtab.sh_link * sizeof(symtab))) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (FindSymbol(pc, fd, out, out_size, base_address, &strtab, &symtab)) {
|
if (FindSymbol(pc, fd, out, out_size, base_address, &strtab, &symtab)) {
|
||||||
@ -359,8 +362,9 @@ static bool GetSymbolFromObjectFile(const int fd,
|
|||||||
// If the symbol is not found, then consult a dynamic symbol table.
|
// If the symbol is not found, then consult a dynamic symbol table.
|
||||||
if (GetSectionHeaderByType(fd, elf_header.e_shnum, elf_header.e_shoff,
|
if (GetSectionHeaderByType(fd, elf_header.e_shnum, elf_header.e_shoff,
|
||||||
SHT_DYNSYM, &symtab)) {
|
SHT_DYNSYM, &symtab)) {
|
||||||
if (!ReadFromOffsetExact(fd, &strtab, sizeof(strtab), elf_header.e_shoff +
|
if (!ReadFromOffsetExact(
|
||||||
symtab.sh_link * sizeof(symtab))) {
|
fd, &strtab, sizeof(strtab),
|
||||||
|
elf_header.e_shoff + symtab.sh_link * sizeof(symtab))) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (FindSymbol(pc, fd, out, out_size, base_address, &strtab, &symtab)) {
|
if (FindSymbol(pc, fd, out, out_size, base_address, &strtab, &symtab)) {
|
||||||
@ -451,26 +455,21 @@ class LineReader {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Beginning of line.
|
// Beginning of line.
|
||||||
const char *bol() {
|
const char* bol() { return bol_; }
|
||||||
return bol_;
|
|
||||||
}
|
|
||||||
|
|
||||||
// End of line.
|
// End of line.
|
||||||
const char *eol() {
|
const char* eol() { return eol_; }
|
||||||
return eol_;
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
LineReader(const LineReader&) = delete;
|
LineReader(const LineReader&) = delete;
|
||||||
void operator=(const LineReader&) = delete;
|
void operator=(const LineReader&) = delete;
|
||||||
|
|
||||||
char* FindLineFeed() {
|
char* FindLineFeed() {
|
||||||
return reinterpret_cast<char *>(memchr(bol_, '\n', static_cast<size_t>(eod_ - bol_)));
|
return reinterpret_cast<char*>(
|
||||||
|
memchr(bol_, '\n', static_cast<size_t>(eod_ - bol_)));
|
||||||
}
|
}
|
||||||
|
|
||||||
bool BufferIsEmpty() {
|
bool BufferIsEmpty() { return buf_ == eod_; }
|
||||||
return buf_ == eod_;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool HasCompleteLine() {
|
bool HasCompleteLine() {
|
||||||
return !BufferIsEmpty() && FindLineFeed() != nullptr;
|
return !BufferIsEmpty() && FindLineFeed() != nullptr;
|
||||||
@ -493,9 +492,10 @@ static char *GetHex(const char *start, const char *end, uint64_t *hex) {
|
|||||||
const char* p;
|
const char* p;
|
||||||
for (p = start; p < end; ++p) {
|
for (p = start; p < end; ++p) {
|
||||||
int ch = *p;
|
int ch = *p;
|
||||||
if ((ch >= '0' && ch <= '9') ||
|
if ((ch >= '0' && ch <= '9') || (ch >= 'A' && ch <= 'F') ||
|
||||||
(ch >= 'A' && ch <= 'F') || (ch >= 'a' && ch <= 'f')) {
|
(ch >= 'a' && ch <= 'f')) {
|
||||||
*hex = (*hex << 4U) | (ch < 'A' ? static_cast<uint64_t>(ch - '0') : (ch & 0xF) + 9U);
|
*hex = (*hex << 4U) |
|
||||||
|
(ch < 'A' ? static_cast<uint64_t>(ch - '0') : (ch & 0xF) + 9U);
|
||||||
} else { // Encountered the first non-hex character.
|
} else { // Encountered the first non-hex character.
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -512,12 +512,9 @@ static char *GetHex(const char *start, const char *end, uint64_t *hex) {
|
|||||||
// file is opened successfully, returns the file descriptor. Otherwise,
|
// file is opened successfully, returns the file descriptor. Otherwise,
|
||||||
// returns -1. |out_file_name_size| is the size of the file name buffer
|
// returns -1. |out_file_name_size| is the size of the file name buffer
|
||||||
// (including the null-terminator).
|
// (including the null-terminator).
|
||||||
static ATTRIBUTE_NOINLINE int
|
static ATTRIBUTE_NOINLINE int OpenObjectFileContainingPcAndGetStartAddress(
|
||||||
OpenObjectFileContainingPcAndGetStartAddress(uint64_t pc,
|
uint64_t pc, uint64_t& start_address, uint64_t& base_address,
|
||||||
uint64_t &start_address,
|
char* out_file_name, size_t out_file_name_size) {
|
||||||
uint64_t &base_address,
|
|
||||||
char *out_file_name,
|
|
||||||
size_t out_file_name_size) {
|
|
||||||
int object_fd;
|
int object_fd;
|
||||||
|
|
||||||
int maps_fd;
|
int maps_fd;
|
||||||
@ -672,7 +669,8 @@ OpenObjectFileContainingPcAndGetStartAddress(uint64_t pc,
|
|||||||
// "sz" bytes. Output will be truncated as needed, and a NUL character is always
|
// "sz" bytes. Output will be truncated as needed, and a NUL character is always
|
||||||
// appended.
|
// appended.
|
||||||
// NOTE: code from sandbox/linux/seccomp-bpf/demo.cc.
|
// NOTE: code from sandbox/linux/seccomp-bpf/demo.cc.
|
||||||
static char *itoa_r(uintptr_t i, char *buf, size_t sz, unsigned base, size_t padding) {
|
static char* itoa_r(uintptr_t i, char* buf, size_t sz, unsigned base,
|
||||||
|
size_t padding) {
|
||||||
// Make sure we can write at least one NUL byte.
|
// Make sure we can write at least one NUL byte.
|
||||||
size_t n = 1;
|
size_t n = 1;
|
||||||
if (n > sz) {
|
if (n > sz) {
|
||||||
@ -763,14 +761,11 @@ static ATTRIBUTE_NOINLINE bool SymbolizeAndDemangle(void *pc, char *out,
|
|||||||
SafeAppendString("(", out, out_size);
|
SafeAppendString("(", out, out_size);
|
||||||
|
|
||||||
if (g_symbolize_open_object_file_callback) {
|
if (g_symbolize_open_object_file_callback) {
|
||||||
object_fd = g_symbolize_open_object_file_callback(pc0, start_address,
|
object_fd = g_symbolize_open_object_file_callback(
|
||||||
base_address, out + 1,
|
pc0, start_address, base_address, out + 1, out_size - 1);
|
||||||
out_size - 1);
|
|
||||||
} else {
|
} else {
|
||||||
object_fd = OpenObjectFileContainingPcAndGetStartAddress(pc0, start_address,
|
object_fd = OpenObjectFileContainingPcAndGetStartAddress(
|
||||||
base_address,
|
pc0, start_address, base_address, out + 1, out_size - 1);
|
||||||
out + 1,
|
|
||||||
out_size - 1);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
FileDescriptor wrapped_object_fd(object_fd);
|
FileDescriptor wrapped_object_fd(object_fd);
|
||||||
@ -804,16 +799,15 @@ static ATTRIBUTE_NOINLINE bool SymbolizeAndDemangle(void *pc, char *out,
|
|||||||
// Note: relocation (and much of the rest of this code) will be
|
// Note: relocation (and much of the rest of this code) will be
|
||||||
// wrong for prelinked shared libraries and PIE executables.
|
// wrong for prelinked shared libraries and PIE executables.
|
||||||
uint64_t relocation = (elf_type == ET_DYN) ? start_address : 0;
|
uint64_t relocation = (elf_type == ET_DYN) ? start_address : 0;
|
||||||
int num_bytes_written = g_symbolize_callback(wrapped_object_fd.get(),
|
int num_bytes_written = g_symbolize_callback(wrapped_object_fd.get(), pc,
|
||||||
pc, out, out_size,
|
out, out_size, relocation);
|
||||||
relocation);
|
|
||||||
if (num_bytes_written > 0) {
|
if (num_bytes_written > 0) {
|
||||||
out += static_cast<size_t>(num_bytes_written);
|
out += static_cast<size_t>(num_bytes_written);
|
||||||
out_size -= static_cast<size_t>(num_bytes_written);
|
out_size -= static_cast<size_t>(num_bytes_written);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!GetSymbolFromObjectFile(wrapped_object_fd.get(), pc0,
|
if (!GetSymbolFromObjectFile(wrapped_object_fd.get(), pc0, out, out_size,
|
||||||
out, out_size, base_address)) {
|
base_address)) {
|
||||||
if (out[1] && !g_symbolize_callback) {
|
if (out[1] && !g_symbolize_callback) {
|
||||||
// The object file containing PC was opened successfully however the
|
// The object file containing PC was opened successfully however the
|
||||||
// symbol was not found. The object may have been stripped. This is still
|
// symbol was not found. The object may have been stripped. This is still
|
||||||
@ -838,6 +832,7 @@ static ATTRIBUTE_NOINLINE bool SymbolizeAndDemangle(void *pc, char *out,
|
|||||||
# elif defined(GLOG_OS_MACOSX) && defined(HAVE_DLADDR)
|
# elif defined(GLOG_OS_MACOSX) && defined(HAVE_DLADDR)
|
||||||
|
|
||||||
# include <dlfcn.h>
|
# include <dlfcn.h>
|
||||||
|
|
||||||
# include <cstring>
|
# include <cstring>
|
||||||
|
|
||||||
namespace google {
|
namespace google {
|
||||||
@ -862,8 +857,8 @@ static ATTRIBUTE_NOINLINE bool SymbolizeAndDemangle(void *pc, char *out,
|
|||||||
|
|
||||||
# elif defined(GLOG_OS_WINDOWS) || defined(GLOG_OS_CYGWIN)
|
# elif defined(GLOG_OS_WINDOWS) || defined(GLOG_OS_CYGWIN)
|
||||||
|
|
||||||
#include <windows.h>
|
|
||||||
# include <dbghelp.h>
|
# include <dbghelp.h>
|
||||||
|
# include <windows.h>
|
||||||
|
|
||||||
# ifdef _MSC_VER
|
# ifdef _MSC_VER
|
||||||
# pragma comment(lib, "dbghelp")
|
# pragma comment(lib, "dbghelp")
|
||||||
@ -891,6 +886,7 @@ public:
|
|||||||
SymCleanup(process);
|
SymCleanup(process);
|
||||||
// We do not need to close `HANDLE process` because it's a "pseudo handle."
|
// We do not need to close `HANDLE process` because it's a "pseudo handle."
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
SymInitializer(const SymInitializer&);
|
SymInitializer(const SymInitializer&);
|
||||||
SymInitializer& operator=(const SymInitializer&);
|
SymInitializer& operator=(const SymInitializer&);
|
||||||
@ -910,8 +906,8 @@ static ATTRIBUTE_NOINLINE bool SymbolizeAndDemangle(void *pc, char *out,
|
|||||||
symbol->MaxNameLen = MAX_SYM_NAME;
|
symbol->MaxNameLen = MAX_SYM_NAME;
|
||||||
// We use the ANSI version to ensure the string type is always `char *`.
|
// We use the ANSI version to ensure the string type is always `char *`.
|
||||||
// This could break if a symbol has Unicode in it.
|
// This could break if a symbol has Unicode in it.
|
||||||
BOOL ret = SymFromAddr(symInitializer.process,
|
BOOL ret = SymFromAddr(symInitializer.process, reinterpret_cast<DWORD64>(pc),
|
||||||
reinterpret_cast<DWORD64>(pc), 0, symbol);
|
0, symbol);
|
||||||
if (ret == 1 && static_cast<ssize_t>(symbol->NameLen) < out_size) {
|
if (ret == 1 && static_cast<ssize_t>(symbol->NameLen) < out_size) {
|
||||||
// `NameLen` does not include the null terminating character.
|
// `NameLen` does not include the null terminating character.
|
||||||
strncpy(out, symbol->Name, static_cast<size_t>(symbol->NameLen) + 1);
|
strncpy(out, symbol->Name, static_cast<size_t>(symbol->NameLen) + 1);
|
||||||
|
|||||||
@ -130,8 +130,8 @@ void InstallSymbolizeCallback(SymbolizeCallback callback);
|
|||||||
// file is opened successfully, returns the file descriptor. Otherwise,
|
// file is opened successfully, returns the file descriptor. Otherwise,
|
||||||
// returns -1. |out_file_name_size| is the size of the file name buffer
|
// returns -1. |out_file_name_size| is the size of the file name buffer
|
||||||
// (including the null-terminator).
|
// (including the null-terminator).
|
||||||
using SymbolizeOpenObjectFileCallback = int (*)(uint64_t, uint64_t &,
|
using SymbolizeOpenObjectFileCallback = int (*)(uint64_t, uint64_t&, uint64_t&,
|
||||||
uint64_t &, char *, size_t);
|
char*, size_t);
|
||||||
void InstallSymbolizeOpenObjectFileCallback(
|
void InstallSymbolizeOpenObjectFileCallback(
|
||||||
SymbolizeOpenObjectFileCallback callback);
|
SymbolizeOpenObjectFileCallback callback);
|
||||||
|
|
||||||
|
|||||||
@ -79,7 +79,8 @@ static const char *TrySymbolize(void *pc) {
|
|||||||
# if defined(__GNUC__) && !defined(__OPENCC__)
|
# if defined(__GNUC__) && !defined(__OPENCC__)
|
||||||
# if __GNUC__ >= 4
|
# if __GNUC__ >= 4
|
||||||
# define TEST_WITH_MODERN_GCC
|
# define TEST_WITH_MODERN_GCC
|
||||||
# if defined(__i386__) && __i386__ // always_inline isn't supported for x86_64 with GCC 4.1.0.
|
# if defined(__i386__) && __i386__ // always_inline isn't supported for
|
||||||
|
// x86_64 with GCC 4.1.0.
|
||||||
# undef always_inline
|
# undef always_inline
|
||||||
# define always_inline __attribute__((always_inline))
|
# define always_inline __attribute__((always_inline))
|
||||||
# define HAVE_ALWAYS_INLINE
|
# define HAVE_ALWAYS_INLINE
|
||||||
@ -214,7 +215,6 @@ static int GetStackConsumption(const char* alt_stack) {
|
|||||||
|
|
||||||
// Call Symbolize and figure out the stack footprint of this call.
|
// Call Symbolize and figure out the stack footprint of this call.
|
||||||
static const char* SymbolizeStackConsumption(void* pc, int* stack_consumed) {
|
static const char* SymbolizeStackConsumption(void* pc, int* stack_consumed) {
|
||||||
|
|
||||||
g_pc_to_symbolize = pc;
|
g_pc_to_symbolize = pc;
|
||||||
|
|
||||||
// The alt-signal-stack cannot be heap allocated because there is a
|
// The alt-signal-stack cannot be heap allocated because there is a
|
||||||
|
|||||||
@ -29,13 +29,13 @@
|
|||||||
//
|
//
|
||||||
// Author: Shinichiro Hamaji
|
// Author: Shinichiro Hamaji
|
||||||
|
|
||||||
#include "config.h"
|
|
||||||
#include "utilities.h"
|
#include "utilities.h"
|
||||||
|
|
||||||
|
#include <csignal>
|
||||||
#include <cstdio>
|
#include <cstdio>
|
||||||
#include <cstdlib>
|
#include <cstdlib>
|
||||||
|
|
||||||
#include <csignal>
|
#include "config.h"
|
||||||
#ifdef HAVE_SYS_TIME_H
|
#ifdef HAVE_SYS_TIME_H
|
||||||
# include <sys/time.h>
|
# include <sys/time.h>
|
||||||
#endif
|
#endif
|
||||||
@ -75,9 +75,9 @@ bool IsGoogleLoggingInitialized() {
|
|||||||
// The following APIs are all internal.
|
// The following APIs are all internal.
|
||||||
#ifdef HAVE_STACKTRACE
|
#ifdef HAVE_STACKTRACE
|
||||||
|
|
||||||
|
# include "base/commandlineflags.h"
|
||||||
# include "stacktrace.h"
|
# include "stacktrace.h"
|
||||||
# include "symbolize.h"
|
# include "symbolize.h"
|
||||||
#include "base/commandlineflags.h"
|
|
||||||
|
|
||||||
GLOG_DEFINE_bool(symbolize_stacktrace, true,
|
GLOG_DEFINE_bool(symbolize_stacktrace, true,
|
||||||
"Symbolize the stack trace in the tombstone");
|
"Symbolize the stack trace in the tombstone");
|
||||||
@ -199,7 +199,8 @@ struct timeval {
|
|||||||
long tv_sec, tv_usec;
|
long tv_sec, tv_usec;
|
||||||
};
|
};
|
||||||
|
|
||||||
// Based on: http://www.google.com/codesearch/p?hl=en#dR3YEbitojA/os_win32.c&q=GetSystemTimeAsFileTime%20license:bsd
|
// Based on:
|
||||||
|
// http://www.google.com/codesearch/p?hl=en#dR3YEbitojA/os_win32.c&q=GetSystemTimeAsFileTime%20license:bsd
|
||||||
// See COPYING for copyright information.
|
// See COPYING for copyright information.
|
||||||
static int gettimeofday(struct timeval* tv, void* /*tz*/) {
|
static int gettimeofday(struct timeval* tv, void* /*tz*/) {
|
||||||
# ifdef __GNUC__
|
# ifdef __GNUC__
|
||||||
@ -232,9 +233,7 @@ int64 CycleClock_Now() {
|
|||||||
return static_cast<int64>(tv.tv_sec) * 1000000 + tv.tv_usec;
|
return static_cast<int64>(tv.tv_sec) * 1000000 + tv.tv_usec;
|
||||||
}
|
}
|
||||||
|
|
||||||
int64 UsecToCycles(int64 usec) {
|
int64 UsecToCycles(int64 usec) { return usec; }
|
||||||
return usec;
|
|
||||||
}
|
|
||||||
|
|
||||||
WallTime WallTime_Now() {
|
WallTime WallTime_Now() {
|
||||||
// Now, cycle clock is retuning microseconds since the epoch.
|
// Now, cycle clock is retuning microseconds since the epoch.
|
||||||
@ -242,9 +241,7 @@ WallTime WallTime_Now() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static int32 g_main_thread_pid = getpid();
|
static int32 g_main_thread_pid = getpid();
|
||||||
int32 GetMainThreadPid() {
|
int32 GetMainThreadPid() { return g_main_thread_pid; }
|
||||||
return g_main_thread_pid;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool PidHasChanged() {
|
bool PidHasChanged() {
|
||||||
int32 pid = getpid();
|
int32 pid = getpid();
|
||||||
@ -305,16 +302,13 @@ pid_t GetTID() {
|
|||||||
const char* const_basename(const char* filepath) {
|
const char* const_basename(const char* filepath) {
|
||||||
const char* base = strrchr(filepath, '/');
|
const char* base = strrchr(filepath, '/');
|
||||||
#ifdef GLOG_OS_WINDOWS // Look for either path separator in Windows
|
#ifdef GLOG_OS_WINDOWS // Look for either path separator in Windows
|
||||||
if (!base)
|
if (!base) base = strrchr(filepath, '\\');
|
||||||
base = strrchr(filepath, '\\');
|
|
||||||
#endif
|
#endif
|
||||||
return base ? (base + 1) : filepath;
|
return base ? (base + 1) : filepath;
|
||||||
}
|
}
|
||||||
|
|
||||||
static string g_my_user_name;
|
static string g_my_user_name;
|
||||||
const string& MyUserName() {
|
const string& MyUserName() { return g_my_user_name; }
|
||||||
return g_my_user_name;
|
|
||||||
}
|
|
||||||
static void MyUserNameInitializer() {
|
static void MyUserNameInitializer() {
|
||||||
// TODO(hamaji): Probably this is not portable.
|
// TODO(hamaji): Probably this is not portable.
|
||||||
#if defined(GLOG_OS_WINDOWS)
|
#if defined(GLOG_OS_WINDOWS)
|
||||||
@ -356,8 +350,7 @@ void DumpStackTraceToString(string* stacktrace) {
|
|||||||
static const CrashReason* g_reason = nullptr;
|
static const CrashReason* g_reason = nullptr;
|
||||||
|
|
||||||
void SetCrashReason(const CrashReason* r) {
|
void SetCrashReason(const CrashReason* r) {
|
||||||
sync_val_compare_and_swap(&g_reason,
|
sync_val_compare_and_swap(&g_reason, reinterpret_cast<const CrashReason*>(0),
|
||||||
reinterpret_cast<const CrashReason*>(0),
|
|
||||||
r);
|
r);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -377,7 +370,8 @@ void InitGoogleLoggingUtilities(const char* argv0) {
|
|||||||
|
|
||||||
void ShutdownGoogleLoggingUtilities() {
|
void ShutdownGoogleLoggingUtilities() {
|
||||||
CHECK(IsGoogleLoggingInitialized())
|
CHECK(IsGoogleLoggingInitialized())
|
||||||
<< "You called ShutdownGoogleLogging() without calling InitGoogleLogging() first!";
|
<< "You called ShutdownGoogleLogging() without calling "
|
||||||
|
"InitGoogleLogging() first!";
|
||||||
g_program_invocation_short_name = nullptr;
|
g_program_invocation_short_name = nullptr;
|
||||||
#ifdef HAVE_SYSLOG_H
|
#ifdef HAVE_SYSLOG_H
|
||||||
closelog();
|
closelog();
|
||||||
@ -393,10 +387,10 @@ void ShutdownGoogleLoggingUtilities() {
|
|||||||
# include STACKTRACE_H
|
# include STACKTRACE_H
|
||||||
# if 0
|
# if 0
|
||||||
// For include scanners which can't handle macro expansions.
|
// For include scanners which can't handle macro expansions.
|
||||||
|
# include "stacktrace_generic-inl.h"
|
||||||
# include "stacktrace_libunwind-inl.h"
|
# include "stacktrace_libunwind-inl.h"
|
||||||
|
# include "stacktrace_powerpc-inl.h"
|
||||||
# include "stacktrace_x86-inl.h"
|
# include "stacktrace_x86-inl.h"
|
||||||
# include "stacktrace_x86_64-inl.h"
|
# include "stacktrace_x86_64-inl.h"
|
||||||
# include "stacktrace_powerpc-inl.h"
|
|
||||||
# include "stacktrace_generic-inl.h"
|
|
||||||
# endif
|
# endif
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@ -49,10 +49,13 @@
|
|||||||
|
|
||||||
using std::string;
|
using std::string;
|
||||||
|
|
||||||
GLOG_DEFINE_int32(v, 0, "Show all VLOG(m) messages for m <= this."
|
GLOG_DEFINE_int32(v, 0,
|
||||||
|
"Show all VLOG(m) messages for m <= this."
|
||||||
" Overridable by --vmodule.");
|
" Overridable by --vmodule.");
|
||||||
|
|
||||||
GLOG_DEFINE_string(vmodule, "", "per-module verbose level."
|
GLOG_DEFINE_string(
|
||||||
|
vmodule, "",
|
||||||
|
"per-module verbose level."
|
||||||
" Argument is a comma-separated list of <module name>=<log level>."
|
" Argument is a comma-separated list of <module name>=<log level>."
|
||||||
" <module name> is a glob pattern, matched against the filename base"
|
" <module name> is a glob pattern, matched against the filename base"
|
||||||
" (that is, name ignoring .cc/.h./-inl.h)."
|
" (that is, name ignoring .cc/.h./-inl.h)."
|
||||||
@ -86,7 +89,8 @@ GLOG_EXPORT bool SafeFNMatch_(const char* pattern, size_t patt_len,
|
|||||||
if (pattern[p] == '*') {
|
if (pattern[p] == '*') {
|
||||||
if (p + 1 == patt_len) return true;
|
if (p + 1 == patt_len) return true;
|
||||||
do {
|
do {
|
||||||
if (SafeFNMatch_(pattern+(p+1), patt_len-(p+1), str+s, str_len-s)) {
|
if (SafeFNMatch_(pattern + (p + 1), patt_len - (p + 1), str + s,
|
||||||
|
str_len - s)) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
s += 1;
|
s += 1;
|
||||||
@ -177,8 +181,7 @@ int SetVLOGLevel(const char* module_pattern, int log_level) {
|
|||||||
found = true;
|
found = true;
|
||||||
}
|
}
|
||||||
info->vlog_level = log_level;
|
info->vlog_level = log_level;
|
||||||
} else if (!found &&
|
} else if (!found && SafeFNMatch_(info->module_pattern.c_str(),
|
||||||
SafeFNMatch_(info->module_pattern.c_str(),
|
|
||||||
info->module_pattern.size(),
|
info->module_pattern.size(),
|
||||||
module_pattern, pattern_len)) {
|
module_pattern, pattern_len)) {
|
||||||
result = info->vlog_level;
|
result = info->vlog_level;
|
||||||
@ -216,8 +219,8 @@ int SetVLOGLevel(const char* module_pattern, int log_level) {
|
|||||||
|
|
||||||
// NOTE: Individual VLOG statements cache the integer log level pointers.
|
// NOTE: Individual VLOG statements cache the integer log level pointers.
|
||||||
// NOTE: This function must not allocate memory or require any locks.
|
// NOTE: This function must not allocate memory or require any locks.
|
||||||
bool InitVLOG3__(SiteFlag* site_flag, int32* level_default,
|
bool InitVLOG3__(SiteFlag* site_flag, int32* level_default, const char* fname,
|
||||||
const char* fname, int32 verbose_level) {
|
int32 verbose_level) {
|
||||||
MutexLock l(&vmodule_lock);
|
MutexLock l(&vmodule_lock);
|
||||||
bool read_vmodule_flag = inited_vmodule;
|
bool read_vmodule_flag = inited_vmodule;
|
||||||
if (!read_vmodule_flag) {
|
if (!read_vmodule_flag) {
|
||||||
|
|||||||
@ -25,6 +25,8 @@
|
|||||||
#ifndef WIN32_LEAN_AND_MEAN
|
#ifndef WIN32_LEAN_AND_MEAN
|
||||||
# define WIN32_LEAN_AND_MEAN
|
# define WIN32_LEAN_AND_MEAN
|
||||||
#endif
|
#endif
|
||||||
|
#include <sys/stat.h>
|
||||||
|
#include <sys/types.h>
|
||||||
#include <windows.h>
|
#include <windows.h>
|
||||||
|
|
||||||
#include <cerrno>
|
#include <cerrno>
|
||||||
@ -33,8 +35,6 @@
|
|||||||
#include <cstdlib>
|
#include <cstdlib>
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
#include <cwchar>
|
#include <cwchar>
|
||||||
#include <sys/stat.h>
|
|
||||||
#include <sys/types.h>
|
|
||||||
|
|
||||||
/* Indicates that d_type field is available in dirent structure */
|
/* Indicates that d_type field is available in dirent structure */
|
||||||
#define _DIRENT_HAVE_D_TYPE
|
#define _DIRENT_HAVE_D_TYPE
|
||||||
@ -211,12 +211,10 @@
|
|||||||
/* Return the maximum size of a file name */
|
/* Return the maximum size of a file name */
|
||||||
#define _D_ALLOC_NAMLEN(p) ((PATH_MAX) + 1)
|
#define _D_ALLOC_NAMLEN(p) ((PATH_MAX) + 1)
|
||||||
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
extern "C" {
|
extern "C" {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
/* Wide-character version */
|
/* Wide-character version */
|
||||||
struct _wdirent {
|
struct _wdirent {
|
||||||
/* Always zero */
|
/* Always zero */
|
||||||
@ -288,10 +286,9 @@ static _WDIR *_wopendir (const wchar_t *dirname);
|
|||||||
static struct dirent* readdir(DIR* dirp);
|
static struct dirent* readdir(DIR* dirp);
|
||||||
static struct _wdirent* _wreaddir(_WDIR* dirp);
|
static struct _wdirent* _wreaddir(_WDIR* dirp);
|
||||||
|
|
||||||
static int readdir_r(
|
static int readdir_r(DIR* dirp, struct dirent* entry, struct dirent** result);
|
||||||
DIR *dirp, struct dirent *entry, struct dirent **result);
|
static int _wreaddir_r(_WDIR* dirp, struct _wdirent* entry,
|
||||||
static int _wreaddir_r(
|
struct _wdirent** result);
|
||||||
_WDIR *dirp, struct _wdirent *entry, struct _wdirent **result);
|
|
||||||
|
|
||||||
static int closedir(DIR* dirp);
|
static int closedir(DIR* dirp);
|
||||||
static int _wclosedir(_WDIR* dirp);
|
static int _wclosedir(_WDIR* dirp);
|
||||||
@ -301,13 +298,13 @@ static void _wrewinddir (_WDIR* dirp);
|
|||||||
|
|
||||||
static int scandir(const char* dirname, struct dirent*** namelist,
|
static int scandir(const char* dirname, struct dirent*** namelist,
|
||||||
int (*filter)(const struct dirent*),
|
int (*filter)(const struct dirent*),
|
||||||
int (*compare)(const struct dirent**, const struct dirent**));
|
int (*compare)(const struct dirent**,
|
||||||
|
const struct dirent**));
|
||||||
|
|
||||||
static int alphasort(const struct dirent** a, const struct dirent** b);
|
static int alphasort(const struct dirent** a, const struct dirent** b);
|
||||||
|
|
||||||
static int versionsort(const struct dirent** a, const struct dirent** b);
|
static int versionsort(const struct dirent** a, const struct dirent** b);
|
||||||
|
|
||||||
|
|
||||||
/* For compatibility with Symbian */
|
/* For compatibility with Symbian */
|
||||||
#define wdirent _wdirent
|
#define wdirent _wdirent
|
||||||
#define WDIR _WDIR
|
#define WDIR _WDIR
|
||||||
@ -316,37 +313,26 @@ static int versionsort (const struct dirent **a, const struct dirent **b);
|
|||||||
#define wclosedir _wclosedir
|
#define wclosedir _wclosedir
|
||||||
#define wrewinddir _wrewinddir
|
#define wrewinddir _wrewinddir
|
||||||
|
|
||||||
|
|
||||||
/* Internal utility functions */
|
/* Internal utility functions */
|
||||||
static WIN32_FIND_DATAW* dirent_first(_WDIR* dirp);
|
static WIN32_FIND_DATAW* dirent_first(_WDIR* dirp);
|
||||||
static WIN32_FIND_DATAW* dirent_next(_WDIR* dirp);
|
static WIN32_FIND_DATAW* dirent_next(_WDIR* dirp);
|
||||||
|
|
||||||
static int dirent_mbstowcs_s(
|
static int dirent_mbstowcs_s(size_t* pReturnValue, wchar_t* wcstr,
|
||||||
size_t *pReturnValue,
|
size_t sizeInWords, const char* mbstr,
|
||||||
wchar_t *wcstr,
|
|
||||||
size_t sizeInWords,
|
|
||||||
const char *mbstr,
|
|
||||||
size_t count);
|
size_t count);
|
||||||
|
|
||||||
static int dirent_wcstombs_s(
|
static int dirent_wcstombs_s(size_t* pReturnValue, char* mbstr,
|
||||||
size_t *pReturnValue,
|
size_t sizeInBytes, const wchar_t* wcstr,
|
||||||
char *mbstr,
|
|
||||||
size_t sizeInBytes,
|
|
||||||
const wchar_t *wcstr,
|
|
||||||
size_t count);
|
size_t count);
|
||||||
|
|
||||||
static void dirent_set_errno(int error);
|
static void dirent_set_errno(int error);
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Open directory stream DIRNAME for read and return a pointer to the
|
* Open directory stream DIRNAME for read and return a pointer to the
|
||||||
* internal working area that is used to retrieve individual directory
|
* internal working area that is used to retrieve individual directory
|
||||||
* entries.
|
* entries.
|
||||||
*/
|
*/
|
||||||
static _WDIR*
|
static _WDIR* _wopendir(const wchar_t* dirname) {
|
||||||
_wopendir(
|
|
||||||
const wchar_t *dirname)
|
|
||||||
{
|
|
||||||
_WDIR* dirp;
|
_WDIR* dirp;
|
||||||
DWORD n;
|
DWORD n;
|
||||||
wchar_t* p;
|
wchar_t* p;
|
||||||
@ -444,10 +430,7 @@ exit_closedir:
|
|||||||
* Returns pointer to static directory entry which may be overwritten by
|
* Returns pointer to static directory entry which may be overwritten by
|
||||||
* subsequent calls to _wreaddir().
|
* subsequent calls to _wreaddir().
|
||||||
*/
|
*/
|
||||||
static struct _wdirent*
|
static struct _wdirent* _wreaddir(_WDIR* dirp) {
|
||||||
_wreaddir(
|
|
||||||
_WDIR *dirp)
|
|
||||||
{
|
|
||||||
struct _wdirent* entry;
|
struct _wdirent* entry;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -466,12 +449,8 @@ _wreaddir(
|
|||||||
* Returns zero on success. If end of directory stream is reached, then sets
|
* Returns zero on success. If end of directory stream is reached, then sets
|
||||||
* result to nullptr and returns zero.
|
* result to nullptr and returns zero.
|
||||||
*/
|
*/
|
||||||
static int
|
static int _wreaddir_r(_WDIR* dirp, struct _wdirent* entry,
|
||||||
_wreaddir_r(
|
struct _wdirent** result) {
|
||||||
_WDIR *dirp,
|
|
||||||
struct _wdirent *entry,
|
|
||||||
struct _wdirent **result)
|
|
||||||
{
|
|
||||||
WIN32_FIND_DATAW* datap;
|
WIN32_FIND_DATAW* datap;
|
||||||
|
|
||||||
/* Read next directory entry */
|
/* Read next directory entry */
|
||||||
@ -526,13 +505,9 @@ _wreaddir_r(
|
|||||||
* DIR structure as well as any directory entry read previously by
|
* DIR structure as well as any directory entry read previously by
|
||||||
* _wreaddir().
|
* _wreaddir().
|
||||||
*/
|
*/
|
||||||
static int
|
static int _wclosedir(_WDIR* dirp) {
|
||||||
_wclosedir(
|
|
||||||
_WDIR *dirp)
|
|
||||||
{
|
|
||||||
int ok;
|
int ok;
|
||||||
if (dirp) {
|
if (dirp) {
|
||||||
|
|
||||||
/* Release search handle */
|
/* Release search handle */
|
||||||
if (dirp->handle != INVALID_HANDLE_VALUE) {
|
if (dirp->handle != INVALID_HANDLE_VALUE) {
|
||||||
FindClose(dirp->handle);
|
FindClose(dirp->handle);
|
||||||
@ -546,11 +521,9 @@ _wclosedir(
|
|||||||
ok = /*success*/ 0;
|
ok = /*success*/ 0;
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
/* Invalid directory stream */
|
/* Invalid directory stream */
|
||||||
dirent_set_errno(EBADF);
|
dirent_set_errno(EBADF);
|
||||||
ok = /*failure*/ -1;
|
ok = /*failure*/ -1;
|
||||||
|
|
||||||
}
|
}
|
||||||
return ok;
|
return ok;
|
||||||
}
|
}
|
||||||
@ -559,10 +532,7 @@ _wclosedir(
|
|||||||
* Rewind directory stream such that _wreaddir() returns the very first
|
* Rewind directory stream such that _wreaddir() returns the very first
|
||||||
* file name again.
|
* file name again.
|
||||||
*/
|
*/
|
||||||
static void
|
static void _wrewinddir(_WDIR* dirp) {
|
||||||
_wrewinddir(
|
|
||||||
_WDIR* dirp)
|
|
||||||
{
|
|
||||||
if (dirp) {
|
if (dirp) {
|
||||||
/* Release existing search handle */
|
/* Release existing search handle */
|
||||||
if (dirp->handle != INVALID_HANDLE_VALUE) {
|
if (dirp->handle != INVALID_HANDLE_VALUE) {
|
||||||
@ -575,10 +545,7 @@ _wrewinddir(
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Get first directory entry (internal) */
|
/* Get first directory entry (internal) */
|
||||||
static WIN32_FIND_DATAW*
|
static WIN32_FIND_DATAW* dirent_first(_WDIR* dirp) {
|
||||||
dirent_first(
|
|
||||||
_WDIR *dirp)
|
|
||||||
{
|
|
||||||
WIN32_FIND_DATAW* datap;
|
WIN32_FIND_DATAW* datap;
|
||||||
DWORD error;
|
DWORD error;
|
||||||
|
|
||||||
@ -586,13 +553,11 @@ dirent_first(
|
|||||||
dirp->handle = FindFirstFileExW(dirp->patt, FindExInfoStandard, &dirp->data,
|
dirp->handle = FindFirstFileExW(dirp->patt, FindExInfoStandard, &dirp->data,
|
||||||
FindExSearchNameMatch, nullptr, 0);
|
FindExSearchNameMatch, nullptr, 0);
|
||||||
if (dirp->handle != INVALID_HANDLE_VALUE) {
|
if (dirp->handle != INVALID_HANDLE_VALUE) {
|
||||||
|
|
||||||
/* a directory entry is now waiting in memory */
|
/* a directory entry is now waiting in memory */
|
||||||
datap = &dirp->data;
|
datap = &dirp->data;
|
||||||
dirp->cached = 1;
|
dirp->cached = 1;
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
/* Failed to open directory: no directory entry in memory */
|
/* Failed to open directory: no directory entry in memory */
|
||||||
dirp->cached = 0;
|
dirp->cached = 0;
|
||||||
datap = nullptr;
|
datap = nullptr;
|
||||||
@ -615,7 +580,6 @@ dirent_first(
|
|||||||
/* Cannot find the file */
|
/* Cannot find the file */
|
||||||
dirent_set_errno(ENOENT);
|
dirent_set_errno(ENOENT);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
return datap;
|
return datap;
|
||||||
}
|
}
|
||||||
@ -625,21 +589,16 @@ dirent_first(
|
|||||||
*
|
*
|
||||||
* Returns
|
* Returns
|
||||||
*/
|
*/
|
||||||
static WIN32_FIND_DATAW*
|
static WIN32_FIND_DATAW* dirent_next(_WDIR* dirp) {
|
||||||
dirent_next(
|
|
||||||
_WDIR *dirp)
|
|
||||||
{
|
|
||||||
WIN32_FIND_DATAW* p;
|
WIN32_FIND_DATAW* p;
|
||||||
|
|
||||||
/* Get next directory entry */
|
/* Get next directory entry */
|
||||||
if (dirp->cached != 0) {
|
if (dirp->cached != 0) {
|
||||||
|
|
||||||
/* A valid directory entry already in memory */
|
/* A valid directory entry already in memory */
|
||||||
p = &dirp->data;
|
p = &dirp->data;
|
||||||
dirp->cached = 0;
|
dirp->cached = 0;
|
||||||
|
|
||||||
} else if (dirp->handle != INVALID_HANDLE_VALUE) {
|
} else if (dirp->handle != INVALID_HANDLE_VALUE) {
|
||||||
|
|
||||||
/* Get the next directory entry from stream */
|
/* Get the next directory entry from stream */
|
||||||
if (FindNextFileW(dirp->handle, &dirp->data) != FALSE) {
|
if (FindNextFileW(dirp->handle, &dirp->data) != FALSE) {
|
||||||
/* Got a file */
|
/* Got a file */
|
||||||
@ -652,7 +611,6 @@ dirent_next(
|
|||||||
}
|
}
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
/* End of directory stream reached */
|
/* End of directory stream reached */
|
||||||
p = nullptr;
|
p = nullptr;
|
||||||
}
|
}
|
||||||
@ -663,10 +621,7 @@ dirent_next(
|
|||||||
/*
|
/*
|
||||||
* Open directory stream using plain old C-string.
|
* Open directory stream using plain old C-string.
|
||||||
*/
|
*/
|
||||||
static DIR*
|
static DIR* opendir(const char* dirname) {
|
||||||
opendir(
|
|
||||||
const char *dirname)
|
|
||||||
{
|
|
||||||
struct DIR* dirp;
|
struct DIR* dirp;
|
||||||
|
|
||||||
/* Must have directory name */
|
/* Must have directory name */
|
||||||
@ -686,8 +641,7 @@ opendir(
|
|||||||
size_t n;
|
size_t n;
|
||||||
|
|
||||||
/* Convert directory name to wide-character string */
|
/* Convert directory name to wide-character string */
|
||||||
error = dirent_mbstowcs_s(
|
error = dirent_mbstowcs_s(&n, wname, PATH_MAX + 1, dirname, PATH_MAX + 1);
|
||||||
&n, wname, PATH_MAX + 1, dirname, PATH_MAX + 1);
|
|
||||||
if (error) {
|
if (error) {
|
||||||
/*
|
/*
|
||||||
* Cannot convert file name to wide-character string. This
|
* Cannot convert file name to wide-character string. This
|
||||||
@ -698,13 +652,11 @@ opendir(
|
|||||||
goto exit_free;
|
goto exit_free;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* Open directory stream using wide-character name */
|
/* Open directory stream using wide-character name */
|
||||||
dirp->wdirp = _wopendir(wname);
|
dirp->wdirp = _wopendir(wname);
|
||||||
if (!dirp->wdirp) {
|
if (!dirp->wdirp) {
|
||||||
goto exit_free;
|
goto exit_free;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Success */
|
/* Success */
|
||||||
@ -719,10 +671,7 @@ exit_free:
|
|||||||
/*
|
/*
|
||||||
* Read next directory entry.
|
* Read next directory entry.
|
||||||
*/
|
*/
|
||||||
static struct dirent*
|
static struct dirent* readdir(DIR* dirp) {
|
||||||
readdir(
|
|
||||||
DIR *dirp)
|
|
||||||
{
|
|
||||||
struct dirent* entry;
|
struct dirent* entry;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -741,12 +690,7 @@ readdir(
|
|||||||
* Returns zero on success. If the end of directory stream is reached, then
|
* Returns zero on success. If the end of directory stream is reached, then
|
||||||
* sets result to nullptr and returns zero.
|
* sets result to nullptr and returns zero.
|
||||||
*/
|
*/
|
||||||
static int
|
static int readdir_r(DIR* dirp, struct dirent* entry, struct dirent** result) {
|
||||||
readdir_r(
|
|
||||||
DIR *dirp,
|
|
||||||
struct dirent *entry,
|
|
||||||
struct dirent **result)
|
|
||||||
{
|
|
||||||
WIN32_FIND_DATAW* datap;
|
WIN32_FIND_DATAW* datap;
|
||||||
|
|
||||||
/* Read next directory entry */
|
/* Read next directory entry */
|
||||||
@ -756,8 +700,8 @@ readdir_r(
|
|||||||
int error;
|
int error;
|
||||||
|
|
||||||
/* Attempt to convert file name to multi-byte string */
|
/* Attempt to convert file name to multi-byte string */
|
||||||
error = dirent_wcstombs_s(
|
error = dirent_wcstombs_s(&n, entry->d_name, PATH_MAX + 1, datap->cFileName,
|
||||||
&n, entry->d_name, PATH_MAX + 1, datap->cFileName, PATH_MAX + 1);
|
PATH_MAX + 1);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If the file name cannot be represented by a multi-byte string,
|
* If the file name cannot be represented by a multi-byte string,
|
||||||
@ -770,8 +714,7 @@ readdir_r(
|
|||||||
* VirtualBox shared folders fail to do this.
|
* VirtualBox shared folders fail to do this.
|
||||||
*/
|
*/
|
||||||
if (error && datap->cAlternateFileName[0] != '\0') {
|
if (error && datap->cAlternateFileName[0] != '\0') {
|
||||||
error = dirent_wcstombs_s(
|
error = dirent_wcstombs_s(&n, entry->d_name, PATH_MAX + 1,
|
||||||
&n, entry->d_name, PATH_MAX + 1,
|
|
||||||
datap->cAlternateFileName, PATH_MAX + 1);
|
datap->cAlternateFileName, PATH_MAX + 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -810,14 +753,12 @@ readdir_r(
|
|||||||
entry->d_ino = 0;
|
entry->d_ino = 0;
|
||||||
entry->d_off = -1;
|
entry->d_off = -1;
|
||||||
entry->d_reclen = 0;
|
entry->d_reclen = 0;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Return pointer to directory entry */
|
/* Return pointer to directory entry */
|
||||||
*result = entry;
|
*result = entry;
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
/* No more directory entries */
|
/* No more directory entries */
|
||||||
*result = nullptr;
|
*result = nullptr;
|
||||||
}
|
}
|
||||||
@ -828,13 +769,9 @@ readdir_r(
|
|||||||
/*
|
/*
|
||||||
* Close directory stream.
|
* Close directory stream.
|
||||||
*/
|
*/
|
||||||
static int
|
static int closedir(DIR* dirp) {
|
||||||
closedir(
|
|
||||||
DIR *dirp)
|
|
||||||
{
|
|
||||||
int ok;
|
int ok;
|
||||||
if (dirp) {
|
if (dirp) {
|
||||||
|
|
||||||
/* Close wide-character directory stream */
|
/* Close wide-character directory stream */
|
||||||
ok = _wclosedir(dirp->wdirp);
|
ok = _wclosedir(dirp->wdirp);
|
||||||
dirp->wdirp = nullptr;
|
dirp->wdirp = nullptr;
|
||||||
@ -843,11 +780,9 @@ closedir(
|
|||||||
free(dirp);
|
free(dirp);
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
/* Invalid directory stream */
|
/* Invalid directory stream */
|
||||||
dirent_set_errno(EBADF);
|
dirent_set_errno(EBADF);
|
||||||
ok = /*failure*/ -1;
|
ok = /*failure*/ -1;
|
||||||
|
|
||||||
}
|
}
|
||||||
return ok;
|
return ok;
|
||||||
}
|
}
|
||||||
@ -855,10 +790,7 @@ closedir(
|
|||||||
/*
|
/*
|
||||||
* Rewind directory stream to beginning.
|
* Rewind directory stream to beginning.
|
||||||
*/
|
*/
|
||||||
static void
|
static void rewinddir(DIR* dirp) {
|
||||||
rewinddir(
|
|
||||||
DIR* dirp)
|
|
||||||
{
|
|
||||||
/* Rewind wide-character string directory stream */
|
/* Rewind wide-character string directory stream */
|
||||||
_wrewinddir(dirp->wdirp);
|
_wrewinddir(dirp->wdirp);
|
||||||
}
|
}
|
||||||
@ -866,13 +798,10 @@ rewinddir(
|
|||||||
/*
|
/*
|
||||||
* Scan directory for entries.
|
* Scan directory for entries.
|
||||||
*/
|
*/
|
||||||
static int
|
static int scandir(const char* dirname, struct dirent*** namelist,
|
||||||
scandir(
|
|
||||||
const char *dirname,
|
|
||||||
struct dirent ***namelist,
|
|
||||||
int (*filter)(const struct dirent*),
|
int (*filter)(const struct dirent*),
|
||||||
int (*compare)(const struct dirent**, const struct dirent**))
|
int (*compare)(const struct dirent**,
|
||||||
{
|
const struct dirent**)) {
|
||||||
struct dirent** files = nullptr;
|
struct dirent** files = nullptr;
|
||||||
size_t size = 0;
|
size_t size = 0;
|
||||||
size_t allocated = 0;
|
size_t allocated = 0;
|
||||||
@ -886,10 +815,8 @@ scandir(
|
|||||||
/* Open directory stream */
|
/* Open directory stream */
|
||||||
dir = opendir(dirname);
|
dir = opendir(dirname);
|
||||||
if (dir) {
|
if (dir) {
|
||||||
|
|
||||||
/* Read directory entries to memory */
|
/* Read directory entries to memory */
|
||||||
while (1) {
|
while (1) {
|
||||||
|
|
||||||
/* Enlarge pointer table to make room for another pointer */
|
/* Enlarge pointer table to make room for another pointer */
|
||||||
if (size >= allocated) {
|
if (size >= allocated) {
|
||||||
void* p;
|
void* p;
|
||||||
@ -929,7 +856,6 @@ scandir(
|
|||||||
|
|
||||||
/* Read directory entry to temporary area */
|
/* Read directory entry to temporary area */
|
||||||
if (readdir_r(dir, tmp, &entry) == /*OK*/ 0) {
|
if (readdir_r(dir, tmp, &entry) == /*OK*/ 0) {
|
||||||
|
|
||||||
/* Did we get an entry? */
|
/* Did we get an entry? */
|
||||||
if (entry != nullptr) {
|
if (entry != nullptr) {
|
||||||
int pass;
|
int pass;
|
||||||
@ -967,7 +893,6 @@ scandir(
|
|||||||
result = /*Error*/ -1;
|
result = /*Error*/ -1;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
@ -1000,31 +925,20 @@ scandir(
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Alphabetical sorting */
|
/* Alphabetical sorting */
|
||||||
static int
|
static int alphasort(const struct dirent** a, const struct dirent** b) {
|
||||||
alphasort(
|
|
||||||
const struct dirent **a, const struct dirent **b)
|
|
||||||
{
|
|
||||||
return strcoll((*a)->d_name, (*b)->d_name);
|
return strcoll((*a)->d_name, (*b)->d_name);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Sort versions */
|
/* Sort versions */
|
||||||
static int
|
static int versionsort(const struct dirent** a, const struct dirent** b) {
|
||||||
versionsort(
|
|
||||||
const struct dirent **a, const struct dirent **b)
|
|
||||||
{
|
|
||||||
/* FIXME: implement strverscmp and use that */
|
/* FIXME: implement strverscmp and use that */
|
||||||
return alphasort(a, b);
|
return alphasort(a, b);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Convert multi-byte string to wide character string */
|
/* Convert multi-byte string to wide character string */
|
||||||
static int
|
static int dirent_mbstowcs_s(size_t* pReturnValue, wchar_t* wcstr,
|
||||||
dirent_mbstowcs_s(
|
size_t sizeInWords, const char* mbstr,
|
||||||
size_t *pReturnValue,
|
size_t count) {
|
||||||
wchar_t *wcstr,
|
|
||||||
size_t sizeInWords,
|
|
||||||
const char *mbstr,
|
|
||||||
size_t count)
|
|
||||||
{
|
|
||||||
int error;
|
int error;
|
||||||
|
|
||||||
#if defined(_MSC_VER) && _MSC_VER >= 1400
|
#if defined(_MSC_VER) && _MSC_VER >= 1400
|
||||||
@ -1040,7 +954,6 @@ dirent_mbstowcs_s(
|
|||||||
/* Convert to wide-character string (or count characters) */
|
/* Convert to wide-character string (or count characters) */
|
||||||
n = mbstowcs(wcstr, mbstr, sizeInWords);
|
n = mbstowcs(wcstr, mbstr, sizeInWords);
|
||||||
if (!wcstr || n < count) {
|
if (!wcstr || n < count) {
|
||||||
|
|
||||||
/* Zero-terminate output buffer */
|
/* Zero-terminate output buffer */
|
||||||
if (wcstr && sizeInWords) {
|
if (wcstr && sizeInWords) {
|
||||||
if (n >= sizeInWords) {
|
if (n >= sizeInWords) {
|
||||||
@ -1058,10 +971,8 @@ dirent_mbstowcs_s(
|
|||||||
error = 0;
|
error = 0;
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
/* Could not convert string */
|
/* Could not convert string */
|
||||||
error = 1;
|
error = 1;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
@ -1069,14 +980,9 @@ dirent_mbstowcs_s(
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Convert wide-character string to multi-byte string */
|
/* Convert wide-character string to multi-byte string */
|
||||||
static int
|
static int dirent_wcstombs_s(size_t* pReturnValue, char* mbstr,
|
||||||
dirent_wcstombs_s(
|
|
||||||
size_t *pReturnValue,
|
|
||||||
char *mbstr,
|
|
||||||
size_t sizeInBytes, /* max size of mbstr */
|
size_t sizeInBytes, /* max size of mbstr */
|
||||||
const wchar_t *wcstr,
|
const wchar_t* wcstr, size_t count) {
|
||||||
size_t count)
|
|
||||||
{
|
|
||||||
int error;
|
int error;
|
||||||
|
|
||||||
#if defined(_MSC_VER) && _MSC_VER >= 1400
|
#if defined(_MSC_VER) && _MSC_VER >= 1400
|
||||||
@ -1092,7 +998,6 @@ dirent_wcstombs_s(
|
|||||||
/* Convert to multi-byte string (or count the number of bytes needed) */
|
/* Convert to multi-byte string (or count the number of bytes needed) */
|
||||||
n = wcstombs(mbstr, wcstr, sizeInBytes);
|
n = wcstombs(mbstr, wcstr, sizeInBytes);
|
||||||
if (!mbstr || n < count) {
|
if (!mbstr || n < count) {
|
||||||
|
|
||||||
/* Zero-terminate output buffer */
|
/* Zero-terminate output buffer */
|
||||||
if (mbstr && sizeInBytes) {
|
if (mbstr && sizeInBytes) {
|
||||||
if (n >= sizeInBytes) {
|
if (n >= sizeInBytes) {
|
||||||
@ -1110,10 +1015,8 @@ dirent_wcstombs_s(
|
|||||||
error = 0;
|
error = 0;
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
/* Cannot convert string */
|
/* Cannot convert string */
|
||||||
error = 1;
|
error = 1;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
@ -1121,10 +1024,7 @@ dirent_wcstombs_s(
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Set errno variable */
|
/* Set errno variable */
|
||||||
static void
|
static void dirent_set_errno(int error) {
|
||||||
dirent_set_errno(
|
|
||||||
int error)
|
|
||||||
{
|
|
||||||
#if defined(_MSC_VER) && _MSC_VER >= 1400
|
#if defined(_MSC_VER) && _MSC_VER >= 1400
|
||||||
|
|
||||||
/* Microsoft Visual Studio 2005 and later */
|
/* Microsoft Visual Studio 2005 and later */
|
||||||
@ -1138,7 +1038,6 @@ dirent_set_errno(
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@ -132,7 +132,8 @@ typedef DWORD pthread_key_t;
|
|||||||
typedef LONG pthread_once_t;
|
typedef LONG pthread_once_t;
|
||||||
enum { PTHREAD_ONCE_INIT = 0 }; // important that this be 0! for SpinLock
|
enum { PTHREAD_ONCE_INIT = 0 }; // important that this be 0! for SpinLock
|
||||||
# define pthread_self GetCurrentThreadId
|
# define pthread_self GetCurrentThreadId
|
||||||
#define pthread_equal(pthread_t_1, pthread_t_2) ((pthread_t_1)==(pthread_t_2))
|
# define pthread_equal(pthread_t_1, pthread_t_2) \
|
||||||
|
((pthread_t_1) == (pthread_t_2))
|
||||||
# endif // HAVE_PTHREAD
|
# endif // HAVE_PTHREAD
|
||||||
|
|
||||||
# ifndef HAVE_LOCALTIME_R
|
# ifndef HAVE_LOCALTIME_R
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user