summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--indra/llcommon/llallocator.h126
-rw-r--r--indra/llcommon/llapr.h518
-rw-r--r--indra/llcommon/llassettype.h374
-rw-r--r--indra/llcommon/llcoros.h298
-rw-r--r--indra/llcommon/lleventdispatcher.h248
-rw-r--r--indra/llcommon/llevents.h1850
-rw-r--r--indra/llcommon/llfasttimer.h704
-rw-r--r--indra/llcommon/llmemory.h130
-rw-r--r--indra/llcommon/llmemtype.h496
-rw-r--r--indra/llcommon/llstacktrace.cpp283
-rw-r--r--indra/llcommon/llstacktrace.h88
-rw-r--r--indra/llcommon/llstring.h2946
-rw-r--r--indra/newview/llfloaterabout.cpp563
13 files changed, 4312 insertions, 4312 deletions
diff --git a/indra/llcommon/llallocator.h b/indra/llcommon/llallocator.h
index 2b70fee0b8..0d6f18c5d4 100644
--- a/indra/llcommon/llallocator.h
+++ b/indra/llcommon/llallocator.h
@@ -1,63 +1,63 @@
-/**
- * @file llallocator.h
- * @brief Declaration of the LLAllocator class.
- *
- * $LicenseInfo:firstyear=2009&license=viewergpl$
- *
- * Copyright (c) 2009-2009, Linden Research, Inc.
- *
- * Second Life Viewer Source Code
- * The source code in this file ("Source Code") is provided by Linden Lab
- * to you under the terms of the GNU General Public License, version 2.0
- * ("GPL"), unless you have obtained a separate licensing agreement
- * ("Other License"), formally executed by you and Linden Lab. Terms of
- * the GPL can be found in doc/GPL-license.txt in this distribution, or
- * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
- *
- * There are special exceptions to the terms and conditions of the GPL as
- * it is applied to this Source Code. View the full text of the exception
- * in the file doc/FLOSS-exception.txt in this software distribution, or
- * online at
- * http://secondlifegrid.net/programs/open_source/licensing/flossexception
- *
- * By copying, modifying or distributing this software, you acknowledge
- * that you have read and understood your obligations described above,
- * and agree to abide by those obligations.
- *
- * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
- * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
- * COMPLETENESS OR PERFORMANCE.
- * $/LicenseInfo$
- */
-
-#ifndef LL_LLALLOCATOR_H
-#define LL_LLALLOCATOR_H
-
-#include <string>
-
-#include "llmemtype.h"
-#include "llallocator_heap_profile.h"
-
-class LLAllocator {
- friend class LLMemoryView;
- friend class LLMemType;
-
-private:
- static void pushMemType(S32 type);
- static S32 popMemType();
-
-public:
- void setProfilingEnabled(bool should_enable);
-
- static bool isProfiling();
-
- LLAllocatorHeapProfile const & getProfile();
-
-private:
- std::string getRawProfile();
-
-private:
- LLAllocatorHeapProfile mProf;
-};
-
-#endif // LL_LLALLOCATOR_H
+/**
+ * @file llallocator.h
+ * @brief Declaration of the LLAllocator class.
+ *
+ * $LicenseInfo:firstyear=2009&license=viewergpl$
+ *
+ * Copyright (c) 2009-2009, Linden Research, Inc.
+ *
+ * Second Life Viewer Source Code
+ * The source code in this file ("Source Code") is provided by Linden Lab
+ * to you under the terms of the GNU General Public License, version 2.0
+ * ("GPL"), unless you have obtained a separate licensing agreement
+ * ("Other License"), formally executed by you and Linden Lab. Terms of
+ * the GPL can be found in doc/GPL-license.txt in this distribution, or
+ * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
+ *
+ * There are special exceptions to the terms and conditions of the GPL as
+ * it is applied to this Source Code. View the full text of the exception
+ * in the file doc/FLOSS-exception.txt in this software distribution, or
+ * online at
+ * http://secondlifegrid.net/programs/open_source/licensing/flossexception
+ *
+ * By copying, modifying or distributing this software, you acknowledge
+ * that you have read and understood your obligations described above,
+ * and agree to abide by those obligations.
+ *
+ * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
+ * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
+ * COMPLETENESS OR PERFORMANCE.
+ * $/LicenseInfo$
+ */
+
+#ifndef LL_LLALLOCATOR_H
+#define LL_LLALLOCATOR_H
+
+#include <string>
+
+#include "llmemtype.h"
+#include "llallocator_heap_profile.h"
+
+class LL_COMMON_API LLAllocator {
+ friend class LLMemoryView;
+ friend class LLMemType;
+
+private:
+ static void pushMemType(S32 type);
+ static S32 popMemType();
+
+public:
+ void setProfilingEnabled(bool should_enable);
+
+ static bool isProfiling();
+
+ LLAllocatorHeapProfile const & getProfile();
+
+private:
+ std::string getRawProfile();
+
+private:
+ LLAllocatorHeapProfile mProf;
+};
+
+#endif // LL_LLALLOCATOR_H
diff --git a/indra/llcommon/llapr.h b/indra/llcommon/llapr.h
index e13b3734f9..f968eabc18 100644
--- a/indra/llcommon/llapr.h
+++ b/indra/llcommon/llapr.h
@@ -1,259 +1,259 @@
-/**
- * @file llapr.h
- * @author Phoenix
- * @date 2004-11-28
- * @brief Helper functions for using the apache portable runtime library.
- *
- * $LicenseInfo:firstyear=2004&license=viewergpl$
- *
- * Copyright (c) 2004-2009, Linden Research, Inc.
- *
- * Second Life Viewer Source Code
- * The source code in this file ("Source Code") is provided by Linden Lab
- * to you under the terms of the GNU General Public License, version 2.0
- * ("GPL"), unless you have obtained a separate licensing agreement
- * ("Other License"), formally executed by you and Linden Lab. Terms of
- * the GPL can be found in doc/GPL-license.txt in this distribution, or
- * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
- *
- * There are special exceptions to the terms and conditions of the GPL as
- * it is applied to this Source Code. View the full text of the exception
- * in the file doc/FLOSS-exception.txt in this software distribution, or
- * online at
- * http://secondlifegrid.net/programs/open_source/licensing/flossexception
- *
- * By copying, modifying or distributing this software, you acknowledge
- * that you have read and understood your obligations described above,
- * and agree to abide by those obligations.
- *
- * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
- * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
- * COMPLETENESS OR PERFORMANCE.
- * $/LicenseInfo$
- */
-
-#ifndef LL_LLAPR_H
-#define LL_LLAPR_H
-
-#if LL_LINUX || LL_SOLARIS
-#include <sys/param.h> // Need PATH_MAX in APR headers...
-#endif
-
-#include <boost/noncopyable.hpp>
-
-#include "apr_thread_proc.h"
-#include "apr_thread_mutex.h"
-#include "apr_getopt.h"
-#include "apr_signal.h"
-#include "apr_atomic.h"
-#include "llstring.h"
-
-extern LL_COMMON_API apr_thread_mutex_t* gLogMutexp;
-extern apr_thread_mutex_t* gCallStacksLogMutexp;
-
-/**
- * @brief initialize the common apr constructs -- apr itself, the
- * global pool, and a mutex.
- */
-void LL_COMMON_API ll_init_apr();
-
-/**
- * @brief Cleanup those common apr constructs.
- */
-void LL_COMMON_API ll_cleanup_apr();
-
-//
-//LL apr_pool
-//manage apr_pool_t, destroy allocated apr_pool in the destruction function.
-//
-class LL_COMMON_API LLAPRPool
-{
-public:
- LLAPRPool(apr_pool_t *parent = NULL, apr_size_t size = 0, BOOL releasePoolFlag = TRUE) ;
- ~LLAPRPool() ;
-
- apr_pool_t* getAPRPool() ;
- apr_status_t getStatus() {return mStatus ; }
-
-protected:
- void releaseAPRPool() ;
- void createAPRPool() ;
-
-protected:
- apr_pool_t* mPool ; //pointing to an apr_pool
- apr_pool_t* mParent ; //parent pool
- apr_size_t mMaxSize ; //max size of mPool, mPool should return memory to system if allocated memory beyond this limit. However it seems not to work.
- apr_status_t mStatus ; //status when creating the pool
- BOOL mReleasePoolFlag ; //if set, mPool is destroyed when LLAPRPool is deleted. default value is true.
-};
-
-//
-//volatile LL apr_pool
-//which clears memory automatically.
-//so it can not hold static data or data after memory is cleared
-//
-class LL_COMMON_API LLVolatileAPRPool : public LLAPRPool
-{
-public:
- LLVolatileAPRPool(apr_pool_t *parent = NULL, apr_size_t size = 0, BOOL releasePoolFlag = TRUE);
- ~LLVolatileAPRPool(){}
-
- apr_pool_t* getVolatileAPRPool() ;
-
- void clearVolatileAPRPool() ;
-
- BOOL isFull() ;
- BOOL isEmpty() {return !mNumActiveRef ;}
-private:
- S32 mNumActiveRef ; //number of active pointers pointing to the apr_pool.
- S32 mNumTotalRef ; //number of total pointers pointing to the apr_pool since last creating.
-} ;
-
-/**
- * @class LLScopedLock
- * @brief Small class to help lock and unlock mutexes.
- *
- * This class is used to have a stack level lock once you already have
- * an apr mutex handy. The constructor handles the lock, and the
- * destructor handles the unlock. Instances of this class are
- * <b>not</b> thread safe.
- */
-class LL_COMMON_API LLScopedLock : private boost::noncopyable
-{
-public:
- /**
- * @brief Constructor which accepts a mutex, and locks it.
- *
- * @param mutex An allocated APR mutex. If you pass in NULL,
- * this wrapper will not lock.
- */
- LLScopedLock(apr_thread_mutex_t* mutex);
-
- /**
- * @brief Destructor which unlocks the mutex if still locked.
- */
- ~LLScopedLock();
-
- /**
- * @brief Check lock.
- */
- bool isLocked() const { return mLocked; }
-
- /**
- * @brief This method unlocks the mutex.
- */
- void unlock();
-
-protected:
- bool mLocked;
- apr_thread_mutex_t* mMutex;
-};
-
-template <typename Type> class LL_COMMON_API LLAtomic32
-{
-public:
- LLAtomic32<Type>() {};
- LLAtomic32<Type>(Type x) {apr_atomic_set32(&mData, apr_uint32_t(x)); };
- ~LLAtomic32<Type>() {};
-
- operator const Type() { apr_uint32_t data = apr_atomic_read32(&mData); return Type(data); }
- Type operator =(const Type& x) { apr_atomic_set32(&mData, apr_uint32_t(x)); return Type(mData); }
- void operator -=(Type x) { apr_atomic_sub32(&mData, apr_uint32_t(x)); }
- void operator +=(Type x) { apr_atomic_add32(&mData, apr_uint32_t(x)); }
- Type operator ++(int) { return apr_atomic_inc32(&mData); } // Type++
- Type operator --(int) { return apr_atomic_dec32(&mData); } // Type--
-
-private:
- apr_uint32_t mData;
-};
-
-typedef LLAtomic32<U32> LLAtomicU32;
-typedef LLAtomic32<S32> LLAtomicS32;
-
-// File IO convenience functions.
-// Returns NULL if the file fails to openm sets *sizep to file size of not NULL
-// abbreviated flags
-#define LL_APR_R (APR_READ) // "r"
-#define LL_APR_W (APR_CREATE|APR_TRUNCATE|APR_WRITE) // "w"
-#define LL_APR_RB (APR_READ|APR_BINARY) // "rb"
-#define LL_APR_WB (APR_CREATE|APR_TRUNCATE|APR_WRITE|APR_BINARY) // "wb"
-#define LL_APR_RPB (APR_READ|APR_WRITE|APR_BINARY) // "r+b"
-#define LL_APR_WPB (APR_CREATE|APR_TRUNCATE|APR_READ|APR_WRITE|APR_BINARY) // "w+b"
-
-//
-//apr_file manager
-//which: 1)only keeps one file open;
-// 2)closes the open file in the destruction function
-// 3)informs the apr_pool to clean the memory when the file is closed.
-//Note: please close an open file at the earliest convenience.
-// especially do not put some time-costly operations between open() and close().
-// otherwise it might lock the APRFilePool.
-//there are two different apr_pools the APRFile can use:
-// 1, a temperary pool passed to an APRFile function, which is used within this function and only once.
-// 2, a global pool.
-//
-class LL_COMMON_API LLAPRFile
-{
-private:
- apr_file_t* mFile ;
- LLVolatileAPRPool *mCurrentFilePoolp ; //currently in use apr_pool, could be one of them: sAPRFilePoolp, or a temp pool.
-
-public:
- LLAPRFile() ;
- ~LLAPRFile() ;
-
- apr_status_t open(LLVolatileAPRPool* pool, const std::string& filename, apr_int32_t flags, S32* sizep = NULL);
- apr_status_t open(const std::string& filename, apr_int32_t flags, apr_pool_t* pool = NULL, S32* sizep = NULL);
- apr_status_t close() ;
-
- // Returns actual offset, -1 if seek fails
- S32 seek(apr_seek_where_t where, S32 offset);
- apr_status_t eof() { return apr_file_eof(mFile);}
-
- // Returns bytes read/written, 0 if read/write fails:
- S32 read(void* buf, S32 nbytes);
- S32 write(const void* buf, S32 nbytes);
-
- apr_file_t* getFileHandle() {return mFile;}
-
-private:
- apr_pool_t* getAPRFilePool(apr_pool_t* pool) ;
-
-//
-//*******************************************************************************************************************************
-//static components
-//
-public:
- static LLVolatileAPRPool *sAPRFilePoolp ; //a global apr_pool for APRFile, which is used only when local pool does not exist.
-
-private:
- static apr_file_t* open(const std::string& filename, LLVolatileAPRPool* pool, apr_int32_t flags);
- static apr_status_t close(apr_file_t* file, LLVolatileAPRPool* pool) ;
- static S32 seek(apr_file_t* file, apr_seek_where_t where, S32 offset);
-public:
- // returns false if failure:
- static bool remove(const std::string& filename, LLVolatileAPRPool* pool = NULL);
- static bool rename(const std::string& filename, const std::string& newname, LLVolatileAPRPool* pool = NULL);
- static bool isExist(const std::string& filename, LLVolatileAPRPool* pool = NULL, apr_int32_t flags = APR_READ);
- static S32 size(const std::string& filename, LLVolatileAPRPool* pool = NULL);
- static bool makeDir(const std::string& dirname, LLVolatileAPRPool* pool = NULL);
- static bool removeDir(const std::string& dirname, LLVolatileAPRPool* pool = NULL);
-
- // Returns bytes read/written, 0 if read/write fails:
- static S32 readEx(const std::string& filename, void *buf, S32 offset, S32 nbytes, LLVolatileAPRPool* pool = NULL);
- static S32 writeEx(const std::string& filename, void *buf, S32 offset, S32 nbytes, LLVolatileAPRPool* pool = NULL);
-//*******************************************************************************************************************************
-};
-
-/**
- * @brief Function which approprately logs error or remains quiet on
- * APR_SUCCESS.
- * @return Returns <code>true</code> if status is an error condition.
- */
-bool LL_COMMON_API ll_apr_warn_status(apr_status_t status);
-
-void LL_COMMON_API ll_apr_assert_status(apr_status_t status);
-
-extern "C" LL_COMMON_API apr_pool_t* gAPRPoolp; // Global APR memory pool
-
-#endif // LL_LLAPR_H
+/**
+ * @file llapr.h
+ * @author Phoenix
+ * @date 2004-11-28
+ * @brief Helper functions for using the apache portable runtime library.
+ *
+ * $LicenseInfo:firstyear=2004&license=viewergpl$
+ *
+ * Copyright (c) 2004-2009, Linden Research, Inc.
+ *
+ * Second Life Viewer Source Code
+ * The source code in this file ("Source Code") is provided by Linden Lab
+ * to you under the terms of the GNU General Public License, version 2.0
+ * ("GPL"), unless you have obtained a separate licensing agreement
+ * ("Other License"), formally executed by you and Linden Lab. Terms of
+ * the GPL can be found in doc/GPL-license.txt in this distribution, or
+ * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
+ *
+ * There are special exceptions to the terms and conditions of the GPL as
+ * it is applied to this Source Code. View the full text of the exception
+ * in the file doc/FLOSS-exception.txt in this software distribution, or
+ * online at
+ * http://secondlifegrid.net/programs/open_source/licensing/flossexception
+ *
+ * By copying, modifying or distributing this software, you acknowledge
+ * that you have read and understood your obligations described above,
+ * and agree to abide by those obligations.
+ *
+ * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
+ * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
+ * COMPLETENESS OR PERFORMANCE.
+ * $/LicenseInfo$
+ */
+
+#ifndef LL_LLAPR_H
+#define LL_LLAPR_H
+
+#if LL_LINUX || LL_SOLARIS
+#include <sys/param.h> // Need PATH_MAX in APR headers...
+#endif
+
+#include <boost/noncopyable.hpp>
+
+#include "apr_thread_proc.h"
+#include "apr_thread_mutex.h"
+#include "apr_getopt.h"
+#include "apr_signal.h"
+#include "apr_atomic.h"
+#include "llstring.h"
+
+extern LL_COMMON_API apr_thread_mutex_t* gLogMutexp;
+extern apr_thread_mutex_t* gCallStacksLogMutexp;
+
+/**
+ * @brief initialize the common apr constructs -- apr itself, the
+ * global pool, and a mutex.
+ */
+void LL_COMMON_API ll_init_apr();
+
+/**
+ * @brief Cleanup those common apr constructs.
+ */
+void LL_COMMON_API ll_cleanup_apr();
+
+//
+//LL apr_pool
+//manage apr_pool_t, destroy allocated apr_pool in the destruction function.
+//
+class LL_COMMON_API LLAPRPool
+{
+public:
+ LLAPRPool(apr_pool_t *parent = NULL, apr_size_t size = 0, BOOL releasePoolFlag = TRUE) ;
+ ~LLAPRPool() ;
+
+ apr_pool_t* getAPRPool() ;
+ apr_status_t getStatus() {return mStatus ; }
+
+protected:
+ void releaseAPRPool() ;
+ void createAPRPool() ;
+
+protected:
+ apr_pool_t* mPool ; //pointing to an apr_pool
+ apr_pool_t* mParent ; //parent pool
+ apr_size_t mMaxSize ; //max size of mPool, mPool should return memory to system if allocated memory beyond this limit. However it seems not to work.
+ apr_status_t mStatus ; //status when creating the pool
+ BOOL mReleasePoolFlag ; //if set, mPool is destroyed when LLAPRPool is deleted. default value is true.
+};
+
+//
+//volatile LL apr_pool
+//which clears memory automatically.
+//so it can not hold static data or data after memory is cleared
+//
+class LL_COMMON_API LLVolatileAPRPool : public LLAPRPool
+{
+public:
+ LLVolatileAPRPool(apr_pool_t *parent = NULL, apr_size_t size = 0, BOOL releasePoolFlag = TRUE);
+ ~LLVolatileAPRPool(){}
+
+ apr_pool_t* getVolatileAPRPool() ;
+
+ void clearVolatileAPRPool() ;
+
+ BOOL isFull() ;
+ BOOL isEmpty() {return !mNumActiveRef ;}
+private:
+ S32 mNumActiveRef ; //number of active pointers pointing to the apr_pool.
+ S32 mNumTotalRef ; //number of total pointers pointing to the apr_pool since last creating.
+} ;
+
+/**
+ * @class LLScopedLock
+ * @brief Small class to help lock and unlock mutexes.
+ *
+ * This class is used to have a stack level lock once you already have
+ * an apr mutex handy. The constructor handles the lock, and the
+ * destructor handles the unlock. Instances of this class are
+ * <b>not</b> thread safe.
+ */
+class LL_COMMON_API LLScopedLock : private boost::noncopyable
+{
+public:
+ /**
+ * @brief Constructor which accepts a mutex, and locks it.
+ *
+ * @param mutex An allocated APR mutex. If you pass in NULL,
+ * this wrapper will not lock.
+ */
+ LLScopedLock(apr_thread_mutex_t* mutex);
+
+ /**
+ * @brief Destructor which unlocks the mutex if still locked.
+ */
+ ~LLScopedLock();
+
+ /**
+ * @brief Check lock.
+ */
+ bool isLocked() const { return mLocked; }
+
+ /**
+ * @brief This method unlocks the mutex.
+ */
+ void unlock();
+
+protected:
+ bool mLocked;
+ apr_thread_mutex_t* mMutex;
+};
+
+template <typename Type> class LLAtomic32
+{
+public:
+ LLAtomic32<Type>() {};
+ LLAtomic32<Type>(Type x) {apr_atomic_set32(&mData, apr_uint32_t(x)); };
+ ~LLAtomic32<Type>() {};
+
+ operator const Type() { apr_uint32_t data = apr_atomic_read32(&mData); return Type(data); }
+ Type operator =(const Type& x) { apr_atomic_set32(&mData, apr_uint32_t(x)); return Type(mData); }
+ void operator -=(Type x) { apr_atomic_sub32(&mData, apr_uint32_t(x)); }
+ void operator +=(Type x) { apr_atomic_add32(&mData, apr_uint32_t(x)); }
+ Type operator ++(int) { return apr_atomic_inc32(&mData); } // Type++
+ Type operator --(int) { return apr_atomic_dec32(&mData); } // Type--
+
+private:
+ apr_uint32_t mData;
+};
+
+typedef LL_COMMON_API LLAtomic32<U32> LLAtomicU32;
+typedef LL_COMMON_API LLAtomic32<S32> LLAtomicS32;
+
+// File IO convenience functions.
+// Returns NULL if the file fails to openm sets *sizep to file size of not NULL
+// abbreviated flags
+#define LL_APR_R (APR_READ) // "r"
+#define LL_APR_W (APR_CREATE|APR_TRUNCATE|APR_WRITE) // "w"
+#define LL_APR_RB (APR_READ|APR_BINARY) // "rb"
+#define LL_APR_WB (APR_CREATE|APR_TRUNCATE|APR_WRITE|APR_BINARY) // "wb"
+#define LL_APR_RPB (APR_READ|APR_WRITE|APR_BINARY) // "r+b"
+#define LL_APR_WPB (APR_CREATE|APR_TRUNCATE|APR_READ|APR_WRITE|APR_BINARY) // "w+b"
+
+//
+//apr_file manager
+//which: 1)only keeps one file open;
+// 2)closes the open file in the destruction function
+// 3)informs the apr_pool to clean the memory when the file is closed.
+//Note: please close an open file at the earliest convenience.
+// especially do not put some time-costly operations between open() and close().
+// otherwise it might lock the APRFilePool.
+//there are two different apr_pools the APRFile can use:
+// 1, a temperary pool passed to an APRFile function, which is used within this function and only once.
+// 2, a global pool.
+//
+class LL_COMMON_API LLAPRFile
+{
+private:
+ apr_file_t* mFile ;
+ LLVolatileAPRPool *mCurrentFilePoolp ; //currently in use apr_pool, could be one of them: sAPRFilePoolp, or a temp pool.
+
+public:
+ LLAPRFile() ;
+ ~LLAPRFile() ;
+
+ apr_status_t open(LLVolatileAPRPool* pool, const std::string& filename, apr_int32_t flags, S32* sizep = NULL);
+ apr_status_t open(const std::string& filename, apr_int32_t flags, apr_pool_t* pool = NULL, S32* sizep = NULL);
+ apr_status_t close() ;
+
+ // Returns actual offset, -1 if seek fails
+ S32 seek(apr_seek_where_t where, S32 offset);
+ apr_status_t eof() { return apr_file_eof(mFile);}
+
+ // Returns bytes read/written, 0 if read/write fails:
+ S32 read(void* buf, S32 nbytes);
+ S32 write(const void* buf, S32 nbytes);
+
+ apr_file_t* getFileHandle() {return mFile;}
+
+private:
+ apr_pool_t* getAPRFilePool(apr_pool_t* pool) ;
+
+//
+//*******************************************************************************************************************************
+//static components
+//
+public:
+ static LLVolatileAPRPool *sAPRFilePoolp ; //a global apr_pool for APRFile, which is used only when local pool does not exist.
+
+private:
+ static apr_file_t* open(const std::string& filename, LLVolatileAPRPool* pool, apr_int32_t flags);
+ static apr_status_t close(apr_file_t* file, LLVolatileAPRPool* pool) ;
+ static S32 seek(apr_file_t* file, apr_seek_where_t where, S32 offset);
+public:
+ // returns false if failure:
+ static bool remove(const std::string& filename, LLVolatileAPRPool* pool = NULL);
+ static bool rename(const std::string& filename, const std::string& newname, LLVolatileAPRPool* pool = NULL);
+ static bool isExist(const std::string& filename, LLVolatileAPRPool* pool = NULL, apr_int32_t flags = APR_READ);
+ static S32 size(const std::string& filename, LLVolatileAPRPool* pool = NULL);
+ static bool makeDir(const std::string& dirname, LLVolatileAPRPool* pool = NULL);
+ static bool removeDir(const std::string& dirname, LLVolatileAPRPool* pool = NULL);
+
+ // Returns bytes read/written, 0 if read/write fails:
+ static S32 readEx(const std::string& filename, void *buf, S32 offset, S32 nbytes, LLVolatileAPRPool* pool = NULL);
+ static S32 writeEx(const std::string& filename, void *buf, S32 offset, S32 nbytes, LLVolatileAPRPool* pool = NULL);
+//*******************************************************************************************************************************
+};
+
+/**
+ * @brief Function which approprately logs error or remains quiet on
+ * APR_SUCCESS.
+ * @return Returns <code>true</code> if status is an error condition.
+ */
+bool LL_COMMON_API ll_apr_warn_status(apr_status_t status);
+
+void LL_COMMON_API ll_apr_assert_status(apr_status_t status);
+
+extern "C" LL_COMMON_API apr_pool_t* gAPRPoolp; // Global APR memory pool
+
+#endif // LL_LLAPR_H
diff --git a/indra/llcommon/llassettype.h b/indra/llcommon/llassettype.h
index 353bd57bb9..8d524f1e28 100644
--- a/indra/llcommon/llassettype.h
+++ b/indra/llcommon/llassettype.h
@@ -1,187 +1,187 @@
-/**
- * @file llassettype.h
- * @brief Declaration of LLAssetType.
- *
- * $LicenseInfo:firstyear=2001&license=viewergpl$
- *
- * Copyright (c) 2001-2009, Linden Research, Inc.
- *
- * Second Life Viewer Source Code
- * The source code in this file ("Source Code") is provided by Linden Lab
- * to you under the terms of the GNU General Public License, version 2.0
- * ("GPL"), unless you have obtained a separate licensing agreement
- * ("Other License"), formally executed by you and Linden Lab. Terms of
- * the GPL can be found in doc/GPL-license.txt in this distribution, or
- * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
- *
- * There are special exceptions to the terms and conditions of the GPL as
- * it is applied to this Source Code. View the full text of the exception
- * in the file doc/FLOSS-exception.txt in this software distribution, or
- * online at
- * http://secondlifegrid.net/programs/open_source/licensing/flossexception
- *
- * By copying, modifying or distributing this software, you acknowledge
- * that you have read and understood your obligations described above,
- * and agree to abide by those obligations.
- *
- * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
- * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
- * COMPLETENESS OR PERFORMANCE.
- * $/LicenseInfo$
- */
-
-#ifndef LL_LLASSETTYPE_H
-#define LL_LLASSETTYPE_H
-
-#include <string>
-
-#include "stdenums.h" // for EDragAndDropType
-
-class LLAssetType
-{
-public:
- enum EType
- {
- AT_TEXTURE = 0,
- // Used for painting the faces of geometry.
- // Stored in typical j2c stream format.
-
- AT_SOUND = 1,
- // Used to fill the aural spectrum.
-
- AT_CALLINGCARD = 2,
- // Links instant message access to the user on the card.
- // : E.G. A card for yourself, for linden support, for
- // : the guy you were talking to in the coliseum.
-
- AT_LANDMARK = 3,
- // Links to places in the world with location and a screen shot or image saved.
- // : E.G. Home, linden headquarters, the coliseum, destinations where
- // : we want to increase traffic.
-
- AT_SCRIPT = 4,
- // Valid scripts that can be attached to an object.
- // : E.G. Open a door, jump into the air.
-
- AT_CLOTHING = 5,
- // A collection of textures and parameters that can be worn by an avatar.
-
- AT_OBJECT = 6,
- // Any combination of textures, sounds, and scripts that are
- // associated with a fixed piece of geometry.
- // : E.G. A hot tub, a house with working door.
-
- AT_NOTECARD = 7,
- // Just text.
-
- AT_CATEGORY = 8,
- // Holds a collection of inventory items.
- // It's treated as an item in the inventory and therefore needs a type.
-
- AT_ROOT_CATEGORY = 9,
- // A user's root inventory category.
- // We decided to expose it visually, so it seems logical to fold
- // it into the asset types.
-
- AT_LSL_TEXT = 10,
- AT_LSL_BYTECODE = 11,
- // The LSL is the scripting language.
- // We've split it into a text and bytecode representation.
-
- AT_TEXTURE_TGA = 12,
- // Uncompressed TGA texture.
-
- AT_BODYPART = 13,
- // A collection of textures and parameters that can be worn by an avatar.
-
- AT_TRASH = 14,
- // Only to be used as a marker for a category preferred type.
- // Using this, we can throw things in the trash before completely deleting.
-
- AT_SNAPSHOT_CATEGORY = 15,
- // A marker for a folder meant for snapshots.
- // No actual assets will be snapshots, though if there were, you
- // could interpret them as textures.
-
- AT_LOST_AND_FOUND = 16,
- // Used to stuff lost&found items into.
-
- AT_SOUND_WAV = 17,
- // Uncompressed sound.
-
- AT_IMAGE_TGA = 18,
- // Uncompressed image, non-square.
- // Not appropriate for use as a texture.
-
- AT_IMAGE_JPEG = 19,
- // Compressed image, non-square.
- // Not appropriate for use as a texture.
-
- AT_ANIMATION = 20,
- // Animation.
-
- AT_GESTURE = 21,
- // Gesture, sequence of animations, sounds, chat, wait steps.
-
- AT_SIMSTATE = 22,
- // Simstate file.
-
- AT_FAVORITE = 23,
- // favorite items
-
- AT_LINK = 24,
- // Inventory symbolic link
-
- AT_LINK_FOLDER = 25,
- // Inventory folder link
-
- AT_COUNT = 26,
-
- // +************************************************+
- // | TO ADD AN ELEMENT TO THIS ENUM: |
- // +************************************************+
- // | 1. INSERT BEFORE AT_COUNT |
- // | 2. INCREMENT AT_COUNT BY 1 |
- // | 3. ADD TO LLAssetDictionary in llassettype.cpp |
- // +************************************************+
-
- AT_NONE = -1
- };
-
- // machine transation between type and strings
- static EType lookup(const char* name); // safe conversion to std::string, *TODO: deprecate
- static EType lookup(const std::string& type_name);
- static const char* lookup(EType asset_type);
-
- // translation from a type to a human readable form.
- static EType lookupHumanReadable(const char* desc_name); // safe conversion to std::string, *TODO: deprecate
- static EType lookupHumanReadable(const std::string& readable_name);
- static const char* lookupHumanReadable(EType asset_type);
-
- static const char* lookupCategoryName(EType asset_type);
-
- // Generate a good default description. You may want to add a verb
- // or agent name after this depending on your application.
- static void generateDescriptionFor(LLAssetType::EType asset_type,
- std::string& description);
-
- static EType getType(const std::string& desc_name);
- static const std::string& getDesc(EType asset_type);
- static EDragAndDropType lookupDragAndDropType(EType asset_type);
- static bool lookupCanLink(EType asset_type);
- static bool lookupIsLinkType(EType asset_type);
-
- /* TODO: Change return types from "const char *" to "const std::string &".
- This is fairly straightforward, but requires changing some calls to use .c_str().
- e.g.:
- - fprintf(fp, "\t\ttype\t%s\n", LLAssetType::lookup(mType));
- + fprintf(fp, "\t\ttype\t%s\n", LLAssetType::lookup(mType).c_str());
- */
-
-private:
- // don't instantiate or derive one of these objects
- LLAssetType() {}
- ~LLAssetType() {}
-};
-
-#endif // LL_LLASSETTYPE_H
+/**
+ * @file llassettype.h
+ * @brief Declaration of LLAssetType.
+ *
+ * $LicenseInfo:firstyear=2001&license=viewergpl$
+ *
+ * Copyright (c) 2001-2009, Linden Research, Inc.
+ *
+ * Second Life Viewer Source Code
+ * The source code in this file ("Source Code") is provided by Linden Lab
+ * to you under the terms of the GNU General Public License, version 2.0
+ * ("GPL"), unless you have obtained a separate licensing agreement
+ * ("Other License"), formally executed by you and Linden Lab. Terms of
+ * the GPL can be found in doc/GPL-license.txt in this distribution, or
+ * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
+ *
+ * There are special exceptions to the terms and conditions of the GPL as
+ * it is applied to this Source Code. View the full text of the exception
+ * in the file doc/FLOSS-exception.txt in this software distribution, or
+ * online at
+ * http://secondlifegrid.net/programs/open_source/licensing/flossexception
+ *
+ * By copying, modifying or distributing this software, you acknowledge
+ * that you have read and understood your obligations described above,
+ * and agree to abide by those obligations.
+ *
+ * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
+ * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
+ * COMPLETENESS OR PERFORMANCE.
+ * $/LicenseInfo$
+ */
+
+#ifndef LL_LLASSETTYPE_H
+#define LL_LLASSETTYPE_H
+
+#include <string>
+
+#include "stdenums.h" // for EDragAndDropType
+
+class LL_COMMON_API LLAssetType
+{
+public:
+ enum EType
+ {
+ AT_TEXTURE = 0,
+ // Used for painting the faces of geometry.
+ // Stored in typical j2c stream format.
+
+ AT_SOUND = 1,
+ // Used to fill the aural spectrum.
+
+ AT_CALLINGCARD = 2,
+ // Links instant message access to the user on the card.
+ // : E.G. A card for yourself, for linden support, for
+ // : the guy you were talking to in the coliseum.
+
+ AT_LANDMARK = 3,
+ // Links to places in the world with location and a screen shot or image saved.
+ // : E.G. Home, linden headquarters, the coliseum, destinations where
+ // : we want to increase traffic.
+
+ AT_SCRIPT = 4,
+ // Valid scripts that can be attached to an object.
+ // : E.G. Open a door, jump into the air.
+
+ AT_CLOTHING = 5,
+ // A collection of textures and parameters that can be worn by an avatar.
+
+ AT_OBJECT = 6,
+ // Any combination of textures, sounds, and scripts that are
+ // associated with a fixed piece of geometry.
+ // : E.G. A hot tub, a house with working door.
+
+ AT_NOTECARD = 7,
+ // Just text.
+
+ AT_CATEGORY = 8,
+ // Holds a collection of inventory items.
+ // It's treated as an item in the inventory and therefore needs a type.
+
+ AT_ROOT_CATEGORY = 9,
+ // A user's root inventory category.
+ // We decided to expose it visually, so it seems logical to fold
+ // it into the asset types.
+
+ AT_LSL_TEXT = 10,
+ AT_LSL_BYTECODE = 11,
+ // The LSL is the scripting language.
+ // We've split it into a text and bytecode representation.
+
+ AT_TEXTURE_TGA = 12,
+ // Uncompressed TGA texture.
+
+ AT_BODYPART = 13,
+ // A collection of textures and parameters that can be worn by an avatar.
+
+ AT_TRASH = 14,
+ // Only to be used as a marker for a category preferred type.
+ // Using this, we can throw things in the trash before completely deleting.
+
+ AT_SNAPSHOT_CATEGORY = 15,
+ // A marker for a folder meant for snapshots.
+ // No actual assets will be snapshots, though if there were, you
+ // could interpret them as textures.
+
+ AT_LOST_AND_FOUND = 16,
+ // Used to stuff lost&found items into.
+
+ AT_SOUND_WAV = 17,
+ // Uncompressed sound.
+
+ AT_IMAGE_TGA = 18,
+ // Uncompressed image, non-square.
+ // Not appropriate for use as a texture.
+
+ AT_IMAGE_JPEG = 19,
+ // Compressed image, non-square.
+ // Not appropriate for use as a texture.
+
+ AT_ANIMATION = 20,
+ // Animation.
+
+ AT_GESTURE = 21,
+ // Gesture, sequence of animations, sounds, chat, wait steps.
+
+ AT_SIMSTATE = 22,
+ // Simstate file.
+
+ AT_FAVORITE = 23,
+ // favorite items
+
+ AT_LINK = 24,
+ // Inventory symbolic link
+
+ AT_LINK_FOLDER = 25,
+ // Inventory folder link
+
+ AT_COUNT = 26,
+
+ // +************************************************+
+ // | TO ADD AN ELEMENT TO THIS ENUM: |
+ // +************************************************+
+ // | 1. INSERT BEFORE AT_COUNT |
+ // | 2. INCREMENT AT_COUNT BY 1 |
+ // | 3. ADD TO LLAssetDictionary in llassettype.cpp |
+ // +************************************************+
+
+ AT_NONE = -1
+ };
+
+ // machine transation between type and strings
+ static EType lookup(const char* name); // safe conversion to std::string, *TODO: deprecate
+ static EType lookup(const std::string& type_name);
+ static const char* lookup(EType asset_type);
+
+ // translation from a type to a human readable form.
+ static EType lookupHumanReadable(const char* desc_name); // safe conversion to std::string, *TODO: deprecate
+ static EType lookupHumanReadable(const std::string& readable_name);
+ static const char* lookupHumanReadable(EType asset_type);
+
+ static const char* lookupCategoryName(EType asset_type);
+
+ // Generate a good default description. You may want to add a verb
+ // or agent name after this depending on your application.
+ static void generateDescriptionFor(LLAssetType::EType asset_type,
+ std::string& description);
+
+ static EType getType(const std::string& desc_name);
+ static const std::string& getDesc(EType asset_type);
+ static EDragAndDropType lookupDragAndDropType(EType asset_type);
+ static bool lookupCanLink(EType asset_type);
+ static bool lookupIsLinkType(EType asset_type);
+
+ /* TODO: Change return types from "const char *" to "const std::string &".
+ This is fairly straightforward, but requires changing some calls to use .c_str().
+ e.g.:
+ - fprintf(fp, "\t\ttype\t%s\n", LLAssetType::lookup(mType));
+ + fprintf(fp, "\t\ttype\t%s\n", LLAssetType::lookup(mType).c_str());
+ */
+
+private:
+ // don't instantiate or derive one of these objects
+ LLAssetType() {}
+ ~LLAssetType() {}
+};
+
+#endif // LL_LLASSETTYPE_H
diff --git a/indra/llcommon/llcoros.h b/indra/llcommon/llcoros.h
index 6b07ba4105..6c5fa5af6d 100644
--- a/indra/llcommon/llcoros.h
+++ b/indra/llcommon/llcoros.h
@@ -1,149 +1,149 @@
-/**
- * @file llcoros.h
- * @author Nat Goodspeed
- * @date 2009-06-02
- * @brief Manage running boost::coroutine instances
- *
- * $LicenseInfo:firstyear=2009&license=viewergpl$
- * Copyright (c) 2009, Linden Research, Inc.
- * $/LicenseInfo$
- */
-
-#if ! defined(LL_LLCOROS_H)
-#define LL_LLCOROS_H
-
-#include <boost/coroutine/coroutine.hpp>
-#include "llsingleton.h"
-#include <boost/ptr_container/ptr_map.hpp>
-#include <string>
-#include <boost/preprocessor/repetition/enum_params.hpp>
-#include <boost/preprocessor/repetition/enum_binary_params.hpp>
-#include <boost/preprocessor/iteration/local.hpp>
-#include <stdexcept>
-
-/**
- * Registry of named Boost.Coroutine instances
- *
- * The Boost.Coroutine library supports the general case of a coroutine
- * accepting arbitrary parameters and yielding multiple (sets of) results. For
- * such use cases, it's natural for the invoking code to retain the coroutine
- * instance: the consumer repeatedly calls into the coroutine, perhaps passing
- * new parameter values, prompting it to yield its next result.
- *
- * Our typical coroutine usage is different, though. For us, coroutines
- * provide an alternative to the @c Responder pattern. Our typical coroutine
- * has @c void return, invoked in fire-and-forget mode: the handler for some
- * user gesture launches the coroutine and promptly returns to the main loop.
- * The coroutine initiates some action that will take multiple frames (e.g. a
- * capability request), waits for its result, processes it and silently steals
- * away.
- *
- * This usage poses two (related) problems:
- *
- * # Who should own the coroutine instance? If it's simply local to the
- * handler code that launches it, return from the handler will destroy the
- * coroutine object, terminating the coroutine.
- * # Once the coroutine terminates, in whatever way, who's responsible for
- * cleaning up the coroutine object?
- *
- * LLCoros is a Singleton collection of currently-active coroutine instances.
- * Each has a name. You ask LLCoros to launch a new coroutine with a suggested
- * name prefix; from your prefix it generates a distinct name, registers the
- * new coroutine and returns the actual name.
- *
- * The name can be used to kill off the coroutine prematurely, if needed. It
- * can also provide diagnostic info: we can look up the name of the
- * currently-running coroutine.
- *
- * Finally, the next frame ("mainloop" event) after the coroutine terminates,
- * LLCoros will notice its demise and destroy it.
- */
-class LLCoros: public LLSingleton<LLCoros>
-{
-public:
- /// Canonical boost::coroutines::coroutine signature we use
- typedef boost::coroutines::coroutine<void()> coro;
- /// Canonical 'self' type
- typedef coro::self self;
-
- /**
- * Create and start running a new coroutine with specified name. The name
- * string you pass is a suggestion; it will be tweaked for uniqueness. The
- * actual name is returned to you.
- *
- * Usage looks like this, for (e.g.) two coroutine parameters:
- * @code
- * class MyClass
- * {
- * public:
- * ...
- * // Do NOT NOT NOT accept reference params other than 'self'!
- * // Pass by value only!
- * void myCoroutineMethod(LLCoros::self& self, std::string, LLSD);
- * ...
- * };
- * ...
- * std::string name = LLCoros::instance().launch(
- * "mycoro", boost::bind(&MyClass::myCoroutineMethod, this, _1,
- * "somestring", LLSD(17));
- * @endcode
- *
- * Your function/method must accept LLCoros::self& as its first parameter.
- * It can accept any other parameters you want -- but ONLY BY VALUE!
- * Other reference parameters are a BAD IDEA! You Have Been Warned. See
- * DEV-32777 comments for an explanation.
- *
- * Pass a callable that accepts the single LLCoros::self& parameter. It
- * may work to pass a free function whose only parameter is 'self'; for
- * all other cases use boost::bind(). Of course, for a non-static class
- * method, the first parameter must be the class instance. Use the
- * placeholder _1 for the 'self' parameter. Any other parameters should be
- * passed via the bind() expression.
- *
- * launch() tweaks the suggested name so it won't collide with any
- * existing coroutine instance, creates the coroutine instance, registers
- * it with the tweaked name and runs it until its first wait. At that
- * point it returns the tweaked name.
- */
- template <typename CALLABLE>
- std::string launch(const std::string& prefix, const CALLABLE& callable)
- {
- return launchImpl(prefix, new coro(callable));
- }
-
- /**
- * Abort a running coroutine by name. Normally, when a coroutine either
- * runs to completion or terminates with an exception, LLCoros quietly
- * cleans it up. This is for use only when you must explicitly interrupt
- * one prematurely. Returns @c true if the specified name was found and
- * still running at the time.
- */
- bool kill(const std::string& name);
-
- /**
- * From within a coroutine, pass its @c self object to look up the
- * (tweaked) name string by which this coroutine is registered. Returns
- * the empty string if not found (e.g. if the coroutine was launched by
- * hand rather than using LLCoros::launch()).
- */
- template <typename COROUTINE_SELF>
- std::string getName(const COROUTINE_SELF& self) const
- {
- return getNameByID(self.get_id());
- }
-
- /// getName() by self.get_id()
- std::string getNameByID(const void* self_id) const;
-
-private:
- friend class LLSingleton<LLCoros>;
- LLCoros();
- std::string launchImpl(const std::string& prefix, coro* newCoro);
- std::string generateDistinctName(const std::string& prefix) const;
- bool cleanup(const LLSD&);
-
- typedef boost::ptr_map<std::string, coro> CoroMap;
- CoroMap mCoros;
-};
-
-#endif /* ! defined(LL_LLCOROS_H) */
+/**
+ * @file llcoros.h
+ * @author Nat Goodspeed
+ * @date 2009-06-02
+ * @brief Manage running boost::coroutine instances
+ *
+ * $LicenseInfo:firstyear=2009&license=viewergpl$
+ * Copyright (c) 2009, Linden Research, Inc.
+ * $/LicenseInfo$
+ */
+
+#if ! defined(LL_LLCOROS_H)
+#define LL_LLCOROS_H
+
+#include <boost/coroutine/coroutine.hpp>
+#include "llsingleton.h"
+#include <boost/ptr_container/ptr_map.hpp>
+#include <string>
+#include <boost/preprocessor/repetition/enum_params.hpp>
+#include <boost/preprocessor/repetition/enum_binary_params.hpp>
+#include <boost/preprocessor/iteration/local.hpp>
+#include <stdexcept>
+
+/**
+ * Registry of named Boost.Coroutine instances
+ *
+ * The Boost.Coroutine library supports the general case of a coroutine
+ * accepting arbitrary parameters and yielding multiple (sets of) results. For
+ * such use cases, it's natural for the invoking code to retain the coroutine
+ * instance: the consumer repeatedly calls into the coroutine, perhaps passing
+ * new parameter values, prompting it to yield its next result.
+ *
+ * Our typical coroutine usage is different, though. For us, coroutines
+ * provide an alternative to the @c Responder pattern. Our typical coroutine
+ * has @c void return, invoked in fire-and-forget mode: the handler for some
+ * user gesture launches the coroutine and promptly returns to the main loop.
+ * The coroutine initiates some action that will take multiple frames (e.g. a
+ * capability request), waits for its result, processes it and silently steals
+ * away.
+ *
+ * This usage poses two (related) problems:
+ *
+ * # Who should own the coroutine instance? If it's simply local to the
+ * handler code that launches it, return from the handler will destroy the
+ * coroutine object, terminating the coroutine.
+ * # Once the coroutine terminates, in whatever way, who's responsible for
+ * cleaning up the coroutine object?
+ *
+ * LLCoros is a Singleton collection of currently-active coroutine instances.
+ * Each has a name. You ask LLCoros to launch a new coroutine with a suggested
+ * name prefix; from your prefix it generates a distinct name, registers the
+ * new coroutine and returns the actual name.
+ *
+ * The name can be used to kill off the coroutine prematurely, if needed. It
+ * can also provide diagnostic info: we can look up the name of the
+ * currently-running coroutine.
+ *
+ * Finally, the next frame ("mainloop" event) after the coroutine terminates,
+ * LLCoros will notice its demise and destroy it.
+ */
+class LL_COMMON_API LLCoros: public LLSingleton<LLCoros>
+{
+public:
+ /// Canonical boost::coroutines::coroutine signature we use
+ typedef boost::coroutines::coroutine<void()> coro;
+ /// Canonical 'self' type
+ typedef coro::self self;
+
+ /**
+ * Create and start running a new coroutine with specified name. The name
+ * string you pass is a suggestion; it will be tweaked for uniqueness. The
+ * actual name is returned to you.
+ *
+ * Usage looks like this, for (e.g.) two coroutine parameters:
+ * @code
+ * class MyClass
+ * {
+ * public:
+ * ...
+ * // Do NOT NOT NOT accept reference params other than 'self'!
+ * // Pass by value only!
+ * void myCoroutineMethod(LLCoros::self& self, std::string, LLSD);
+ * ...
+ * };
+ * ...
+ * std::string name = LLCoros::instance().launch(
+ * "mycoro", boost::bind(&MyClass::myCoroutineMethod, this, _1,
+ * "somestring", LLSD(17));
+ * @endcode
+ *
+ * Your function/method must accept LLCoros::self& as its first parameter.
+ * It can accept any other parameters you want -- but ONLY BY VALUE!
+ * Other reference parameters are a BAD IDEA! You Have Been Warned. See
+ * DEV-32777 comments for an explanation.
+ *
+ * Pass a callable that accepts the single LLCoros::self& parameter. It
+ * may work to pass a free function whose only parameter is 'self'; for
+ * all other cases use boost::bind(). Of course, for a non-static class
+ * method, the first parameter must be the class instance. Use the
+ * placeholder _1 for the 'self' parameter. Any other parameters should be
+ * passed via the bind() expression.
+ *
+ * launch() tweaks the suggested name so it won't collide with any
+ * existing coroutine instance, creates the coroutine instance, registers
+ * it with the tweaked name and runs it until its first wait. At that
+ * point it returns the tweaked name.
+ */
+ template <typename CALLABLE>
+ std::string launch(const std::string& prefix, const CALLABLE& callable)
+ {
+ return launchImpl(prefix, new coro(callable));
+ }
+
+ /**
+ * Abort a running coroutine by name. Normally, when a coroutine either
+ * runs to completion or terminates with an exception, LLCoros quietly
+ * cleans it up. This is for use only when you must explicitly interrupt
+ * one prematurely. Returns @c true if the specified name was found and
+ * still running at the time.
+ */
+ bool kill(const std::string& name);
+
+ /**
+ * From within a coroutine, pass its @c self object to look up the
+ * (tweaked) name string by which this coroutine is registered. Returns
+ * the empty string if not found (e.g. if the coroutine was launched by
+ * hand rather than using LLCoros::launch()).
+ */
+ template <typename COROUTINE_SELF>
+ std::string getName(const COROUTINE_SELF& self) const
+ {
+ return getNameByID(self.get_id());
+ }
+
+ /// getName() by self.get_id()
+ std::string getNameByID(const void* self_id) const;
+
+private:
+ friend class LLSingleton<LLCoros>;
+ LLCoros();
+ std::string launchImpl(const std::string& prefix, coro* newCoro);
+ std::string generateDistinctName(const std::string& prefix) const;
+ bool cleanup(const LLSD&);
+
+ typedef boost::ptr_map<std::string, coro> CoroMap;
+ CoroMap mCoros;
+};
+
+#endif /* ! defined(LL_LLCOROS_H) */
diff --git a/indra/llcommon/lleventdispatcher.h b/indra/llcommon/lleventdispatcher.h
index 4da0a01c69..155fe0648f 100644
--- a/indra/llcommon/lleventdispatcher.h
+++ b/indra/llcommon/lleventdispatcher.h
@@ -1,124 +1,124 @@
-/**
- * @file lleventdispatcher.h
- * @author Nat Goodspeed
- * @date 2009-06-18
- * @brief Central mechanism for dispatching events by string name. This is
- * useful when you have a single LLEventPump listener on which you can
- * request different operations, vs. instantiating a different
- * LLEventPump for each such operation.
- *
- * $LicenseInfo:firstyear=2009&license=viewergpl$
- * Copyright (c) 2009, Linden Research, Inc.
- * $/LicenseInfo$
- */
-
-#if ! defined(LL_LLEVENTDISPATCHER_H)
-#define LL_LLEVENTDISPATCHER_H
-
-#include <string>
-#include <map>
-#include <boost/function.hpp>
-#include <boost/bind.hpp>
-#include <typeinfo>
-#include "llevents.h"
-
-class LLSD;
-
-/**
- * Given an LLSD map, examine a string-valued key and call a corresponding
- * callable. This class is designed to be contained by an LLEventPump
- * listener class that will register some of its own methods, though any
- * callable can be used.
- */
-class LLEventDispatcher
-{
-public:
- LLEventDispatcher(const std::string& desc, const std::string& key);
- virtual ~LLEventDispatcher();
-
- /// Accept any C++ callable, typically a boost::bind() expression
- typedef boost::function<void(const LLSD&)> Callable;
-
- /**
- * Register a @a callable by @a name. The optional @a required parameter
- * is used to validate the structure of each incoming event (see
- * llsd_matches()).
- */
- void add(const std::string& name, const Callable& callable, const LLSD& required=LLSD());
-
- /**
- * Special case: a subclass of this class can pass an unbound member
- * function pointer without explicitly specifying the
- * <tt>boost::bind()</tt> expression.
- */
- template <class CLASS>
- void add(const std::string& name, void (CLASS::*method)(const LLSD&),
- const LLSD& required=LLSD())
- {
- addMethod<CLASS>(name, method, required);
- }
-
- /// Overload for both const and non-const methods
- template <class CLASS>
- void add(const std::string& name, void (CLASS::*method)(const LLSD&) const,
- const LLSD& required=LLSD())
- {
- addMethod<CLASS>(name, method, required);
- }
-
- /// Unregister a callable
- bool remove(const std::string& name);
-
- /// Call a registered callable with an explicitly-specified name. If no
- /// such callable exists, die with LL_ERRS. If the @a event fails to match
- /// the @a required prototype specified at add() time, die with LL_ERRS.
- void operator()(const std::string& name, const LLSD& event) const;
-
- /// Extract the @a key value from the incoming @a event, and call the
- /// callable whose name is specified by that map @a key. If no such
- /// callable exists, die with LL_ERRS. If the @a event fails to match the
- /// @a required prototype specified at add() time, die with LL_ERRS.
- void operator()(const LLSD& event) const;
-
-private:
- template <class CLASS, typename METHOD>
- void addMethod(const std::string& name, const METHOD& method, const LLSD& required)
- {
- CLASS* downcast = dynamic_cast<CLASS*>(this);
- if (! downcast)
- {
- addFail(name, typeid(CLASS).name());
- }
- else
- {
- add(name, boost::bind(method, downcast, _1), required);
- }
- }
- void addFail(const std::string& name, const std::string& classname) const;
- /// try to dispatch, return @c true if success
- bool attemptCall(const std::string& name, const LLSD& event) const;
-
- std::string mDesc, mKey;
- typedef std::map<std::string, std::pair<Callable, LLSD> > DispatchMap;
- DispatchMap mDispatch;
-};
-
-/**
- * Bundle an LLEventPump and a listener with an LLEventDispatcher. A class
- * that contains (or derives from) LLDispatchListener need only specify the
- * LLEventPump name and dispatch key, and add() its methods. Incoming events
- * will automatically be dispatched.
- */
-class LLDispatchListener: public LLEventDispatcher
-{
-public:
- LLDispatchListener(const std::string& pumpname, const std::string& key);
-
-private:
- bool process(const LLSD& event);
-
- LLEventStream mPump;
- LLTempBoundListener mBoundListener;
-};
-
-#endif /* ! defined(LL_LLEVENTDISPATCHER_H) */
+/**
+ * @file lleventdispatcher.h
+ * @author Nat Goodspeed
+ * @date 2009-06-18
+ * @brief Central mechanism for dispatching events by string name. This is
+ * useful when you have a single LLEventPump listener on which you can
+ * request different operations, vs. instantiating a different
+ * LLEventPump for each such operation.
+ *
+ * $LicenseInfo:firstyear=2009&license=viewergpl$
+ * Copyright (c) 2009, Linden Research, Inc.
+ * $/LicenseInfo$
+ */
+
+#if ! defined(LL_LLEVENTDISPATCHER_H)
+#define LL_LLEVENTDISPATCHER_H
+
+#include <string>
+#include <map>
+#include <boost/function.hpp>
+#include <boost/bind.hpp>
+#include <typeinfo>
+#include "llevents.h"
+
+class LLSD;
+
+/**
+ * Given an LLSD map, examine a string-valued key and call a corresponding
+ * callable. This class is designed to be contained by an LLEventPump
+ * listener class that will register some of its own methods, though any
+ * callable can be used.
+ */
+class LL_COMMON_API LLEventDispatcher
+{
+public:
+ LLEventDispatcher(const std::string& desc, const std::string& key);
+ virtual ~LLEventDispatcher();
+
+ /// Accept any C++ callable, typically a boost::bind() expression
+ typedef boost::function<void(const LLSD&)> Callable;
+
+ /**
+ * Register a @a callable by @a name. The optional @a required parameter
+ * is used to validate the structure of each incoming event (see
+ * llsd_matches()).
+ */
+ void add(const std::string& name, const Callable& callable, const LLSD& required=LLSD());
+
+ /**
+ * Special case: a subclass of this class can pass an unbound member
+ * function pointer without explicitly specifying the
+ * <tt>boost::bind()</tt> expression.
+ */
+ template <class CLASS>
+ void add(const std::string& name, void (CLASS::*method)(const LLSD&),
+ const LLSD& required=LLSD())
+ {
+ addMethod<CLASS>(name, method, required);
+ }
+
+ /// Overload for both const and non-const methods
+ template <class CLASS>
+ void add(const std::string& name, void (CLASS::*method)(const LLSD&) const,
+ const LLSD& required=LLSD())
+ {
+ addMethod<CLASS>(name, method, required);
+ }
+
+ /// Unregister a callable
+ bool remove(const std::string& name);
+
+ /// Call a registered callable with an explicitly-specified name. If no
+ /// such callable exists, die with LL_ERRS. If the @a event fails to match
+ /// the @a required prototype specified at add() time, die with LL_ERRS.
+ void operator()(const std::string& name, const LLSD& event) const;
+
+ /// Extract the @a key value from the incoming @a event, and call the
+ /// callable whose name is specified by that map @a key. If no such
+ /// callable exists, die with LL_ERRS. If the @a event fails to match the
+ /// @a required prototype specified at add() time, die with LL_ERRS.
+ void operator()(const LLSD& event) const;
+
+private:
+ template <class CLASS, typename METHOD>
+ void addMethod(const std::string& name, const METHOD& method, const LLSD& required)
+ {
+ CLASS* downcast = dynamic_cast<CLASS*>(this);
+ if (! downcast)
+ {
+ addFail(name, typeid(CLASS).name());
+ }
+ else
+ {
+ add(name, boost::bind(method, downcast, _1), required);
+ }
+ }
+ void addFail(const std::string& name, const std::string& classname) const;
+ /// try to dispatch, return @c true if success
+ bool attemptCall(const std::string& name, const LLSD& event) const;
+
+ std::string mDesc, mKey;
+ typedef std::map<std::string, std::pair<Callable, LLSD> > DispatchMap;
+ DispatchMap mDispatch;
+};
+
+/**
+ * Bundle an LLEventPump and a listener with an LLEventDispatcher. A class
+ * that contains (or derives from) LLDispatchListener need only specify the
+ * LLEventPump name and dispatch key, and add() its methods. Incoming events
+ * will automatically be dispatched.
+ */
+class LL_COMMON_API LLDispatchListener: public LLEventDispatcher
+{
+public:
+ LLDispatchListener(const std::string& pumpname, const std::string& key);
+
+private:
+ bool process(const LLSD& event);
+
+ LLEventStream mPump;
+ LLTempBoundListener mBoundListener;
+};
+
+#endif /* ! defined(LL_LLEVENTDISPATCHER_H) */
diff --git a/indra/llcommon/llevents.h b/indra/llcommon/llevents.h
index c5a27ab68e..8ebffc008f 100644
--- a/indra/llcommon/llevents.h
+++ b/indra/llcommon/llevents.h
@@ -1,925 +1,925 @@
-/**
- * @file llevents.h
- * @author Kent Quirk, Nat Goodspeed
- * @date 2008-09-11
- * @brief This is an implementation of the event system described at
- * https://wiki.lindenlab.com/wiki/Viewer:Messaging/Event_System,
- * originally introduced in llnotifications.h. It has nothing
- * whatsoever to do with the older system in llevent.h.
- *
- * $LicenseInfo:firstyear=2008&license=viewergpl$
- * Copyright (c) 2008, Linden Research, Inc.
- * $/LicenseInfo$
- */
-
-#if ! defined(LL_LLEVENTS_H)
-#define LL_LLEVENTS_H
-
-#include <string>
-#include <map>
-#include <set>
-#include <vector>
-#include <deque>
-#include <stdexcept>
-#include <boost/signals2.hpp>
-#include <boost/bind.hpp>
-#include <boost/shared_ptr.hpp>
-#include <boost/enable_shared_from_this.hpp>
-#include <boost/utility.hpp> // noncopyable
-#include <boost/optional/optional.hpp>
-#include <boost/visit_each.hpp>
-#include <boost/ref.hpp> // reference_wrapper
-#include <boost/type_traits/is_pointer.hpp>
-#include <boost/function.hpp>
-#include <boost/static_assert.hpp>
-#include "llsd.h"
-#include "llsingleton.h"
-#include "lldependencies.h"
-
-// override this to allow binding free functions with more parameters
-#ifndef LLEVENTS_LISTENER_ARITY
-#define LLEVENTS_LISTENER_ARITY 10
-#endif
-
-// hack for testing
-#ifndef testable
-#define testable private
-#endif
-
-/*****************************************************************************
-* Signal and handler declarations
-* Using a single handler signature means that we can have a common handler
-* type, rather than needing a distinct one for each different handler.
-*****************************************************************************/
-
-/**
- * A boost::signals Combiner that stops the first time a handler returns true
- * We need this because we want to have our handlers return bool, so that
- * we have the option to cause a handler to stop further processing. The
- * default handler fails when the signal returns a value but has no slots.
- */
-struct LLStopWhenHandled
-{
- typedef bool result_type;
-
- template<typename InputIterator>
- result_type operator()(InputIterator first, InputIterator last) const
- {
- for (InputIterator si = first; si != last; ++si)
- {
- if (*si)
- {
- return true;
- }
- }
- return false;
- }
-};
-
-/**
- * We want to have a standard signature for all signals; this way,
- * we can easily document a protocol for communicating across
- * dlls and into scripting languages someday.
- *
- * We want to return a bool to indicate whether the signal has been
- * handled and should NOT be passed on to other listeners.
- * Return true to stop further handling of the signal, and false
- * to continue.
- *
- * We take an LLSD because this way the contents of the signal
- * are independent of the API used to communicate it.
- * It is const ref because then there's low cost to pass it;
- * if you only need to inspect it, it's very cheap.
- *
- * @internal
- * The @c float template parameter indicates that we will internally use @c
- * float to indicate relative listener order on a given LLStandardSignal.
- * Don't worry, the @c float values are strictly internal! They are not part
- * of the interface, for the excellent reason that requiring the caller to
- * specify a numeric key to establish order means that the caller must know
- * the universe of possible values. We use LLDependencies for that instead.
- */
-typedef boost::signals2::signal<bool(const LLSD&), LLStopWhenHandled, float> LLStandardSignal;
-/// Methods that forward listeners (e.g. constructed with
-/// <tt>boost::bind()</tt>) should accept (const LLEventListener&)
-typedef LLStandardSignal::slot_type LLEventListener;
-/// Result of registering a listener, supports <tt>connected()</tt>,
-/// <tt>disconnect()</tt> and <tt>blocked()</tt>
-typedef boost::signals2::connection LLBoundListener;
-/// Storing an LLBoundListener in LLTempBoundListener will disconnect the
-/// referenced listener when the LLTempBoundListener instance is destroyed.
-typedef boost::signals2::scoped_connection LLTempBoundListener;
-
-/**
- * A common idiom for event-based code is to accept either a callable --
- * directly called on completion -- or the string name of an LLEventPump on
- * which to post the completion event. Specifying a parameter as <tt>const
- * LLListenerOrPumpName&</tt> allows either.
- *
- * Calling a validly-constructed LLListenerOrPumpName, passing the LLSD
- * 'event' object, either calls the callable or posts the event to the named
- * LLEventPump.
- *
- * A default-constructed LLListenerOrPumpName is 'empty'. (This is useful as
- * the default value of an optional method parameter.) Calling it throws
- * LLListenerOrPumpName::Empty. Test for this condition beforehand using
- * either <tt>if (param)</tt> or <tt>if (! param)</tt>.
- */
-class LL_COMMON_API LLListenerOrPumpName
-{
-public:
- /// passing string name of LLEventPump
- LLListenerOrPumpName(const std::string& pumpname);
- /// passing string literal (overload so compiler isn't forced to infer
- /// double conversion)
- LLListenerOrPumpName(const char* pumpname);
- /// passing listener -- the "anything else" catch-all case. The type of an
- /// object constructed by boost::bind() isn't intended to be written out.
- /// Normally we'd just accept 'const LLEventListener&', but that would
- /// require double implicit conversion: boost::bind() object to
- /// LLEventListener, LLEventListener to LLListenerOrPumpName. So use a
- /// template to forward anything.
- template<typename T>
- LLListenerOrPumpName(const T& listener): mListener(listener) {}
-
- /// for omitted method parameter: uninitialized mListener
- LLListenerOrPumpName() {}
-
- /// test for validity
- operator bool() const { return bool(mListener); }
- bool operator! () const { return ! mListener; }
-
- /// explicit accessor
- const LLEventListener& getListener() const { return *mListener; }
-
- /// implicit conversion to LLEventListener
- operator LLEventListener() const { return *mListener; }
-
- /// allow calling directly
- bool operator()(const LLSD& event) const;
-
- /// exception if you try to call when empty
- struct Empty: public std::runtime_error
- {
- Empty(const std::string& what):
- std::runtime_error(std::string("LLListenerOrPumpName::Empty: ") + what) {}
- };
-
-private:
- boost::optional<LLEventListener> mListener;
-};
-
-/*****************************************************************************
-* LLEventPumps
-*****************************************************************************/
-class LL_COMMON_API LLEventPump;
-
-/**
- * LLEventPumps is a Singleton manager through which one typically accesses
- * this subsystem.
- */
-class LL_COMMON_API LLEventPumps: public LLSingleton<LLEventPumps>
-{
- friend class LLSingleton<LLEventPumps>;
-public:
- /**
- * Find or create an LLEventPump instance with a specific name. We return
- * a reference so there's no question about ownership. obtain() @em finds
- * an instance without conferring @em ownership.
- */
- LLEventPump& obtain(const std::string& name);
- /**
- * Flush all known LLEventPump instances
- */
- void flush();
-
-private:
- friend class LLEventPump;
- /**
- * Register a new LLEventPump instance (internal)
- */
- std::string registerNew(const LLEventPump&, const std::string& name, bool tweak);
- /**
- * Unregister a doomed LLEventPump instance (internal)
- */
- void unregister(const LLEventPump&);
-
-private:
- LLEventPumps();
- ~LLEventPumps();
-
-testable:
- // Map of all known LLEventPump instances, whether or not we instantiated
- // them. We store a plain old LLEventPump* because this map doesn't claim
- // ownership of the instances. Though the common usage pattern is to
- // request an instance using obtain(), it's fair to instantiate an
- // LLEventPump subclass statically, as a class member, on the stack or on
- // the heap. In such cases, the instantiating party is responsible for its
- // lifespan.
- typedef std::map<std::string, LLEventPump*> PumpMap;
- PumpMap mPumpMap;
- // Set of all LLEventPumps we instantiated. Membership in this set means
- // we claim ownership, and will delete them when this LLEventPumps is
- // destroyed.
- typedef std::set<LLEventPump*> PumpSet;
- PumpSet mOurPumps;
- // LLEventPump names that should be instantiated as LLEventQueue rather
- // than as LLEventStream
- typedef std::set<std::string> PumpNames;
- PumpNames mQueueNames;
-};
-
-/*****************************************************************************
-* details
-*****************************************************************************/
-namespace LLEventDetail
-{
- /// Any callable capable of connecting an LLEventListener to an
- /// LLStandardSignal to produce an LLBoundListener can be mapped to this
- /// signature.
- typedef boost::function<LLBoundListener(const LLEventListener&)> ConnectFunc;
-
- /**
- * Utility template function to use Visitor appropriately
- *
- * @param listener Callable to connect, typically a boost::bind()
- * expression. This will be visited by Visitor using boost::visit_each().
- * @param connect_func Callable that will connect() @a listener to an
- * LLStandardSignal, returning LLBoundListener.
- */
- template <typename LISTENER>
- LLBoundListener visit_and_connect(const LISTENER& listener,
- const ConnectFunc& connect_func);
-} // namespace LLEventDetail
-
-/*****************************************************************************
-* LLEventTrackable
-*****************************************************************************/
-/**
- * LLEventTrackable wraps boost::signals2::trackable, which resembles
- * boost::trackable. Derive your listener class from LLEventTrackable instead,
- * and use something like
- * <tt>LLEventPump::listen(boost::bind(&YourTrackableSubclass::method,
- * instance, _1))</tt>. This will implicitly disconnect when the object
- * referenced by @c instance is destroyed.
- *
- * @note
- * LLEventTrackable doesn't address a couple of cases:
- * * Object destroyed during call
- * - You enter a slot call in thread A.
- * - Thread B destroys the object, which of course disconnects it from any
- * future slot calls.
- * - Thread A's call uses 'this', which now refers to a defunct object.
- * Undefined behavior results.
- * * Call during destruction
- * - @c MySubclass is derived from LLEventTrackable.
- * - @c MySubclass registers one of its own methods using
- * <tt>LLEventPump::listen()</tt>.
- * - The @c MySubclass object begins destruction. <tt>~MySubclass()</tt>
- * runs, destroying state specific to the subclass. (For instance, a
- * <tt>Foo*</tt> data member is <tt>delete</tt>d but not zeroed.)
- * - The listening method will not be disconnected until
- * <tt>~LLEventTrackable()</tt> runs.
- * - Before we get there, another thread posts data to the @c LLEventPump
- * instance, calling the @c MySubclass method.
- * - The method in question relies on valid @c MySubclass state. (For
- * instance, it attempts to dereference the <tt>Foo*</tt> pointer that was
- * <tt>delete</tt>d but not zeroed.)
- * - Undefined behavior results.
- * If you suspect you may encounter any such scenario, you're better off
- * managing the lifespan of your object with <tt>boost::shared_ptr</tt>.
- * Passing <tt>LLEventPump::listen()</tt> a <tt>boost::bind()</tt> expression
- * involving a <tt>boost::weak_ptr<Foo></tt> is recognized specially, engaging
- * thread-safe Boost.Signals2 machinery.
- */
-typedef boost::signals2::trackable LLEventTrackable;
-
-/*****************************************************************************
-* LLEventPump
-*****************************************************************************/
-/**
- * LLEventPump is the base class interface through which we access the
- * concrete subclasses LLEventStream and LLEventQueue.
- *
- * @NOTE
- * LLEventPump derives from LLEventTrackable so that when you "chain"
- * LLEventPump instances together, they will automatically disconnect on
- * destruction. Please see LLEventTrackable documentation for situations in
- * which this may be perilous across threads.
- */
-class LL_COMMON_API LLEventPump: public LLEventTrackable
-{
-public:
- /**
- * Exception thrown by LLEventPump(). You are trying to instantiate an
- * LLEventPump (subclass) using the same name as some other instance, and
- * you didn't pass <tt>tweak=true</tt> to permit it to generate a unique
- * variant.
- */
- struct DupPumpName: public std::runtime_error
- {
- DupPumpName(const std::string& what):
- std::runtime_error(std::string("DupPumpName: ") + what) {}
- };
-
- /**
- * Instantiate an LLEventPump (subclass) with the string name by which it
- * can be found using LLEventPumps::obtain().
- *
- * If you pass (or default) @a tweak to @c false, then a duplicate name
- * will throw DupPumpName. This won't happen if LLEventPumps::obtain()
- * instantiates the LLEventPump, because obtain() uses find-or-create
- * logic. It can only happen if you instantiate an LLEventPump in your own
- * code -- and a collision with the name of some other LLEventPump is
- * likely to cause much more subtle problems!
- *
- * When you hand-instantiate an LLEventPump, consider passing @a tweak as
- * @c true. This directs LLEventPump() to append a suffix to the passed @a
- * name to make it unique. You can retrieve the adjusted name by calling
- * getName() on your new instance.
- */
- LLEventPump(const std::string& name, bool tweak=false);
- virtual ~LLEventPump();
-
- /// group exceptions thrown by listen(). We use exceptions because these
- /// particular errors are likely to be coding errors, found and fixed by
- /// the developer even before preliminary checkin.
- struct ListenError: public std::runtime_error
- {
- ListenError(const std::string& what): std::runtime_error(what) {}
- };
- /**
- * exception thrown by listen(). You are attempting to register a
- * listener on this LLEventPump using the same listener name as an
- * already-registered listener.
- */
- struct DupListenerName: public ListenError
- {
- DupListenerName(const std::string& what):
- ListenError(std::string("DupListenerName: ") + what)
- {}
- };
- /**
- * exception thrown by listen(). The order dependencies specified for your
- * listener are incompatible with existing listeners.
- *
- * Consider listener "a" which specifies before "b" and "b" which
- * specifies before "c". You are now attempting to register "c" before
- * "a". There is no order that can satisfy all constraints.
- */
- struct Cycle: public ListenError
- {
- Cycle(const std::string& what): ListenError(std::string("Cycle: ") + what) {}
- };
- /**
- * exception thrown by listen(). This one means that your new listener
- * would force a change to the order of previously-registered listeners,
- * and we don't have a good way to implement that.
- *
- * Consider listeners "some", "other" and "third". "some" and "other" are
- * registered earlier without specifying relative order, so "other"
- * happens to be first. Now you attempt to register "third" after "some"
- * and before "other". Whoops, that would require swapping "some" and
- * "other", which we can't do. Instead we throw this exception.
- *
- * It may not be possible to change the registration order so we already
- * know "third"s order requirement by the time we register the second of
- * "some" and "other". A solution would be to specify that "some" must
- * come before "other", or equivalently that "other" must come after
- * "some".
- */
- struct OrderChange: public ListenError
- {
- OrderChange(const std::string& what): ListenError(std::string("OrderChange: ") + what) {}
- };
-
- /// used by listen()
- typedef std::vector<std::string> NameList;
- /// convenience placeholder for when you explicitly want to pass an empty
- /// NameList
- const static NameList empty;
-
- /// Get this LLEventPump's name
- std::string getName() const { return mName; }
-
- /**
- * Register a new listener with a unique name. Specify an optional list
- * of other listener names after which this one must be called, likewise
- * an optional list of other listener names before which this one must be
- * called. The other listeners mentioned need not yet be registered
- * themselves. listen() can throw any ListenError; see ListenError
- * subclasses.
- *
- * The listener name must be unique among active listeners for this
- * LLEventPump, else you get DupListenerName. If you don't care to invent
- * a name yourself, use inventName(). (I was tempted to recognize e.g. ""
- * and internally generate a distinct name for that case. But that would
- * handle badly the scenario in which you want to add, remove, re-add,
- * etc. the same listener: each new listen() call would necessarily
- * perform a new dependency sort. Assuming you specify the same
- * after/before lists each time, using inventName() when you first
- * instantiate your listener, then passing the same name on each listen()
- * call, allows us to optimize away the second and subsequent dependency
- * sorts.
- *
- * If (as is typical) you pass a <tt>boost::bind()</tt> expression as @a
- * listener, listen() will inspect the components of that expression. If a
- * bound object matches any of several cases, the connection will
- * automatically be disconnected when that object is destroyed.
- *
- * * You bind a <tt>boost::weak_ptr</tt>.
- * * Binding a <tt>boost::shared_ptr</tt> that way would ensure that the
- * referenced object would @em never be destroyed, since the @c
- * shared_ptr stored in the LLEventPump would remain an outstanding
- * reference. Use the weaken() function to convert your @c shared_ptr to
- * @c weak_ptr. Because this is easy to forget, binding a @c shared_ptr
- * will produce a compile error (@c BOOST_STATIC_ASSERT failure).
- * * You bind a simple pointer or reference to an object derived from
- * <tt>boost::enable_shared_from_this</tt>. (UNDER CONSTRUCTION)
- * * You bind a simple pointer or reference to an object derived from
- * LLEventTrackable. Unlike the cases described above, though, this is
- * vulnerable to a couple of cross-thread race conditions, as described
- * in the LLEventTrackable documentation.
- */
- template <typename LISTENER>
- LLBoundListener listen(const std::string& name, const LISTENER& listener,
- const NameList& after=NameList(),
- const NameList& before=NameList())
- {
- // Examine listener, using our listen_impl() method to make the
- // actual connection.
- // This is why listen() is a template. Conversion from boost::bind()
- // to LLEventListener performs type erasure, so it's important to look
- // at the boost::bind object itself before that happens.
- return LLEventDetail::visit_and_connect(listener,
- boost::bind(&LLEventPump::listen_impl,
- this,
- name,
- _1,
- after,
- before));
- }
-
- /// Get the LLBoundListener associated with the passed name (dummy
- /// LLBoundListener if not found)
- virtual LLBoundListener getListener(const std::string& name) const;
- /**
- * Instantiate one of these to block an existing connection:
- * @code
- * { // in some local scope
- * LLEventPump::Blocker block(someLLBoundListener);
- * // code that needs the connection blocked
- * } // unblock the connection again
- * @endcode
- */
- typedef boost::signals2::shared_connection_block Blocker;
- /// Unregister a listener by name. Prefer this to
- /// <tt>getListener(name).disconnect()</tt> because stopListening() also
- /// forgets this name.
- virtual void stopListening(const std::string& name);
- /// Post an event to all listeners. The @c bool return is only meaningful
- /// if the underlying leaf class is LLEventStream -- beware of relying on
- /// it too much! Truthfully, we return @c bool mostly to permit chaining
- /// one LLEventPump as a listener on another.
- virtual bool post(const LLSD&) = 0;
- /// Enable/disable: while disabled, silently ignore all post() calls
- virtual void enable(bool enabled=true) { mEnabled = enabled; }
- /// query
- virtual bool enabled() const { return mEnabled; }
-
- /// Generate a distinct name for a listener -- see listen()
- static std::string inventName(const std::string& pfx="listener");
-
-private:
- friend class LLEventPumps;
- /// flush queued events
- virtual void flush() {}
-
-private:
- virtual LLBoundListener listen_impl(const std::string& name, const LLEventListener&,
- const NameList& after,
- const NameList& before);
- std::string mName;
-
-protected:
- /// implement the dispatching
- LLStandardSignal mSignal;
- /// valve open?
- bool mEnabled;
- /// Map of named listeners. This tracks the listeners that actually exist
- /// at this moment. When we stopListening(), we discard the entry from
- /// this map.
- typedef std::map<std::string, boost::signals2::connection> ConnectionMap;
- ConnectionMap mConnections;
- typedef LLDependencies<std::string, float> DependencyMap;
- /// Dependencies between listeners. For each listener, track the float
- /// used to establish its place in mSignal's order. This caches all the
- /// listeners that have ever registered; stopListening() does not discard
- /// the entry from this map. This is to avoid a new dependency sort if the
- /// same listener with the same dependencies keeps hopping on and off this
- /// LLEventPump.
- DependencyMap mDeps;
-};
-
-/*****************************************************************************
-* LLEventStream
-*****************************************************************************/
-/**
- * LLEventStream is a thin wrapper around LLStandardSignal. Posting an
- * event immediately calls all registered listeners.
- */
-class LL_COMMON_API LLEventStream: public LLEventPump
-{
-public:
- LLEventStream(const std::string& name, bool tweak=false): LLEventPump(name, tweak) {}
- virtual ~LLEventStream() {}
-
- /// Post an event to all listeners
- virtual bool post(const LLSD& event);
-};
-
-/*****************************************************************************
-* LLEventQueue
-*****************************************************************************/
-/**
- * LLEventQueue isa LLEventPump whose post() method defers calling registered
- * listeners until flush() is called.
- */
-class LL_COMMON_API LLEventQueue: public LLEventPump
-{
-public:
- LLEventQueue(const std::string& name, bool tweak=false): LLEventPump(name, tweak) {}
- virtual ~LLEventQueue() {}
-
- /// Post an event to all listeners
- virtual bool post(const LLSD& event);
-
-private:
- /// flush queued events
- virtual void flush();
-
-private:
- typedef std::deque<LLSD> EventQueue;
- EventQueue mEventQueue;
-};
-
-/*****************************************************************************
-* LLReqID
-*****************************************************************************/
-/**
- * This class helps the implementer of a given event API to honor the
- * ["reqid"] convention. By this convention, each event API stamps into its
- * response LLSD a ["reqid"] key whose value echoes the ["reqid"] value, if
- * any, from the corresponding request.
- *
- * This supports an (atypical, but occasionally necessary) use case in which
- * two or more asynchronous requests are multiplexed onto the same ["reply"]
- * LLEventPump. Since the response events could arrive in arbitrary order, the
- * caller must be able to demux them. It does so by matching the ["reqid"]
- * value in each response with the ["reqid"] value in the corresponding
- * request.
- *
- * It is the caller's responsibility to ensure distinct ["reqid"] values for
- * that case. Though LLSD::UUID is guaranteed to work, it might be overkill:
- * the "namespace" of unique ["reqid"] values is simply the set of requests
- * specifying the same ["reply"] LLEventPump name.
- *
- * Making a given event API echo the request's ["reqid"] into the response is
- * nearly trivial. This helper is mostly for mnemonic purposes, to serve as a
- * place to put these comments. We hope that each time a coder implements a
- * new event API based on some existing one, s/he will say, "Huh, what's an
- * LLReqID?" and look up this material.
- *
- * The hardest part about the convention is deciding where to store the
- * ["reqid"] value. Ironically, LLReqID can't help with that: you must store
- * an LLReqID instance in whatever storage will persist until the reply is
- * sent. For example, if the request ultimately ends up using a Responder
- * subclass, storing an LLReqID instance in the Responder works.
- *
- * @note
- * The @em implementer of an event API must honor the ["reqid"] convention.
- * However, the @em caller of an event API need only use it if s/he is sharing
- * the same ["reply"] LLEventPump for two or more asynchronous event API
- * requests.
- *
- * In most cases, it's far easier for the caller to instantiate a local
- * LLEventStream and pass its name to the event API in question. Then it's
- * perfectly reasonable not to set a ["reqid"] key in the request, ignoring
- * the @c isUndefined() ["reqid"] value in the response.
- */
-class LLReqID
-{
-public:
- /**
- * If you have the request in hand at the time you instantiate the
- * LLReqID, pass that request to extract its ["reqid"].
- */
- LLReqID(const LLSD& request):
- mReqid(request["reqid"])
- {}
- /// If you don't yet have the request, use setFrom() later.
- LLReqID() {}
-
- /// Extract and store the ["reqid"] value from an incoming request.
- void setFrom(const LLSD& request)
- {
- mReqid = request["reqid"];
- }
-
- /// Set ["reqid"] key into a pending response LLSD object.
- void stamp(LLSD& response) const;
-
- /// Make a whole new response LLSD object with our ["reqid"].
- LLSD makeResponse() const
- {
- LLSD response;
- stamp(response);
- return response;
- }
-
- /// Not really sure of a use case for this accessor...
- LLSD getReqID() const { return mReqid; }
-
-private:
- LLSD mReqid;
-};
-
-/*****************************************************************************
-* Underpinnings
-*****************************************************************************/
-/**
- * We originally provided a suite of overloaded
- * LLEventTrackable::listenTo(LLEventPump&, ...) methods that would call
- * LLEventPump::listen(...) and then pass the returned LLBoundListener to
- * LLEventTrackable::track(). This was workable but error-prone: the coder
- * must remember to call listenTo() rather than the more straightforward
- * listen() method.
- *
- * Now we publish only the single canonical listen() method, so there's a
- * uniform mechanism. Having a single way to do this is good, in that there's
- * no question in the coder's mind which of several alternatives to choose.
- *
- * To support automatic connection management, we use boost::visit_each
- * (http://www.boost.org/doc/libs/1_37_0/doc/html/boost/visit_each.html) to
- * inspect each argument of a boost::bind expression. (Although the visit_each
- * mechanism was first introduced with the original Boost.Signals library, it
- * was only later documented.)
- *
- * Cases:
- * * At least one of the function's arguments is a boost::weak_ptr<T>. Pass
- * the corresponding shared_ptr to slot_type::track(). Ideally that would be
- * the object whose method we want to call, but in fact we do the same for
- * any weak_ptr we might find among the bound arguments. If we're passing
- * our bound method a weak_ptr to some object, wouldn't the destruction of
- * that object invalidate the call? So we disconnect automatically when any
- * such object is destroyed. This is the mechanism preferred by boost::
- * signals2.
- * * One of the functions's arguments is a boost::shared_ptr<T>. This produces
- * a compile error: the bound copy of the shared_ptr stored in the
- * boost_bind object stored in the signal object would make the referenced
- * T object immortal. We provide a weaken() function. Pass
- * weaken(your_shared_ptr) instead. (We can inspect, but not modify, the
- * boost::bind object. Otherwise we'd replace the shared_ptr with weak_ptr
- * implicitly and just proceed.)
- * * One of the function's arguments is a plain pointer/reference to an object
- * derived from boost::enable_shared_from_this. We assume that this object
- * is managed using boost::shared_ptr, so we implicitly extract a shared_ptr
- * and track that. (UNDER CONSTRUCTION)
- * * One of the function's arguments is derived from LLEventTrackable. Pass
- * the LLBoundListener to its LLEventTrackable::track(). This is vulnerable
- * to a couple different race conditions, as described in LLEventTrackable
- * documentation. (NOTE: Now that LLEventTrackable is a typedef for
- * boost::signals2::trackable, the Signals2 library handles this itself, so
- * our visitor needs no special logic for this case.)
- * * Any other argument type is irrelevant to automatic connection management.
- */
-
-namespace LLEventDetail
-{
- template <typename F>
- const F& unwrap(const F& f) { return f; }
-
- template <typename F>
- const F& unwrap(const boost::reference_wrapper<F>& f) { return f.get(); }
-
- // Most of the following is lifted from the Boost.Signals use of
- // visit_each.
- template<bool Cond> struct truth {};
-
- /**
- * boost::visit_each() Visitor, used on a template argument <tt>const F&
- * f</tt> as follows (see visit_and_connect()):
- * @code
- * LLEventListener listener(f);
- * Visitor visitor(listener); // bind listener so it can track() shared_ptrs
- * using boost::visit_each; // allow unqualified visit_each() call for ADL
- * visit_each(visitor, unwrap(f));
- * @endcode
- */
- class Visitor
- {
- public:
- /**
- * Visitor binds a reference to LLEventListener so we can track() any
- * shared_ptrs we find in the argument list.
- */
- Visitor(LLEventListener& listener):
- mListener(listener)
- {
- }
-
- /**
- * boost::visit_each() calls this method for each component of a
- * boost::bind() expression.
- */
- template <typename T>
- void operator()(const T& t) const
- {
- decode(t, 0);
- }
-
- private:
- // decode() decides between a reference wrapper and anything else
- // boost::ref() variant
- template<typename T>
- void decode(const boost::reference_wrapper<T>& t, int) const
- {
-// add_if_trackable(t.get_pointer());
- }
-
- // decode() anything else
- template<typename T>
- void decode(const T& t, long) const
- {
- typedef truth<(boost::is_pointer<T>::value)> is_a_pointer;
- maybe_get_pointer(t, is_a_pointer());
- }
-
- // maybe_get_pointer() decides between a pointer and a non-pointer
- // plain pointer variant
- template<typename T>
- void maybe_get_pointer(const T& t, truth<true>) const
- {
-// add_if_trackable(t);
- }
-
- // shared_ptr variant
- template<typename T>
- void maybe_get_pointer(const boost::shared_ptr<T>& t, truth<false>) const
- {
- // If we have a shared_ptr to this object, it doesn't matter
- // whether the object is derived from LLEventTrackable, so no
- // further analysis of T is needed.
-// mListener.track(t);
-
- // Make this case illegal. Passing a bound shared_ptr to
- // slot_type::track() is useless, since the bound shared_ptr will
- // keep the object alive anyway! Force the coder to cast to weak_ptr.
-
- // Trivial as it is, make the BOOST_STATIC_ASSERT() condition
- // dependent on template param so the macro is only evaluated if
- // this method is in fact instantiated, as described here:
- // http://www.boost.org/doc/libs/1_34_1/doc/html/boost_staticassert.html
-
- // ATTENTION: Don't bind a shared_ptr<anything> using
- // LLEventPump::listen(boost::bind()). Doing so captures a copy of
- // the shared_ptr, making the referenced object effectively
- // immortal. Use the weaken() function, e.g.:
- // somepump.listen(boost::bind(...weaken(my_shared_ptr)...));
- // This lets us automatically disconnect when the referenced
- // object is destroyed.
- BOOST_STATIC_ASSERT(sizeof(T) == 0);
- }
-
- // weak_ptr variant
- template<typename T>
- void maybe_get_pointer(const boost::weak_ptr<T>& t, truth<false>) const
- {
- // If we have a weak_ptr to this object, it doesn't matter
- // whether the object is derived from LLEventTrackable, so no
- // further analysis of T is needed.
- mListener.track(t);
-// std::cout << "Found weak_ptr<" << typeid(T).name() << ">!\n";
- }
-
-#if 0
- // reference to anything derived from boost::enable_shared_from_this
- template <typename T>
- inline void maybe_get_pointer(const boost::enable_shared_from_this<T>& ct,
- truth<false>) const
- {
- // Use the slot_type::track(shared_ptr) mechanism. Cast away
- // const-ness because (in our code base anyway) it's unusual
- // to find shared_ptr<const T>.
- boost::enable_shared_from_this<T>&
- t(const_cast<boost::enable_shared_from_this<T>&>(ct));
- std::cout << "Capturing shared_from_this()" << std::endl;
- boost::shared_ptr<T> sp(t.shared_from_this());
-/*==========================================================================*|
- std::cout << "Capturing weak_ptr" << std::endl;
- boost::weak_ptr<T> wp(sp);
-|*==========================================================================*/
- std::cout << "Tracking shared__ptr" << std::endl;
- mListener.track(sp);
- }
-#endif
-
- // non-pointer variant
- template<typename T>
- void maybe_get_pointer(const T& t, truth<false>) const
- {
- // Take the address of this object, because the object itself may be
- // trackable
-// add_if_trackable(boost::addressof(t));
- }
-
-/*==========================================================================*|
- // add_if_trackable() adds LLEventTrackable objects to mTrackables
- inline void add_if_trackable(const LLEventTrackable* t) const
- {
- if (t)
- {
- }
- }
-
- // pointer to anything not an LLEventTrackable subclass
- inline void add_if_trackable(const void*) const
- {
- }
-
- // pointer to free function
- // The following construct uses the preprocessor to generate
- // add_if_trackable() overloads accepting pointer-to-function taking
- // 0, 1, ..., LLEVENTS_LISTENER_ARITY parameters of arbitrary type.
-#define BOOST_PP_LOCAL_MACRO(n) \
- template <typename R \
- BOOST_PP_COMMA_IF(n) \
- BOOST_PP_ENUM_PARAMS(n, typename T)> \
- inline void \
- add_if_trackable(R (*)(BOOST_PP_ENUM_PARAMS(n, T))) const \
- { \
- }
-#define BOOST_PP_LOCAL_LIMITS (0, LLEVENTS_LISTENER_ARITY)
-#include BOOST_PP_LOCAL_ITERATE()
-#undef BOOST_PP_LOCAL_MACRO
-#undef BOOST_PP_LOCAL_LIMITS
-|*==========================================================================*/
-
- /// Bind a reference to the LLEventListener to call its track() method.
- LLEventListener& mListener;
- };
-
- /**
- * Utility template function to use Visitor appropriately
- *
- * @param raw_listener Callable to connect, typically a boost::bind()
- * expression. This will be visited by Visitor using boost::visit_each().
- * @param connect_funct Callable that will connect() @a raw_listener to an
- * LLStandardSignal, returning LLBoundListener.
- */
- template <typename LISTENER>
- LLBoundListener visit_and_connect(const LISTENER& raw_listener,
- const ConnectFunc& connect_func)
- {
- // Capture the listener
- LLEventListener listener(raw_listener);
- // Define our Visitor, binding the listener so we can call
- // listener.track() if we discover any shared_ptr<Foo>.
- LLEventDetail::Visitor visitor(listener);
- // Allow unqualified visit_each() call for ADL
- using boost::visit_each;
- // Visit each component of a boost::bind() expression. Pass
- // 'raw_listener', our template argument, rather than 'listener' from
- // which type details have been erased. unwrap() comes from
- // Boost.Signals, in case we were passed a boost::ref().
- visit_each(visitor, LLEventDetail::unwrap(raw_listener));
- // Make the connection using passed function. At present, wrapping
- // this functionality into this function is a bit silly: we don't
- // really need a visit_and_connect() function any more, just a visit()
- // function. The definition of this function dates from when, after
- // visit_each(), after establishing the connection, we had to
- // postprocess the new connection with the visitor object. That's no
- // longer necessary.
- return connect_func(listener);
- }
-} // namespace LLEventDetail
-
-// Somewhat to my surprise, passing boost::bind(...boost::weak_ptr<T>...) to
-// listen() fails in Boost code trying to instantiate LLEventListener (i.e.
-// LLStandardSignal::slot_type) because the boost::get_pointer() utility function isn't
-// specialized for boost::weak_ptr. This remedies that omission.
-namespace boost
-{
- template <typename T>
- T* get_pointer(const weak_ptr<T>& ptr) { return shared_ptr<T>(ptr).get(); }
-}
-
-/// Since we forbid use of listen(boost::bind(...shared_ptr<T>...)), provide an
-/// easy way to cast to the corresponding weak_ptr.
-template <typename T>
-boost::weak_ptr<T> weaken(const boost::shared_ptr<T>& ptr)
-{
- return boost::weak_ptr<T>(ptr);
-}
-
-#endif /* ! defined(LL_LLEVENTS_H) */
+/**
+ * @file llevents.h
+ * @author Kent Quirk, Nat Goodspeed
+ * @date 2008-09-11
+ * @brief This is an implementation of the event system described at
+ * https://wiki.lindenlab.com/wiki/Viewer:Messaging/Event_System,
+ * originally introduced in llnotifications.h. It has nothing
+ * whatsoever to do with the older system in llevent.h.
+ *
+ * $LicenseInfo:firstyear=2008&license=viewergpl$
+ * Copyright (c) 2008, Linden Research, Inc.
+ * $/LicenseInfo$
+ */
+
+#if ! defined(LL_LLEVENTS_H)
+#define LL_LLEVENTS_H
+
+#include <string>
+#include <map>
+#include <set>
+#include <vector>
+#include <deque>
+#include <stdexcept>
+#include <boost/signals2.hpp>
+#include <boost/bind.hpp>
+#include <boost/shared_ptr.hpp>
+#include <boost/enable_shared_from_this.hpp>
+#include <boost/utility.hpp> // noncopyable
+#include <boost/optional/optional.hpp>
+#include <boost/visit_each.hpp>
+#include <boost/ref.hpp> // reference_wrapper
+#include <boost/type_traits/is_pointer.hpp>
+#include <boost/function.hpp>
+#include <boost/static_assert.hpp>
+#include "llsd.h"
+#include "llsingleton.h"
+#include "lldependencies.h"
+
+// override this to allow binding free functions with more parameters
+#ifndef LLEVENTS_LISTENER_ARITY
+#define LLEVENTS_LISTENER_ARITY 10
+#endif
+
+// hack for testing
+#ifndef testable
+#define testable private
+#endif
+
+/*****************************************************************************
+* Signal and handler declarations
+* Using a single handler signature means that we can have a common handler
+* type, rather than needing a distinct one for each different handler.
+*****************************************************************************/
+
+/**
+ * A boost::signals Combiner that stops the first time a handler returns true
+ * We need this because we want to have our handlers return bool, so that
+ * we have the option to cause a handler to stop further processing. The
+ * default handler fails when the signal returns a value but has no slots.
+ */
+struct LLStopWhenHandled
+{
+ typedef bool result_type;
+
+ template<typename InputIterator>
+ result_type operator()(InputIterator first, InputIterator last) const
+ {
+ for (InputIterator si = first; si != last; ++si)
+ {
+ if (*si)
+ {
+ return true;
+ }
+ }
+ return false;
+ }
+};
+
+/**
+ * We want to have a standard signature for all signals; this way,
+ * we can easily document a protocol for communicating across
+ * dlls and into scripting languages someday.
+ *
+ * We want to return a bool to indicate whether the signal has been
+ * handled and should NOT be passed on to other listeners.
+ * Return true to stop further handling of the signal, and false
+ * to continue.
+ *
+ * We take an LLSD because this way the contents of the signal
+ * are independent of the API used to communicate it.
+ * It is const ref because then there's low cost to pass it;
+ * if you only need to inspect it, it's very cheap.
+ *
+ * @internal
+ * The @c float template parameter indicates that we will internally use @c
+ * float to indicate relative listener order on a given LLStandardSignal.
+ * Don't worry, the @c float values are strictly internal! They are not part
+ * of the interface, for the excellent reason that requiring the caller to
+ * specify a numeric key to establish order means that the caller must know
+ * the universe of possible values. We use LLDependencies for that instead.
+ */
+typedef boost::signals2::signal<bool(const LLSD&), LLStopWhenHandled, float> LLStandardSignal;
+/// Methods that forward listeners (e.g. constructed with
+/// <tt>boost::bind()</tt>) should accept (const LLEventListener&)
+typedef LLStandardSignal::slot_type LLEventListener;
+/// Result of registering a listener, supports <tt>connected()</tt>,
+/// <tt>disconnect()</tt> and <tt>blocked()</tt>
+typedef boost::signals2::connection LLBoundListener;
+/// Storing an LLBoundListener in LLTempBoundListener will disconnect the
+/// referenced listener when the LLTempBoundListener instance is destroyed.
+typedef boost::signals2::scoped_connection LLTempBoundListener;
+
+/**
+ * A common idiom for event-based code is to accept either a callable --
+ * directly called on completion -- or the string name of an LLEventPump on
+ * which to post the completion event. Specifying a parameter as <tt>const
+ * LLListenerOrPumpName&</tt> allows either.
+ *
+ * Calling a validly-constructed LLListenerOrPumpName, passing the LLSD
+ * 'event' object, either calls the callable or posts the event to the named
+ * LLEventPump.
+ *
+ * A default-constructed LLListenerOrPumpName is 'empty'. (This is useful as
+ * the default value of an optional method parameter.) Calling it throws
+ * LLListenerOrPumpName::Empty. Test for this condition beforehand using
+ * either <tt>if (param)</tt> or <tt>if (! param)</tt>.
+ */
+class LL_COMMON_API LLListenerOrPumpName
+{
+public:
+ /// passing string name of LLEventPump
+ LLListenerOrPumpName(const std::string& pumpname);
+ /// passing string literal (overload so compiler isn't forced to infer
+ /// double conversion)
+ LLListenerOrPumpName(const char* pumpname);
+ /// passing listener -- the "anything else" catch-all case. The type of an
+ /// object constructed by boost::bind() isn't intended to be written out.
+ /// Normally we'd just accept 'const LLEventListener&', but that would
+ /// require double implicit conversion: boost::bind() object to
+ /// LLEventListener, LLEventListener to LLListenerOrPumpName. So use a
+ /// template to forward anything.
+ template<typename T>
+ LLListenerOrPumpName(const T& listener): mListener(listener) {}
+
+ /// for omitted method parameter: uninitialized mListener
+ LLListenerOrPumpName() {}
+
+ /// test for validity
+ operator bool() const { return bool(mListener); }
+ bool operator! () const { return ! mListener; }
+
+ /// explicit accessor
+ const LLEventListener& getListener() const { return *mListener; }
+
+ /// implicit conversion to LLEventListener
+ operator LLEventListener() const { return *mListener; }
+
+ /// allow calling directly
+ bool operator()(const LLSD& event) const;
+
+ /// exception if you try to call when empty
+ struct Empty: public std::runtime_error
+ {
+ Empty(const std::string& what):
+ std::runtime_error(std::string("LLListenerOrPumpName::Empty: ") + what) {}
+ };
+
+private:
+ boost::optional<LLEventListener> mListener;
+};
+
+/*****************************************************************************
+* LLEventPumps
+*****************************************************************************/
+class LL_COMMON_API LLEventPump;
+
+/**
+ * LLEventPumps is a Singleton manager through which one typically accesses
+ * this subsystem.
+ */
+class LL_COMMON_API LLEventPumps: public LLSingleton<LLEventPumps>
+{
+ friend class LLSingleton<LLEventPumps>;
+public:
+ /**
+ * Find or create an LLEventPump instance with a specific name. We return
+ * a reference so there's no question about ownership. obtain() @em finds
+ * an instance without conferring @em ownership.
+ */
+ LLEventPump& obtain(const std::string& name);
+ /**
+ * Flush all known LLEventPump instances
+ */
+ void flush();
+
+private:
+ friend class LLEventPump;
+ /**
+ * Register a new LLEventPump instance (internal)
+ */
+ std::string registerNew(const LLEventPump&, const std::string& name, bool tweak);
+ /**
+ * Unregister a doomed LLEventPump instance (internal)
+ */
+ void unregister(const LLEventPump&);
+
+private:
+ LLEventPumps();
+ ~LLEventPumps();
+
+testable:
+ // Map of all known LLEventPump instances, whether or not we instantiated
+ // them. We store a plain old LLEventPump* because this map doesn't claim
+ // ownership of the instances. Though the common usage pattern is to
+ // request an instance using obtain(), it's fair to instantiate an
+ // LLEventPump subclass statically, as a class member, on the stack or on
+ // the heap. In such cases, the instantiating party is responsible for its
+ // lifespan.
+ typedef std::map<std::string, LLEventPump*> PumpMap;
+ PumpMap mPumpMap;
+ // Set of all LLEventPumps we instantiated. Membership in this set means
+ // we claim ownership, and will delete them when this LLEventPumps is
+ // destroyed.
+ typedef std::set<LLEventPump*> PumpSet;
+ PumpSet mOurPumps;
+ // LLEventPump names that should be instantiated as LLEventQueue rather
+ // than as LLEventStream
+ typedef std::set<std::string> PumpNames;
+ PumpNames mQueueNames;
+};
+
+/*****************************************************************************
+* details
+*****************************************************************************/
+namespace LLEventDetail
+{
+ /// Any callable capable of connecting an LLEventListener to an
+ /// LLStandardSignal to produce an LLBoundListener can be mapped to this
+ /// signature.
+ typedef boost::function<LLBoundListener(const LLEventListener&)> ConnectFunc;
+
+ /**
+ * Utility template function to use Visitor appropriately
+ *
+ * @param listener Callable to connect, typically a boost::bind()
+ * expression. This will be visited by Visitor using boost::visit_each().
+ * @param connect_func Callable that will connect() @a listener to an
+ * LLStandardSignal, returning LLBoundListener.
+ */
+ template <typename LISTENER>
+ LLBoundListener visit_and_connect(const LISTENER& listener,
+ const ConnectFunc& connect_func);
+} // namespace LLEventDetail
+
+/*****************************************************************************
+* LLEventTrackable
+*****************************************************************************/
+/**
+ * LLEventTrackable wraps boost::signals2::trackable, which resembles
+ * boost::trackable. Derive your listener class from LLEventTrackable instead,
+ * and use something like
+ * <tt>LLEventPump::listen(boost::bind(&YourTrackableSubclass::method,
+ * instance, _1))</tt>. This will implicitly disconnect when the object
+ * referenced by @c instance is destroyed.
+ *
+ * @note
+ * LLEventTrackable doesn't address a couple of cases:
+ * * Object destroyed during call
+ * - You enter a slot call in thread A.
+ * - Thread B destroys the object, which of course disconnects it from any
+ * future slot calls.
+ * - Thread A's call uses 'this', which now refers to a defunct object.
+ * Undefined behavior results.
+ * * Call during destruction
+ * - @c MySubclass is derived from LLEventTrackable.
+ * - @c MySubclass registers one of its own methods using
+ * <tt>LLEventPump::listen()</tt>.
+ * - The @c MySubclass object begins destruction. <tt>~MySubclass()</tt>
+ * runs, destroying state specific to the subclass. (For instance, a
+ * <tt>Foo*</tt> data member is <tt>delete</tt>d but not zeroed.)
+ * - The listening method will not be disconnected until
+ * <tt>~LLEventTrackable()</tt> runs.
+ * - Before we get there, another thread posts data to the @c LLEventPump
+ * instance, calling the @c MySubclass method.
+ * - The method in question relies on valid @c MySubclass state. (For
+ * instance, it attempts to dereference the <tt>Foo*</tt> pointer that was
+ * <tt>delete</tt>d but not zeroed.)
+ * - Undefined behavior results.
+ * If you suspect you may encounter any such scenario, you're better off
+ * managing the lifespan of your object with <tt>boost::shared_ptr</tt>.
+ * Passing <tt>LLEventPump::listen()</tt> a <tt>boost::bind()</tt> expression
+ * involving a <tt>boost::weak_ptr<Foo></tt> is recognized specially, engaging
+ * thread-safe Boost.Signals2 machinery.
+ */
+typedef boost::signals2::trackable LLEventTrackable;
+
+/*****************************************************************************
+* LLEventPump
+*****************************************************************************/
+/**
+ * LLEventPump is the base class interface through which we access the
+ * concrete subclasses LLEventStream and LLEventQueue.
+ *
+ * @NOTE
+ * LLEventPump derives from LLEventTrackable so that when you "chain"
+ * LLEventPump instances together, they will automatically disconnect on
+ * destruction. Please see LLEventTrackable documentation for situations in
+ * which this may be perilous across threads.
+ */
+class LL_COMMON_API LLEventPump: public LLEventTrackable
+{
+public:
+ /**
+ * Exception thrown by LLEventPump(). You are trying to instantiate an
+ * LLEventPump (subclass) using the same name as some other instance, and
+ * you didn't pass <tt>tweak=true</tt> to permit it to generate a unique
+ * variant.
+ */
+ struct DupPumpName: public std::runtime_error
+ {
+ DupPumpName(const std::string& what):
+ std::runtime_error(std::string("DupPumpName: ") + what) {}
+ };
+
+ /**
+ * Instantiate an LLEventPump (subclass) with the string name by which it
+ * can be found using LLEventPumps::obtain().
+ *
+ * If you pass (or default) @a tweak to @c false, then a duplicate name
+ * will throw DupPumpName. This won't happen if LLEventPumps::obtain()
+ * instantiates the LLEventPump, because obtain() uses find-or-create
+ * logic. It can only happen if you instantiate an LLEventPump in your own
+ * code -- and a collision with the name of some other LLEventPump is
+ * likely to cause much more subtle problems!
+ *
+ * When you hand-instantiate an LLEventPump, consider passing @a tweak as
+ * @c true. This directs LLEventPump() to append a suffix to the passed @a
+ * name to make it unique. You can retrieve the adjusted name by calling
+ * getName() on your new instance.
+ */
+ LLEventPump(const std::string& name, bool tweak=false);
+ virtual ~LLEventPump();
+
+ /// group exceptions thrown by listen(). We use exceptions because these
+ /// particular errors are likely to be coding errors, found and fixed by
+ /// the developer even before preliminary checkin.
+ struct ListenError: public std::runtime_error
+ {
+ ListenError(const std::string& what): std::runtime_error(what) {}
+ };
+ /**
+ * exception thrown by listen(). You are attempting to register a
+ * listener on this LLEventPump using the same listener name as an
+ * already-registered listener.
+ */
+ struct DupListenerName: public ListenError
+ {
+ DupListenerName(const std::string& what):
+ ListenError(std::string("DupListenerName: ") + what)
+ {}
+ };
+ /**
+ * exception thrown by listen(). The order dependencies specified for your
+ * listener are incompatible with existing listeners.
+ *
+ * Consider listener "a" which specifies before "b" and "b" which
+ * specifies before "c". You are now attempting to register "c" before
+ * "a". There is no order that can satisfy all constraints.
+ */
+ struct Cycle: public ListenError
+ {
+ Cycle(const std::string& what): ListenError(std::string("Cycle: ") + what) {}
+ };
+ /**
+ * exception thrown by listen(). This one means that your new listener
+ * would force a change to the order of previously-registered listeners,
+ * and we don't have a good way to implement that.
+ *
+ * Consider listeners "some", "other" and "third". "some" and "other" are
+ * registered earlier without specifying relative order, so "other"
+ * happens to be first. Now you attempt to register "third" after "some"
+ * and before "other". Whoops, that would require swapping "some" and
+ * "other", which we can't do. Instead we throw this exception.
+ *
+ * It may not be possible to change the registration order so we already
+ * know "third"s order requirement by the time we register the second of
+ * "some" and "other". A solution would be to specify that "some" must
+ * come before "other", or equivalently that "other" must come after
+ * "some".
+ */
+ struct OrderChange: public ListenError
+ {
+ OrderChange(const std::string& what): ListenError(std::string("OrderChange: ") + what) {}
+ };
+
+ /// used by listen()
+ typedef std::vector<std::string> NameList;
+ /// convenience placeholder for when you explicitly want to pass an empty
+ /// NameList
+ const static NameList empty;
+
+ /// Get this LLEventPump's name
+ std::string getName() const { return mName; }
+
+ /**
+ * Register a new listener with a unique name. Specify an optional list
+ * of other listener names after which this one must be called, likewise
+ * an optional list of other listener names before which this one must be
+ * called. The other listeners mentioned need not yet be registered
+ * themselves. listen() can throw any ListenError; see ListenError
+ * subclasses.
+ *
+ * The listener name must be unique among active listeners for this
+ * LLEventPump, else you get DupListenerName. If you don't care to invent
+ * a name yourself, use inventName(). (I was tempted to recognize e.g. ""
+ * and internally generate a distinct name for that case. But that would
+ * handle badly the scenario in which you want to add, remove, re-add,
+ * etc. the same listener: each new listen() call would necessarily
+ * perform a new dependency sort. Assuming you specify the same
+ * after/before lists each time, using inventName() when you first
+ * instantiate your listener, then passing the same name on each listen()
+ * call, allows us to optimize away the second and subsequent dependency
+ * sorts.
+ *
+ * If (as is typical) you pass a <tt>boost::bind()</tt> expression as @a
+ * listener, listen() will inspect the components of that expression. If a
+ * bound object matches any of several cases, the connection will
+ * automatically be disconnected when that object is destroyed.
+ *
+ * * You bind a <tt>boost::weak_ptr</tt>.
+ * * Binding a <tt>boost::shared_ptr</tt> that way would ensure that the
+ * referenced object would @em never be destroyed, since the @c
+ * shared_ptr stored in the LLEventPump would remain an outstanding
+ * reference. Use the weaken() function to convert your @c shared_ptr to
+ * @c weak_ptr. Because this is easy to forget, binding a @c shared_ptr
+ * will produce a compile error (@c BOOST_STATIC_ASSERT failure).
+ * * You bind a simple pointer or reference to an object derived from
+ * <tt>boost::enable_shared_from_this</tt>. (UNDER CONSTRUCTION)
+ * * You bind a simple pointer or reference to an object derived from
+ * LLEventTrackable. Unlike the cases described above, though, this is
+ * vulnerable to a couple of cross-thread race conditions, as described
+ * in the LLEventTrackable documentation.
+ */
+ template <typename LISTENER>
+ LLBoundListener listen(const std::string& name, const LISTENER& listener,
+ const NameList& after=NameList(),
+ const NameList& before=NameList())
+ {
+ // Examine listener, using our listen_impl() method to make the
+ // actual connection.
+ // This is why listen() is a template. Conversion from boost::bind()
+ // to LLEventListener performs type erasure, so it's important to look
+ // at the boost::bind object itself before that happens.
+ return LLEventDetail::visit_and_connect(listener,
+ boost::bind(&LLEventPump::listen_impl,
+ this,
+ name,
+ _1,
+ after,
+ before));
+ }
+
+ /// Get the LLBoundListener associated with the passed name (dummy
+ /// LLBoundListener if not found)
+ virtual LLBoundListener getListener(const std::string& name) const;
+ /**
+ * Instantiate one of these to block an existing connection:
+ * @code
+ * { // in some local scope
+ * LLEventPump::Blocker block(someLLBoundListener);
+ * // code that needs the connection blocked
+ * } // unblock the connection again
+ * @endcode
+ */
+ typedef boost::signals2::shared_connection_block Blocker;
+ /// Unregister a listener by name. Prefer this to
+ /// <tt>getListener(name).disconnect()</tt> because stopListening() also
+ /// forgets this name.
+ virtual void stopListening(const std::string& name);
+ /// Post an event to all listeners. The @c bool return is only meaningful
+ /// if the underlying leaf class is LLEventStream -- beware of relying on
+ /// it too much! Truthfully, we return @c bool mostly to permit chaining
+ /// one LLEventPump as a listener on another.
+ virtual bool post(const LLSD&) = 0;
+ /// Enable/disable: while disabled, silently ignore all post() calls
+ virtual void enable(bool enabled=true) { mEnabled = enabled; }
+ /// query
+ virtual bool enabled() const { return mEnabled; }
+
+ /// Generate a distinct name for a listener -- see listen()
+ static std::string inventName(const std::string& pfx="listener");
+
+private:
+ friend class LLEventPumps;
+ /// flush queued events
+ virtual void flush() {}
+
+private:
+ virtual LLBoundListener listen_impl(const std::string& name, const LLEventListener&,
+ const NameList& after,
+ const NameList& before);
+ std::string mName;
+
+protected:
+ /// implement the dispatching
+ LLStandardSignal mSignal;
+ /// valve open?
+ bool mEnabled;
+ /// Map of named listeners. This tracks the listeners that actually exist
+ /// at this moment. When we stopListening(), we discard the entry from
+ /// this map.
+ typedef std::map<std::string, boost::signals2::connection> ConnectionMap;
+ ConnectionMap mConnections;
+ typedef LLDependencies<std::string, float> DependencyMap;
+ /// Dependencies between listeners. For each listener, track the float
+ /// used to establish its place in mSignal's order. This caches all the
+ /// listeners that have ever registered; stopListening() does not discard
+ /// the entry from this map. This is to avoid a new dependency sort if the
+ /// same listener with the same dependencies keeps hopping on and off this
+ /// LLEventPump.
+ DependencyMap mDeps;
+};
+
+/*****************************************************************************
+* LLEventStream
+*****************************************************************************/
+/**
+ * LLEventStream is a thin wrapper around LLStandardSignal. Posting an
+ * event immediately calls all registered listeners.
+ */
+class LL_COMMON_API LLEventStream: public LLEventPump
+{
+public:
+ LLEventStream(const std::string& name, bool tweak=false): LLEventPump(name, tweak) {}
+ virtual ~LLEventStream() {}
+
+ /// Post an event to all listeners
+ virtual bool post(const LLSD& event);
+};
+
+/*****************************************************************************
+* LLEventQueue
+*****************************************************************************/
+/**
+ * LLEventQueue isa LLEventPump whose post() method defers calling registered
+ * listeners until flush() is called.
+ */
+class LL_COMMON_API LLEventQueue: public LLEventPump
+{
+public:
+ LLEventQueue(const std::string& name, bool tweak=false): LLEventPump(name, tweak) {}
+ virtual ~LLEventQueue() {}
+
+ /// Post an event to all listeners
+ virtual bool post(const LLSD& event);
+
+private:
+ /// flush queued events
+ virtual void flush();
+
+private:
+ typedef std::deque<LLSD> EventQueue;
+ EventQueue mEventQueue;
+};
+
+/*****************************************************************************
+* LLReqID
+*****************************************************************************/
+/**
+ * This class helps the implementer of a given event API to honor the
+ * ["reqid"] convention. By this convention, each event API stamps into its
+ * response LLSD a ["reqid"] key whose value echoes the ["reqid"] value, if
+ * any, from the corresponding request.
+ *
+ * This supports an (atypical, but occasionally necessary) use case in which
+ * two or more asynchronous requests are multiplexed onto the same ["reply"]
+ * LLEventPump. Since the response events could arrive in arbitrary order, the
+ * caller must be able to demux them. It does so by matching the ["reqid"]
+ * value in each response with the ["reqid"] value in the corresponding
+ * request.
+ *
+ * It is the caller's responsibility to ensure distinct ["reqid"] values for
+ * that case. Though LLSD::UUID is guaranteed to work, it might be overkill:
+ * the "namespace" of unique ["reqid"] values is simply the set of requests
+ * specifying the same ["reply"] LLEventPump name.
+ *
+ * Making a given event API echo the request's ["reqid"] into the response is
+ * nearly trivial. This helper is mostly for mnemonic purposes, to serve as a
+ * place to put these comments. We hope that each time a coder implements a
+ * new event API based on some existing one, s/he will say, "Huh, what's an
+ * LLReqID?" and look up this material.
+ *
+ * The hardest part about the convention is deciding where to store the
+ * ["reqid"] value. Ironically, LLReqID can't help with that: you must store
+ * an LLReqID instance in whatever storage will persist until the reply is
+ * sent. For example, if the request ultimately ends up using a Responder
+ * subclass, storing an LLReqID instance in the Responder works.
+ *
+ * @note
+ * The @em implementer of an event API must honor the ["reqid"] convention.
+ * However, the @em caller of an event API need only use it if s/he is sharing
+ * the same ["reply"] LLEventPump for two or more asynchronous event API
+ * requests.
+ *
+ * In most cases, it's far easier for the caller to instantiate a local
+ * LLEventStream and pass its name to the event API in question. Then it's
+ * perfectly reasonable not to set a ["reqid"] key in the request, ignoring
+ * the @c isUndefined() ["reqid"] value in the response.
+ */
+class LL_COMMON_API LLReqID
+{
+public:
+ /**
+ * If you have the request in hand at the time you instantiate the
+ * LLReqID, pass that request to extract its ["reqid"].
+ */
+ LLReqID(const LLSD& request):
+ mReqid(request["reqid"])
+ {}
+ /// If you don't yet have the request, use setFrom() later.
+ LLReqID() {}
+
+ /// Extract and store the ["reqid"] value from an incoming request.
+ void setFrom(const LLSD& request)
+ {
+ mReqid = request["reqid"];
+ }
+
+ /// Set ["reqid"] key into a pending response LLSD object.
+ void stamp(LLSD& response) const;
+
+ /// Make a whole new response LLSD object with our ["reqid"].
+ LLSD makeResponse() const
+ {
+ LLSD response;
+ stamp(response);
+ return response;
+ }
+
+ /// Not really sure of a use case for this accessor...
+ LLSD getReqID() const { return mReqid; }
+
+private:
+ LLSD mReqid;
+};
+
+/*****************************************************************************
+* Underpinnings
+*****************************************************************************/
+/**
+ * We originally provided a suite of overloaded
+ * LLEventTrackable::listenTo(LLEventPump&, ...) methods that would call
+ * LLEventPump::listen(...) and then pass the returned LLBoundListener to
+ * LLEventTrackable::track(). This was workable but error-prone: the coder
+ * must remember to call listenTo() rather than the more straightforward
+ * listen() method.
+ *
+ * Now we publish only the single canonical listen() method, so there's a
+ * uniform mechanism. Having a single way to do this is good, in that there's
+ * no question in the coder's mind which of several alternatives to choose.
+ *
+ * To support automatic connection management, we use boost::visit_each
+ * (http://www.boost.org/doc/libs/1_37_0/doc/html/boost/visit_each.html) to
+ * inspect each argument of a boost::bind expression. (Although the visit_each
+ * mechanism was first introduced with the original Boost.Signals library, it
+ * was only later documented.)
+ *
+ * Cases:
+ * * At least one of the function's arguments is a boost::weak_ptr<T>. Pass
+ * the corresponding shared_ptr to slot_type::track(). Ideally that would be
+ * the object whose method we want to call, but in fact we do the same for
+ * any weak_ptr we might find among the bound arguments. If we're passing
+ * our bound method a weak_ptr to some object, wouldn't the destruction of
+ * that object invalidate the call? So we disconnect automatically when any
+ * such object is destroyed. This is the mechanism preferred by boost::
+ * signals2.
+ * * One of the functions's arguments is a boost::shared_ptr<T>. This produces
+ * a compile error: the bound copy of the shared_ptr stored in the
+ * boost_bind object stored in the signal object would make the referenced
+ * T object immortal. We provide a weaken() function. Pass
+ * weaken(your_shared_ptr) instead. (We can inspect, but not modify, the
+ * boost::bind object. Otherwise we'd replace the shared_ptr with weak_ptr
+ * implicitly and just proceed.)
+ * * One of the function's arguments is a plain pointer/reference to an object
+ * derived from boost::enable_shared_from_this. We assume that this object
+ * is managed using boost::shared_ptr, so we implicitly extract a shared_ptr
+ * and track that. (UNDER CONSTRUCTION)
+ * * One of the function's arguments is derived from LLEventTrackable. Pass
+ * the LLBoundListener to its LLEventTrackable::track(). This is vulnerable
+ * to a couple different race conditions, as described in LLEventTrackable
+ * documentation. (NOTE: Now that LLEventTrackable is a typedef for
+ * boost::signals2::trackable, the Signals2 library handles this itself, so
+ * our visitor needs no special logic for this case.)
+ * * Any other argument type is irrelevant to automatic connection management.
+ */
+
+namespace LLEventDetail
+{
+ template <typename F>
+ const F& unwrap(const F& f) { return f; }
+
+ template <typename F>
+ const F& unwrap(const boost::reference_wrapper<F>& f) { return f.get(); }
+
+ // Most of the following is lifted from the Boost.Signals use of
+ // visit_each.
+ template<bool Cond> struct truth {};
+
+ /**
+ * boost::visit_each() Visitor, used on a template argument <tt>const F&
+ * f</tt> as follows (see visit_and_connect()):
+ * @code
+ * LLEventListener listener(f);
+ * Visitor visitor(listener); // bind listener so it can track() shared_ptrs
+ * using boost::visit_each; // allow unqualified visit_each() call for ADL
+ * visit_each(visitor, unwrap(f));
+ * @endcode
+ */
+ class Visitor
+ {
+ public:
+ /**
+ * Visitor binds a reference to LLEventListener so we can track() any
+ * shared_ptrs we find in the argument list.
+ */
+ Visitor(LLEventListener& listener):
+ mListener(listener)
+ {
+ }
+
+ /**
+ * boost::visit_each() calls this method for each component of a
+ * boost::bind() expression.
+ */
+ template <typename T>
+ void operator()(const T& t) const
+ {
+ decode(t, 0);
+ }
+
+ private:
+ // decode() decides between a reference wrapper and anything else
+ // boost::ref() variant
+ template<typename T>
+ void decode(const boost::reference_wrapper<T>& t, int) const
+ {
+// add_if_trackable(t.get_pointer());
+ }
+
+ // decode() anything else
+ template<typename T>
+ void decode(const T& t, long) const
+ {
+ typedef truth<(boost::is_pointer<T>::value)> is_a_pointer;
+ maybe_get_pointer(t, is_a_pointer());
+ }
+
+ // maybe_get_pointer() decides between a pointer and a non-pointer
+ // plain pointer variant
+ template<typename T>
+ void maybe_get_pointer(const T& t, truth<true>) const
+ {
+// add_if_trackable(t);
+ }
+
+ // shared_ptr variant
+ template<typename T>
+ void maybe_get_pointer(const boost::shared_ptr<T>& t, truth<false>) const
+ {
+ // If we have a shared_ptr to this object, it doesn't matter
+ // whether the object is derived from LLEventTrackable, so no
+ // further analysis of T is needed.
+// mListener.track(t);
+
+ // Make this case illegal. Passing a bound shared_ptr to
+ // slot_type::track() is useless, since the bound shared_ptr will
+ // keep the object alive anyway! Force the coder to cast to weak_ptr.
+
+ // Trivial as it is, make the BOOST_STATIC_ASSERT() condition
+ // dependent on template param so the macro is only evaluated if
+ // this method is in fact instantiated, as described here:
+ // http://www.boost.org/doc/libs/1_34_1/doc/html/boost_staticassert.html
+
+ // ATTENTION: Don't bind a shared_ptr<anything> using
+ // LLEventPump::listen(boost::bind()). Doing so captures a copy of
+ // the shared_ptr, making the referenced object effectively
+ // immortal. Use the weaken() function, e.g.:
+ // somepump.listen(boost::bind(...weaken(my_shared_ptr)...));
+ // This lets us automatically disconnect when the referenced
+ // object is destroyed.
+ BOOST_STATIC_ASSERT(sizeof(T) == 0);
+ }
+
+ // weak_ptr variant
+ template<typename T>
+ void maybe_get_pointer(const boost::weak_ptr<T>& t, truth<false>) const
+ {
+ // If we have a weak_ptr to this object, it doesn't matter
+ // whether the object is derived from LLEventTrackable, so no
+ // further analysis of T is needed.
+ mListener.track(t);
+// std::cout << "Found weak_ptr<" << typeid(T).name() << ">!\n";
+ }
+
+#if 0
+ // reference to anything derived from boost::enable_shared_from_this
+ template <typename T>
+ inline void maybe_get_pointer(const boost::enable_shared_from_this<T>& ct,
+ truth<false>) const
+ {
+ // Use the slot_type::track(shared_ptr) mechanism. Cast away
+ // const-ness because (in our code base anyway) it's unusual
+ // to find shared_ptr<const T>.
+ boost::enable_shared_from_this<T>&
+ t(const_cast<boost::enable_shared_from_this<T>&>(ct));
+ std::cout << "Capturing shared_from_this()" << std::endl;
+ boost::shared_ptr<T> sp(t.shared_from_this());
+/*==========================================================================*|
+ std::cout << "Capturing weak_ptr" << std::endl;
+ boost::weak_ptr<T> wp(sp);
+|*==========================================================================*/
+ std::cout << "Tracking shared__ptr" << std::endl;
+ mListener.track(sp);
+ }
+#endif
+
+ // non-pointer variant
+ template<typename T>
+ void maybe_get_pointer(const T& t, truth<false>) const
+ {
+ // Take the address of this object, because the object itself may be
+ // trackable
+// add_if_trackable(boost::addressof(t));
+ }
+
+/*==========================================================================*|
+ // add_if_trackable() adds LLEventTrackable objects to mTrackables
+ inline void add_if_trackable(const LLEventTrackable* t) const
+ {
+ if (t)
+ {
+ }
+ }
+
+ // pointer to anything not an LLEventTrackable subclass
+ inline void add_if_trackable(const void*) const
+ {
+ }
+
+ // pointer to free function
+ // The following construct uses the preprocessor to generate
+ // add_if_trackable() overloads accepting pointer-to-function taking
+ // 0, 1, ..., LLEVENTS_LISTENER_ARITY parameters of arbitrary type.
+#define BOOST_PP_LOCAL_MACRO(n) \
+ template <typename R \
+ BOOST_PP_COMMA_IF(n) \
+ BOOST_PP_ENUM_PARAMS(n, typename T)> \
+ inline void \
+ add_if_trackable(R (*)(BOOST_PP_ENUM_PARAMS(n, T))) const \
+ { \
+ }
+#define BOOST_PP_LOCAL_LIMITS (0, LLEVENTS_LISTENER_ARITY)
+#include BOOST_PP_LOCAL_ITERATE()
+#undef BOOST_PP_LOCAL_MACRO
+#undef BOOST_PP_LOCAL_LIMITS
+|*==========================================================================*/
+
+ /// Bind a reference to the LLEventListener to call its track() method.
+ LLEventListener& mListener;
+ };
+
+ /**
+ * Utility template function to use Visitor appropriately
+ *
+ * @param raw_listener Callable to connect, typically a boost::bind()
+ * expression. This will be visited by Visitor using boost::visit_each().
+ * @param connect_funct Callable that will connect() @a raw_listener to an
+ * LLStandardSignal, returning LLBoundListener.
+ */
+ template <typename LISTENER>
+ LLBoundListener visit_and_connect(const LISTENER& raw_listener,
+ const ConnectFunc& connect_func)
+ {
+ // Capture the listener
+ LLEventListener listener(raw_listener);
+ // Define our Visitor, binding the listener so we can call
+ // listener.track() if we discover any shared_ptr<Foo>.
+ LLEventDetail::Visitor visitor(listener);
+ // Allow unqualified visit_each() call for ADL
+ using boost::visit_each;
+ // Visit each component of a boost::bind() expression. Pass
+ // 'raw_listener', our template argument, rather than 'listener' from
+ // which type details have been erased. unwrap() comes from
+ // Boost.Signals, in case we were passed a boost::ref().
+ visit_each(visitor, LLEventDetail::unwrap(raw_listener));
+ // Make the connection using passed function. At present, wrapping
+ // this functionality into this function is a bit silly: we don't
+ // really need a visit_and_connect() function any more, just a visit()
+ // function. The definition of this function dates from when, after
+ // visit_each(), after establishing the connection, we had to
+ // postprocess the new connection with the visitor object. That's no
+ // longer necessary.
+ return connect_func(listener);
+ }
+} // namespace LLEventDetail
+
+// Somewhat to my surprise, passing boost::bind(...boost::weak_ptr<T>...) to
+// listen() fails in Boost code trying to instantiate LLEventListener (i.e.
+// LLStandardSignal::slot_type) because the boost::get_pointer() utility function isn't
+// specialized for boost::weak_ptr. This remedies that omission.
+namespace boost
+{
+ template <typename T>
+ T* get_pointer(const weak_ptr<T>& ptr) { return shared_ptr<T>(ptr).get(); }
+}
+
+/// Since we forbid use of listen(boost::bind(...shared_ptr<T>...)), provide an
+/// easy way to cast to the corresponding weak_ptr.
+template <typename T>
+boost::weak_ptr<T> weaken(const boost::shared_ptr<T>& ptr)
+{
+ return boost::weak_ptr<T>(ptr);
+}
+
+#endif /* ! defined(LL_LLEVENTS_H) */
diff --git a/indra/llcommon/llfasttimer.h b/indra/llcommon/llfasttimer.h
index 612068b202..0488585fd4 100644
--- a/indra/llcommon/llfasttimer.h
+++ b/indra/llcommon/llfasttimer.h
@@ -1,352 +1,352 @@
-/**
- * @file llfasttimer.h
- * @brief Declaration of a fast timer.
- *
- * $LicenseInfo:firstyear=2004&license=viewergpl$
- *
- * Copyright (c) 2004-2009, Linden Research, Inc.
- *
- * Second Life Viewer Source Code
- * The source code in this file ("Source Code") is provided by Linden Lab
- * to you under the terms of the GNU General Public License, version 2.0
- * ("GPL"), unless you have obtained a separate licensing agreement
- * ("Other License"), formally executed by you and Linden Lab. Terms of
- * the GPL can be found in doc/GPL-license.txt in this distribution, or
- * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
- *
- * There are special exceptions to the terms and conditions of the GPL as
- * it is applied to this Source Code. View the full text of the exception
- * in the file doc/FLOSS-exception.txt in this software distribution, or
- * online at
- * http://secondlifegrid.net/programs/open_source/licensing/flossexception
- *
- * By copying, modifying or distributing this software, you acknowledge
- * that you have read and understood your obligations described above,
- * and agree to abide by those obligations.
- *
- * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
- * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
- * COMPLETENESS OR PERFORMANCE.
- * $/LicenseInfo$
- */
-
-#ifndef LL_FASTTIMER_H
-#define LL_FASTTIMER_H
-
-#include "llinstancetracker.h"
-
-#define FAST_TIMER_ON 1
-
-U64 get_cpu_clock_count();
-
-class LLMutex;
-
-#include <queue>
-#include "llsd.h"
-
-
-class LLFastTimer
-{
-public:
- // stores a "named" timer instance to be reused via multiple LLFastTimer stack instances
- class NamedTimer
- : public LLInstanceTracker<NamedTimer>
- {
- public:
- ~NamedTimer();
-
- enum { HISTORY_NUM = 60 };
-
- const std::string& getName() { return mName; }
- NamedTimer* getParent() { return mParent; }
- void setParent(NamedTimer* parent);
- S32 getDepth();
- std::string getToolTip(S32 history_index = -1);
-
- typedef std::vector<NamedTimer*>::const_iterator child_const_iter;
- child_const_iter beginChildren();
- child_const_iter endChildren();
- std::vector<NamedTimer*>& getChildren();
-
- void setCollapsed(bool collapsed) { mCollapsed = collapsed; }
- bool getCollapsed() { return mCollapsed; }
-
- U64 getCountAverage() { return mCountAverage; }
- U64 getCallAverage() { return mCallAverage; }
-
- U64 getHistoricalCount(S32 history_index = 0);
- U64 getHistoricalCalls(S32 history_index = 0);
-
- static NamedTimer& getRootNamedTimer();
-
- struct FrameState
- {
- FrameState(NamedTimer* timerp);
-
- U64 mSelfTimeCounter;
- U64 mLastStartTime; // most recent time when this timer was started
- U32 mCalls;
- FrameState* mParent; // info for caller timer
- FrameState* mLastCaller; // used to bootstrap tree construction
- NamedTimer* mTimer;
- U16 mActiveCount; // number of timers with this ID active on stack
- bool mMoveUpTree; // needs to be moved up the tree of timers at the end of frame
- };
-
- FrameState& getFrameStateFast() const
- {
- return (*sTimerInfos)[mFrameStateIndex];
- }
-
- S32 getFrameStateIndex() const { return mFrameStateIndex; }
-
- FrameState& getFrameState() const;
-
-
- private:
- friend class LLFastTimer;
- friend class NamedTimerFactory;
-
- //
- // methods
- //
- NamedTimer(const std::string& name);
- // recursive call to gather total time from children
- static void accumulateTimings();
-
- // called once per frame by LLFastTimer
- static void processFrame();
-
- static void buildHierarchy();
- static void resetFrame();
- static void reset();
-
- typedef std::vector<FrameState> info_list_t;
- static info_list_t& getFrameStateList();
- static void createFrameStateList(); // must call before any call to getFrameStateList()
-
- //
- // members
- //
- S32 mFrameStateIndex;
-
- std::string mName;
-
- U64 mTotalTimeCounter;
-
- U64 mCountAverage;
- U64 mCallAverage;
-
- U64* mCountHistory;
- U64* mCallHistory;
-
- // tree structure
- NamedTimer* mParent; // NamedTimer of caller(parent)
- std::vector<NamedTimer*> mChildren;
- bool mCollapsed; // don't show children
- bool mNeedsSorting; // sort children whenever child added
-
- static info_list_t* sTimerInfos;
- };
-
- // used to statically declare a new named timer
- class DeclareTimer
- {
- public:
- DeclareTimer(const std::string& name, bool open);
- DeclareTimer(const std::string& name);
-
- // convertable to NamedTimer::FrameState for convenient usage of LLFastTimer(declared_timer)
- operator NamedTimer::FrameState&() { return mNamedTimer.getFrameStateFast(); }
- private:
- NamedTimer& mNamedTimer;
- };
-
- static DeclareTimer FTM_ARRANGE;
- static DeclareTimer FTM_ATTACHMENT_UPDATE;
- static DeclareTimer FTM_AUDIO_UPDATE;
- static DeclareTimer FTM_AUTO_SELECT;
- static DeclareTimer FTM_AVATAR_UPDATE;
- static DeclareTimer FTM_CLEANUP;
- static DeclareTimer FTM_CLIENT_COPY;
- static DeclareTimer FTM_CREATE_OBJECT;
- static DeclareTimer FTM_CULL;
- static DeclareTimer FTM_CULL_REBOUND;
- static DeclareTimer FTM_FILTER;
- static DeclareTimer FTM_FLEXIBLE_UPDATE;
- static DeclareTimer FTM_FRAME;
- static DeclareTimer FTM_FRUSTUM_CULL;
- static DeclareTimer FTM_GEN_FLEX;
- static DeclareTimer FTM_GEN_TRIANGLES;
- static DeclareTimer FTM_GEN_VOLUME;
- static DeclareTimer FTM_GEO_SKY;
- static DeclareTimer FTM_GEO_UPDATE;
- static DeclareTimer FTM_HUD_EFFECTS;
- static DeclareTimer FTM_HUD_UPDATE;
- static DeclareTimer FTM_IDLE;
- static DeclareTimer FTM_IDLE_CB;
- static DeclareTimer FTM_IDLE_NETWORK;
- static DeclareTimer FTM_IMAGE_CREATE;
- static DeclareTimer FTM_IMAGE_MARK_DIRTY;
- static DeclareTimer FTM_IMAGE_UPDATE;
- static DeclareTimer FTM_INVENTORY;
- static DeclareTimer FTM_JOINT_UPDATE;
- static DeclareTimer FTM_KEYHANDLER;
- static DeclareTimer FTM_LOAD_AVATAR;
- static DeclareTimer FTM_LOD_UPDATE;
- static DeclareTimer FTM_MESSAGES;
- static DeclareTimer FTM_MOUSEHANDLER;
- static DeclareTimer FTM_NETWORK;
- static DeclareTimer FTM_OBJECTLIST_UPDATE;
- static DeclareTimer FTM_OCCLUSION_READBACK;
- static DeclareTimer FTM_OCTREE_BALANCE;
- static DeclareTimer FTM_PICK;
- static DeclareTimer FTM_PIPELINE;
- static DeclareTimer FTM_POOLRENDER;
- static DeclareTimer FTM_POOLS;
- static DeclareTimer FTM_PROCESS_IMAGES;
- static DeclareTimer FTM_PROCESS_MESSAGES;
- static DeclareTimer FTM_PROCESS_OBJECTS;
- static DeclareTimer FTM_PUMP;
- static DeclareTimer FTM_REBUILD_GRASS_VB;
- static DeclareTimer FTM_REBUILD_PARTICLE_VB;
- static DeclareTimer FTM_REBUILD_TERRAIN_VB;
- static DeclareTimer FTM_REBUILD_VBO;
- static DeclareTimer FTM_REBUILD_VOLUME_VB;
- static DeclareTimer FTM_REFRESH;
- static DeclareTimer FTM_REGION_UPDATE;
- static DeclareTimer FTM_RENDER;
- static DeclareTimer FTM_RENDER_ALPHA;
- static DeclareTimer FTM_RENDER_BLOOM;
- static DeclareTimer FTM_RENDER_BLOOM_FBO;
- static DeclareTimer FTM_RENDER_BUMP;
- static DeclareTimer FTM_RENDER_CHARACTERS;
- static DeclareTimer FTM_RENDER_FAKE_VBO_UPDATE;
- static DeclareTimer FTM_RENDER_FONTS;
- static DeclareTimer FTM_RENDER_FULLBRIGHT;
- static DeclareTimer FTM_RENDER_GEOMETRY;
- static DeclareTimer FTM_RENDER_GLOW;
- static DeclareTimer FTM_RENDER_GRASS;
- static DeclareTimer FTM_RENDER_INVISIBLE;
- static DeclareTimer FTM_RENDER_OCCLUSION;
- static DeclareTimer FTM_RENDER_SHINY;
- static DeclareTimer FTM_RENDER_SIMPLE;
- static DeclareTimer FTM_RENDER_TERRAIN;
- static DeclareTimer FTM_RENDER_TREES;
- static DeclareTimer FTM_RENDER_UI;
- static DeclareTimer FTM_RENDER_WATER;
- static DeclareTimer FTM_RENDER_WL_SKY;
- static DeclareTimer FTM_RESET_DRAWORDER;
- static DeclareTimer FTM_SHADOW_ALPHA;
- static DeclareTimer FTM_SHADOW_AVATAR;
- static DeclareTimer FTM_SHADOW_RENDER;
- static DeclareTimer FTM_SHADOW_SIMPLE;
- static DeclareTimer FTM_SHADOW_TERRAIN;
- static DeclareTimer FTM_SHADOW_TREE;
- static DeclareTimer FTM_SIMULATE_PARTICLES;
- static DeclareTimer FTM_SLEEP;
- static DeclareTimer FTM_SORT;
- static DeclareTimer FTM_STATESORT;
- static DeclareTimer FTM_STATESORT_DRAWABLE;
- static DeclareTimer FTM_STATESORT_POSTSORT;
- static DeclareTimer FTM_SWAP;
- static DeclareTimer FTM_TEMP1;
- static DeclareTimer FTM_TEMP2;
- static DeclareTimer FTM_TEMP3;
- static DeclareTimer FTM_TEMP4;
- static DeclareTimer FTM_TEMP5;
- static DeclareTimer FTM_TEMP6;
- static DeclareTimer FTM_TEMP7;
- static DeclareTimer FTM_TEMP8;
- static DeclareTimer FTM_UPDATE_ANIMATION;
- static DeclareTimer FTM_UPDATE_AVATAR;
- static DeclareTimer FTM_UPDATE_CLOUDS;
- static DeclareTimer FTM_UPDATE_GRASS;
- static DeclareTimer FTM_UPDATE_MOVE;
- static DeclareTimer FTM_UPDATE_PARTICLES;
- static DeclareTimer FTM_UPDATE_PRIMITIVES;
- static DeclareTimer FTM_UPDATE_SKY;
- static DeclareTimer FTM_UPDATE_TERRAIN;
- static DeclareTimer FTM_UPDATE_TEXTURES;
- static DeclareTimer FTM_UPDATE_TREE;
- static DeclareTimer FTM_UPDATE_WATER;
- static DeclareTimer FTM_UPDATE_WLPARAM;
- static DeclareTimer FTM_VFILE_WAIT;
- static DeclareTimer FTM_WORLD_UPDATE;
-
-public:
- enum RootTimerMarker { ROOT };
-
- static LLMutex* sLogLock;
- static std::queue<LLSD> sLogQueue;
- static BOOL sLog;
- static BOOL sMetricLog;
-
- LLFastTimer(RootTimerMarker);
-
- LLFastTimer(NamedTimer::FrameState& timer)
- : mFrameState(&timer)
- {
- NamedTimer::FrameState* frame_state = mFrameState;
- frame_state->mLastStartTime = get_cpu_clock_count();
- mStartSelfTime = frame_state->mLastStartTime;
-
- frame_state->mActiveCount++;
- frame_state->mCalls++;
- // keep current parent as long as it is active when we are
- frame_state->mMoveUpTree |= (frame_state->mParent->mActiveCount == 0);
-
- mLastTimer = sCurTimer;
- sCurTimer = this;
- }
-
- ~LLFastTimer()
- {
-#if FAST_TIMER_ON
- NamedTimer::FrameState* frame_state = mFrameState;
- U64 cur_time = get_cpu_clock_count();
- frame_state->mSelfTimeCounter += cur_time - mStartSelfTime;
-
- frame_state->mActiveCount--;
- LLFastTimer* last_timer = mLastTimer;
- sCurTimer = last_timer;
-
- // store last caller to bootstrap tree creation
- frame_state->mLastCaller = last_timer->mFrameState;
-
- // we are only tracking self time, so subtract our total time delta from parents
- U64 total_time = cur_time - frame_state->mLastStartTime;
- last_timer->mStartSelfTime += total_time;
-#endif
- }
-
-
- // call this once a frame to reset timers
- static void nextFrame();
-
- // call this to reset timer hierarchy, averages, etc.
- static void reset();
-
- static U64 countsPerSecond();
- static S32 getLastFrameIndex() { return sLastFrameIndex; }
- static S32 getCurFrameIndex() { return sCurFrameIndex; }
-
- static void writeLog(std::ostream& os);
-
-public:
- static bool sPauseHistory;
- static bool sResetHistory;
-
-private:
- typedef std::vector<LLFastTimer*> timer_stack_t;
- static LLFastTimer* sCurTimer;
- static S32 sCurFrameIndex;
- static S32 sLastFrameIndex;
-
- static F64 sCPUClockFrequency;
- U64 mStartSelfTime; // start time + time of all child timers
- NamedTimer::FrameState* mFrameState;
- LLFastTimer* mLastTimer;
-};
-
-#endif // LL_LLFASTTIMER_H
+/**
+ * @file llfasttimer.h
+ * @brief Declaration of a fast timer.
+ *
+ * $LicenseInfo:firstyear=2004&license=viewergpl$
+ *
+ * Copyright (c) 2004-2009, Linden Research, Inc.
+ *
+ * Second Life Viewer Source Code
+ * The source code in this file ("Source Code") is provided by Linden Lab
+ * to you under the terms of the GNU General Public License, version 2.0
+ * ("GPL"), unless you have obtained a separate licensing agreement
+ * ("Other License"), formally executed by you and Linden Lab. Terms of
+ * the GPL can be found in doc/GPL-license.txt in this distribution, or
+ * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
+ *
+ * There are special exceptions to the terms and conditions of the GPL as
+ * it is applied to this Source Code. View the full text of the exception
+ * in the file doc/FLOSS-exception.txt in this software distribution, or
+ * online at
+ * http://secondlifegrid.net/programs/open_source/licensing/flossexception
+ *
+ * By copying, modifying or distributing this software, you acknowledge
+ * that you have read and understood your obligations described above,
+ * and agree to abide by those obligations.
+ *
+ * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
+ * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
+ * COMPLETENESS OR PERFORMANCE.
+ * $/LicenseInfo$
+ */
+
+#ifndef LL_FASTTIMER_H
+#define LL_FASTTIMER_H
+
+#include "llinstancetracker.h"
+
+#define FAST_TIMER_ON 1
+
+LL_COMMON_API U64 get_cpu_clock_count();
+
+class LLMutex;
+
+#include <queue>
+#include "llsd.h"
+
+
+class LL_COMMON_API LLFastTimer
+{
+public:
+ // stores a "named" timer instance to be reused via multiple LLFastTimer stack instances
+ class LL_COMMON_API NamedTimer
+ : public LLInstanceTracker<NamedTimer>
+ {
+ public:
+ ~NamedTimer();
+
+ enum { HISTORY_NUM = 60 };
+
+ const std::string& getName() { return mName; }
+ NamedTimer* getParent() { return mParent; }
+ void setParent(NamedTimer* parent);
+ S32 getDepth();
+ std::string getToolTip(S32 history_index = -1);
+
+ typedef std::vector<NamedTimer*>::const_iterator child_const_iter;
+ child_const_iter beginChildren();
+ child_const_iter endChildren();
+ std::vector<NamedTimer*>& getChildren();
+
+ void setCollapsed(bool collapsed) { mCollapsed = collapsed; }
+ bool getCollapsed() { return mCollapsed; }
+
+ U64 getCountAverage() { return mCountAverage; }
+ U64 getCallAverage() { return mCallAverage; }
+
+ U64 getHistoricalCount(S32 history_index = 0);
+ U64 getHistoricalCalls(S32 history_index = 0);
+
+ static NamedTimer& getRootNamedTimer();
+
+ struct FrameState
+ {
+ FrameState(NamedTimer* timerp);
+
+ U64 mSelfTimeCounter;
+ U64 mLastStartTime; // most recent time when this timer was started
+ U32 mCalls;
+ FrameState* mParent; // info for caller timer
+ FrameState* mLastCaller; // used to bootstrap tree construction
+ NamedTimer* mTimer;
+ U16 mActiveCount; // number of timers with this ID active on stack
+ bool mMoveUpTree; // needs to be moved up the tree of timers at the end of frame
+ };
+
+ FrameState& getFrameStateFast() const
+ {
+ return (*sTimerInfos)[mFrameStateIndex];
+ }
+
+ S32 getFrameStateIndex() const { return mFrameStateIndex; }
+
+ FrameState& getFrameState() const;
+
+
+ private:
+ friend class LLFastTimer;
+ friend class NamedTimerFactory;
+
+ //
+ // methods
+ //
+ NamedTimer(const std::string& name);
+ // recursive call to gather total time from children
+ static void accumulateTimings();
+
+ // called once per frame by LLFastTimer
+ static void processFrame();
+
+ static void buildHierarchy();
+ static void resetFrame();
+ static void reset();
+
+ typedef std::vector<FrameState> info_list_t;
+ static info_list_t& getFrameStateList();
+ static void createFrameStateList(); // must call before any call to getFrameStateList()
+
+ //
+ // members
+ //
+ S32 mFrameStateIndex;
+
+ std::string mName;
+
+ U64 mTotalTimeCounter;
+
+ U64 mCountAverage;
+ U64 mCallAverage;
+
+ U64* mCountHistory;
+ U64* mCallHistory;
+
+ // tree structure
+ NamedTimer* mParent; // NamedTimer of caller(parent)
+ std::vector<NamedTimer*> mChildren;
+ bool mCollapsed; // don't show children
+ bool mNeedsSorting; // sort children whenever child added
+
+ static info_list_t* sTimerInfos;
+ };
+
+ // used to statically declare a new named timer
+ class LL_COMMON_API DeclareTimer
+ {
+ public:
+ DeclareTimer(const std::string& name, bool open);
+ DeclareTimer(const std::string& name);
+
+ // convertable to NamedTimer::FrameState for convenient usage of LLFastTimer(declared_timer)
+ operator NamedTimer::FrameState&() { return mNamedTimer.getFrameStateFast(); }
+ private:
+ NamedTimer& mNamedTimer;
+ };
+
+ static DeclareTimer FTM_ARRANGE;
+ static DeclareTimer FTM_ATTACHMENT_UPDATE;
+ static DeclareTimer FTM_AUDIO_UPDATE;
+ static DeclareTimer FTM_AUTO_SELECT;
+ static DeclareTimer FTM_AVATAR_UPDATE;
+ static DeclareTimer FTM_CLEANUP;
+ static DeclareTimer FTM_CLIENT_COPY;
+ static DeclareTimer FTM_CREATE_OBJECT;
+ static DeclareTimer FTM_CULL;
+ static DeclareTimer FTM_CULL_REBOUND;
+ static DeclareTimer FTM_FILTER;
+ static DeclareTimer FTM_FLEXIBLE_UPDATE;
+ static DeclareTimer FTM_FRAME;
+ static DeclareTimer FTM_FRUSTUM_CULL;
+ static DeclareTimer FTM_GEN_FLEX;
+ static DeclareTimer FTM_GEN_TRIANGLES;
+ static DeclareTimer FTM_GEN_VOLUME;
+ static DeclareTimer FTM_GEO_SKY;
+ static DeclareTimer FTM_GEO_UPDATE;
+ static DeclareTimer FTM_HUD_EFFECTS;
+ static DeclareTimer FTM_HUD_UPDATE;
+ static DeclareTimer FTM_IDLE;
+ static DeclareTimer FTM_IDLE_CB;
+ static DeclareTimer FTM_IDLE_NETWORK;
+ static DeclareTimer FTM_IMAGE_CREATE;
+ static DeclareTimer FTM_IMAGE_MARK_DIRTY;
+ static DeclareTimer FTM_IMAGE_UPDATE;
+ static DeclareTimer FTM_INVENTORY;
+ static DeclareTimer FTM_JOINT_UPDATE;
+ static DeclareTimer FTM_KEYHANDLER;
+ static DeclareTimer FTM_LOAD_AVATAR;
+ static DeclareTimer FTM_LOD_UPDATE;
+ static DeclareTimer FTM_MESSAGES;
+ static DeclareTimer FTM_MOUSEHANDLER;
+ static DeclareTimer FTM_NETWORK;
+ static DeclareTimer FTM_OBJECTLIST_UPDATE;
+ static DeclareTimer FTM_OCCLUSION_READBACK;
+ static DeclareTimer FTM_OCTREE_BALANCE;
+ static DeclareTimer FTM_PICK;
+ static DeclareTimer FTM_PIPELINE;
+ static DeclareTimer FTM_POOLRENDER;
+ static DeclareTimer FTM_POOLS;
+ static DeclareTimer FTM_PROCESS_IMAGES;
+ static DeclareTimer FTM_PROCESS_MESSAGES;
+ static DeclareTimer FTM_PROCESS_OBJECTS;
+ static DeclareTimer FTM_PUMP;
+ static DeclareTimer FTM_REBUILD_GRASS_VB;
+ static DeclareTimer FTM_REBUILD_PARTICLE_VB;
+ static DeclareTimer FTM_REBUILD_TERRAIN_VB;
+ static DeclareTimer FTM_REBUILD_VBO;
+ static DeclareTimer FTM_REBUILD_VOLUME_VB;
+ static DeclareTimer FTM_REFRESH;
+ static DeclareTimer FTM_REGION_UPDATE;
+ static DeclareTimer FTM_RENDER;
+ static DeclareTimer FTM_RENDER_ALPHA;
+ static DeclareTimer FTM_RENDER_BLOOM;
+ static DeclareTimer FTM_RENDER_BLOOM_FBO;
+ static DeclareTimer FTM_RENDER_BUMP;
+ static DeclareTimer FTM_RENDER_CHARACTERS;
+ static DeclareTimer FTM_RENDER_FAKE_VBO_UPDATE;
+ static DeclareTimer FTM_RENDER_FONTS;
+ static DeclareTimer FTM_RENDER_FULLBRIGHT;
+ static DeclareTimer FTM_RENDER_GEOMETRY;
+ static DeclareTimer FTM_RENDER_GLOW;
+ static DeclareTimer FTM_RENDER_GRASS;
+ static DeclareTimer FTM_RENDER_INVISIBLE;
+ static DeclareTimer FTM_RENDER_OCCLUSION;
+ static DeclareTimer FTM_RENDER_SHINY;
+ static DeclareTimer FTM_RENDER_SIMPLE;
+ static DeclareTimer FTM_RENDER_TERRAIN;
+ static DeclareTimer FTM_RENDER_TREES;
+ static DeclareTimer FTM_RENDER_UI;
+ static DeclareTimer FTM_RENDER_WATER;
+ static DeclareTimer FTM_RENDER_WL_SKY;
+ static DeclareTimer FTM_RESET_DRAWORDER;
+ static DeclareTimer FTM_SHADOW_ALPHA;
+ static DeclareTimer FTM_SHADOW_AVATAR;
+ static DeclareTimer FTM_SHADOW_RENDER;
+ static DeclareTimer FTM_SHADOW_SIMPLE;
+ static DeclareTimer FTM_SHADOW_TERRAIN;
+ static DeclareTimer FTM_SHADOW_TREE;
+ static DeclareTimer FTM_SIMULATE_PARTICLES;
+ static DeclareTimer FTM_SLEEP;
+ static DeclareTimer FTM_SORT;
+ static DeclareTimer FTM_STATESORT;
+ static DeclareTimer FTM_STATESORT_DRAWABLE;
+ static DeclareTimer FTM_STATESORT_POSTSORT;
+ static DeclareTimer FTM_SWAP;
+ static DeclareTimer FTM_TEMP1;
+ static DeclareTimer FTM_TEMP2;
+ static DeclareTimer FTM_TEMP3;
+ static DeclareTimer FTM_TEMP4;
+ static DeclareTimer FTM_TEMP5;
+ static DeclareTimer FTM_TEMP6;
+ static DeclareTimer FTM_TEMP7;
+ static DeclareTimer FTM_TEMP8;
+ static DeclareTimer FTM_UPDATE_ANIMATION;
+ static DeclareTimer FTM_UPDATE_AVATAR;
+ static DeclareTimer FTM_UPDATE_CLOUDS;
+ static DeclareTimer FTM_UPDATE_GRASS;
+ static DeclareTimer FTM_UPDATE_MOVE;
+ static DeclareTimer FTM_UPDATE_PARTICLES;
+ static DeclareTimer FTM_UPDATE_PRIMITIVES;
+ static DeclareTimer FTM_UPDATE_SKY;
+ static DeclareTimer FTM_UPDATE_TERRAIN;
+ static DeclareTimer FTM_UPDATE_TEXTURES;
+ static DeclareTimer FTM_UPDATE_TREE;
+ static DeclareTimer FTM_UPDATE_WATER;
+ static DeclareTimer FTM_UPDATE_WLPARAM;
+ static DeclareTimer FTM_VFILE_WAIT;
+ static DeclareTimer FTM_WORLD_UPDATE;
+
+public:
+ enum RootTimerMarker { ROOT };
+
+ static LLMutex* sLogLock;
+ static std::queue<LLSD> sLogQueue;
+ static BOOL sLog;
+ static BOOL sMetricLog;
+
+ LLFastTimer(RootTimerMarker);
+
+ LLFastTimer(NamedTimer::FrameState& timer)
+ : mFrameState(&timer)
+ {
+ NamedTimer::FrameState* frame_state = mFrameState;
+ frame_state->mLastStartTime = get_cpu_clock_count();
+ mStartSelfTime = frame_state->mLastStartTime;
+
+ frame_state->mActiveCount++;
+ frame_state->mCalls++;
+ // keep current parent as long as it is active when we are
+ frame_state->mMoveUpTree |= (frame_state->mParent->mActiveCount == 0);
+
+ mLastTimer = sCurTimer;
+ sCurTimer = this;
+ }
+
+ ~LLFastTimer()
+ {
+#if FAST_TIMER_ON
+ NamedTimer::FrameState* frame_state = mFrameState;
+ U64 cur_time = get_cpu_clock_count();
+ frame_state->mSelfTimeCounter += cur_time - mStartSelfTime;
+
+ frame_state->mActiveCount--;
+ LLFastTimer* last_timer = mLastTimer;
+ sCurTimer = last_timer;
+
+ // store last caller to bootstrap tree creation
+ frame_state->mLastCaller = last_timer->mFrameState;
+
+ // we are only tracking self time, so subtract our total time delta from parents
+ U64 total_time = cur_time - frame_state->mLastStartTime;
+ last_timer->mStartSelfTime += total_time;
+#endif
+ }
+
+
+ // call this once a frame to reset timers
+ static void nextFrame();
+
+ // call this to reset timer hierarchy, averages, etc.
+ static void reset();
+
+ static U64 countsPerSecond();
+ static S32 getLastFrameIndex() { return sLastFrameIndex; }
+ static S32 getCurFrameIndex() { return sCurFrameIndex; }
+
+ static void writeLog(std::ostream& os);
+
+public:
+ static bool sPauseHistory;
+ static bool sResetHistory;
+
+private:
+ typedef std::vector<LLFastTimer*> timer_stack_t;
+ static LLFastTimer* sCurTimer;
+ static S32 sCurFrameIndex;
+ static S32 sLastFrameIndex;
+
+ static F64 sCPUClockFrequency;
+ U64 mStartSelfTime; // start time + time of all child timers
+ NamedTimer::FrameState* mFrameState;
+ LLFastTimer* mLastTimer;
+};
+
+#endif // LL_LLFASTTIMER_H
diff --git a/indra/llcommon/llmemory.h b/indra/llcommon/llmemory.h
index f41da37ba6..09f19532b7 100644
--- a/indra/llcommon/llmemory.h
+++ b/indra/llcommon/llmemory.h
@@ -1,65 +1,65 @@
-/**
- * @file llmemory.h
- * @brief Memory allocation/deallocation header-stuff goes here.
- *
- * $LicenseInfo:firstyear=2002&license=viewergpl$
- *
- * Copyright (c) 2002-2009, Linden Research, Inc.
- *
- * Second Life Viewer Source Code
- * The source code in this file ("Source Code") is provided by Linden Lab
- * to you under the terms of the GNU General Public License, version 2.0
- * ("GPL"), unless you have obtained a separate licensing agreement
- * ("Other License"), formally executed by you and Linden Lab. Terms of
- * the GPL can be found in doc/GPL-license.txt in this distribution, or
- * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
- *
- * There are special exceptions to the terms and conditions of the GPL as
- * it is applied to this Source Code. View the full text of the exception
- * in the file doc/FLOSS-exception.txt in this software distribution, or
- * online at
- * http://secondlifegrid.net/programs/open_source/licensing/flossexception
- *
- * By copying, modifying or distributing this software, you acknowledge
- * that you have read and understood your obligations described above,
- * and agree to abide by those obligations.
- *
- * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
- * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
- * COMPLETENESS OR PERFORMANCE.
- * $/LicenseInfo$
- */
-#ifndef LLMEMORY_H
-#define LLMEMORY_H
-
-
-
-extern S32 gTotalDAlloc;
-extern S32 gTotalDAUse;
-extern S32 gDACount;
-
-extern void* ll_allocate (size_t size);
-extern void ll_release (void *p);
-
-class LLMemory
-{
-public:
- static void initClass();
- static void cleanupClass();
- static void freeReserve();
- // Return the resident set size of the current process, in bytes.
- // Return value is zero if not known.
- static U64 getCurrentRSS();
-private:
- static char* reserveMem;
-};
-
-// LLRefCount moved to llrefcount.h
-
-// LLPointer moved to llpointer.h
-
-// LLSafeHandle moved to llsafehandle.h
-
-// LLSingleton moved to llsingleton.h
-
-#endif
+/**
+ * @file llmemory.h
+ * @brief Memory allocation/deallocation header-stuff goes here.
+ *
+ * $LicenseInfo:firstyear=2002&license=viewergpl$
+ *
+ * Copyright (c) 2002-2009, Linden Research, Inc.
+ *
+ * Second Life Viewer Source Code
+ * The source code in this file ("Source Code") is provided by Linden Lab
+ * to you under the terms of the GNU General Public License, version 2.0
+ * ("GPL"), unless you have obtained a separate licensing agreement
+ * ("Other License"), formally executed by you and Linden Lab. Terms of
+ * the GPL can be found in doc/GPL-license.txt in this distribution, or
+ * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
+ *
+ * There are special exceptions to the terms and conditions of the GPL as
+ * it is applied to this Source Code. View the full text of the exception
+ * in the file doc/FLOSS-exception.txt in this software distribution, or
+ * online at
+ * http://secondlifegrid.net/programs/open_source/licensing/flossexception
+ *
+ * By copying, modifying or distributing this software, you acknowledge
+ * that you have read and understood your obligations described above,
+ * and agree to abide by those obligations.
+ *
+ * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
+ * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
+ * COMPLETENESS OR PERFORMANCE.
+ * $/LicenseInfo$
+ */
+#ifndef LLMEMORY_H
+#define LLMEMORY_H
+
+
+
+extern S32 gTotalDAlloc;
+extern S32 gTotalDAUse;
+extern S32 gDACount;
+
+extern void* ll_allocate (size_t size);
+extern void ll_release (void *p);
+
+class LL_COMMON_API LLMemory
+{
+public:
+ static void initClass();
+ static void cleanupClass();
+ static void freeReserve();
+ // Return the resident set size of the current process, in bytes.
+ // Return value is zero if not known.
+ static U64 getCurrentRSS();
+private:
+ static char* reserveMem;
+};
+
+// LLRefCount moved to llrefcount.h
+
+// LLPointer moved to llpointer.h
+
+// LLSafeHandle moved to llsafehandle.h
+
+// LLSingleton moved to llsingleton.h
+
+#endif
diff --git a/indra/llcommon/llmemtype.h b/indra/llcommon/llmemtype.h
index 12310fcdb4..5952a3a7c5 100644
--- a/indra/llcommon/llmemtype.h
+++ b/indra/llcommon/llmemtype.h
@@ -1,248 +1,248 @@
-/**
- * @file llmemtype.h
- * @brief Runtime memory usage debugging utilities.
- *
- * $LicenseInfo:firstyear=2005&license=viewergpl$
- *
- * Copyright (c) 2005-2009, Linden Research, Inc.
- *
- * Second Life Viewer Source Code
- * The source code in this file ("Source Code") is provided by Linden Lab
- * to you under the terms of the GNU General Public License, version 2.0
- * ("GPL"), unless you have obtained a separate licensing agreement
- * ("Other License"), formally executed by you and Linden Lab. Terms of
- * the GPL can be found in doc/GPL-license.txt in this distribution, or
- * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
- *
- * There are special exceptions to the terms and conditions of the GPL as
- * it is applied to this Source Code. View the full text of the exception
- * in the file doc/FLOSS-exception.txt in this software distribution, or
- * online at
- * http://secondlifegrid.net/programs/open_source/licensing/flossexception
- *
- * By copying, modifying or distributing this software, you acknowledge
- * that you have read and understood your obligations described above,
- * and agree to abide by those obligations.
- *
- * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
- * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
- * COMPLETENESS OR PERFORMANCE.
- * $/LicenseInfo$
- */
-
-#ifndef LL_MEMTYPE_H
-#define LL_MEMTYPE_H
-
-//----------------------------------------------------------------------------
-//----------------------------------------------------------------------------
-
-//----------------------------------------------------------------------------
-
-#include "linden_common.h"
-//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
-// WARNING: Never commit with MEM_TRACK_MEM == 1
-//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
-#define MEM_TRACK_MEM (0 && LL_WINDOWS)
-
-#include <vector>
-
-#define MEM_TYPE_NEW(T)
-
-class LLMemType
-{
-public:
-
- // class we'll initialize all instances of as
- // static members of MemType. Then use
- // to construct any new mem type.
- class DeclareMemType
- {
- public:
- DeclareMemType(char const * st);
- ~DeclareMemType();
-
- S32 mID;
- char const * mName;
-
- // array so we can map an index ID to Name
- static std::vector<char const *> mNameList;
- };
-
- LLMemType(DeclareMemType& dt);
- ~LLMemType();
-
- static char const * getNameFromID(S32 id);
-
- static DeclareMemType MTYPE_INIT;
- static DeclareMemType MTYPE_STARTUP;
- static DeclareMemType MTYPE_MAIN;
- static DeclareMemType MTYPE_FRAME;
-
- static DeclareMemType MTYPE_GATHER_INPUT;
- static DeclareMemType MTYPE_JOY_KEY;
-
- static DeclareMemType MTYPE_IDLE;
- static DeclareMemType MTYPE_IDLE_PUMP;
- static DeclareMemType MTYPE_IDLE_NETWORK;
- static DeclareMemType MTYPE_IDLE_UPDATE_REGIONS;
- static DeclareMemType MTYPE_IDLE_UPDATE_VIEWER_REGION;
- static DeclareMemType MTYPE_IDLE_UPDATE_SURFACE;
- static DeclareMemType MTYPE_IDLE_UPDATE_PARCEL_OVERLAY;
- static DeclareMemType MTYPE_IDLE_AUDIO;
-
- static DeclareMemType MTYPE_CACHE_PROCESS_PENDING;
- static DeclareMemType MTYPE_CACHE_PROCESS_PENDING_ASKS;
- static DeclareMemType MTYPE_CACHE_PROCESS_PENDING_REPLIES;
-
- static DeclareMemType MTYPE_MESSAGE_CHECK_ALL;
- static DeclareMemType MTYPE_MESSAGE_PROCESS_ACKS;
-
- static DeclareMemType MTYPE_RENDER;
- static DeclareMemType MTYPE_SLEEP;
-
- static DeclareMemType MTYPE_NETWORK;
- static DeclareMemType MTYPE_PHYSICS;
- static DeclareMemType MTYPE_INTERESTLIST;
-
- static DeclareMemType MTYPE_IMAGEBASE;
- static DeclareMemType MTYPE_IMAGERAW;
- static DeclareMemType MTYPE_IMAGEFORMATTED;
-
- static DeclareMemType MTYPE_APPFMTIMAGE;
- static DeclareMemType MTYPE_APPRAWIMAGE;
- static DeclareMemType MTYPE_APPAUXRAWIMAGE;
-
- static DeclareMemType MTYPE_DRAWABLE;
-
- static DeclareMemType MTYPE_OBJECT;
- static DeclareMemType MTYPE_OBJECT_PROCESS_UPDATE;
- static DeclareMemType MTYPE_OBJECT_PROCESS_UPDATE_CORE;
-
- static DeclareMemType MTYPE_DISPLAY;
- static DeclareMemType MTYPE_DISPLAY_UPDATE;
- static DeclareMemType MTYPE_DISPLAY_UPDATE_CAMERA;
- static DeclareMemType MTYPE_DISPLAY_UPDATE_GEOM;
- static DeclareMemType MTYPE_DISPLAY_SWAP;
- static DeclareMemType MTYPE_DISPLAY_UPDATE_HUD;
- static DeclareMemType MTYPE_DISPLAY_GEN_REFLECTION;
- static DeclareMemType MTYPE_DISPLAY_IMAGE_UPDATE;
- static DeclareMemType MTYPE_DISPLAY_STATE_SORT;
- static DeclareMemType MTYPE_DISPLAY_SKY;
- static DeclareMemType MTYPE_DISPLAY_RENDER_GEOM;
- static DeclareMemType MTYPE_DISPLAY_RENDER_FLUSH;
- static DeclareMemType MTYPE_DISPLAY_RENDER_UI;
- static DeclareMemType MTYPE_DISPLAY_RENDER_ATTACHMENTS;
-
- static DeclareMemType MTYPE_VERTEX_DATA;
- static DeclareMemType MTYPE_VERTEX_CONSTRUCTOR;
- static DeclareMemType MTYPE_VERTEX_DESTRUCTOR;
- static DeclareMemType MTYPE_VERTEX_CREATE_VERTICES;
- static DeclareMemType MTYPE_VERTEX_CREATE_INDICES;
- static DeclareMemType MTYPE_VERTEX_DESTROY_BUFFER;
- static DeclareMemType MTYPE_VERTEX_DESTROY_INDICES;
- static DeclareMemType MTYPE_VERTEX_UPDATE_VERTS;
- static DeclareMemType MTYPE_VERTEX_UPDATE_INDICES;
- static DeclareMemType MTYPE_VERTEX_ALLOCATE_BUFFER;
- static DeclareMemType MTYPE_VERTEX_RESIZE_BUFFER;
- static DeclareMemType MTYPE_VERTEX_MAP_BUFFER;
- static DeclareMemType MTYPE_VERTEX_MAP_BUFFER_VERTICES;
- static DeclareMemType MTYPE_VERTEX_MAP_BUFFER_INDICES;
- static DeclareMemType MTYPE_VERTEX_UNMAP_BUFFER;
- static DeclareMemType MTYPE_VERTEX_SET_STRIDE;
- static DeclareMemType MTYPE_VERTEX_SET_BUFFER;
- static DeclareMemType MTYPE_VERTEX_SETUP_VERTEX_BUFFER;
- static DeclareMemType MTYPE_VERTEX_CLEANUP_CLASS;
-
- static DeclareMemType MTYPE_SPACE_PARTITION;
-
- static DeclareMemType MTYPE_PIPELINE;
- static DeclareMemType MTYPE_PIPELINE_INIT;
- static DeclareMemType MTYPE_PIPELINE_CREATE_BUFFERS;
- static DeclareMemType MTYPE_PIPELINE_RESTORE_GL;
- static DeclareMemType MTYPE_PIPELINE_UNLOAD_SHADERS;
- static DeclareMemType MTYPE_PIPELINE_LIGHTING_DETAIL;
- static DeclareMemType MTYPE_PIPELINE_GET_POOL_TYPE;
- static DeclareMemType MTYPE_PIPELINE_ADD_POOL;
- static DeclareMemType MTYPE_PIPELINE_ALLOCATE_DRAWABLE;
- static DeclareMemType MTYPE_PIPELINE_ADD_OBJECT;
- static DeclareMemType MTYPE_PIPELINE_CREATE_OBJECTS;
- static DeclareMemType MTYPE_PIPELINE_UPDATE_MOVE;
- static DeclareMemType MTYPE_PIPELINE_UPDATE_GEOM;
- static DeclareMemType MTYPE_PIPELINE_MARK_VISIBLE;
- static DeclareMemType MTYPE_PIPELINE_MARK_MOVED;
- static DeclareMemType MTYPE_PIPELINE_MARK_SHIFT;
- static DeclareMemType MTYPE_PIPELINE_SHIFT_OBJECTS;
- static DeclareMemType MTYPE_PIPELINE_MARK_TEXTURED;
- static DeclareMemType MTYPE_PIPELINE_MARK_REBUILD;
- static DeclareMemType MTYPE_PIPELINE_UPDATE_CULL;
- static DeclareMemType MTYPE_PIPELINE_STATE_SORT;
- static DeclareMemType MTYPE_PIPELINE_POST_SORT;
-
- static DeclareMemType MTYPE_PIPELINE_RENDER_HUD_ELS;
- static DeclareMemType MTYPE_PIPELINE_RENDER_HL;
- static DeclareMemType MTYPE_PIPELINE_RENDER_GEOM;
- static DeclareMemType MTYPE_PIPELINE_RENDER_GEOM_DEFFERRED;
- static DeclareMemType MTYPE_PIPELINE_RENDER_GEOM_POST_DEF;
- static DeclareMemType MTYPE_PIPELINE_RENDER_GEOM_SHADOW;
- static DeclareMemType MTYPE_PIPELINE_RENDER_SELECT;
- static DeclareMemType MTYPE_PIPELINE_REBUILD_POOLS;
- static DeclareMemType MTYPE_PIPELINE_QUICK_LOOKUP;
- static DeclareMemType MTYPE_PIPELINE_RENDER_OBJECTS;
- static DeclareMemType MTYPE_PIPELINE_GENERATE_IMPOSTOR;
- static DeclareMemType MTYPE_PIPELINE_RENDER_BLOOM;
-
- static DeclareMemType MTYPE_UPKEEP_POOLS;
-
- static DeclareMemType MTYPE_AVATAR;
- static DeclareMemType MTYPE_AVATAR_MESH;
- static DeclareMemType MTYPE_PARTICLES;
- static DeclareMemType MTYPE_REGIONS;
-
- static DeclareMemType MTYPE_INVENTORY;
- static DeclareMemType MTYPE_INVENTORY_DRAW;
- static DeclareMemType MTYPE_INVENTORY_BUILD_NEW_VIEWS;
- static DeclareMemType MTYPE_INVENTORY_DO_FOLDER;
- static DeclareMemType MTYPE_INVENTORY_POST_BUILD;
- static DeclareMemType MTYPE_INVENTORY_FROM_XML;
- static DeclareMemType MTYPE_INVENTORY_CREATE_NEW_ITEM;
- static DeclareMemType MTYPE_INVENTORY_VIEW_INIT;
- static DeclareMemType MTYPE_INVENTORY_VIEW_SHOW;
- static DeclareMemType MTYPE_INVENTORY_VIEW_TOGGLE;
-
- static DeclareMemType MTYPE_ANIMATION;
- static DeclareMemType MTYPE_VOLUME;
- static DeclareMemType MTYPE_PRIMITIVE;
-
- static DeclareMemType MTYPE_SCRIPT;
- static DeclareMemType MTYPE_SCRIPT_RUN;
- static DeclareMemType MTYPE_SCRIPT_BYTECODE;
-
- static DeclareMemType MTYPE_IO_PUMP;
- static DeclareMemType MTYPE_IO_TCP;
- static DeclareMemType MTYPE_IO_BUFFER;
- static DeclareMemType MTYPE_IO_HTTP_SERVER;
- static DeclareMemType MTYPE_IO_SD_SERVER;
- static DeclareMemType MTYPE_IO_SD_CLIENT;
- static DeclareMemType MTYPE_IO_URL_REQUEST;
-
- static DeclareMemType MTYPE_DIRECTX_INIT;
-
- static DeclareMemType MTYPE_TEMP1;
- static DeclareMemType MTYPE_TEMP2;
- static DeclareMemType MTYPE_TEMP3;
- static DeclareMemType MTYPE_TEMP4;
- static DeclareMemType MTYPE_TEMP5;
- static DeclareMemType MTYPE_TEMP6;
- static DeclareMemType MTYPE_TEMP7;
- static DeclareMemType MTYPE_TEMP8;
- static DeclareMemType MTYPE_TEMP9;
-
- static DeclareMemType MTYPE_OTHER; // Special; used by display code
-
- S32 mTypeIndex;
-};
-
-//----------------------------------------------------------------------------
-
-#endif
-
+/**
+ * @file llmemtype.h
+ * @brief Runtime memory usage debugging utilities.
+ *
+ * $LicenseInfo:firstyear=2005&license=viewergpl$
+ *
+ * Copyright (c) 2005-2009, Linden Research, Inc.
+ *
+ * Second Life Viewer Source Code
+ * The source code in this file ("Source Code") is provided by Linden Lab
+ * to you under the terms of the GNU General Public License, version 2.0
+ * ("GPL"), unless you have obtained a separate licensing agreement
+ * ("Other License"), formally executed by you and Linden Lab. Terms of
+ * the GPL can be found in doc/GPL-license.txt in this distribution, or
+ * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
+ *
+ * There are special exceptions to the terms and conditions of the GPL as
+ * it is applied to this Source Code. View the full text of the exception
+ * in the file doc/FLOSS-exception.txt in this software distribution, or
+ * online at
+ * http://secondlifegrid.net/programs/open_source/licensing/flossexception
+ *
+ * By copying, modifying or distributing this software, you acknowledge
+ * that you have read and understood your obligations described above,
+ * and agree to abide by those obligations.
+ *
+ * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
+ * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
+ * COMPLETENESS OR PERFORMANCE.
+ * $/LicenseInfo$
+ */
+
+#ifndef LL_MEMTYPE_H
+#define LL_MEMTYPE_H
+
+//----------------------------------------------------------------------------
+//----------------------------------------------------------------------------
+
+//----------------------------------------------------------------------------
+
+#include "linden_common.h"
+//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+// WARNING: Never commit with MEM_TRACK_MEM == 1
+//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+#define MEM_TRACK_MEM (0 && LL_WINDOWS)
+
+#include <vector>
+
+#define MEM_TYPE_NEW(T)
+
+class LL_COMMON_API LLMemType
+{
+public:
+
+ // class we'll initialize all instances of as
+ // static members of MemType. Then use
+ // to construct any new mem type.
+ class LL_COMMON_API DeclareMemType
+ {
+ public:
+ DeclareMemType(char const * st);
+ ~DeclareMemType();
+
+ S32 mID;
+ char const * mName;
+
+ // array so we can map an index ID to Name
+ static std::vector<char const *> mNameList;
+ };
+
+ LLMemType(DeclareMemType& dt);
+ ~LLMemType();
+
+ static char const * getNameFromID(S32 id);
+
+ static DeclareMemType MTYPE_INIT;
+ static DeclareMemType MTYPE_STARTUP;
+ static DeclareMemType MTYPE_MAIN;
+ static DeclareMemType MTYPE_FRAME;
+
+ static DeclareMemType MTYPE_GATHER_INPUT;
+ static DeclareMemType MTYPE_JOY_KEY;
+
+ static DeclareMemType MTYPE_IDLE;
+ static DeclareMemType MTYPE_IDLE_PUMP;
+ static DeclareMemType MTYPE_IDLE_NETWORK;
+ static DeclareMemType MTYPE_IDLE_UPDATE_REGIONS;
+ static DeclareMemType MTYPE_IDLE_UPDATE_VIEWER_REGION;
+ static DeclareMemType MTYPE_IDLE_UPDATE_SURFACE;
+ static DeclareMemType MTYPE_IDLE_UPDATE_PARCEL_OVERLAY;
+ static DeclareMemType MTYPE_IDLE_AUDIO;
+
+ static DeclareMemType MTYPE_CACHE_PROCESS_PENDING;
+ static DeclareMemType MTYPE_CACHE_PROCESS_PENDING_ASKS;
+ static DeclareMemType MTYPE_CACHE_PROCESS_PENDING_REPLIES;
+
+ static DeclareMemType MTYPE_MESSAGE_CHECK_ALL;
+ static DeclareMemType MTYPE_MESSAGE_PROCESS_ACKS;
+
+ static DeclareMemType MTYPE_RENDER;
+ static DeclareMemType MTYPE_SLEEP;
+
+ static DeclareMemType MTYPE_NETWORK;
+ static DeclareMemType MTYPE_PHYSICS;
+ static DeclareMemType MTYPE_INTERESTLIST;
+
+ static DeclareMemType MTYPE_IMAGEBASE;
+ static DeclareMemType MTYPE_IMAGERAW;
+ static DeclareMemType MTYPE_IMAGEFORMATTED;
+
+ static DeclareMemType MTYPE_APPFMTIMAGE;
+ static DeclareMemType MTYPE_APPRAWIMAGE;
+ static DeclareMemType MTYPE_APPAUXRAWIMAGE;
+
+ static DeclareMemType MTYPE_DRAWABLE;
+
+ static DeclareMemType MTYPE_OBJECT;
+ static DeclareMemType MTYPE_OBJECT_PROCESS_UPDATE;
+ static DeclareMemType MTYPE_OBJECT_PROCESS_UPDATE_CORE;
+
+ static DeclareMemType MTYPE_DISPLAY;
+ static DeclareMemType MTYPE_DISPLAY_UPDATE;
+ static DeclareMemType MTYPE_DISPLAY_UPDATE_CAMERA;
+ static DeclareMemType MTYPE_DISPLAY_UPDATE_GEOM;
+ static DeclareMemType MTYPE_DISPLAY_SWAP;
+ static DeclareMemType MTYPE_DISPLAY_UPDATE_HUD;
+ static DeclareMemType MTYPE_DISPLAY_GEN_REFLECTION;
+ static DeclareMemType MTYPE_DISPLAY_IMAGE_UPDATE;
+ static DeclareMemType MTYPE_DISPLAY_STATE_SORT;
+ static DeclareMemType MTYPE_DISPLAY_SKY;
+ static DeclareMemType MTYPE_DISPLAY_RENDER_GEOM;
+ static DeclareMemType MTYPE_DISPLAY_RENDER_FLUSH;
+ static DeclareMemType MTYPE_DISPLAY_RENDER_UI;
+ static DeclareMemType MTYPE_DISPLAY_RENDER_ATTACHMENTS;
+
+ static DeclareMemType MTYPE_VERTEX_DATA;
+ static DeclareMemType MTYPE_VERTEX_CONSTRUCTOR;
+ static DeclareMemType MTYPE_VERTEX_DESTRUCTOR;
+ static DeclareMemType MTYPE_VERTEX_CREATE_VERTICES;
+ static DeclareMemType MTYPE_VERTEX_CREATE_INDICES;
+ static DeclareMemType MTYPE_VERTEX_DESTROY_BUFFER;
+ static DeclareMemType MTYPE_VERTEX_DESTROY_INDICES;
+ static DeclareMemType MTYPE_VERTEX_UPDATE_VERTS;
+ static DeclareMemType MTYPE_VERTEX_UPDATE_INDICES;
+ static DeclareMemType MTYPE_VERTEX_ALLOCATE_BUFFER;
+ static DeclareMemType MTYPE_VERTEX_RESIZE_BUFFER;
+ static DeclareMemType MTYPE_VERTEX_MAP_BUFFER;
+ static DeclareMemType MTYPE_VERTEX_MAP_BUFFER_VERTICES;
+ static DeclareMemType MTYPE_VERTEX_MAP_BUFFER_INDICES;
+ static DeclareMemType MTYPE_VERTEX_UNMAP_BUFFER;
+ static DeclareMemType MTYPE_VERTEX_SET_STRIDE;
+ static DeclareMemType MTYPE_VERTEX_SET_BUFFER;
+ static DeclareMemType MTYPE_VERTEX_SETUP_VERTEX_BUFFER;
+ static DeclareMemType MTYPE_VERTEX_CLEANUP_CLASS;
+
+ static DeclareMemType MTYPE_SPACE_PARTITION;
+
+ static DeclareMemType MTYPE_PIPELINE;
+ static DeclareMemType MTYPE_PIPELINE_INIT;
+ static DeclareMemType MTYPE_PIPELINE_CREATE_BUFFERS;
+ static DeclareMemType MTYPE_PIPELINE_RESTORE_GL;
+ static DeclareMemType MTYPE_PIPELINE_UNLOAD_SHADERS;
+ static DeclareMemType MTYPE_PIPELINE_LIGHTING_DETAIL;
+ static DeclareMemType MTYPE_PIPELINE_GET_POOL_TYPE;
+ static DeclareMemType MTYPE_PIPELINE_ADD_POOL;
+ static DeclareMemType MTYPE_PIPELINE_ALLOCATE_DRAWABLE;
+ static DeclareMemType MTYPE_PIPELINE_ADD_OBJECT;
+ static DeclareMemType MTYPE_PIPELINE_CREATE_OBJECTS;
+ static DeclareMemType MTYPE_PIPELINE_UPDATE_MOVE;
+ static DeclareMemType MTYPE_PIPELINE_UPDATE_GEOM;
+ static DeclareMemType MTYPE_PIPELINE_MARK_VISIBLE;
+ static DeclareMemType MTYPE_PIPELINE_MARK_MOVED;
+ static DeclareMemType MTYPE_PIPELINE_MARK_SHIFT;
+ static DeclareMemType MTYPE_PIPELINE_SHIFT_OBJECTS;
+ static DeclareMemType MTYPE_PIPELINE_MARK_TEXTURED;
+ static DeclareMemType MTYPE_PIPELINE_MARK_REBUILD;
+ static DeclareMemType MTYPE_PIPELINE_UPDATE_CULL;
+ static DeclareMemType MTYPE_PIPELINE_STATE_SORT;
+ static DeclareMemType MTYPE_PIPELINE_POST_SORT;
+
+ static DeclareMemType MTYPE_PIPELINE_RENDER_HUD_ELS;
+ static DeclareMemType MTYPE_PIPELINE_RENDER_HL;
+ static DeclareMemType MTYPE_PIPELINE_RENDER_GEOM;
+ static DeclareMemType MTYPE_PIPELINE_RENDER_GEOM_DEFFERRED;
+ static DeclareMemType MTYPE_PIPELINE_RENDER_GEOM_POST_DEF;
+ static DeclareMemType MTYPE_PIPELINE_RENDER_GEOM_SHADOW;
+ static DeclareMemType MTYPE_PIPELINE_RENDER_SELECT;
+ static DeclareMemType MTYPE_PIPELINE_REBUILD_POOLS;
+ static DeclareMemType MTYPE_PIPELINE_QUICK_LOOKUP;
+ static DeclareMemType MTYPE_PIPELINE_RENDER_OBJECTS;
+ static DeclareMemType MTYPE_PIPELINE_GENERATE_IMPOSTOR;
+ static DeclareMemType MTYPE_PIPELINE_RENDER_BLOOM;
+
+ static DeclareMemType MTYPE_UPKEEP_POOLS;
+
+ static DeclareMemType MTYPE_AVATAR;
+ static DeclareMemType MTYPE_AVATAR_MESH;
+ static DeclareMemType MTYPE_PARTICLES;
+ static DeclareMemType MTYPE_REGIONS;
+
+ static DeclareMemType MTYPE_INVENTORY;
+ static DeclareMemType MTYPE_INVENTORY_DRAW;
+ static DeclareMemType MTYPE_INVENTORY_BUILD_NEW_VIEWS;
+ static DeclareMemType MTYPE_INVENTORY_DO_FOLDER;
+ static DeclareMemType MTYPE_INVENTORY_POST_BUILD;
+ static DeclareMemType MTYPE_INVENTORY_FROM_XML;
+ static DeclareMemType MTYPE_INVENTORY_CREATE_NEW_ITEM;
+ static DeclareMemType MTYPE_INVENTORY_VIEW_INIT;
+ static DeclareMemType MTYPE_INVENTORY_VIEW_SHOW;
+ static DeclareMemType MTYPE_INVENTORY_VIEW_TOGGLE;
+
+ static DeclareMemType MTYPE_ANIMATION;
+ static DeclareMemType MTYPE_VOLUME;
+ static DeclareMemType MTYPE_PRIMITIVE;
+
+ static DeclareMemType MTYPE_SCRIPT;
+ static DeclareMemType MTYPE_SCRIPT_RUN;
+ static DeclareMemType MTYPE_SCRIPT_BYTECODE;
+
+ static DeclareMemType MTYPE_IO_PUMP;
+ static DeclareMemType MTYPE_IO_TCP;
+ static DeclareMemType MTYPE_IO_BUFFER;
+ static DeclareMemType MTYPE_IO_HTTP_SERVER;
+ static DeclareMemType MTYPE_IO_SD_SERVER;
+ static DeclareMemType MTYPE_IO_SD_CLIENT;
+ static DeclareMemType MTYPE_IO_URL_REQUEST;
+
+ static DeclareMemType MTYPE_DIRECTX_INIT;
+
+ static DeclareMemType MTYPE_TEMP1;
+ static DeclareMemType MTYPE_TEMP2;
+ static DeclareMemType MTYPE_TEMP3;
+ static DeclareMemType MTYPE_TEMP4;
+ static DeclareMemType MTYPE_TEMP5;
+ static DeclareMemType MTYPE_TEMP6;
+ static DeclareMemType MTYPE_TEMP7;
+ static DeclareMemType MTYPE_TEMP8;
+ static DeclareMemType MTYPE_TEMP9;
+
+ static DeclareMemType MTYPE_OTHER; // Special; used by display code
+
+ S32 mTypeIndex;
+};
+
+//----------------------------------------------------------------------------
+
+#endif
+
diff --git a/indra/llcommon/llstacktrace.cpp b/indra/llcommon/llstacktrace.cpp
index 4be91b5b11..3cb074257b 100644
--- a/indra/llcommon/llstacktrace.cpp
+++ b/indra/llcommon/llstacktrace.cpp
@@ -1,141 +1,142 @@
-/**
- * @file llstacktrace.cpp
- * @brief stack tracing functionality
- *
- * $LicenseInfo:firstyear=2001&license=viewergpl$
- *
- * Copyright (c) 2001-2009, Linden Research, Inc.
- *
- * Second Life Viewer Source Code
- * The source code in this file ("Source Code") is provided by Linden Lab
- * to you under the terms of the GNU General Public License, version 2.0
- * ("GPL"), unless you have obtained a separate licensing agreement
- * ("Other License"), formally executed by you and Linden Lab. Terms of
- * the GPL can be found in doc/GPL-license.txt in this distribution, or
- * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
- *
- * There are special exceptions to the terms and conditions of the GPL as
- * it is applied to this Source Code. View the full text of the exception
- * in the file doc/FLOSS-exception.txt in this software distribution, or
- * online at
- * http://secondlifegrid.net/programs/open_source/licensing/flossexception
- *
- * By copying, modifying or distributing this software, you acknowledge
- * that you have read and understood your obligations described above,
- * and agree to abide by those obligations.
- *
- * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
- * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
- * COMPLETENESS OR PERFORMANCE.
- * $/LicenseInfo$
- */
-
-#include "llstacktrace.h"
-
-#ifdef LL_WINDOWS
-
-#include <iostream>
-#include <sstream>
-
-#include "windows.h"
-#include "Dbghelp.h"
-
-typedef USHORT NTAPI RtlCaptureStackBackTrace_Function(
- IN ULONG frames_to_skip,
- IN ULONG frames_to_capture,
- OUT PVOID *backtrace,
- OUT PULONG backtrace_hash);
-
-static RtlCaptureStackBackTrace_Function* const RtlCaptureStackBackTrace_fn =
- (RtlCaptureStackBackTrace_Function*)
- GetProcAddress(GetModuleHandleA("ntdll.dll"), "RtlCaptureStackBackTrace");
-
-bool ll_get_stack_trace(std::vector<std::string>& lines)
-{
- const S32 MAX_STACK_DEPTH = 32;
- const S32 STRING_NAME_LENGTH = 200;
- const S32 FRAME_SKIP = 2;
- static BOOL symbolsLoaded = false;
- static BOOL firstCall = true;
-
- HANDLE hProc = GetCurrentProcess();
-
- // load the symbols if they're not loaded
- if(!symbolsLoaded && firstCall)
- {
- symbolsLoaded = SymInitialize(hProc, NULL, true);
- firstCall = false;
- }
-
- // if loaded, get the call stack
- if(symbolsLoaded)
- {
- // create the frames to hold the addresses
- void* frames[MAX_STACK_DEPTH];
- memset(frames, 0, sizeof(void*)*MAX_STACK_DEPTH);
- S32 depth = 0;
-
- // get the addresses
- depth = RtlCaptureStackBackTrace_fn(FRAME_SKIP, MAX_STACK_DEPTH, frames, NULL);
-
- IMAGEHLP_LINE64 line;
- memset(&line, 0, sizeof(IMAGEHLP_LINE64));
- line.SizeOfStruct = sizeof(IMAGEHLP_LINE64);
-
- // create something to hold address info
- PIMAGEHLP_SYMBOL64 pSym;
- pSym = (PIMAGEHLP_SYMBOL64)malloc(sizeof(IMAGEHLP_SYMBOL64) + STRING_NAME_LENGTH);
- memset(pSym, 0, sizeof(IMAGEHLP_SYMBOL64) + STRING_NAME_LENGTH);
- pSym->MaxNameLength = STRING_NAME_LENGTH;
- pSym->SizeOfStruct = sizeof(IMAGEHLP_SYMBOL64);
-
- // get address info for each address frame
- // and store
- for(S32 i=0; i < depth; i++)
- {
- std::stringstream stack_line;
- BOOL ret;
-
- DWORD64 addr = (DWORD64)frames[i];
- ret = SymGetSymFromAddr64(hProc, addr, 0, pSym);
- if(ret)
- {
- stack_line << pSym->Name << " ";
- }
-
- DWORD dummy;
- ret = SymGetLineFromAddr64(hProc, addr, &dummy, &line);
- if(ret)
- {
- std::string file_name = line.FileName;
- std::string::size_type index = file_name.rfind("\\");
- stack_line << file_name.substr(index + 1, file_name.size()) << ":" << line.LineNumber;
- }
-
- lines.push_back(stack_line.str());
- }
-
- free(pSym);
-
- // TODO: figure out a way to cleanup symbol loading
- // Not hugely necessary, however.
- //SymCleanup(hProc);
- return true;
- }
- else
- {
- lines.push_back("Stack Trace Failed. PDB symbol info not loaded");
- }
-
- return false;
-}
-
-#else
-
-bool ll_get_stack_trace(std::vector<std::string>& lines)
-{
- return false;
-}
-
-#endif
-
+/**
+ * @file llstacktrace.cpp
+ * @brief stack tracing functionality
+ *
+ * $LicenseInfo:firstyear=2001&license=viewergpl$
+ *
+ * Copyright (c) 2001-2009, Linden Research, Inc.
+ *
+ * Second Life Viewer Source Code
+ * The source code in this file ("Source Code") is provided by Linden Lab
+ * to you under the terms of the GNU General Public License, version 2.0
+ * ("GPL"), unless you have obtained a separate licensing agreement
+ * ("Other License"), formally executed by you and Linden Lab. Terms of
+ * the GPL can be found in doc/GPL-license.txt in this distribution, or
+ * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
+ *
+ * There are special exceptions to the terms and conditions of the GPL as
+ * it is applied to this Source Code. View the full text of the exception
+ * in the file doc/FLOSS-exception.txt in this software distribution, or
+ * online at
+ * http://secondlifegrid.net/programs/open_source/licensing/flossexception
+ *
+ * By copying, modifying or distributing this software, you acknowledge
+ * that you have read and understood your obligations described above,
+ * and agree to abide by those obligations.
+ *
+ * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
+ * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
+ * COMPLETENESS OR PERFORMANCE.
+ * $/LicenseInfo$
+ */
+
+#include "linden_common.h"
+#include "llstacktrace.h"
+
+#ifdef LL_WINDOWS
+
+#include <iostream>
+#include <sstream>
+
+#include "windows.h"
+#include "Dbghelp.h"
+
+typedef USHORT NTAPI RtlCaptureStackBackTrace_Function(
+ IN ULONG frames_to_skip,
+ IN ULONG frames_to_capture,
+ OUT PVOID *backtrace,
+ OUT PULONG backtrace_hash);
+
+static RtlCaptureStackBackTrace_Function* const RtlCaptureStackBackTrace_fn =
+ (RtlCaptureStackBackTrace_Function*)
+ GetProcAddress(GetModuleHandleA("ntdll.dll"), "RtlCaptureStackBackTrace");
+
+bool ll_get_stack_trace(std::vector<std::string>& lines)
+{
+ const S32 MAX_STACK_DEPTH = 32;
+ const S32 STRING_NAME_LENGTH = 200;
+ const S32 FRAME_SKIP = 2;
+ static BOOL symbolsLoaded = false;
+ static BOOL firstCall = true;
+
+ HANDLE hProc = GetCurrentProcess();
+
+ // load the symbols if they're not loaded
+ if(!symbolsLoaded && firstCall)
+ {
+ symbolsLoaded = SymInitialize(hProc, NULL, true);
+ firstCall = false;
+ }
+
+ // if loaded, get the call stack
+ if(symbolsLoaded)
+ {
+ // create the frames to hold the addresses
+ void* frames[MAX_STACK_DEPTH];
+ memset(frames, 0, sizeof(void*)*MAX_STACK_DEPTH);
+ S32 depth = 0;
+
+ // get the addresses
+ depth = RtlCaptureStackBackTrace_fn(FRAME_SKIP, MAX_STACK_DEPTH, frames, NULL);
+
+ IMAGEHLP_LINE64 line;
+ memset(&line, 0, sizeof(IMAGEHLP_LINE64));
+ line.SizeOfStruct = sizeof(IMAGEHLP_LINE64);
+
+ // create something to hold address info
+ PIMAGEHLP_SYMBOL64 pSym;
+ pSym = (PIMAGEHLP_SYMBOL64)malloc(sizeof(IMAGEHLP_SYMBOL64) + STRING_NAME_LENGTH);
+ memset(pSym, 0, sizeof(IMAGEHLP_SYMBOL64) + STRING_NAME_LENGTH);
+ pSym->MaxNameLength = STRING_NAME_LENGTH;
+ pSym->SizeOfStruct = sizeof(IMAGEHLP_SYMBOL64);
+
+ // get address info for each address frame
+ // and store
+ for(S32 i=0; i < depth; i++)
+ {
+ std::stringstream stack_line;
+ BOOL ret;
+
+ DWORD64 addr = (DWORD64)frames[i];
+ ret = SymGetSymFromAddr64(hProc, addr, 0, pSym);
+ if(ret)
+ {
+ stack_line << pSym->Name << " ";
+ }
+
+ DWORD dummy;
+ ret = SymGetLineFromAddr64(hProc, addr, &dummy, &line);
+ if(ret)
+ {
+ std::string file_name = line.FileName;
+ std::string::size_type index = file_name.rfind("\\");
+ stack_line << file_name.substr(index + 1, file_name.size()) << ":" << line.LineNumber;
+ }
+
+ lines.push_back(stack_line.str());
+ }
+
+ free(pSym);
+
+ // TODO: figure out a way to cleanup symbol loading
+ // Not hugely necessary, however.
+ //SymCleanup(hProc);
+ return true;
+ }
+ else
+ {
+ lines.push_back("Stack Trace Failed. PDB symbol info not loaded");
+ }
+
+ return false;
+}
+
+#else
+
+bool ll_get_stack_trace(std::vector<std::string>& lines)
+{
+ return false;
+}
+
+#endif
+
diff --git a/indra/llcommon/llstacktrace.h b/indra/llcommon/llstacktrace.h
index 609b934a97..b84b1aa6ad 100644
--- a/indra/llcommon/llstacktrace.h
+++ b/indra/llcommon/llstacktrace.h
@@ -1,44 +1,44 @@
-/**
- * @file llstacktrace.h
- * @brief stack trace functions
- *
- * $LicenseInfo:firstyear=2001&license=viewergpl$
- *
- * Copyright (c) 2001-2009, Linden Research, Inc.
- *
- * Second Life Viewer Source Code
- * The source code in this file ("Source Code") is provided by Linden Lab
- * to you under the terms of the GNU General Public License, version 2.0
- * ("GPL"), unless you have obtained a separate licensing agreement
- * ("Other License"), formally executed by you and Linden Lab. Terms of
- * the GPL can be found in doc/GPL-license.txt in this distribution, or
- * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
- *
- * There are special exceptions to the terms and conditions of the GPL as
- * it is applied to this Source Code. View the full text of the exception
- * in the file doc/FLOSS-exception.txt in this software distribution, or
- * online at
- * http://secondlifegrid.net/programs/open_source/licensing/flossexception
- *
- * By copying, modifying or distributing this software, you acknowledge
- * that you have read and understood your obligations described above,
- * and agree to abide by those obligations.
- *
- * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
- * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
- * COMPLETENESS OR PERFORMANCE.
- * $/LicenseInfo$
- */
-
-
-#ifndef LL_LLSTACKTRACE_H
-#define LL_LLSTACKTRACE_H
-
-#include "stdtypes.h"
-#include <vector>
-#include <string>
-
-bool ll_get_stack_trace(std::vector<std::string>& lines);
-
-#endif
-
+/**
+ * @file llstacktrace.h
+ * @brief stack trace functions
+ *
+ * $LicenseInfo:firstyear=2001&license=viewergpl$
+ *
+ * Copyright (c) 2001-2009, Linden Research, Inc.
+ *
+ * Second Life Viewer Source Code
+ * The source code in this file ("Source Code") is provided by Linden Lab
+ * to you under the terms of the GNU General Public License, version 2.0
+ * ("GPL"), unless you have obtained a separate licensing agreement
+ * ("Other License"), formally executed by you and Linden Lab. Terms of
+ * the GPL can be found in doc/GPL-license.txt in this distribution, or
+ * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
+ *
+ * There are special exceptions to the terms and conditions of the GPL as
+ * it is applied to this Source Code. View the full text of the exception
+ * in the file doc/FLOSS-exception.txt in this software distribution, or
+ * online at
+ * http://secondlifegrid.net/programs/open_source/licensing/flossexception
+ *
+ * By copying, modifying or distributing this software, you acknowledge
+ * that you have read and understood your obligations described above,
+ * and agree to abide by those obligations.
+ *
+ * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
+ * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
+ * COMPLETENESS OR PERFORMANCE.
+ * $/LicenseInfo$
+ */
+
+
+#ifndef LL_LLSTACKTRACE_H
+#define LL_LLSTACKTRACE_H
+
+#include "stdtypes.h"
+#include <vector>
+#include <string>
+
+LL_COMMON_API bool ll_get_stack_trace(std::vector<std::string>& lines);
+
+#endif
+
diff --git a/indra/llcommon/llstring.h b/indra/llcommon/llstring.h
index 813e2656ae..eb36dafee3 100644
--- a/indra/llcommon/llstring.h
+++ b/indra/llcommon/llstring.h
@@ -1,527 +1,527 @@
-/**
- * @file llstring.h
- * @brief String utility functions and std::string class.
- *
- * $LicenseInfo:firstyear=2001&license=viewergpl$
- *
- * Copyright (c) 2001-2009, Linden Research, Inc.
- *
- * Second Life Viewer Source Code
- * The source code in this file ("Source Code") is provided by Linden Lab
- * to you under the terms of the GNU General Public License, version 2.0
- * ("GPL"), unless you have obtained a separate licensing agreement
- * ("Other License"), formally executed by you and Linden Lab. Terms of
- * the GPL can be found in doc/GPL-license.txt in this distribution, or
- * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
- *
- * There are special exceptions to the terms and conditions of the GPL as
- * it is applied to this Source Code. View the full text of the exception
- * in the file doc/FLOSS-exception.txt in this software distribution, or
- * online at
- * http://secondlifegrid.net/programs/open_source/licensing/flossexception
- *
- * By copying, modifying or distributing this software, you acknowledge
- * that you have read and understood your obligations described above,
- * and agree to abide by those obligations.
- *
- * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
- * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
- * COMPLETENESS OR PERFORMANCE.
- * $/LicenseInfo$
- */
-
-#ifndef LL_LLSTRING_H
-#define LL_LLSTRING_H
-
-#include <string>
-#include <locale>
-#include <iomanip>
-#include <boost/regex.hpp>
-#include "llsd.h"
-
-#if LL_LINUX || LL_SOLARIS
-#include <wctype.h>
-#include <wchar.h>
-#endif
-
-#include <string.h>
-
-#if LL_SOLARIS
-// stricmp and strnicmp do not exist on Solaris:
-#define stricmp strcasecmp
-#define strnicmp strncasecmp
-#endif
-
-const char LL_UNKNOWN_CHAR = '?';
-
-#if LL_DARWIN || LL_LINUX || LL_SOLARIS
-// Template specialization of char_traits for U16s. Only necessary on Mac and Linux (exists on Windows already)
-#include <cstring>
-
-namespace std
-{
-template<>
-struct char_traits<U16>
-{
- typedef U16 char_type;
- typedef int int_type;
- typedef streampos pos_type;
- typedef streamoff off_type;
- typedef mbstate_t state_type;
-
- static void
- assign(char_type& __c1, const char_type& __c2)
- { __c1 = __c2; }
-
- static bool
- eq(const char_type& __c1, const char_type& __c2)
- { return __c1 == __c2; }
-
- static bool
- lt(const char_type& __c1, const char_type& __c2)
- { return __c1 < __c2; }
-
- static int
- compare(const char_type* __s1, const char_type* __s2, size_t __n)
- { return memcmp(__s1, __s2, __n * sizeof(char_type)); }
-
- static size_t
- length(const char_type* __s)
- {
- const char_type *cur_char = __s;
- while (*cur_char != 0)
- {
- ++cur_char;
- }
- return cur_char - __s;
- }
-
- static const char_type*
- find(const char_type* __s, size_t __n, const char_type& __a)
- { return static_cast<const char_type*>(memchr(__s, __a, __n * sizeof(char_type))); }
-
- static char_type*
- move(char_type* __s1, const char_type* __s2, size_t __n)
- { return static_cast<char_type*>(memmove(__s1, __s2, __n * sizeof(char_type))); }
-
- static char_type*
- copy(char_type* __s1, const char_type* __s2, size_t __n)
- { return static_cast<char_type*>(memcpy(__s1, __s2, __n * sizeof(char_type))); } /* Flawfinder: ignore */
-
- static char_type*
- assign(char_type* __s, size_t __n, char_type __a)
- {
- // This isn't right.
- //return static_cast<char_type*>(memset(__s, __a, __n * sizeof(char_type)));
-
- // I don't think there's a standard 'memset' for 16-bit values.
- // Do this the old-fashioned way.
-
- size_t __i;
- for(__i = 0; __i < __n; __i++)
- {
- __s[__i] = __a;
- }
- return __s;
- }
-
- static char_type
- to_char_type(const int_type& __c)
- { return static_cast<char_type>(__c); }
-
- static int_type
- to_int_type(const char_type& __c)
- { return static_cast<int_type>(__c); }
-
- static bool
- eq_int_type(const int_type& __c1, const int_type& __c2)
- { return __c1 == __c2; }
-
- static int_type
- eof() { return static_cast<int_type>(EOF); }
-
- static int_type
- not_eof(const int_type& __c)
- { return (__c == eof()) ? 0 : __c; }
- };
-};
-#endif
-
-class LLStringOps
-{
-private:
- static long sltOffset;
- static long localTimeOffset;
- static bool daylightSavings;
- static std::map<std::string, std::string> datetimeToCodes;
-
-public:
- static char toUpper(char elem) { return toupper((unsigned char)elem); }
- static llwchar toUpper(llwchar elem) { return towupper(elem); }
-
- static char toLower(char elem) { return tolower((unsigned char)elem); }
- static llwchar toLower(llwchar elem) { return towlower(elem); }
-
- static bool isSpace(char elem) { return isspace((unsigned char)elem) != 0; }
- static bool isSpace(llwchar elem) { return iswspace(elem) != 0; }
-
- static bool isUpper(char elem) { return isupper((unsigned char)elem) != 0; }
- static bool isUpper(llwchar elem) { return iswupper(elem) != 0; }
-
- static bool isLower(char elem) { return islower((unsigned char)elem) != 0; }
- static bool isLower(llwchar elem) { return iswlower(elem) != 0; }
-
- static bool isDigit(char a) { return isdigit((unsigned char)a) != 0; }
- static bool isDigit(llwchar a) { return iswdigit(a) != 0; }
-
- static bool isPunct(char a) { return ispunct((unsigned char)a) != 0; }
- static bool isPunct(llwchar a) { return iswpunct(a) != 0; }
-
- static bool isAlnum(char a) { return isalnum((unsigned char)a) != 0; }
- static bool isAlnum(llwchar a) { return iswalnum(a) != 0; }
-
- static S32 collate(const char* a, const char* b) { return strcoll(a, b); }
- static S32 collate(const llwchar* a, const llwchar* b);
-
- static void setupDatetimeInfo (bool daylight);
- static long getSltOffset (void) {return sltOffset;}
- static long getLocalTimeOffset (void) {return localTimeOffset;}
- static bool getDaylightSavings (void) {return daylightSavings;}
- static std::string getDatetimeCode (std::string key);
-};
-
-/**
- * @brief Return a string constructed from in without crashing if the
- * pointer is NULL.
- */
-std::string ll_safe_string(const char* in);
-std::string ll_safe_string(const char* in, S32 maxlen);
-
-
-// Allowing assignments from non-strings into format_map_t is apparently
-// *really* error-prone, so subclass std::string with just basic c'tors.
-class LLFormatMapString
-{
-public:
- LLFormatMapString() {};
- LLFormatMapString(const char* s) : mString(ll_safe_string(s)) {};
- LLFormatMapString(const std::string& s) : mString(s) {};
- operator std::string() const { return mString; }
- bool operator<(const LLFormatMapString& rhs) const { return mString < rhs.mString; }
- std::size_t length() const { return mString.length(); }
-
-private:
- std::string mString;
-};
-
-template <class T>
-class LLStringUtilBase
-{
-private:
- static std::string sLocale;
-
-public:
- typedef typename std::basic_string<T>::size_type size_type;
-
-public:
- /////////////////////////////////////////////////////////////////////////////////////////
- // Static Utility functions that operate on std::strings
-
- static std::basic_string<T> null;
-
- typedef std::map<LLFormatMapString, LLFormatMapString> format_map_t;
- static void getTokens (std::basic_string<T> input, std::vector<std::basic_string<T> >& tokens);
- static void formatNumber(std::basic_string<T>& numStr, std::basic_string<T> decimals);
- static bool formatDatetime(std::basic_string<T>& replacement, std::basic_string<T> token, std::basic_string<T> param, const LLSD& substitutions);
- static S32 format(std::basic_string<T>& s, const LLSD& substitutions);
- static S32 format(std::basic_string<T>& s, const format_map_t& fmt_map);
- static bool simpleReplacement(std::basic_string<T>& replacement, std::basic_string<T> token, const LLSD& substitutions);
- static void setLocale (std::string inLocale) {sLocale = inLocale;};
- static std::string getLocale (void) {return sLocale;};
-
- static bool isValidIndex(const std::basic_string<T>& string, size_type i)
- {
- return !string.empty() && (0 <= i) && (i <= string.size());
- }
-
- static void trimHead(std::basic_string<T>& string);
- static void trimTail(std::basic_string<T>& string);
- static void trim(std::basic_string<T>& string) { trimHead(string); trimTail(string); }
- static void truncate(std::basic_string<T>& string, size_type count);
-
- static void toUpper(std::basic_string<T>& string);
- static void toLower(std::basic_string<T>& string);
-
- // True if this is the head of s.
- static BOOL isHead( const std::basic_string<T>& string, const T* s );
-
- /**
- * @brief Returns true if string starts with substr
- *
- * If etither string or substr are empty, this method returns false.
- */
- static bool startsWith(
- const std::basic_string<T>& string,
- const std::basic_string<T>& substr);
-
- /**
- * @brief Returns true if string ends in substr
- *
- * If etither string or substr are empty, this method returns false.
- */
- static bool endsWith(
- const std::basic_string<T>& string,
- const std::basic_string<T>& substr);
-
- static void addCRLF(std::basic_string<T>& string);
- static void removeCRLF(std::basic_string<T>& string);
-
- static void replaceTabsWithSpaces( std::basic_string<T>& string, size_type spaces_per_tab );
- static void replaceNonstandardASCII( std::basic_string<T>& string, T replacement );
- static void replaceChar( std::basic_string<T>& string, T target, T replacement );
-
- static BOOL containsNonprintable(const std::basic_string<T>& string);
- static void stripNonprintable(std::basic_string<T>& string);
-
- /**
- * @brief Unsafe way to make ascii characters. You should probably
- * only call this when interacting with the host operating system.
- * The 1 byte std::string does not work correctly.
- * The 2 and 4 byte std::string probably work, so LLWStringUtil::_makeASCII
- * should work.
- */
- static void _makeASCII(std::basic_string<T>& string);
-
- // Conversion to other data types
- static BOOL convertToBOOL(const std::basic_string<T>& string, BOOL& value);
- static BOOL convertToU8(const std::basic_string<T>& string, U8& value);
- static BOOL convertToS8(const std::basic_string<T>& string, S8& value);
- static BOOL convertToS16(const std::basic_string<T>& string, S16& value);
- static BOOL convertToU16(const std::basic_string<T>& string, U16& value);
- static BOOL convertToU32(const std::basic_string<T>& string, U32& value);
- static BOOL convertToS32(const std::basic_string<T>& string, S32& value);
- static BOOL convertToF32(const std::basic_string<T>& string, F32& value);
- static BOOL convertToF64(const std::basic_string<T>& string, F64& value);
-
- /////////////////////////////////////////////////////////////////////////////////////////
- // Utility functions for working with char*'s and strings
-
- // Like strcmp but also handles empty strings. Uses
- // current locale.
- static S32 compareStrings(const T* lhs, const T* rhs);
- static S32 compareStrings(const std::basic_string<T>& lhs, const std::basic_string<T>& rhs);
-
- // case insensitive version of above. Uses current locale on
- // Win32, and falls back to a non-locale aware comparison on
- // Linux.
- static S32 compareInsensitive(const T* lhs, const T* rhs);
- static S32 compareInsensitive(const std::basic_string<T>& lhs, const std::basic_string<T>& rhs);
-
- // Case sensitive comparison with good handling of numbers. Does not use current locale.
- // a.k.a. strdictcmp()
- static S32 compareDict(const std::basic_string<T>& a, const std::basic_string<T>& b);
-
- // Case *in*sensitive comparison with good handling of numbers. Does not use current locale.
- // a.k.a. strdictcmp()
- static S32 compareDictInsensitive(const std::basic_string<T>& a, const std::basic_string<T>& b);
-
- // Puts compareDict() in a form appropriate for LL container classes to use for sorting.
- static BOOL precedesDict( const std::basic_string<T>& a, const std::basic_string<T>& b );
-
- // A replacement for strncpy.
- // If the dst buffer is dst_size bytes long or more, ensures that dst is null terminated and holds
- // up to dst_size-1 characters of src.
- static void copy(T* dst, const T* src, size_type dst_size);
-
- // Copies src into dst at a given offset.
- static void copyInto(std::basic_string<T>& dst, const std::basic_string<T>& src, size_type offset);
-
-#ifdef _DEBUG
- static void testHarness();
-#endif
-
-};
-
-template<class T> std::basic_string<T> LLStringUtilBase<T>::null;
-template<class T> std::string LLStringUtilBase<T>::sLocale;
-
-typedef LLStringUtilBase<char> LLStringUtil;
-typedef LLStringUtilBase<llwchar> LLWStringUtil;
-typedef std::basic_string<llwchar> LLWString;
-
-//@ Use this where we want to disallow input in the form of "foo"
-// This is used to catch places where english text is embedded in the code
-// instead of in a translatable XUI file.
-class LLStringExplicit : public std::string
-{
-public:
- explicit LLStringExplicit(const char* s) : std::string(s) {}
- LLStringExplicit(const std::string& s) : std::string(s) {}
- LLStringExplicit(const std::string& s, size_type pos, size_type n = std::string::npos) : std::string(s, pos, n) {}
-};
-
-struct LLDictionaryLess
-{
-public:
- bool operator()(const std::string& a, const std::string& b)
- {
- return (LLStringUtil::precedesDict(a, b) ? true : false);
- }
-};
-
-
-/**
- * Simple support functions
- */
-
-/**
- * @brief chop off the trailing characters in a string.
- *
- * This function works on bytes rather than glyphs, so this will
- * incorrectly truncate non-single byte strings.
- * Use utf8str_truncate() for utf8 strings
- * @return a copy of in string minus the trailing count bytes.
- */
-inline std::string chop_tail_copy(
- const std::string& in,
- std::string::size_type count)
-{
- return std::string(in, 0, in.length() - count);
-}
-
-/**
- * @brief This translates a nybble stored as a hex value from 0-f back
- * to a nybble in the low order bits of the return byte.
- */
-U8 hex_as_nybble(char hex);
-
-/**
- * @brief read the contents of a file into a string.
- *
- * Since this function has no concept of character encoding, most
- * anything you do with this method ill-advised. Please avoid.
- * @param str [out] The string which will have.
- * @param filename The full name of the file to read.
- * @return Returns true on success. If false, str is unmodified.
- */
-bool _read_file_into_string(std::string& str, const std::string& filename);
-bool iswindividual(llwchar elem);
-
-/**
- * Unicode support
- */
-
-// Make the incoming string a utf8 string. Replaces any unknown glyph
-// with the UNKOWN_CHARACTER. Once any unknown glph is found, the rest
-// of the data may not be recovered.
-std::string rawstr_to_utf8(const std::string& raw);
-
-//
-// We should never use UTF16 except when communicating with Win32!
-//
-typedef std::basic_string<U16> llutf16string;
-
-LLWString utf16str_to_wstring(const llutf16string &utf16str, S32 len);
-LLWString utf16str_to_wstring(const llutf16string &utf16str);
-
-llutf16string wstring_to_utf16str(const LLWString &utf32str, S32 len);
-llutf16string wstring_to_utf16str(const LLWString &utf32str);
-
-llutf16string utf8str_to_utf16str ( const std::string& utf8str, S32 len);
-llutf16string utf8str_to_utf16str ( const std::string& utf8str );
-
-LLWString utf8str_to_wstring(const std::string &utf8str, S32 len);
-LLWString utf8str_to_wstring(const std::string &utf8str);
-// Same function, better name. JC
-inline LLWString utf8string_to_wstring(const std::string& utf8_string) { return utf8str_to_wstring(utf8_string); }
-
-//
-S32 wchar_to_utf8chars(llwchar inchar, char* outchars);
-
-std::string wstring_to_utf8str(const LLWString &utf32str, S32 len);
-std::string wstring_to_utf8str(const LLWString &utf32str);
-
-std::string utf16str_to_utf8str(const llutf16string &utf16str, S32 len);
-std::string utf16str_to_utf8str(const llutf16string &utf16str);
-
-// Length of this UTF32 string in bytes when transformed to UTF8
-S32 wstring_utf8_length(const LLWString& wstr);
-
-// Length in bytes of this wide char in a UTF8 string
-S32 wchar_utf8_length(const llwchar wc);
-
-std::string utf8str_tolower(const std::string& utf8str);
-
-// Length in llwchar (UTF-32) of the first len units (16 bits) of the given UTF-16 string.
-S32 utf16str_wstring_length(const llutf16string &utf16str, S32 len);
-
-// Length in utf16string (UTF-16) of wlen wchars beginning at woffset.
-S32 wstring_utf16_length(const LLWString & wstr, S32 woffset, S32 wlen);
-
-// Length in wstring (i.e., llwchar count) of a part of a wstring specified by utf16 length (i.e., utf16 units.)
-S32 wstring_wstring_length_from_utf16_length(const LLWString & wstr, S32 woffset, S32 utf16_length, BOOL *unaligned = NULL);
-
-/**
- * @brief Properly truncate a utf8 string to a maximum byte count.
- *
- * The returned string may be less than max_len if the truncation
- * happens in the middle of a glyph. If max_len is longer than the
- * string passed in, the return value == utf8str.
- * @param utf8str A valid utf8 string to truncate.
- * @param max_len The maximum number of bytes in the return value.
- * @return Returns a valid utf8 string with byte count <= max_len.
- */
-std::string utf8str_truncate(const std::string& utf8str, const S32 max_len);
-
-std::string utf8str_trim(const std::string& utf8str);
-
-S32 utf8str_compare_insensitive(
- const std::string& lhs,
- const std::string& rhs);
-
-/**
- * @brief Replace all occurences of target_char with replace_char
- *
- * @param utf8str A utf8 string to process.
- * @param target_char The wchar to be replaced
- * @param replace_char The wchar which is written on replace
- */
-std::string utf8str_substChar(
- const std::string& utf8str,
- const llwchar target_char,
- const llwchar replace_char);
-
-std::string utf8str_makeASCII(const std::string& utf8str);
-
-// Hack - used for evil notecards.
-std::string mbcsstring_makeASCII(const std::string& str);
-
-std::string utf8str_removeCRLF(const std::string& utf8str);
-
-
-#if LL_WINDOWS
-/* @name Windows string helpers
- */
-//@{
-
-/**
- * @brief Implementation the expected snprintf interface.
- *
- * If the size of the passed in buffer is not large enough to hold the string,
- * two bad things happen:
- * 1. resulting formatted string is NOT null terminated
- * 2. Depending on the platform, the return value could be a) the required
- * size of the buffer to copy the entire formatted string or b) -1.
- * On Windows with VS.Net 2003, it returns -1 e.g.
- *
- * safe_snprintf always adds a NULL terminator so that the caller does not
- * need to check for return value or need to add the NULL terminator.
- * It does not, however change the return value - to let the caller know
- * that the passed in buffer size was not large enough to hold the
- * formatted string.
- *
- */
-
+/**
+ * @file llstring.h
+ * @brief String utility functions and std::string class.
+ *
+ * $LicenseInfo:firstyear=2001&license=viewergpl$
+ *
+ * Copyright (c) 2001-2009, Linden Research, Inc.
+ *
+ * Second Life Viewer Source Code
+ * The source code in this file ("Source Code") is provided by Linden Lab
+ * to you under the terms of the GNU General Public License, version 2.0
+ * ("GPL"), unless you have obtained a separate licensing agreement
+ * ("Other License"), formally executed by you and Linden Lab. Terms of
+ * the GPL can be found in doc/GPL-license.txt in this distribution, or
+ * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
+ *
+ * There are special exceptions to the terms and conditions of the GPL as
+ * it is applied to this Source Code. View the full text of the exception
+ * in the file doc/FLOSS-exception.txt in this software distribution, or
+ * online at
+ * http://secondlifegrid.net/programs/open_source/licensing/flossexception
+ *
+ * By copying, modifying or distributing this software, you acknowledge
+ * that you have read and understood your obligations described above,
+ * and agree to abide by those obligations.
+ *
+ * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
+ * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
+ * COMPLETENESS OR PERFORMANCE.
+ * $/LicenseInfo$
+ */
+
+#ifndef LL_LLSTRING_H
+#define LL_LLSTRING_H
+
+#include <string>
+#include <locale>
+#include <iomanip>
+#include <boost/regex.hpp>
+#include "llsd.h"
+
+#if LL_LINUX || LL_SOLARIS
+#include <wctype.h>
+#include <wchar.h>
+#endif
+
+#include <string.h>
+
+#if LL_SOLARIS
+// stricmp and strnicmp do not exist on Solaris:
+#define stricmp strcasecmp
+#define strnicmp strncasecmp
+#endif
+
+const char LL_UNKNOWN_CHAR = '?';
+
+#if LL_DARWIN || LL_LINUX || LL_SOLARIS
+// Template specialization of char_traits for U16s. Only necessary on Mac and Linux (exists on Windows already)
+#include <cstring>
+
+namespace std
+{
+template<>
+struct char_traits<U16>
+{
+ typedef U16 char_type;
+ typedef int int_type;
+ typedef streampos pos_type;
+ typedef streamoff off_type;
+ typedef mbstate_t state_type;
+
+ static void
+ assign(char_type& __c1, const char_type& __c2)
+ { __c1 = __c2; }
+
+ static bool
+ eq(const char_type& __c1, const char_type& __c2)
+ { return __c1 == __c2; }
+
+ static bool
+ lt(const char_type& __c1, const char_type& __c2)
+ { return __c1 < __c2; }
+
+ static int
+ compare(const char_type* __s1, const char_type* __s2, size_t __n)
+ { return memcmp(__s1, __s2, __n * sizeof(char_type)); }
+
+ static size_t
+ length(const char_type* __s)
+ {
+ const char_type *cur_char = __s;
+ while (*cur_char != 0)
+ {
+ ++cur_char;
+ }
+ return cur_char - __s;
+ }
+
+ static const char_type*
+ find(const char_type* __s, size_t __n, const char_type& __a)
+ { return static_cast<const char_type*>(memchr(__s, __a, __n * sizeof(char_type))); }
+
+ static char_type*
+ move(char_type* __s1, const char_type* __s2, size_t __n)
+ { return static_cast<char_type*>(memmove(__s1, __s2, __n * sizeof(char_type))); }
+
+ static char_type*
+ copy(char_type* __s1, const char_type* __s2, size_t __n)
+ { return static_cast<char_type*>(memcpy(__s1, __s2, __n * sizeof(char_type))); } /* Flawfinder: ignore */
+
+ static char_type*
+ assign(char_type* __s, size_t __n, char_type __a)
+ {
+ // This isn't right.
+ //return static_cast<char_type*>(memset(__s, __a, __n * sizeof(char_type)));
+
+ // I don't think there's a standard 'memset' for 16-bit values.
+ // Do this the old-fashioned way.
+
+ size_t __i;
+ for(__i = 0; __i < __n; __i++)
+ {
+ __s[__i] = __a;
+ }
+ return __s;
+ }
+
+ static char_type
+ to_char_type(const int_type& __c)
+ { return static_cast<char_type>(__c); }
+
+ static int_type
+ to_int_type(const char_type& __c)
+ { return static_cast<int_type>(__c); }
+
+ static bool
+ eq_int_type(const int_type& __c1, const int_type& __c2)
+ { return __c1 == __c2; }
+
+ static int_type
+ eof() { return static_cast<int_type>(EOF); }
+
+ static int_type
+ not_eof(const int_type& __c)
+ { return (__c == eof()) ? 0 : __c; }
+ };
+};
+#endif
+
+class LL_COMMON_API LLStringOps
+{
+private:
+ static long sltOffset;
+ static long localTimeOffset;
+ static bool daylightSavings;
+ static std::map<std::string, std::string> datetimeToCodes;
+
+public:
+ static char toUpper(char elem) { return toupper((unsigned char)elem); }
+ static llwchar toUpper(llwchar elem) { return towupper(elem); }
+
+ static char toLower(char elem) { return tolower((unsigned char)elem); }
+ static llwchar toLower(llwchar elem) { return towlower(elem); }
+
+ static bool isSpace(char elem) { return isspace((unsigned char)elem) != 0; }
+ static bool isSpace(llwchar elem) { return iswspace(elem) != 0; }
+
+ static bool isUpper(char elem) { return isupper((unsigned char)elem) != 0; }
+ static bool isUpper(llwchar elem) { return iswupper(elem) != 0; }
+
+ static bool isLower(char elem) { return islower((unsigned char)elem) != 0; }
+ static bool isLower(llwchar elem) { return iswlower(elem) != 0; }
+
+ static bool isDigit(char a) { return isdigit((unsigned char)a) != 0; }
+ static bool isDigit(llwchar a) { return iswdigit(a) != 0; }
+
+ static bool isPunct(char a) { return ispunct((unsigned char)a) != 0; }
+ static bool isPunct(llwchar a) { return iswpunct(a) != 0; }
+
+ static bool isAlnum(char a) { return isalnum((unsigned char)a) != 0; }
+ static bool isAlnum(llwchar a) { return iswalnum(a) != 0; }
+
+ static S32 collate(const char* a, const char* b) { return strcoll(a, b); }
+ static S32 collate(const llwchar* a, const llwchar* b);
+
+ static void setupDatetimeInfo (bool daylight);
+ static long getSltOffset (void) {return sltOffset;}
+ static long getLocalTimeOffset (void) {return localTimeOffset;}
+ static bool getDaylightSavings (void) {return daylightSavings;}
+ static std::string getDatetimeCode (std::string key);
+};
+
+/**
+ * @brief Return a string constructed from in without crashing if the
+ * pointer is NULL.
+ */
+LL_COMMON_API std::string ll_safe_string(const char* in);
+LL_COMMON_API std::string ll_safe_string(const char* in, S32 maxlen);
+
+
+// Allowing assignments from non-strings into format_map_t is apparently
+// *really* error-prone, so subclass std::string with just basic c'tors.
+class LLFormatMapString
+{
+public:
+ LLFormatMapString() {};
+ LLFormatMapString(const char* s) : mString(ll_safe_string(s)) {};
+ LLFormatMapString(const std::string& s) : mString(s) {};
+ operator std::string() const { return mString; }
+ bool operator<(const LLFormatMapString& rhs) const { return mString < rhs.mString; }
+ std::size_t length() const { return mString.length(); }
+
+private:
+ std::string mString;
+};
+
+template <class T>
+class LLStringUtilBase
+{
+private:
+ static std::string sLocale;
+
+public:
+ typedef typename std::basic_string<T>::size_type size_type;
+
+public:
+ /////////////////////////////////////////////////////////////////////////////////////////
+ // Static Utility functions that operate on std::strings
+
+ static std::basic_string<T> null;
+
+ typedef std::map<LLFormatMapString, LLFormatMapString> format_map_t;
+ static void getTokens (std::basic_string<T> input, std::vector<std::basic_string<T> >& tokens);
+ static void formatNumber(std::basic_string<T>& numStr, std::basic_string<T> decimals);
+ static bool formatDatetime(std::basic_string<T>& replacement, std::basic_string<T> token, std::basic_string<T> param, const LLSD& substitutions);
+ static S32 format(std::basic_string<T>& s, const LLSD& substitutions);
+ static S32 format(std::basic_string<T>& s, const format_map_t& fmt_map);
+ static bool simpleReplacement(std::basic_string<T>& replacement, std::basic_string<T> token, const LLSD& substitutions);
+ static void setLocale (std::string inLocale) {sLocale = inLocale;};
+ static std::string getLocale (void) {return sLocale;};
+
+ static bool isValidIndex(const std::basic_string<T>& string, size_type i)
+ {
+ return !string.empty() && (0 <= i) && (i <= string.size());
+ }
+
+ static void trimHead(std::basic_string<T>& string);
+ static void trimTail(std::basic_string<T>& string);
+ static void trim(std::basic_string<T>& string) { trimHead(string); trimTail(string); }
+ static void truncate(std::basic_string<T>& string, size_type count);
+
+ static void toUpper(std::basic_string<T>& string);
+ static void toLower(std::basic_string<T>& string);
+
+ // True if this is the head of s.
+ static BOOL isHead( const std::basic_string<T>& string, const T* s );
+
+ /**
+ * @brief Returns true if string starts with substr
+ *
+ * If etither string or substr are empty, this method returns false.
+ */
+ static bool startsWith(
+ const std::basic_string<T>& string,
+ const std::basic_string<T>& substr);
+
+ /**
+ * @brief Returns true if string ends in substr
+ *
+ * If etither string or substr are empty, this method returns false.
+ */
+ static bool endsWith(
+ const std::basic_string<T>& string,
+ const std::basic_string<T>& substr);
+
+ static void addCRLF(std::basic_string<T>& string);
+ static void removeCRLF(std::basic_string<T>& string);
+
+ static void replaceTabsWithSpaces( std::basic_string<T>& string, size_type spaces_per_tab );
+ static void replaceNonstandardASCII( std::basic_string<T>& string, T replacement );
+ static void replaceChar( std::basic_string<T>& string, T target, T replacement );
+
+ static BOOL containsNonprintable(const std::basic_string<T>& string);
+ static void stripNonprintable(std::basic_string<T>& string);
+
+ /**
+ * @brief Unsafe way to make ascii characters. You should probably
+ * only call this when interacting with the host operating system.
+ * The 1 byte std::string does not work correctly.
+ * The 2 and 4 byte std::string probably work, so LLWStringUtil::_makeASCII
+ * should work.
+ */
+ static void _makeASCII(std::basic_string<T>& string);
+
+ // Conversion to other data types
+ static BOOL convertToBOOL(const std::basic_string<T>& string, BOOL& value);
+ static BOOL convertToU8(const std::basic_string<T>& string, U8& value);
+ static BOOL convertToS8(const std::basic_string<T>& string, S8& value);
+ static BOOL convertToS16(const std::basic_string<T>& string, S16& value);
+ static BOOL convertToU16(const std::basic_string<T>& string, U16& value);
+ static BOOL convertToU32(const std::basic_string<T>& string, U32& value);
+ static BOOL convertToS32(const std::basic_string<T>& string, S32& value);
+ static BOOL convertToF32(const std::basic_string<T>& string, F32& value);
+ static BOOL convertToF64(const std::basic_string<T>& string, F64& value);
+
+ /////////////////////////////////////////////////////////////////////////////////////////
+ // Utility functions for working with char*'s and strings
+
+ // Like strcmp but also handles empty strings. Uses
+ // current locale.
+ static S32 compareStrings(const T* lhs, const T* rhs);
+ static S32 compareStrings(const std::basic_string<T>& lhs, const std::basic_string<T>& rhs);
+
+ // case insensitive version of above. Uses current locale on
+ // Win32, and falls back to a non-locale aware comparison on
+ // Linux.
+ static S32 compareInsensitive(const T* lhs, const T* rhs);
+ static S32 compareInsensitive(const std::basic_string<T>& lhs, const std::basic_string<T>& rhs);
+
+ // Case sensitive comparison with good handling of numbers. Does not use current locale.
+ // a.k.a. strdictcmp()
+ static S32 compareDict(const std::basic_string<T>& a, const std::basic_string<T>& b);
+
+ // Case *in*sensitive comparison with good handling of numbers. Does not use current locale.
+ // a.k.a. strdictcmp()
+ static S32 compareDictInsensitive(const std::basic_string<T>& a, const std::basic_string<T>& b);
+
+ // Puts compareDict() in a form appropriate for LL container classes to use for sorting.
+ static BOOL precedesDict( const std::basic_string<T>& a, const std::basic_string<T>& b );
+
+ // A replacement for strncpy.
+ // If the dst buffer is dst_size bytes long or more, ensures that dst is null terminated and holds
+ // up to dst_size-1 characters of src.
+ static void copy(T* dst, const T* src, size_type dst_size);
+
+ // Copies src into dst at a given offset.
+ static void copyInto(std::basic_string<T>& dst, const std::basic_string<T>& src, size_type offset);
+
+#ifdef _DEBUG
+ static void testHarness();
+#endif
+
+};
+
+template<class T> std::basic_string<T> LLStringUtilBase<T>::null;
+template<class T> std::string LLStringUtilBase<T>::sLocale;
+
+typedef LL_COMMON_API LLStringUtilBase<char> LLStringUtil;
+typedef LL_COMMON_API LLStringUtilBase<llwchar> LLWStringUtil;
+typedef LL_COMMON_API std::basic_string<llwchar> LLWString;
+
+//@ Use this where we want to disallow input in the form of "foo"
+// This is used to catch places where english text is embedded in the code
+// instead of in a translatable XUI file.
+class LLStringExplicit : public std::string
+{
+public:
+ explicit LLStringExplicit(const char* s) : std::string(s) {}
+ LLStringExplicit(const std::string& s) : std::string(s) {}
+ LLStringExplicit(const std::string& s, size_type pos, size_type n = std::string::npos) : std::string(s, pos, n) {}
+};
+
+struct LLDictionaryLess
+{
+public:
+ bool operator()(const std::string& a, const std::string& b)
+ {
+ return (LLStringUtil::precedesDict(a, b) ? true : false);
+ }
+};
+
+
+/**
+ * Simple support functions
+ */
+
+/**
+ * @brief chop off the trailing characters in a string.
+ *
+ * This function works on bytes rather than glyphs, so this will
+ * incorrectly truncate non-single byte strings.
+ * Use utf8str_truncate() for utf8 strings
+ * @return a copy of in string minus the trailing count bytes.
+ */
+inline std::string chop_tail_copy(
+ const std::string& in,
+ std::string::size_type count)
+{
+ return std::string(in, 0, in.length() - count);
+}
+
+/**
+ * @brief This translates a nybble stored as a hex value from 0-f back
+ * to a nybble in the low order bits of the return byte.
+ */
+LL_COMMON_API U8 hex_as_nybble(char hex);
+
+/**
+ * @brief read the contents of a file into a string.
+ *
+ * Since this function has no concept of character encoding, most
+ * anything you do with this method ill-advised. Please avoid.
+ * @param str [out] The string which will have.
+ * @param filename The full name of the file to read.
+ * @return Returns true on success. If false, str is unmodified.
+ */
+LL_COMMON_API bool _read_file_into_string(std::string& str, const std::string& filename);
+LL_COMMON_API bool iswindividual(llwchar elem);
+
+/**
+ * Unicode support
+ */
+
+// Make the incoming string a utf8 string. Replaces any unknown glyph
+// with the UNKOWN_CHARACTER. Once any unknown glph is found, the rest
+// of the data may not be recovered.
+LL_COMMON_API std::string rawstr_to_utf8(const std::string& raw);
+
+//
+// We should never use UTF16 except when communicating with Win32!
+//
+typedef LL_COMMON_API std::basic_string<U16> llutf16string;
+
+LL_COMMON_API LLWString utf16str_to_wstring(const llutf16string &utf16str, S32 len);
+LL_COMMON_API LLWString utf16str_to_wstring(const llutf16string &utf16str);
+
+LL_COMMON_API llutf16string wstring_to_utf16str(const LLWString &utf32str, S32 len);
+LL_COMMON_API llutf16string wstring_to_utf16str(const LLWString &utf32str);
+
+LL_COMMON_API llutf16string utf8str_to_utf16str ( const std::string& utf8str, S32 len);
+LL_COMMON_API llutf16string utf8str_to_utf16str ( const std::string& utf8str );
+
+LL_COMMON_API LLWString utf8str_to_wstring(const std::string &utf8str, S32 len);
+LL_COMMON_API LLWString utf8str_to_wstring(const std::string &utf8str);
+// Same function, better name. JC
+inline LLWString utf8string_to_wstring(const std::string& utf8_string) { return utf8str_to_wstring(utf8_string); }
+
+//
+LL_COMMON_API S32 wchar_to_utf8chars(llwchar inchar, char* outchars);
+
+LL_COMMON_API std::string wstring_to_utf8str(const LLWString &utf32str, S32 len);
+LL_COMMON_API std::string wstring_to_utf8str(const LLWString &utf32str);
+
+LL_COMMON_API std::string utf16str_to_utf8str(const llutf16string &utf16str, S32 len);
+LL_COMMON_API std::string utf16str_to_utf8str(const llutf16string &utf16str);
+
+// Length of this UTF32 string in bytes when transformed to UTF8
+LL_COMMON_API S32 wstring_utf8_length(const LLWString& wstr);
+
+// Length in bytes of this wide char in a UTF8 string
+LL_COMMON_API S32 wchar_utf8_length(const llwchar wc);
+
+LL_COMMON_API std::string utf8str_tolower(const std::string& utf8str);
+
+// Length in llwchar (UTF-32) of the first len units (16 bits) of the given UTF-16 string.
+LL_COMMON_API S32 utf16str_wstring_length(const llutf16string &utf16str, S32 len);
+
+// Length in utf16string (UTF-16) of wlen wchars beginning at woffset.
+LL_COMMON_API S32 wstring_utf16_length(const LLWString & wstr, S32 woffset, S32 wlen);
+
+// Length in wstring (i.e., llwchar count) of a part of a wstring specified by utf16 length (i.e., utf16 units.)
+LL_COMMON_API S32 wstring_wstring_length_from_utf16_length(const LLWString & wstr, S32 woffset, S32 utf16_length, BOOL *unaligned = NULL);
+
+/**
+ * @brief Properly truncate a utf8 string to a maximum byte count.
+ *
+ * The returned string may be less than max_len if the truncation
+ * happens in the middle of a glyph. If max_len is longer than the
+ * string passed in, the return value == utf8str.
+ * @param utf8str A valid utf8 string to truncate.
+ * @param max_len The maximum number of bytes in the return value.
+ * @return Returns a valid utf8 string with byte count <= max_len.
+ */
+LL_COMMON_API std::string utf8str_truncate(const std::string& utf8str, const S32 max_len);
+
+LL_COMMON_API std::string utf8str_trim(const std::string& utf8str);
+
+LL_COMMON_API S32 utf8str_compare_insensitive(
+ const std::string& lhs,
+ const std::string& rhs);
+
+/**
+ * @brief Replace all occurences of target_char with replace_char
+ *
+ * @param utf8str A utf8 string to process.
+ * @param target_char The wchar to be replaced
+ * @param replace_char The wchar which is written on replace
+ */
+LL_COMMON_API std::string utf8str_substChar(
+ const std::string& utf8str,
+ const llwchar target_char,
+ const llwchar replace_char);
+
+LL_COMMON_API std::string utf8str_makeASCII(const std::string& utf8str);
+
+// Hack - used for evil notecards.
+LL_COMMON_API std::string mbcsstring_makeASCII(const std::string& str);
+
+LL_COMMON_API std::string utf8str_removeCRLF(const std::string& utf8str);
+
+
+#if LL_WINDOWS
+/* @name Windows string helpers
+ */
+//@{
+
+/**
+ * @brief Implementation the expected snprintf interface.
+ *
+ * If the size of the passed in buffer is not large enough to hold the string,
+ * two bad things happen:
+ * 1. resulting formatted string is NOT null terminated
+ * 2. Depending on the platform, the return value could be a) the required
+ * size of the buffer to copy the entire formatted string or b) -1.
+ * On Windows with VS.Net 2003, it returns -1 e.g.
+ *
+ * safe_snprintf always adds a NULL terminator so that the caller does not
+ * need to check for return value or need to add the NULL terminator.
+ * It does not, however change the return value - to let the caller know
+ * that the passed in buffer size was not large enough to hold the
+ * formatted string.
+ *
+ */
+
// Deal with the differeneces on Windows
namespace snprintf_hack
{
@@ -529,952 +529,952 @@ namespace snprintf_hack
}
using snprintf_hack::snprintf;
-
-/**
- * @brief Convert a wide string to std::string
- *
- * This replaces the unsafe W2A macro from ATL.
- */
-std::string ll_convert_wide_to_string(const wchar_t* in);
-
-//@}
-#endif // LL_WINDOWS
-
-/**
- * Many of the 'strip' and 'replace' methods of LLStringUtilBase need
- * specialization to work with the signed char type.
- * Sadly, it is not possible (AFAIK) to specialize a single method of
- * a template class.
- * That stuff should go here.
- */
-namespace LLStringFn
-{
- /**
- * @brief Replace all non-printable characters with replacement in
- * string.
- * NOTE - this will zap non-ascii
- *
- * @param [in,out] string the to modify. out value is the string
- * with zero non-printable characters.
- * @param The replacement character. use LL_UNKNOWN_CHAR if unsure.
- */
- void replace_nonprintable_in_ascii(
- std::basic_string<char>& string,
- char replacement);
-
-
- /**
- * @brief Replace all non-printable characters and pipe characters
- * with replacement in a string.
- * NOTE - this will zap non-ascii
- *
- * @param [in,out] the string to modify. out value is the string
- * with zero non-printable characters and zero pipe characters.
- * @param The replacement character. use LL_UNKNOWN_CHAR if unsure.
- */
- void replace_nonprintable_and_pipe_in_ascii(std::basic_string<char>& str,
- char replacement);
-
-
- /**
- * @brief Remove all characters that are not allowed in XML 1.0.
- * Returns a copy of the string with those characters removed.
- * Works with US ASCII and UTF-8 encoded strings. JC
- */
- std::string strip_invalid_xml(const std::string& input);
-
-
- /**
- * @brief Replace all control characters (0 <= c < 0x20) with replacement in
- * string. This is safe for utf-8
- *
- * @param [in,out] string the to modify. out value is the string
- * with zero non-printable characters.
- * @param The replacement character. use LL_UNKNOWN_CHAR if unsure.
- */
- void replace_ascii_controlchars(
- std::basic_string<char>& string,
- char replacement);
-}
-
-////////////////////////////////////////////////////////////
-
-//static
-template<class T>
-void LLStringUtilBase<T>::getTokens (std::basic_string<T> input, std::vector<std::basic_string<T> >& tokens)
-{
- const std::basic_string<T> delims (",");
- std::basic_string<T> currToken;
- size_type begIdx, endIdx;
-
- begIdx = input.find_first_not_of (delims);
- while (begIdx != std::basic_string<T>::npos)
- {
- endIdx = input.find_first_of (delims, begIdx);
- if (endIdx == std::basic_string<T>::npos)
- {
- endIdx = input.length();
- }
-
- currToken = input.substr(begIdx, endIdx - begIdx);
- trim (currToken);
- tokens.push_back(currToken);
- begIdx = input.find_first_not_of (delims, endIdx);
- }
-}
-
-// static
-template<class T>
-S32 LLStringUtilBase<T>::format(std::basic_string<T>& s, const format_map_t& fmt_map)
-{
- LLSD llsdMap;
-
- for (format_map_t::const_iterator iter = fmt_map.begin();
- iter != fmt_map.end();
- ++iter)
- {
- llsdMap[iter->first] = iter->second;
- }
-
- return format (s, llsdMap);
-}
-
-//static
-template<class T>
-S32 LLStringUtilBase<T>::format(std::basic_string<T>& s, const LLSD& substitutions)
-{
- S32 res = 0;
-
- if (!substitutions.isMap())
- {
- return res;
- }
-
- std::basic_ostringstream<T> output;
- // match strings like [NAME,number,3]
- const boost::regex key("\\[((\\s)*([0-9_A-Za-z]+)((\\s)*,(\\s)*[0-9_A-Za-z\\s]*){0,2}(\\s)*)]");
-
-
- typename std::basic_string<T>::const_iterator start = s.begin();
- typename std::basic_string<T>::const_iterator end = s.end();
- boost::smatch match;
-
-
- while (boost::regex_search(start, end, match, key, boost::match_default))
- {
- bool found_replacement = false;
- std::vector<std::basic_string<T> > tokens;
- std::basic_string<T> replacement;
-
- getTokens (std::basic_string<T>(match[1].first, match[1].second), tokens);
-
- if (tokens.size() == 1)
- {
- found_replacement = simpleReplacement (replacement, tokens[0], substitutions);
- }
- else if (tokens[1] == "number")
- {
- std::basic_string<T> param = "0";
-
- if (tokens.size() > 2) param = tokens[2];
- found_replacement = simpleReplacement (replacement, tokens[0], substitutions);
- if (found_replacement) formatNumber (replacement, param);
- }
- else if (tokens[1] == "datetime")
- {
- std::basic_string<T> param;
- if (tokens.size() > 2) param = tokens[2];
-
- found_replacement = formatDatetime (replacement, tokens[0], param, substitutions);
- }
-
- if (found_replacement)
- {
- output << std::basic_string<T>(start, match[0].first) << replacement;
- res++;
- }
- else
- {
- // we had no replacement, so leave the string we searched for so that it gets noticed by QA
- // "hello [NAME_NOT_FOUND]" is output
- output << std::basic_string<T>(start, match[0].second);
- }
-
- // update search position
- start = match[0].second;
- }
- // send the remainder of the string (with no further matches for bracketed names)
- output << std::basic_string<T>(start, end);
- s = output.str();
- return res;
-}
-
-// static
-template<class T>
-bool LLStringUtilBase<T>::simpleReplacement(std::basic_string<T> &replacement, std::basic_string<T> token, const LLSD &substitutions)
-{
- // see if we have a replacement for the bracketed string (without the brackets)
- // test first using has() because if we just look up with operator[] we get back an
- // empty string even if the value is missing. We want to distinguish between
- // missing replacements and deliberately empty replacement strings.
- if (substitutions.has(token))
- {
- replacement = substitutions[token].asString();
- return true;
- }
- // if not, see if there's one WITH brackets
- else if (substitutions.has(std::basic_string<T>("[" + token + "]")))
- {
- replacement = substitutions[std::basic_string<T>("[" + token + "]")].asString();
- return true;
- }
-
- return false;
-}
-
-// static
-template<class T>
-void LLStringUtilBase<T>::formatNumber(std::basic_string<T>& numStr, std::basic_string<T> decimals)
-{
- typedef typename std::basic_string<T>::size_type string_size_type_t;
- std::basic_stringstream<T> strStream;
- S32 intDecimals = 0;
-
- convertToS32 (decimals, intDecimals);
- if (!sLocale.empty())
- {
- strStream.imbue (std::locale(sLocale.c_str()));
- }
-
- if (!intDecimals)
- {
- S32 intStr;
-
- if (convertToS32(numStr, intStr))
- {
- strStream << intStr;
- numStr = strStream.str();
- }
- }
- else
- {
- F32 floatStr;
-
- if (convertToF32(numStr, floatStr))
- {
- strStream << std::fixed << std::showpoint << std::setprecision(intDecimals) << floatStr;
- numStr = strStream.str();
- }
- }
-}
-
-// static
-template<class T>
-bool LLStringUtilBase<T>::formatDatetime(std::basic_string<T>& replacement, std::basic_string<T> token,
- std::basic_string<T> param, const LLSD& substitutions)
-{
- S32 secFromEpoch = (long) substitutions["datetime"].asInteger();
-
- if (param == "local") // local
- {
- secFromEpoch -= LLStringOps::getLocalTimeOffset();
- }
- else if (param != "utc") // slt
- {
- secFromEpoch -= LLStringOps::getSltOffset();
- }
-
- // if never fell into those two ifs above, param must be utc
- if (secFromEpoch < 0) secFromEpoch = 0;
-
- LLDate * datetime = new LLDate((F64)secFromEpoch);
- std::string code = LLStringOps::getDatetimeCode (token);
-
- // special case to handle timezone
- if (code == "%Z") {
- if (param == "utc") replacement = "GMT";
- else if (param != "local") replacement = LLStringOps::getDaylightSavings()? "PDT" : "PST";
- return true;
- }
-
- replacement = datetime->toHTTPDateString(code);
- if (code.empty())
- {
- return false;
- }
- else
- {
- return true;
- }
-}
-
-// static
-template<class T>
-S32 LLStringUtilBase<T>::compareStrings(const T* lhs, const T* rhs)
-{
- S32 result;
- if( lhs == rhs )
- {
- result = 0;
- }
- else
- if ( !lhs || !lhs[0] )
- {
- result = ((!rhs || !rhs[0]) ? 0 : 1);
- }
- else
- if ( !rhs || !rhs[0])
- {
- result = -1;
- }
- else
- {
- result = LLStringOps::collate(lhs, rhs);
- }
- return result;
-}
-
-//static
-template<class T>
-S32 LLStringUtilBase<T>::compareStrings(const std::basic_string<T>& lhs, const std::basic_string<T>& rhs)
-{
- return LLStringOps::collate(lhs.c_str(), rhs.c_str());
-}
-
-// static
-template<class T>
-S32 LLStringUtilBase<T>::compareInsensitive(const T* lhs, const T* rhs )
-{
- S32 result;
- if( lhs == rhs )
- {
- result = 0;
- }
- else
- if ( !lhs || !lhs[0] )
- {
- result = ((!rhs || !rhs[0]) ? 0 : 1);
- }
- else
- if ( !rhs || !rhs[0] )
- {
- result = -1;
- }
- else
- {
- std::basic_string<T> lhs_string(lhs);
- std::basic_string<T> rhs_string(rhs);
- LLStringUtilBase<T>::toUpper(lhs_string);
- LLStringUtilBase<T>::toUpper(rhs_string);
- result = LLStringOps::collate(lhs_string.c_str(), rhs_string.c_str());
- }
- return result;
-}
-
-//static
-template<class T>
-S32 LLStringUtilBase<T>::compareInsensitive(const std::basic_string<T>& lhs, const std::basic_string<T>& rhs)
-{
- std::basic_string<T> lhs_string(lhs);
- std::basic_string<T> rhs_string(rhs);
- LLStringUtilBase<T>::toUpper(lhs_string);
- LLStringUtilBase<T>::toUpper(rhs_string);
- return LLStringOps::collate(lhs_string.c_str(), rhs_string.c_str());
-}
-
-// Case sensitive comparison with good handling of numbers. Does not use current locale.
-// a.k.a. strdictcmp()
-
-//static
-template<class T>
-S32 LLStringUtilBase<T>::compareDict(const std::basic_string<T>& astr, const std::basic_string<T>& bstr)
-{
- const T* a = astr.c_str();
- const T* b = bstr.c_str();
- T ca, cb;
- S32 ai, bi, cnt = 0;
- S32 bias = 0;
-
- ca = *(a++);
- cb = *(b++);
- while( ca && cb ){
- if( bias==0 ){
- if( LLStringOps::isUpper(ca) ){ ca = LLStringOps::toLower(ca); bias--; }
- if( LLStringOps::isUpper(cb) ){ cb = LLStringOps::toLower(cb); bias++; }
- }else{
- if( LLStringOps::isUpper(ca) ){ ca = LLStringOps::toLower(ca); }
- if( LLStringOps::isUpper(cb) ){ cb = LLStringOps::toLower(cb); }
- }
- if( LLStringOps::isDigit(ca) ){
- if( cnt-->0 ){
- if( cb!=ca ) break;
- }else{
- if( !LLStringOps::isDigit(cb) ) break;
- for(ai=0; LLStringOps::isDigit(a[ai]); ai++);
- for(bi=0; LLStringOps::isDigit(b[bi]); bi++);
- if( ai<bi ){ ca=0; break; }
- if( bi<ai ){ cb=0; break; }
- if( ca!=cb ) break;
- cnt = ai;
- }
- }else if( ca!=cb ){ break;
- }
- ca = *(a++);
- cb = *(b++);
- }
- if( ca==cb ) ca += bias;
- return ca-cb;
-}
-
-// static
-template<class T>
-S32 LLStringUtilBase<T>::compareDictInsensitive(const std::basic_string<T>& astr, const std::basic_string<T>& bstr)
-{
- const T* a = astr.c_str();
- const T* b = bstr.c_str();
- T ca, cb;
- S32 ai, bi, cnt = 0;
-
- ca = *(a++);
- cb = *(b++);
- while( ca && cb ){
- if( LLStringOps::isUpper(ca) ){ ca = LLStringOps::toLower(ca); }
- if( LLStringOps::isUpper(cb) ){ cb = LLStringOps::toLower(cb); }
- if( LLStringOps::isDigit(ca) ){
- if( cnt-->0 ){
- if( cb!=ca ) break;
- }else{
- if( !LLStringOps::isDigit(cb) ) break;
- for(ai=0; LLStringOps::isDigit(a[ai]); ai++);
- for(bi=0; LLStringOps::isDigit(b[bi]); bi++);
- if( ai<bi ){ ca=0; break; }
- if( bi<ai ){ cb=0; break; }
- if( ca!=cb ) break;
- cnt = ai;
- }
- }else if( ca!=cb ){ break;
- }
- ca = *(a++);
- cb = *(b++);
- }
- return ca-cb;
-}
-
-// Puts compareDict() in a form appropriate for LL container classes to use for sorting.
-// static
-template<class T>
-BOOL LLStringUtilBase<T>::precedesDict( const std::basic_string<T>& a, const std::basic_string<T>& b )
-{
- if( a.size() && b.size() )
- {
- return (LLStringUtilBase<T>::compareDict(a.c_str(), b.c_str()) < 0);
- }
- else
- {
- return (!b.empty());
- }
-}
-
-//static
-template<class T>
-void LLStringUtilBase<T>::toUpper(std::basic_string<T>& string)
-{
- if( !string.empty() )
- {
- std::transform(
- string.begin(),
- string.end(),
- string.begin(),
- (T(*)(T)) &LLStringOps::toUpper);
- }
-}
-
-//static
-template<class T>
-void LLStringUtilBase<T>::toLower(std::basic_string<T>& string)
-{
- if( !string.empty() )
- {
- std::transform(
- string.begin(),
- string.end(),
- string.begin(),
- (T(*)(T)) &LLStringOps::toLower);
- }
-}
-
-//static
-template<class T>
-void LLStringUtilBase<T>::trimHead(std::basic_string<T>& string)
-{
- if( !string.empty() )
- {
- size_type i = 0;
- while( i < string.length() && LLStringOps::isSpace( string[i] ) )
- {
- i++;
- }
- string.erase(0, i);
- }
-}
-
-//static
-template<class T>
-void LLStringUtilBase<T>::trimTail(std::basic_string<T>& string)
-{
- if( string.size() )
- {
- size_type len = string.length();
- size_type i = len;
- while( i > 0 && LLStringOps::isSpace( string[i-1] ) )
- {
- i--;
- }
-
- string.erase( i, len - i );
- }
-}
-
-
-// Replace line feeds with carriage return-line feed pairs.
-//static
-template<class T>
-void LLStringUtilBase<T>::addCRLF(std::basic_string<T>& string)
-{
- const T LF = 10;
- const T CR = 13;
-
- // Count the number of line feeds
- size_type count = 0;
- size_type len = string.size();
- size_type i;
- for( i = 0; i < len; i++ )
- {
- if( string[i] == LF )
- {
- count++;
- }
- }
-
- // Insert a carriage return before each line feed
- if( count )
- {
- size_type size = len + count;
- T *t = new T[size];
- size_type j = 0;
- for( i = 0; i < len; ++i )
- {
- if( string[i] == LF )
- {
- t[j] = CR;
- ++j;
- }
- t[j] = string[i];
- ++j;
- }
-
- string.assign(t, size);
- }
-}
-
-// Remove all carriage returns
-//static
-template<class T>
-void LLStringUtilBase<T>::removeCRLF(std::basic_string<T>& string)
-{
- const T CR = 13;
-
- size_type cr_count = 0;
- size_type len = string.size();
- size_type i;
- for( i = 0; i < len - cr_count; i++ )
- {
- if( string[i+cr_count] == CR )
- {
- cr_count++;
- }
-
- string[i] = string[i+cr_count];
- }
- string.erase(i, cr_count);
-}
-
-//static
-template<class T>
-void LLStringUtilBase<T>::replaceChar( std::basic_string<T>& string, T target, T replacement )
-{
- size_type found_pos = 0;
- for (found_pos = string.find(target, found_pos);
- found_pos != std::basic_string<T>::npos;
- found_pos = string.find(target, found_pos))
- {
- string[found_pos] = replacement;
- }
-}
-
-//static
-template<class T>
-void LLStringUtilBase<T>::replaceNonstandardASCII( std::basic_string<T>& string, T replacement )
-{
- const char LF = 10;
- const S8 MIN = 32;
-// const S8 MAX = 127;
-
- size_type len = string.size();
- for( size_type i = 0; i < len; i++ )
- {
- // No need to test MAX < mText[i] because we treat mText[i] as a signed char,
- // which has a max value of 127.
- if( ( S8(string[i]) < MIN ) && (string[i] != LF) )
- {
- string[i] = replacement;
- }
- }
-}
-
-//static
-template<class T>
-void LLStringUtilBase<T>::replaceTabsWithSpaces( std::basic_string<T>& str, size_type spaces_per_tab )
-{
- const T TAB = '\t';
- const T SPACE = ' ';
-
- std::basic_string<T> out_str;
- // Replace tabs with spaces
- for (size_type i = 0; i < str.length(); i++)
- {
- if (str[i] == TAB)
- {
- for (size_type j = 0; j < spaces_per_tab; j++)
- out_str += SPACE;
- }
- else
- {
- out_str += str[i];
- }
- }
- str = out_str;
-}
-
-//static
-template<class T>
-BOOL LLStringUtilBase<T>::containsNonprintable(const std::basic_string<T>& string)
-{
- const char MIN = 32;
- BOOL rv = FALSE;
- for (size_type i = 0; i < string.size(); i++)
- {
- if(string[i] < MIN)
- {
- rv = TRUE;
- break;
- }
- }
- return rv;
-}
-
-//static
-template<class T>
-void LLStringUtilBase<T>::stripNonprintable(std::basic_string<T>& string)
-{
- const char MIN = 32;
- size_type j = 0;
- if (string.empty())
- {
- return;
- }
- char* c_string = new char[string.size() + 1];
- if(c_string == NULL)
- {
- return;
- }
- strcpy(c_string, string.c_str()); /*Flawfinder: ignore*/
- char* write_head = &c_string[0];
- for (size_type i = 0; i < string.size(); i++)
- {
- char* read_head = &string[i];
- write_head = &c_string[j];
- if(!(*read_head < MIN))
- {
- *write_head = *read_head;
- ++j;
- }
- }
- c_string[j]= '\0';
- string = c_string;
- delete []c_string;
-}
-
-template<class T>
-void LLStringUtilBase<T>::_makeASCII(std::basic_string<T>& string)
-{
- // Replace non-ASCII chars with LL_UNKNOWN_CHAR
- for (size_type i = 0; i < string.length(); i++)
- {
- if (string[i] > 0x7f)
- {
- string[i] = LL_UNKNOWN_CHAR;
- }
- }
-}
-
-// static
-template<class T>
-void LLStringUtilBase<T>::copy( T* dst, const T* src, size_type dst_size )
-{
- if( dst_size > 0 )
- {
- size_type min_len = 0;
- if( src )
- {
- min_len = llmin( dst_size - 1, strlen( src ) ); /* Flawfinder: ignore */
- memcpy(dst, src, min_len * sizeof(T)); /* Flawfinder: ignore */
- }
- dst[min_len] = '\0';
- }
-}
-
-// static
-template<class T>
-void LLStringUtilBase<T>::copyInto(std::basic_string<T>& dst, const std::basic_string<T>& src, size_type offset)
-{
- if ( offset == dst.length() )
- {
- // special case - append to end of string and avoid expensive
- // (when strings are large) string manipulations
- dst += src;
- }
- else
- {
- std::basic_string<T> tail = dst.substr(offset);
-
- dst = dst.substr(0, offset);
- dst += src;
- dst += tail;
- };
-}
-
-// True if this is the head of s.
-//static
-template<class T>
-BOOL LLStringUtilBase<T>::isHead( const std::basic_string<T>& string, const T* s )
-{
- if( string.empty() )
- {
- // Early exit
- return FALSE;
- }
- else
- {
- return (strncmp( s, string.c_str(), string.size() ) == 0);
- }
-}
-
-// static
-template<class T>
-bool LLStringUtilBase<T>::startsWith(
- const std::basic_string<T>& string,
- const std::basic_string<T>& substr)
-{
- if(string.empty() || (substr.empty())) return false;
- if(0 == string.find(substr)) return true;
- return false;
-}
-
-// static
-template<class T>
-bool LLStringUtilBase<T>::endsWith(
- const std::basic_string<T>& string,
- const std::basic_string<T>& substr)
-{
- if(string.empty() || (substr.empty())) return false;
- std::string::size_type idx = string.rfind(substr);
- if(std::string::npos == idx) return false;
- return (idx == (string.size() - substr.size()));
-}
-
-
-template<class T>
-BOOL LLStringUtilBase<T>::convertToBOOL(const std::basic_string<T>& string, BOOL& value)
-{
- if( string.empty() )
- {
- return FALSE;
- }
-
- std::basic_string<T> temp( string );
- trim(temp);
- if(
- (temp == "1") ||
- (temp == "T") ||
- (temp == "t") ||
- (temp == "TRUE") ||
- (temp == "true") ||
- (temp == "True") )
- {
- value = TRUE;
- return TRUE;
- }
- else
- if(
- (temp == "0") ||
- (temp == "F") ||
- (temp == "f") ||
- (temp == "FALSE") ||
- (temp == "false") ||
- (temp == "False") )
- {
- value = FALSE;
- return TRUE;
- }
-
- return FALSE;
-}
-
-template<class T>
-BOOL LLStringUtilBase<T>::convertToU8(const std::basic_string<T>& string, U8& value)
-{
- S32 value32 = 0;
- BOOL success = convertToS32(string, value32);
- if( success && (U8_MIN <= value32) && (value32 <= U8_MAX) )
- {
- value = (U8) value32;
- return TRUE;
- }
- return FALSE;
-}
-
-template<class T>
-BOOL LLStringUtilBase<T>::convertToS8(const std::basic_string<T>& string, S8& value)
-{
- S32 value32 = 0;
- BOOL success = convertToS32(string, value32);
- if( success && (S8_MIN <= value32) && (value32 <= S8_MAX) )
- {
- value = (S8) value32;
- return TRUE;
- }
- return FALSE;
-}
-
-template<class T>
-BOOL LLStringUtilBase<T>::convertToS16(const std::basic_string<T>& string, S16& value)
-{
- S32 value32 = 0;
- BOOL success = convertToS32(string, value32);
- if( success && (S16_MIN <= value32) && (value32 <= S16_MAX) )
- {
- value = (S16) value32;
- return TRUE;
- }
- return FALSE;
-}
-
-template<class T>
-BOOL LLStringUtilBase<T>::convertToU16(const std::basic_string<T>& string, U16& value)
-{
- S32 value32 = 0;
- BOOL success = convertToS32(string, value32);
- if( success && (U16_MIN <= value32) && (value32 <= U16_MAX) )
- {
- value = (U16) value32;
- return TRUE;
- }
- return FALSE;
-}
-
-template<class T>
-BOOL LLStringUtilBase<T>::convertToU32(const std::basic_string<T>& string, U32& value)
-{
- if( string.empty() )
- {
- return FALSE;
- }
-
- std::basic_string<T> temp( string );
- trim(temp);
- U32 v;
- std::basic_istringstream<T> i_stream((std::basic_string<T>)temp);
- if(i_stream >> v)
- {
- value = v;
- return TRUE;
- }
- return FALSE;
-}
-
-template<class T>
-BOOL LLStringUtilBase<T>::convertToS32(const std::basic_string<T>& string, S32& value)
-{
- if( string.empty() )
- {
- return FALSE;
- }
-
- std::basic_string<T> temp( string );
- trim(temp);
- S32 v;
- std::basic_istringstream<T> i_stream((std::basic_string<T>)temp);
- if(i_stream >> v)
- {
- //TODO: figure out overflow and underflow reporting here
- //if((LONG_MAX == v) || (LONG_MIN == v))
- //{
- // // Underflow or overflow
- // return FALSE;
- //}
-
- value = v;
- return TRUE;
- }
- return FALSE;
-}
-
-template<class T>
-BOOL LLStringUtilBase<T>::convertToF32(const std::basic_string<T>& string, F32& value)
-{
- F64 value64 = 0.0;
- BOOL success = convertToF64(string, value64);
- if( success && (-F32_MAX <= value64) && (value64 <= F32_MAX) )
- {
- value = (F32) value64;
- return TRUE;
- }
- return FALSE;
-}
-
-template<class T>
-BOOL LLStringUtilBase<T>::convertToF64(const std::basic_string<T>& string, F64& value)
-{
- if( string.empty() )
- {
- return FALSE;
- }
-
- std::basic_string<T> temp( string );
- trim(temp);
- F64 v;
- std::basic_istringstream<T> i_stream((std::basic_string<T>)temp);
- if(i_stream >> v)
- {
- //TODO: figure out overflow and underflow reporting here
- //if( ((-HUGE_VAL == v) || (HUGE_VAL == v))) )
- //{
- // // Underflow or overflow
- // return FALSE;
- //}
-
- value = v;
- return TRUE;
- }
- return FALSE;
-}
-
-template<class T>
-void LLStringUtilBase<T>::truncate(std::basic_string<T>& string, size_type count)
-{
- size_type cur_size = string.size();
- string.resize(count < cur_size ? count : cur_size);
-}
-
-#endif // LL_STRING_H
+
+/**
+ * @brief Convert a wide string to std::string
+ *
+ * This replaces the unsafe W2A macro from ATL.
+ */
+LL_COMMON_API std::string ll_convert_wide_to_string(const wchar_t* in);
+
+//@}
+#endif // LL_WINDOWS
+
+/**
+ * Many of the 'strip' and 'replace' methods of LLStringUtilBase need
+ * specialization to work with the signed char type.
+ * Sadly, it is not possible (AFAIK) to specialize a single method of
+ * a template class.
+ * That stuff should go here.
+ */
+namespace LLStringFn
+{
+ /**
+ * @brief Replace all non-printable characters with replacement in
+ * string.
+ * NOTE - this will zap non-ascii
+ *
+ * @param [in,out] string the to modify. out value is the string
+ * with zero non-printable characters.
+ * @param The replacement character. use LL_UNKNOWN_CHAR if unsure.
+ */
+ LL_COMMON_API void replace_nonprintable_in_ascii(
+ std::basic_string<char>& string,
+ char replacement);
+
+
+ /**
+ * @brief Replace all non-printable characters and pipe characters
+ * with replacement in a string.
+ * NOTE - this will zap non-ascii
+ *
+ * @param [in,out] the string to modify. out value is the string
+ * with zero non-printable characters and zero pipe characters.
+ * @param The replacement character. use LL_UNKNOWN_CHAR if unsure.
+ */
+ LL_COMMON_API void replace_nonprintable_and_pipe_in_ascii(std::basic_string<char>& str,
+ char replacement);
+
+
+ /**
+ * @brief Remove all characters that are not allowed in XML 1.0.
+ * Returns a copy of the string with those characters removed.
+ * Works with US ASCII and UTF-8 encoded strings. JC
+ */
+ LL_COMMON_API std::string strip_invalid_xml(const std::string& input);
+
+
+ /**
+ * @brief Replace all control characters (0 <= c < 0x20) with replacement in
+ * string. This is safe for utf-8
+ *
+ * @param [in,out] string the to modify. out value is the string
+ * with zero non-printable characters.
+ * @param The replacement character. use LL_UNKNOWN_CHAR if unsure.
+ */
+ LL_COMMON_API void replace_ascii_controlchars(
+ std::basic_string<char>& string,
+ char replacement);
+}
+
+////////////////////////////////////////////////////////////
+
+//static
+template<class T>
+void LLStringUtilBase<T>::getTokens (std::basic_string<T> input, std::vector<std::basic_string<T> >& tokens)
+{
+ const std::basic_string<T> delims (",");
+ std::basic_string<T> currToken;
+ size_type begIdx, endIdx;
+
+ begIdx = input.find_first_not_of (delims);
+ while (begIdx != std::basic_string<T>::npos)
+ {
+ endIdx = input.find_first_of (delims, begIdx);
+ if (endIdx == std::basic_string<T>::npos)
+ {
+ endIdx = input.length();
+ }
+
+ currToken = input.substr(begIdx, endIdx - begIdx);
+ trim (currToken);
+ tokens.push_back(currToken);
+ begIdx = input.find_first_not_of (delims, endIdx);
+ }
+}
+
+// static
+template<class T>
+S32 LLStringUtilBase<T>::format(std::basic_string<T>& s, const format_map_t& fmt_map)
+{
+ LLSD llsdMap;
+
+ for (format_map_t::const_iterator iter = fmt_map.begin();
+ iter != fmt_map.end();
+ ++iter)
+ {
+ llsdMap[iter->first] = iter->second;
+ }
+
+ return format (s, llsdMap);
+}
+
+//static
+template<class T>
+S32 LLStringUtilBase<T>::format(std::basic_string<T>& s, const LLSD& substitutions)
+{
+ S32 res = 0;
+
+ if (!substitutions.isMap())
+ {
+ return res;
+ }
+
+ std::basic_ostringstream<T> output;
+ // match strings like [NAME,number,3]
+ const boost::regex key("\\[((\\s)*([0-9_A-Za-z]+)((\\s)*,(\\s)*[0-9_A-Za-z\\s]*){0,2}(\\s)*)]");
+
+
+ typename std::basic_string<T>::const_iterator start = s.begin();
+ typename std::basic_string<T>::const_iterator end = s.end();
+ boost::smatch match;
+
+
+ while (boost::regex_search(start, end, match, key, boost::match_default))
+ {
+ bool found_replacement = false;
+ std::vector<std::basic_string<T> > tokens;
+ std::basic_string<T> replacement;
+
+ getTokens (std::basic_string<T>(match[1].first, match[1].second), tokens);
+
+ if (tokens.size() == 1)
+ {
+ found_replacement = simpleReplacement (replacement, tokens[0], substitutions);
+ }
+ else if (tokens[1] == "number")
+ {
+ std::basic_string<T> param = "0";
+
+ if (tokens.size() > 2) param = tokens[2];
+ found_replacement = simpleReplacement (replacement, tokens[0], substitutions);
+ if (found_replacement) formatNumber (replacement, param);
+ }
+ else if (tokens[1] == "datetime")
+ {
+ std::basic_string<T> param;
+ if (tokens.size() > 2) param = tokens[2];
+
+ found_replacement = formatDatetime (replacement, tokens[0], param, substitutions);
+ }
+
+ if (found_replacement)
+ {
+ output << std::basic_string<T>(start, match[0].first) << replacement;
+ res++;
+ }
+ else
+ {
+ // we had no replacement, so leave the string we searched for so that it gets noticed by QA
+ // "hello [NAME_NOT_FOUND]" is output
+ output << std::basic_string<T>(start, match[0].second);
+ }
+
+ // update search position
+ start = match[0].second;
+ }
+ // send the remainder of the string (with no further matches for bracketed names)
+ output << std::basic_string<T>(start, end);
+ s = output.str();
+ return res;
+}
+
+// static
+template<class T>
+bool LLStringUtilBase<T>::simpleReplacement(std::basic_string<T> &replacement, std::basic_string<T> token, const LLSD &substitutions)
+{
+ // see if we have a replacement for the bracketed string (without the brackets)
+ // test first using has() because if we just look up with operator[] we get back an
+ // empty string even if the value is missing. We want to distinguish between
+ // missing replacements and deliberately empty replacement strings.
+ if (substitutions.has(token))
+ {
+ replacement = substitutions[token].asString();
+ return true;
+ }
+ // if not, see if there's one WITH brackets
+ else if (substitutions.has(std::basic_string<T>("[" + token + "]")))
+ {
+ replacement = substitutions[std::basic_string<T>("[" + token + "]")].asString();
+ return true;
+ }
+
+ return false;
+}
+
+// static
+template<class T>
+void LLStringUtilBase<T>::formatNumber(std::basic_string<T>& numStr, std::basic_string<T> decimals)
+{
+ typedef typename std::basic_string<T>::size_type string_size_type_t;
+ std::basic_stringstream<T> strStream;
+ S32 intDecimals = 0;
+
+ convertToS32 (decimals, intDecimals);
+ if (!sLocale.empty())
+ {
+ strStream.imbue (std::locale(sLocale.c_str()));
+ }
+
+ if (!intDecimals)
+ {
+ S32 intStr;
+
+ if (convertToS32(numStr, intStr))
+ {
+ strStream << intStr;
+ numStr = strStream.str();
+ }
+ }
+ else
+ {
+ F32 floatStr;
+
+ if (convertToF32(numStr, floatStr))
+ {
+ strStream << std::fixed << std::showpoint << std::setprecision(intDecimals) << floatStr;
+ numStr = strStream.str();
+ }
+ }
+}
+
+// static
+template<class T>
+bool LLStringUtilBase<T>::formatDatetime(std::basic_string<T>& replacement, std::basic_string<T> token,
+ std::basic_string<T> param, const LLSD& substitutions)
+{
+ S32 secFromEpoch = (long) substitutions["datetime"].asInteger();
+
+ if (param == "local") // local
+ {
+ secFromEpoch -= LLStringOps::getLocalTimeOffset();
+ }
+ else if (param != "utc") // slt
+ {
+ secFromEpoch -= LLStringOps::getSltOffset();
+ }
+
+ // if never fell into those two ifs above, param must be utc
+ if (secFromEpoch < 0) secFromEpoch = 0;
+
+ LLDate * datetime = new LLDate((F64)secFromEpoch);
+ std::string code = LLStringOps::getDatetimeCode (token);
+
+ // special case to handle timezone
+ if (code == "%Z") {
+ if (param == "utc") replacement = "GMT";
+ else if (param != "local") replacement = LLStringOps::getDaylightSavings()? "PDT" : "PST";
+ return true;
+ }
+
+ replacement = datetime->toHTTPDateString(code);
+ if (code.empty())
+ {
+ return false;
+ }
+ else
+ {
+ return true;
+ }
+}
+
+// static
+template<class T>
+S32 LLStringUtilBase<T>::compareStrings(const T* lhs, const T* rhs)
+{
+ S32 result;
+ if( lhs == rhs )
+ {
+ result = 0;
+ }
+ else
+ if ( !lhs || !lhs[0] )
+ {
+ result = ((!rhs || !rhs[0]) ? 0 : 1);
+ }
+ else
+ if ( !rhs || !rhs[0])
+ {
+ result = -1;
+ }
+ else
+ {
+ result = LLStringOps::collate(lhs, rhs);
+ }
+ return result;
+}
+
+//static
+template<class T>
+S32 LLStringUtilBase<T>::compareStrings(const std::basic_string<T>& lhs, const std::basic_string<T>& rhs)
+{
+ return LLStringOps::collate(lhs.c_str(), rhs.c_str());
+}
+
+// static
+template<class T>
+S32 LLStringUtilBase<T>::compareInsensitive(const T* lhs, const T* rhs )
+{
+ S32 result;
+ if( lhs == rhs )
+ {
+ result = 0;
+ }
+ else
+ if ( !lhs || !lhs[0] )
+ {
+ result = ((!rhs || !rhs[0]) ? 0 : 1);
+ }
+ else
+ if ( !rhs || !rhs[0] )
+ {
+ result = -1;
+ }
+ else
+ {
+ std::basic_string<T> lhs_string(lhs);
+ std::basic_string<T> rhs_string(rhs);
+ LLStringUtilBase<T>::toUpper(lhs_string);
+ LLStringUtilBase<T>::toUpper(rhs_string);
+ result = LLStringOps::collate(lhs_string.c_str(), rhs_string.c_str());
+ }
+ return result;
+}
+
+//static
+template<class T>
+S32 LLStringUtilBase<T>::compareInsensitive(const std::basic_string<T>& lhs, const std::basic_string<T>& rhs)
+{
+ std::basic_string<T> lhs_string(lhs);
+ std::basic_string<T> rhs_string(rhs);
+ LLStringUtilBase<T>::toUpper(lhs_string);
+ LLStringUtilBase<T>::toUpper(rhs_string);
+ return LLStringOps::collate(lhs_string.c_str(), rhs_string.c_str());
+}
+
+// Case sensitive comparison with good handling of numbers. Does not use current locale.
+// a.k.a. strdictcmp()
+
+//static
+template<class T>
+S32 LLStringUtilBase<T>::compareDict(const std::basic_string<T>& astr, const std::basic_string<T>& bstr)
+{
+ const T* a = astr.c_str();
+ const T* b = bstr.c_str();
+ T ca, cb;
+ S32 ai, bi, cnt = 0;
+ S32 bias = 0;
+
+ ca = *(a++);
+ cb = *(b++);
+ while( ca && cb ){
+ if( bias==0 ){
+ if( LLStringOps::isUpper(ca) ){ ca = LLStringOps::toLower(ca); bias--; }
+ if( LLStringOps::isUpper(cb) ){ cb = LLStringOps::toLower(cb); bias++; }
+ }else{
+ if( LLStringOps::isUpper(ca) ){ ca = LLStringOps::toLower(ca); }
+ if( LLStringOps::isUpper(cb) ){ cb = LLStringOps::toLower(cb); }
+ }
+ if( LLStringOps::isDigit(ca) ){
+ if( cnt-->0 ){
+ if( cb!=ca ) break;
+ }else{
+ if( !LLStringOps::isDigit(cb) ) break;
+ for(ai=0; LLStringOps::isDigit(a[ai]); ai++);
+ for(bi=0; LLStringOps::isDigit(b[bi]); bi++);
+ if( ai<bi ){ ca=0; break; }
+ if( bi<ai ){ cb=0; break; }
+ if( ca!=cb ) break;
+ cnt = ai;
+ }
+ }else if( ca!=cb ){ break;
+ }
+ ca = *(a++);
+ cb = *(b++);
+ }
+ if( ca==cb ) ca += bias;
+ return ca-cb;
+}
+
+// static
+template<class T>
+S32 LLStringUtilBase<T>::compareDictInsensitive(const std::basic_string<T>& astr, const std::basic_string<T>& bstr)
+{
+ const T* a = astr.c_str();
+ const T* b = bstr.c_str();
+ T ca, cb;
+ S32 ai, bi, cnt = 0;
+
+ ca = *(a++);
+ cb = *(b++);
+ while( ca && cb ){
+ if( LLStringOps::isUpper(ca) ){ ca = LLStringOps::toLower(ca); }
+ if( LLStringOps::isUpper(cb) ){ cb = LLStringOps::toLower(cb); }
+ if( LLStringOps::isDigit(ca) ){
+ if( cnt-->0 ){
+ if( cb!=ca ) break;
+ }else{
+ if( !LLStringOps::isDigit(cb) ) break;
+ for(ai=0; LLStringOps::isDigit(a[ai]); ai++);
+ for(bi=0; LLStringOps::isDigit(b[bi]); bi++);
+ if( ai<bi ){ ca=0; break; }
+ if( bi<ai ){ cb=0; break; }
+ if( ca!=cb ) break;
+ cnt = ai;
+ }
+ }else if( ca!=cb ){ break;
+ }
+ ca = *(a++);
+ cb = *(b++);
+ }
+ return ca-cb;
+}
+
+// Puts compareDict() in a form appropriate for LL container classes to use for sorting.
+// static
+template<class T>
+BOOL LLStringUtilBase<T>::precedesDict( const std::basic_string<T>& a, const std::basic_string<T>& b )
+{
+ if( a.size() && b.size() )
+ {
+ return (LLStringUtilBase<T>::compareDict(a.c_str(), b.c_str()) < 0);
+ }
+ else
+ {
+ return (!b.empty());
+ }
+}
+
+//static
+template<class T>
+void LLStringUtilBase<T>::toUpper(std::basic_string<T>& string)
+{
+ if( !string.empty() )
+ {
+ std::transform(
+ string.begin(),
+ string.end(),
+ string.begin(),
+ (T(*)(T)) &LLStringOps::toUpper);
+ }
+}
+
+//static
+template<class T>
+void LLStringUtilBase<T>::toLower(std::basic_string<T>& string)
+{
+ if( !string.empty() )
+ {
+ std::transform(
+ string.begin(),
+ string.end(),
+ string.begin(),
+ (T(*)(T)) &LLStringOps::toLower);
+ }
+}
+
+//static
+template<class T>
+void LLStringUtilBase<T>::trimHead(std::basic_string<T>& string)
+{
+ if( !string.empty() )
+ {
+ size_type i = 0;
+ while( i < string.length() && LLStringOps::isSpace( string[i] ) )
+ {
+ i++;
+ }
+ string.erase(0, i);
+ }
+}
+
+//static
+template<class T>
+void LLStringUtilBase<T>::trimTail(std::basic_string<T>& string)
+{
+ if( string.size() )
+ {
+ size_type len = string.length();
+ size_type i = len;
+ while( i > 0 && LLStringOps::isSpace( string[i-1] ) )
+ {
+ i--;
+ }
+
+ string.erase( i, len - i );
+ }
+}
+
+
+// Replace line feeds with carriage return-line feed pairs.
+//static
+template<class T>
+void LLStringUtilBase<T>::addCRLF(std::basic_string<T>& string)
+{
+ const T LF = 10;
+ const T CR = 13;
+
+ // Count the number of line feeds
+ size_type count = 0;
+ size_type len = string.size();
+ size_type i;
+ for( i = 0; i < len; i++ )
+ {
+ if( string[i] == LF )
+ {
+ count++;
+ }
+ }
+
+ // Insert a carriage return before each line feed
+ if( count )
+ {
+ size_type size = len + count;
+ T *t = new T[size];
+ size_type j = 0;
+ for( i = 0; i < len; ++i )
+ {
+ if( string[i] == LF )
+ {
+ t[j] = CR;
+ ++j;
+ }
+ t[j] = string[i];
+ ++j;
+ }
+
+ string.assign(t, size);
+ }
+}
+
+// Remove all carriage returns
+//static
+template<class T>
+void LLStringUtilBase<T>::removeCRLF(std::basic_string<T>& string)
+{
+ const T CR = 13;
+
+ size_type cr_count = 0;
+ size_type len = string.size();
+ size_type i;
+ for( i = 0; i < len - cr_count; i++ )
+ {
+ if( string[i+cr_count] == CR )
+ {
+ cr_count++;
+ }
+
+ string[i] = string[i+cr_count];
+ }
+ string.erase(i, cr_count);
+}
+
+//static
+template<class T>
+void LLStringUtilBase<T>::replaceChar( std::basic_string<T>& string, T target, T replacement )
+{
+ size_type found_pos = 0;
+ for (found_pos = string.find(target, found_pos);
+ found_pos != std::basic_string<T>::npos;
+ found_pos = string.find(target, found_pos))
+ {
+ string[found_pos] = replacement;
+ }
+}
+
+//static
+template<class T>
+void LLStringUtilBase<T>::replaceNonstandardASCII( std::basic_string<T>& string, T replacement )
+{
+ const char LF = 10;
+ const S8 MIN = 32;
+// const S8 MAX = 127;
+
+ size_type len = string.size();
+ for( size_type i = 0; i < len; i++ )
+ {
+ // No need to test MAX < mText[i] because we treat mText[i] as a signed char,
+ // which has a max value of 127.
+ if( ( S8(string[i]) < MIN ) && (string[i] != LF) )
+ {
+ string[i] = replacement;
+ }
+ }
+}
+
+//static
+template<class T>
+void LLStringUtilBase<T>::replaceTabsWithSpaces( std::basic_string<T>& str, size_type spaces_per_tab )
+{
+ const T TAB = '\t';
+ const T SPACE = ' ';
+
+ std::basic_string<T> out_str;
+ // Replace tabs with spaces
+ for (size_type i = 0; i < str.length(); i++)
+ {
+ if (str[i] == TAB)
+ {
+ for (size_type j = 0; j < spaces_per_tab; j++)
+ out_str += SPACE;
+ }
+ else
+ {
+ out_str += str[i];
+ }
+ }
+ str = out_str;
+}
+
+//static
+template<class T>
+BOOL LLStringUtilBase<T>::containsNonprintable(const std::basic_string<T>& string)
+{
+ const char MIN = 32;
+ BOOL rv = FALSE;
+ for (size_type i = 0; i < string.size(); i++)
+ {
+ if(string[i] < MIN)
+ {
+ rv = TRUE;
+ break;
+ }
+ }
+ return rv;
+}
+
+//static
+template<class T>
+void LLStringUtilBase<T>::stripNonprintable(std::basic_string<T>& string)
+{
+ const char MIN = 32;
+ size_type j = 0;
+ if (string.empty())
+ {
+ return;
+ }
+ char* c_string = new char[string.size() + 1];
+ if(c_string == NULL)
+ {
+ return;
+ }
+ strcpy(c_string, string.c_str()); /*Flawfinder: ignore*/
+ char* write_head = &c_string[0];
+ for (size_type i = 0; i < string.size(); i++)
+ {
+ char* read_head = &string[i];
+ write_head = &c_string[j];
+ if(!(*read_head < MIN))
+ {
+ *write_head = *read_head;
+ ++j;
+ }
+ }
+ c_string[j]= '\0';
+ string = c_string;
+ delete []c_string;
+}
+
+template<class T>
+void LLStringUtilBase<T>::_makeASCII(std::basic_string<T>& string)
+{
+ // Replace non-ASCII chars with LL_UNKNOWN_CHAR
+ for (size_type i = 0; i < string.length(); i++)
+ {
+ if (string[i] > 0x7f)
+ {
+ string[i] = LL_UNKNOWN_CHAR;
+ }
+ }
+}
+
+// static
+template<class T>
+void LLStringUtilBase<T>::copy( T* dst, const T* src, size_type dst_size )
+{
+ if( dst_size > 0 )
+ {
+ size_type min_len = 0;
+ if( src )
+ {
+ min_len = llmin( dst_size - 1, strlen( src ) ); /* Flawfinder: ignore */
+ memcpy(dst, src, min_len * sizeof(T)); /* Flawfinder: ignore */
+ }
+ dst[min_len] = '\0';
+ }
+}
+
+// static
+template<class T>
+void LLStringUtilBase<T>::copyInto(std::basic_string<T>& dst, const std::basic_string<T>& src, size_type offset)
+{
+ if ( offset == dst.length() )
+ {
+ // special case - append to end of string and avoid expensive
+ // (when strings are large) string manipulations
+ dst += src;
+ }
+ else
+ {
+ std::basic_string<T> tail = dst.substr(offset);
+
+ dst = dst.substr(0, offset);
+ dst += src;
+ dst += tail;
+ };
+}
+
+// True if this is the head of s.
+//static
+template<class T>
+BOOL LLStringUtilBase<T>::isHead( const std::basic_string<T>& string, const T* s )
+{
+ if( string.empty() )
+ {
+ // Early exit
+ return FALSE;
+ }
+ else
+ {
+ return (strncmp( s, string.c_str(), string.size() ) == 0);
+ }
+}
+
+// static
+template<class T>
+bool LLStringUtilBase<T>::startsWith(
+ const std::basic_string<T>& string,
+ const std::basic_string<T>& substr)
+{
+ if(string.empty() || (substr.empty())) return false;
+ if(0 == string.find(substr)) return true;
+ return false;
+}
+
+// static
+template<class T>
+bool LLStringUtilBase<T>::endsWith(
+ const std::basic_string<T>& string,
+ const std::basic_string<T>& substr)
+{
+ if(string.empty() || (substr.empty())) return false;
+ std::string::size_type idx = string.rfind(substr);
+ if(std::string::npos == idx) return false;
+ return (idx == (string.size() - substr.size()));
+}
+
+
+template<class T>
+BOOL LLStringUtilBase<T>::convertToBOOL(const std::basic_string<T>& string, BOOL& value)
+{
+ if( string.empty() )
+ {
+ return FALSE;
+ }
+
+ std::basic_string<T> temp( string );
+ trim(temp);
+ if(
+ (temp == "1") ||
+ (temp == "T") ||
+ (temp == "t") ||
+ (temp == "TRUE") ||
+ (temp == "true") ||
+ (temp == "True") )
+ {
+ value = TRUE;
+ return TRUE;
+ }
+ else
+ if(
+ (temp == "0") ||
+ (temp == "F") ||
+ (temp == "f") ||
+ (temp == "FALSE") ||
+ (temp == "false") ||
+ (temp == "False") )
+ {
+ value = FALSE;
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+template<class T>
+BOOL LLStringUtilBase<T>::convertToU8(const std::basic_string<T>& string, U8& value)
+{
+ S32 value32 = 0;
+ BOOL success = convertToS32(string, value32);
+ if( success && (U8_MIN <= value32) && (value32 <= U8_MAX) )
+ {
+ value = (U8) value32;
+ return TRUE;
+ }
+ return FALSE;
+}
+
+template<class T>
+BOOL LLStringUtilBase<T>::convertToS8(const std::basic_string<T>& string, S8& value)
+{
+ S32 value32 = 0;
+ BOOL success = convertToS32(string, value32);
+ if( success && (S8_MIN <= value32) && (value32 <= S8_MAX) )
+ {
+ value = (S8) value32;
+ return TRUE;
+ }
+ return FALSE;
+}
+
+template<class T>
+BOOL LLStringUtilBase<T>::convertToS16(const std::basic_string<T>& string, S16& value)
+{
+ S32 value32 = 0;
+ BOOL success = convertToS32(string, value32);
+ if( success && (S16_MIN <= value32) && (value32 <= S16_MAX) )
+ {
+ value = (S16) value32;
+ return TRUE;
+ }
+ return FALSE;
+}
+
+template<class T>
+BOOL LLStringUtilBase<T>::convertToU16(const std::basic_string<T>& string, U16& value)
+{
+ S32 value32 = 0;
+ BOOL success = convertToS32(string, value32);
+ if( success && (U16_MIN <= value32) && (value32 <= U16_MAX) )
+ {
+ value = (U16) value32;
+ return TRUE;
+ }
+ return FALSE;
+}
+
+template<class T>
+BOOL LLStringUtilBase<T>::convertToU32(const std::basic_string<T>& string, U32& value)
+{
+ if( string.empty() )
+ {
+ return FALSE;
+ }
+
+ std::basic_string<T> temp( string );
+ trim(temp);
+ U32 v;
+ std::basic_istringstream<T> i_stream((std::basic_string<T>)temp);
+ if(i_stream >> v)
+ {
+ value = v;
+ return TRUE;
+ }
+ return FALSE;
+}
+
+template<class T>
+BOOL LLStringUtilBase<T>::convertToS32(const std::basic_string<T>& string, S32& value)
+{
+ if( string.empty() )
+ {
+ return FALSE;
+ }
+
+ std::basic_string<T> temp( string );
+ trim(temp);
+ S32 v;
+ std::basic_istringstream<T> i_stream((std::basic_string<T>)temp);
+ if(i_stream >> v)
+ {
+ //TODO: figure out overflow and underflow reporting here
+ //if((LONG_MAX == v) || (LONG_MIN == v))
+ //{
+ // // Underflow or overflow
+ // return FALSE;
+ //}
+
+ value = v;
+ return TRUE;
+ }
+ return FALSE;
+}
+
+template<class T>
+BOOL LLStringUtilBase<T>::convertToF32(const std::basic_string<T>& string, F32& value)
+{
+ F64 value64 = 0.0;
+ BOOL success = convertToF64(string, value64);
+ if( success && (-F32_MAX <= value64) && (value64 <= F32_MAX) )
+ {
+ value = (F32) value64;
+ return TRUE;
+ }
+ return FALSE;
+}
+
+template<class T>
+BOOL LLStringUtilBase<T>::convertToF64(const std::basic_string<T>& string, F64& value)
+{
+ if( string.empty() )
+ {
+ return FALSE;
+ }
+
+ std::basic_string<T> temp( string );
+ trim(temp);
+ F64 v;
+ std::basic_istringstream<T> i_stream((std::basic_string<T>)temp);
+ if(i_stream >> v)
+ {
+ //TODO: figure out overflow and underflow reporting here
+ //if( ((-HUGE_VAL == v) || (HUGE_VAL == v))) )
+ //{
+ // // Underflow or overflow
+ // return FALSE;
+ //}
+
+ value = v;
+ return TRUE;
+ }
+ return FALSE;
+}
+
+template<class T>
+void LLStringUtilBase<T>::truncate(std::basic_string<T>& string, size_type count)
+{
+ size_type cur_size = string.size();
+ string.resize(count < cur_size ? count : cur_size);
+}
+
+#endif // LL_STRING_H
diff --git a/indra/newview/llfloaterabout.cpp b/indra/newview/llfloaterabout.cpp
index 9df0a96888..61a031d502 100644
--- a/indra/newview/llfloaterabout.cpp
+++ b/indra/newview/llfloaterabout.cpp
@@ -1,282 +1,281 @@
-/**
- * @file llfloaterabout.cpp
- * @author James Cook
- * @brief The about box from Help->About
- *
- * $LicenseInfo:firstyear=2001&license=viewergpl$
- *
- * Copyright (c) 2001-2009, Linden Research, Inc.
- *
- * Second Life Viewer Source Code
- * The source code in this file ("Source Code") is provided by Linden Lab
- * to you under the terms of the GNU General Public License, version 2.0
- * ("GPL"), unless you have obtained a separate licensing agreement
- * ("Other License"), formally executed by you and Linden Lab. Terms of
- * the GPL can be found in doc/GPL-license.txt in this distribution, or
- * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
- *
- * There are special exceptions to the terms and conditions of the GPL as
- * it is applied to this Source Code. View the full text of the exception
- * in the file doc/FLOSS-exception.txt in this software distribution, or
- * online at
- * http://secondlifegrid.net/programs/open_source/licensing/flossexception
- *
- * By copying, modifying or distributing this software, you acknowledge
- * that you have read and understood your obligations described above,
- * and agree to abide by those obligations.
- *
- * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
- * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
- * COMPLETENESS OR PERFORMANCE.
- * $/LicenseInfo$
- */
-
-#include "llviewerprecompiledheaders.h"
-
-#include "llfloaterabout.h"
-
-#include "llsys.h"
-#include "llgl.h"
-#include "llui.h" // for tr()
-#include "v3dmath.h"
-
-#include "llcurl.h"
-#include "llimagej2c.h"
-#include "audioengine.h"
-
-#include "llviewertexteditor.h"
-#include "llviewercontrol.h"
-#include "llagent.h"
-#include "llviewerstats.h"
-#include "llviewerregion.h"
-#include "llversionviewer.h"
-#include "llviewerbuild.h"
-#include "lluictrlfactory.h"
-#include "lluri.h"
-#include "llweb.h"
-#include "llsecondlifeurls.h"
-#include "lltrans.h"
-#include "llappviewer.h"
-#include "llglheaders.h"
-#include "llmediamanager.h"
-#include "llwindow.h"
-
-#if LL_WINDOWS
-#include "lldxhardware.h"
-#endif
-
-extern LLCPUInfo gSysCPU;
-extern LLMemoryInfo gSysMemory;
-extern U32 gPacketsIn;
-
-static std::string get_viewer_release_notes_url();
-
-
-///----------------------------------------------------------------------------
-/// Class LLFloaterAbout
-///----------------------------------------------------------------------------
-
-// Default constructor
-LLFloaterAbout::LLFloaterAbout(const LLSD& key)
-: LLFloater()
-{
- //LLUICtrlFactory::getInstance()->buildFloater(this, "floater_about.xml");
-
-}
-
-// Destroys the object
-LLFloaterAbout::~LLFloaterAbout()
-{
-}
-
-BOOL LLFloaterAbout::postBuild()
-{
- center();
- LLViewerTextEditor *support_widget =
- getChild<LLViewerTextEditor>("support_editor", true);
-
- LLViewerTextEditor *credits_widget =
- getChild<LLViewerTextEditor>("credits_editor", true);
-
- // For some reason, adding style doesn't work unless this is true.
- support_widget->setParseHTML(TRUE);
-
- // Text styles for release notes hyperlinks
- LLStyleSP viewer_link_style(new LLStyle);
- viewer_link_style->setVisible(true);
- viewer_link_style->setFontName(LLStringUtil::null);
- viewer_link_style->setLinkHREF(get_viewer_release_notes_url());
- viewer_link_style->setColor(gSavedSkinSettings.getColor4("HTMLLinkColor"));
-
- // Version string
- std::string version = LLTrans::getString("SECOND_LIFE_VIEWER")
- + llformat(" %d.%d.%d (%d) %s %s (%s)\n",
- LL_VERSION_MAJOR, LL_VERSION_MINOR, LL_VERSION_PATCH, LL_VIEWER_BUILD,
- __DATE__, __TIME__,
- gSavedSettings.getString("VersionChannelName").c_str());
- support_widget->appendColoredText(version, FALSE, FALSE, LLUI::sSettingGroups["color"]->getColor("TextFgReadOnlyColor"));
- support_widget->appendStyledText(LLTrans::getString("ReleaseNotes"), false, false, viewer_link_style);
-
- std::string support;
- support.append("\n\n");
-
-#if LL_MSVC
- support.append(llformat("Built with MSVC version %d\n\n", _MSC_VER));
-#endif
-
-#if LL_GNUC
- support.append(llformat("Built with GCC version %d\n\n", GCC_VERSION));
-#endif
-
- // Position
- LLViewerRegion* region = gAgent.getRegion();
- if (region)
- {
- LLStyleSP server_link_style(new LLStyle);
- server_link_style->setVisible(true);
- server_link_style->setFontName(LLStringUtil::null);
- server_link_style->setLinkHREF(region->getCapability("ServerReleaseNotes"));
- server_link_style->setColor(gSavedSkinSettings.getColor4("HTMLLinkColor"));
-
- const LLVector3d &pos = gAgent.getPositionGlobal();
- LLUIString pos_text = getString("you_are_at");
- pos_text.setArg("[POSITION]",
- llformat("%.1f, %.1f, %.1f ", pos.mdV[VX], pos.mdV[VY], pos.mdV[VZ]));
- support.append(pos_text);
-
- LLUIString region_text = getString ("in_region") + " ";
- region_text.setArg("[REGION]", llformat ("%s", gAgent.getRegion()->getName().c_str()));
- support.append(region_text);
-
- std::string buffer;
- buffer = gAgent.getRegion()->getHost().getHostName();
- support.append(buffer);
- support.append(" (");
- buffer = gAgent.getRegion()->getHost().getString();
- support.append(buffer);
- support.append(")\n");
- support.append(gLastVersionChannel);
- support.append("\n");
-
- support_widget->appendColoredText(support, FALSE, FALSE, LLUI::sSettingGroups["color"]->getColor("TextFgReadOnlyColor"));
- support_widget->appendStyledText(LLTrans::getString("ReleaseNotes"), false, false, server_link_style);
-
- support = "\n\n";
- }
-
- // *NOTE: Do not translate text like GPU, Graphics Card, etc -
- // Most PC users that know what these mean will be used to the english versions,
- // and this info sometimes gets sent to support
-
- // CPU
- support.append(getString("CPU") + " ");
- support.append( gSysCPU.getCPUString() );
- support.append("\n");
-
- U32 memory = gSysMemory.getPhysicalMemoryKB() / 1024;
- // Moved hack adjustment to Windows memory size into llsys.cpp
-
- LLStringUtil::format_map_t args;
- args["[MEM]"] = llformat ("%u", memory);
- support.append(getString("Memory", args) + "\n");
-
- support.append(getString("OSVersion") + " ");
- support.append( LLAppViewer::instance()->getOSInfo().getOSString() );
- support.append("\n");
-
- support.append(getString("GraphicsCardVendor") + " ");
- support.append( (const char*) glGetString(GL_VENDOR) );
- support.append("\n");
-
- support.append(getString("GraphicsCard") + " ");
- support.append( (const char*) glGetString(GL_RENDERER) );
- support.append("\n");
-
-#if LL_WINDOWS
- getWindow()->incBusyCount();
- getWindow()->setCursor(UI_CURSOR_ARROW);
- support.append("Windows Graphics Driver Version: ");
- LLSD driver_info = gDXHardware.getDisplayInfo();
- if (driver_info.has("DriverVersion"))
- {
- support.append(driver_info["DriverVersion"]);
- }
- support.append("\n");
- getWindow()->decBusyCount();
- getWindow()->setCursor(UI_CURSOR_ARROW);
-#endif
-
- support.append(getString("OpenGLVersion") + " ");
- support.append( (const char*) glGetString(GL_VERSION) );
- support.append("\n");
-
- support.append("\n");
-
- support.append(getString("LibCurlVersion") + " ");
- support.append( LLCurl::getVersionString() );
- support.append("\n");
-
- support.append(getString("J2CDecoderVersion") + " ");
- support.append( LLImageJ2C::getEngineInfo() );
- support.append("\n");
-
- support.append(getString("AudioDriverVersion") + " ");
- bool want_fullname = true;
- support.append( gAudiop ? gAudiop->getDriverName(want_fullname) : getString("none") );
- support.append("\n");
-
- LLMediaManager *mgr = LLMediaManager::getInstance();
- if (mgr)
- {
- LLMediaBase *media_source = mgr->createSourceFromMimeType("http", "text/html");
- if (media_source)
- {
- support.append(getString("LLMozLibVersion") + " ");
- support.append(media_source->getVersion());
- support.append("\n");
- mgr->destroySource(media_source);
- }
- }
-
- if (gPacketsIn > 0)
- {
- args["[LOST]"] = llformat ("%.0f", LLViewerStats::getInstance()->mPacketsLostStat.getCurrent());
- args["[IN]"] = llformat ("%.0f", F32(gPacketsIn));
- args["[PCT]"] = llformat ("%.1f", 100.f*LLViewerStats::getInstance()->mPacketsLostStat.getCurrent() / F32(gPacketsIn) );
- support.append(getString ("PacketsLost", args) + "\n");
- }
-
- support_widget->appendColoredText(support, FALSE, FALSE, LLUI::sSettingGroups["color"]->getColor("TextFgReadOnlyColor"));
-
- // Fix views
- support_widget->setCursorPos(0);
- support_widget->setEnabled(FALSE);
- support_widget->setTakesFocus(TRUE);
- support_widget->setHandleEditKeysDirectly(TRUE);
-
- credits_widget->setCursorPos(0);
- credits_widget->setEnabled(FALSE);
- credits_widget->setTakesFocus(TRUE);
- credits_widget->setHandleEditKeysDirectly(TRUE);
-
- return TRUE;
-}
-
-
- static std::string get_viewer_release_notes_url()
- {
- std::ostringstream version;
- version << LL_VERSION_MAJOR << "."
- << LL_VERSION_MINOR << "."
- << LL_VERSION_PATCH << "."
- << LL_VERSION_BUILD;
-
- LLSD query;
- query["channel"] = gSavedSettings.getString("VersionChannelName");
- query["version"] = version.str();
-
- std::ostringstream url;
- url << LLTrans::getString("RELEASE_NOTES_BASE_URL") << LLURI::mapToQueryString(query);
-
- return url.str();
- }
+/**
+ * @file llfloaterabout.cpp
+ * @author James Cook
+ * @brief The about box from Help->About
+ *
+ * $LicenseInfo:firstyear=2001&license=viewergpl$
+ *
+ * Copyright (c) 2001-2009, Linden Research, Inc.
+ *
+ * Second Life Viewer Source Code
+ * The source code in this file ("Source Code") is provided by Linden Lab
+ * to you under the terms of the GNU General Public License, version 2.0
+ * ("GPL"), unless you have obtained a separate licensing agreement
+ * ("Other License"), formally executed by you and Linden Lab. Terms of
+ * the GPL can be found in doc/GPL-license.txt in this distribution, or
+ * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
+ *
+ * There are special exceptions to the terms and conditions of the GPL as
+ * it is applied to this Source Code. View the full text of the exception
+ * in the file doc/FLOSS-exception.txt in this software distribution, or
+ * online at
+ * http://secondlifegrid.net/programs/open_source/licensing/flossexception
+ *
+ * By copying, modifying or distributing this software, you acknowledge
+ * that you have read and understood your obligations described above,
+ * and agree to abide by those obligations.
+ *
+ * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
+ * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
+ * COMPLETENESS OR PERFORMANCE.
+ * $/LicenseInfo$
+ */
+
+#include "llviewerprecompiledheaders.h"
+
+#include "llfloaterabout.h"
+
+#include "llsys.h"
+#include "llgl.h"
+#include "llui.h" // for tr()
+#include "v3dmath.h"
+
+#include "llcurl.h"
+#include "llimagej2c.h"
+#include "audioengine.h"
+
+#include "llviewertexteditor.h"
+#include "llviewercontrol.h"
+#include "llagent.h"
+#include "llviewerstats.h"
+#include "llviewerregion.h"
+#include "llversionviewer.h"
+#include "llviewerbuild.h"
+#include "lluictrlfactory.h"
+#include "lluri.h"
+#include "llweb.h"
+#include "llsecondlifeurls.h"
+#include "lltrans.h"
+#include "llappviewer.h"
+#include "llglheaders.h"
+#include "llmediamanager.h"
+#include "llwindow.h"
+
+#if LL_WINDOWS
+#include "lldxhardware.h"
+#endif
+
+extern LLMemoryInfo gSysMemory;
+extern U32 gPacketsIn;
+
+static std::string get_viewer_release_notes_url();
+
+
+///----------------------------------------------------------------------------
+/// Class LLFloaterAbout
+///----------------------------------------------------------------------------
+
+// Default constructor
+LLFloaterAbout::LLFloaterAbout(const LLSD& key)
+: LLFloater()
+{
+ //LLUICtrlFactory::getInstance()->buildFloater(this, "floater_about.xml");
+
+}
+
+// Destroys the object
+LLFloaterAbout::~LLFloaterAbout()
+{
+}
+
+BOOL LLFloaterAbout::postBuild()
+{
+ center();
+ LLViewerTextEditor *support_widget =
+ getChild<LLViewerTextEditor>("support_editor", true);
+
+ LLViewerTextEditor *credits_widget =
+ getChild<LLViewerTextEditor>("credits_editor", true);
+
+ // For some reason, adding style doesn't work unless this is true.
+ support_widget->setParseHTML(TRUE);
+
+ // Text styles for release notes hyperlinks
+ LLStyleSP viewer_link_style(new LLStyle);
+ viewer_link_style->setVisible(true);
+ viewer_link_style->setFontName(LLStringUtil::null);
+ viewer_link_style->setLinkHREF(get_viewer_release_notes_url());
+ viewer_link_style->setColor(gSavedSkinSettings.getColor4("HTMLLinkColor"));
+
+ // Version string
+ std::string version = LLTrans::getString("SECOND_LIFE_VIEWER")
+ + llformat(" %d.%d.%d (%d) %s %s (%s)\n",
+ LL_VERSION_MAJOR, LL_VERSION_MINOR, LL_VERSION_PATCH, LL_VIEWER_BUILD,
+ __DATE__, __TIME__,
+ gSavedSettings.getString("VersionChannelName").c_str());
+ support_widget->appendColoredText(version, FALSE, FALSE, LLUI::sSettingGroups["color"]->getColor("TextFgReadOnlyColor"));
+ support_widget->appendStyledText(LLTrans::getString("ReleaseNotes"), false, false, viewer_link_style);
+
+ std::string support;
+ support.append("\n\n");
+
+#if LL_MSVC
+ support.append(llformat("Built with MSVC version %d\n\n", _MSC_VER));
+#endif
+
+#if LL_GNUC
+ support.append(llformat("Built with GCC version %d\n\n", GCC_VERSION));
+#endif
+
+ // Position
+ LLViewerRegion* region = gAgent.getRegion();
+ if (region)
+ {
+ LLStyleSP server_link_style(new LLStyle);
+ server_link_style->setVisible(true);
+ server_link_style->setFontName(LLStringUtil::null);
+ server_link_style->setLinkHREF(region->getCapability("ServerReleaseNotes"));
+ server_link_style->setColor(gSavedSkinSettings.getColor4("HTMLLinkColor"));
+
+ const LLVector3d &pos = gAgent.getPositionGlobal();
+ LLUIString pos_text = getString("you_are_at");
+ pos_text.setArg("[POSITION]",
+ llformat("%.1f, %.1f, %.1f ", pos.mdV[VX], pos.mdV[VY], pos.mdV[VZ]));
+ support.append(pos_text);
+
+ LLUIString region_text = getString ("in_region") + " ";
+ region_text.setArg("[REGION]", llformat ("%s", gAgent.getRegion()->getName().c_str()));
+ support.append(region_text);
+
+ std::string buffer;
+ buffer = gAgent.getRegion()->getHost().getHostName();
+ support.append(buffer);
+ support.append(" (");
+ buffer = gAgent.getRegion()->getHost().getString();
+ support.append(buffer);
+ support.append(")\n");
+ support.append(gLastVersionChannel);
+ support.append("\n");
+
+ support_widget->appendColoredText(support, FALSE, FALSE, LLUI::sSettingGroups["color"]->getColor("TextFgReadOnlyColor"));
+ support_widget->appendStyledText(LLTrans::getString("ReleaseNotes"), false, false, server_link_style);
+
+ support = "\n\n";
+ }
+
+ // *NOTE: Do not translate text like GPU, Graphics Card, etc -
+ // Most PC users that know what these mean will be used to the english versions,
+ // and this info sometimes gets sent to support
+
+ // CPU
+ support.append(getString("CPU") + " ");
+ support.append( gSysCPU.getCPUString() );
+ support.append("\n");
+
+ U32 memory = gSysMemory.getPhysicalMemoryKB() / 1024;
+ // Moved hack adjustment to Windows memory size into llsys.cpp
+
+ LLStringUtil::format_map_t args;
+ args["[MEM]"] = llformat ("%u", memory);
+ support.append(getString("Memory", args) + "\n");
+
+ support.append(getString("OSVersion") + " ");
+ support.append( LLAppViewer::instance()->getOSInfo().getOSString() );
+ support.append("\n");
+
+ support.append(getString("GraphicsCardVendor") + " ");
+ support.append( (const char*) glGetString(GL_VENDOR) );
+ support.append("\n");
+
+ support.append(getString("GraphicsCard") + " ");
+ support.append( (const char*) glGetString(GL_RENDERER) );
+ support.append("\n");
+
+#if LL_WINDOWS
+ getWindow()->incBusyCount();
+ getWindow()->setCursor(UI_CURSOR_ARROW);
+ support.append("Windows Graphics Driver Version: ");
+ LLSD driver_info = gDXHardware.getDisplayInfo();
+ if (driver_info.has("DriverVersion"))
+ {
+ support.append(driver_info["DriverVersion"]);
+ }
+ support.append("\n");
+ getWindow()->decBusyCount();
+ getWindow()->setCursor(UI_CURSOR_ARROW);
+#endif
+
+ support.append(getString("OpenGLVersion") + " ");
+ support.append( (const char*) glGetString(GL_VERSION) );
+ support.append("\n");
+
+ support.append("\n");
+
+ support.append(getString("LibCurlVersion") + " ");
+ support.append( LLCurl::getVersionString() );
+ support.append("\n");
+
+ support.append(getString("J2CDecoderVersion") + " ");
+ support.append( LLImageJ2C::getEngineInfo() );
+ support.append("\n");
+
+ support.append(getString("AudioDriverVersion") + " ");
+ bool want_fullname = true;
+ support.append( gAudiop ? gAudiop->getDriverName(want_fullname) : getString("none") );
+ support.append("\n");
+
+ LLMediaManager *mgr = LLMediaManager::getInstance();
+ if (mgr)
+ {
+ LLMediaBase *media_source = mgr->createSourceFromMimeType("http", "text/html");
+ if (media_source)
+ {
+ support.append(getString("LLMozLibVersion") + " ");
+ support.append(media_source->getVersion());
+ support.append("\n");
+ mgr->destroySource(media_source);
+ }
+ }
+
+ if (gPacketsIn > 0)
+ {
+ args["[LOST]"] = llformat ("%.0f", LLViewerStats::getInstance()->mPacketsLostStat.getCurrent());
+ args["[IN]"] = llformat ("%.0f", F32(gPacketsIn));
+ args["[PCT]"] = llformat ("%.1f", 100.f*LLViewerStats::getInstance()->mPacketsLostStat.getCurrent() / F32(gPacketsIn) );
+ support.append(getString ("PacketsLost", args) + "\n");
+ }
+
+ support_widget->appendColoredText(support, FALSE, FALSE, LLUI::sSettingGroups["color"]->getColor("TextFgReadOnlyColor"));
+
+ // Fix views
+ support_widget->setCursorPos(0);
+ support_widget->setEnabled(FALSE);
+ support_widget->setTakesFocus(TRUE);
+ support_widget->setHandleEditKeysDirectly(TRUE);
+
+ credits_widget->setCursorPos(0);
+ credits_widget->setEnabled(FALSE);
+ credits_widget->setTakesFocus(TRUE);
+ credits_widget->setHandleEditKeysDirectly(TRUE);
+
+ return TRUE;
+}
+
+
+ static std::string get_viewer_release_notes_url()
+ {
+ std::ostringstream version;
+ version << LL_VERSION_MAJOR << "."
+ << LL_VERSION_MINOR << "."
+ << LL_VERSION_PATCH << "."
+ << LL_VERSION_BUILD;
+
+ LLSD query;
+ query["channel"] = gSavedSettings.getString("VersionChannelName");
+ query["version"] = version.str();
+
+ std::ostringstream url;
+ url << LLTrans::getString("RELEASE_NOTES_BASE_URL") << LLURI::mapToQueryString(query);
+
+ return url.str();
+ }