From: Mikko Rasa Date: Fri, 25 May 2007 17:22:57 +0000 (+0000) Subject: Assimilate exceptions and RefPtr from mspmisc X-Git-Tag: 1.0~27 X-Git-Url: http://git.tdb.fi/?p=libs%2Fcore.git;a=commitdiff_plain;h=521cf1db00f8ce2d9f9494dca503d6c17d89ac2f Assimilate exceptions and RefPtr from mspmisc Assimilate GetOpt Do not require pthread on win32 Add an optional feature to generate backtraces on exceptions Allow semaphores to be created with an external mutex Rewrite win32 semaphore implementation to more closely correspond the POSIX one Allow MutexLock to be unlocked initially Rewrite MutexPtr to use a RefPtr instead of being refcounted itself Fix some multiple inclusion guards Add $Id$ tags Fix Time::now() on win32 --- diff --git a/Build b/Build index bec4c61..d172391 100644 --- a/Build +++ b/Build @@ -3,9 +3,13 @@ package "mspcore" version "0.1"; description "Mikkosoft Productions core library"; - require "mspmisc"; - require "pthread"; require "sigc++-2.0"; + if "arch!=win32" + { + require "pthread"; + }; + + feature "exception_backtrace" "Generate a backtrace when an exception is thrown."; library "mspcore" { diff --git a/source/core/application.cpp b/source/core/application.cpp index 1012ea2..0e93a9c 100644 --- a/source/core/application.cpp +++ b/source/core/application.cpp @@ -1,4 +1,5 @@ -/* +/* $Id$ + This file is part of libmspcore Copyright © 2006 Mikko Rasa, Mikkosoft Productions Distributed under the LGPL diff --git a/source/core/application.h b/source/core/application.h index fa0c9c4..81569ad 100644 --- a/source/core/application.h +++ b/source/core/application.h @@ -1,10 +1,11 @@ -/* +/* $Id$ + This file is part of libmspcore Copyright © 2006 Mikko Rasa, Mikkosoft Productions Distributed under the LGPL */ -#ifndef MSP_FRAMEWORK_APPLICATION_H_ -#define MSP_FRAMEWORK_APPLICATION_H_ +#ifndef MSP_CORE_APPLICATION_H_ +#define MSP_CORE_APPLICATION_H_ #include "semaphore.h" @@ -29,7 +30,7 @@ protected: TICK_SLEEP, /// Call tick every iteration, with a short sleep in between TICK_YIELD /// Call tick every iteration, with sched_yield in between }; - + class RegBase { public: diff --git a/source/core/error.cpp b/source/core/error.cpp new file mode 100644 index 0000000..727fa21 --- /dev/null +++ b/source/core/error.cpp @@ -0,0 +1,40 @@ +/* $Id$ + +This file is part of libmspcore +Copyright © 2006-2007 Mikko Rasa, Mikkosoft Productions +Distributed under the LGPL +*/ +#include +#include "backtrace.h" +#include "error.h" + +using namespace std; + +namespace Msp { + +Exception::Exception(const string &w_): + w(w_) +{ +#ifdef WITH_EXCEPTION_BACKTRACE + bt=Backtrace::create(); +#endif +} + +SystemError::SystemError(const string &w_, int e): + Exception(build_what(w_, e)), + err(e) +{ } + +string SystemError::build_what(const string &w, int e) +{ + ostringstream buf; + buf< +#include +#include +#include "backtrace.h" namespace Msp { -class UsageError: public Msp::Exception +/** +Base class for all Msp exceptions. +*/ +class Exception: public std::exception +{ +public: + Exception(const std::string &); + ~Exception() throw() { } + + const char *what() const throw() { return w.c_str(); } + const Backtrace &get_backtrace() const throw() { return bt; } +private: + std::string w; + Backtrace bt; + +}; + +/** +Thrown when a function parameter has an invalid value. +*/ +class InvalidParameterValue: public Exception +{ +public: + InvalidParameterValue(const std::string &w_): Exception(w_) { } +}; + +/** +Thrown when the current object state doesn't allow the requested action. +*/ +class InvalidState: public Exception +{ +public: + InvalidState(const std::string &w_): Exception(w_) { } +}; + +/** +Thrown when the application is invoked with wrong parameters. +*/ +class UsageError: public Exception { public: UsageError(const std::string &r, bool b=true): Exception(r), brief(b) { } @@ -19,6 +60,20 @@ private: bool brief; }; +/** +Thrown when a system call fails. +*/ +class SystemError: public Exception +{ +public: + SystemError(const std::string &, int); + int get_error_code() const { return err; } +private: + int err; + + static std::string build_what(const std::string &, int); +}; + } // namespace Msp #endif diff --git a/source/core/getopt.cpp b/source/core/getopt.cpp new file mode 100644 index 0000000..67c4d41 --- /dev/null +++ b/source/core/getopt.cpp @@ -0,0 +1,214 @@ +/* $Id$ + +This file is part of libmspcore +Copyright © 2006-2007 Mikko Rasa, Mikkosoft Productions +Distributed under the LGPL +*/ +#include "getopt.h" + +using namespace std; + +namespace Msp { + +/** +Generates a single line that gives an overview about the known options. + +@param argv0 The program name to be used in the usage string + +@return The generated usage string +*/ +string GetOpt::generate_usage(const string &argv0) const +{ + ostringstream line; + + line<::const_iterator i=opts.begin(); i!=opts.end(); ++i) + { + line<<" ["; + if((*i)->get_short()) + { + line<<'-'<<(*i)->get_short(); + if(!(*i)->get_long().empty()) + line<<'|'; + else if((*i)->get_arg_type()==OPTIONAL_ARG) + line<<"[ARG]"; + else if((*i)->get_arg_type()==REQUIRED_ARG) + line<<" ARG"; + } + if(!(*i)->get_long().empty()) + { + line<<"--"<<(*i)->get_long(); + + if((*i)->get_arg_type()==OPTIONAL_ARG) + line<<"[=ARG]"; + else if((*i)->get_arg_type()==REQUIRED_ARG) + line<<"=ARG"; + } + line<<']'; + } + + return line.str(); +} + +/** +Generates help for known options in tabular format, one option per line. +The returned string will have a linefeed at the end. +*/ +string GetOpt::generate_help() const +{ + string result; + for(list::const_iterator i=opts.begin(); i!=opts.end(); ++i) + { + ostringstream line; + line<<" "; + if((*i)->get_short()) + { + line<<'-'<<(*i)->get_short(); + if(!(*i)->get_long().empty()) + line<<", "; + else if((*i)->get_arg_type()==OPTIONAL_ARG) + line<<"[ARG]"; + else if((*i)->get_arg_type()==REQUIRED_ARG) + line<<" ARG"; + } + if(!(*i)->get_long().empty()) + { + line<<"--"<<(*i)->get_long(); + + if((*i)->get_arg_type()==OPTIONAL_ARG) + line<<"[=ARG]"; + else if((*i)->get_arg_type()==REQUIRED_ARG) + line<<"=ARG"; + } + + line<<" "<<(*i)->get_help()<<'\n'; + + result+=line.str(); + } + + return result; +} + +void GetOpt::operator()(unsigned argc, const char *const *argv) +{ + unsigned i=1; + for(; i::iterator i=opts.begin(); i!=opts.end(); ++i) + delete *i; +} + +GetOpt::OptBase &GetOpt::get_option(char s) +{ + for(list::iterator i=opts.begin(); i!=opts.end(); ++i) + if((*i)->get_short()==s) + return **i; + throw UsageError(string("Unknown option -")+s); +} + +GetOpt::OptBase &GetOpt::get_option(const string &l) +{ + for(list::iterator i=opts.begin(); i!=opts.end(); ++i) + if((*i)->get_long()==l) + return **i; + throw UsageError(string("Unknown option --")+l); +} + +/** +Processes the given argument as a long option. + +@param argp Pointer to the argument + +@return The number of arguments eaten (1 or 2) +*/ +unsigned GetOpt::process_long(const char *const *argp) +{ + // Skip the -- + const char *arg=argp[0]+2; + + // See if the argument contains an = + unsigned equals=0; + for(; arg[equals] && arg[equals]!='='; ++equals); + + OptBase &opt=get_option(string(arg, equals)); + + if(arg[equals]) + // Process the part after the = as option argument + opt.process(arg+equals+1); + else if(opt.get_arg_type()==REQUIRED_ARG) + { + if(!argp[1]) + throw UsageError("Premature end of arguments"); + + // Process the next argument as option argument + opt.process(argp[1]); + return 2; + } + else + opt.process(); + + return 1; +} + +/** +Processes short options from the given argument. + +@param argp Pointer to the argument + +@return The number of arguments eaten (1 or 2) +*/ +unsigned GetOpt::process_short(const char *const *argp) +{ + // Skip the - + const char *arg=argp[0]+1; + + // Loop through all characters in the argument + for(; *arg; ++arg) + { + OptBase &opt=get_option(*arg); + + if(arg[1] && opt.get_arg_type()!=NO_ARG) + { + // Need an option argument and we have characters left - use them + opt.process(arg+1); + return 1; + } + else if(opt.get_arg_type()==REQUIRED_ARG) + { + if(!argp[1]) + throw UsageError("Premature end of arguments"); + + // Use the next argument as option argument + opt.process(argp[1]); + return 2; + } + else + opt.process(); + } + + return 1; +} + +} // namespace Msp diff --git a/source/core/getopt.h b/source/core/getopt.h new file mode 100644 index 0000000..2824a0b --- /dev/null +++ b/source/core/getopt.h @@ -0,0 +1,144 @@ +/* $Id$ + +This file is part of libmspcore +Copyright © 2006-2007 Mikko Rasa, Mikkosoft Productions +Distributed under the LGPL +*/ +#ifndef MSP_CORE_GETOPT_H_ +#define MSP_CORE_GETOPT_H_ + +#include +#include +#include +#include "error.h" + +namespace Msp { + +class GetOpt +{ +public: + enum ArgType + { + NO_ARG, + OPTIONAL_ARG, + REQUIRED_ARG + }; + + class OptBase + { + public: + OptBase &set_help(const std::string &h) { help=h; return *this; } + char get_short() const { return shrt; } + const std::string &get_long() const { return lng; } + ArgType get_arg_type() const { return arg_type; } + const std::string &get_help() const { return help; } + unsigned get_seen_count() const { return seen_count; } + virtual void process()=0; + virtual void process(const std::string &)=0; + virtual ~OptBase() { } + protected: + char shrt; + std::string lng; + ArgType arg_type; + unsigned seen_count; + std::string help; + + OptBase(char s, const std::string &l, ArgType a): shrt(s), lng(l), arg_type(a), seen_count(0) { } + }; + + const std::list &get_args() const { return args; } + + template + OptBase &add_option(char s, const std::string &l, T &d, ArgType a=NO_ARG) + { opts.push_back(new Option(s, l, d, a)); return *opts.back(); } + + template + OptBase &add_option(char s, const std::string &l, std::list &d, ArgType a=REQUIRED_ARG) + { opts.push_back(new ListOption >(s, l, d, a)); return *opts.back(); } + + template + OptBase &add_option(const std::string &l, T &d, ArgType a) + { return add_option(0, l, d, a); } + + std::string generate_usage(const std::string &) const; + std::string generate_help() const; + void operator()(unsigned, const char *const *); + + ~GetOpt(); +private: + template + class Option: public OptBase + { + public: + Option(char s, const std::string &l, T &d, ArgType a): OptBase(s, l, a), data(d) { } + + virtual void process() + { + if(arg_type==REQUIRED_ARG) + throw UsageError("--"+lng+" requires an argument"); + process_(); + ++seen_count; + } + + virtual void process(const std::string &a) + { + if(arg_type==NO_ARG) + throw UsageError("--"+lng+" takes no argument"); + + T tmp; + std::istringstream ss(a); + ss>>tmp; + if(ss.fail()) + throw UsageError("Invalid argument for --"+lng); + + data=tmp; + ++seen_count; + } + private: + T &data; + + void process_() { } + }; + + template + class ListOption: public OptBase + { + public: + ListOption(char s, const std::string &l, T &d, ArgType a): OptBase(s, l, a), data(d) + { if(arg_type!=REQUIRED_ARG) throw Exception("ListOption with arg_type!=REQUIRED makes no sense"); } + + virtual void process() + { + throw UsageError("--"+lng+" requires an argument"); + } + + virtual void process(const std::string &a) + { + typename T::value_type tmp; + std::istringstream ss(a); + ss>>tmp; + if(ss.fail()) + throw UsageError("Invalid argument for --"+lng); + + data.push_back(tmp); + ++seen_count; + } + private: + T &data; + }; + + std::list opts; + std::list args; + + OptBase &get_option(char); + OptBase &get_option(const std::string &); + unsigned process_long(const char *const *); + unsigned process_short(const char *const *); +}; + +template<> inline void GetOpt::Option::process_() { data=true; } +template<> inline void GetOpt::Option::process_() { ++data; } + +} // namespace Msp + +#endif diff --git a/source/core/main.cpp b/source/core/main.cpp index de62f75..9fdaba2 100644 --- a/source/core/main.cpp +++ b/source/core/main.cpp @@ -1,4 +1,5 @@ -/* +/* $Id$ + This file is part of libmspcore Copyright © 2006 Mikko Rasa, Mikkosoft Productions Distributed under the LGPL @@ -10,10 +11,10 @@ Distributed under the LGPL #include "application.h" #ifdef WIN32 -int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) +int APIENTRY WinMain(HINSTANCE /*hInstance*/, HINSTANCE /*hPrevInstance*/, LPSTR /*lpCmdLine*/, int /*nCmdShow*/) { int argc = 0; - LPWSTR *argv = CommandLineToArgvW(GetCommandLineW(), &argc); + LPWSTR *argv=CommandLineToArgvW(GetCommandLineW(), &argc); return Msp::Application::run(argc, (char **)argv); } #endif diff --git a/source/core/mutex.h b/source/core/mutex.h index 146b982..8088a28 100644 --- a/source/core/mutex.h +++ b/source/core/mutex.h @@ -1,12 +1,13 @@ -/* +/* $Id$ + This file is part of libmspcore Copyright © 2006 Mikko Rasa, Mikkosoft Productions Distributed under the LGPL */ -#ifndef MSP_FRAMEWORK_MUTEX_H_ -#define MSP_FRAMEWORK_MUTEX_H_ +#ifndef MSP_CORE_MUTEX_H_ +#define MSP_CORE_MUTEX_H_ -#include +#include "refptr.h" #include "types.h" namespace Msp { @@ -33,11 +34,16 @@ private: friend class Semaphore; }; +/** +Locks the mutex for te lifetime of the object. +*/ class MutexLock { public: - MutexLock(Mutex &m): mutex(m) { mutex.lock(); } - ~MutexLock() { mutex.unlock(); } + MutexLock(Mutex &m, bool l=true): mutex(m) { if(l) mutex.lock(); } + ~MutexLock() { mutex.unlock(); } + + int lock() { return mutex.lock(); } private: Mutex &mutex; @@ -45,8 +51,25 @@ private: MutexLock &operator=(const MutexLock &); }; - +/** +Protects a pointer with a mutex. As long as the MutexPtr (or a copy of it) +exists, the mutex will stay locked. +*/ template +class MutexPtr +{ +public: + MutexPtr(T *d, Mutex &m): mutex(new MutexLock(m)), data(d) { } + + T &operator*() const { return *data; } + T *operator->() const { return data; } + void clear() { mutex=0; data=0; } +private: + RefPtr mutex; + T *data; +}; + +/*template class MutexPtr: public RefCount { public: @@ -69,7 +92,7 @@ protected: } return true; } -}; +};*/ } diff --git a/source/core/refptr.h b/source/core/refptr.h new file mode 100644 index 0000000..ee020e0 --- /dev/null +++ b/source/core/refptr.h @@ -0,0 +1,66 @@ +/* $Id$ + +This file is part of libmspcore +Copyright © 2006-2007 Mikko Rasa, Mikkosoft Productions +Distributed under the LGPL +*/ +#ifndef MSP_CORE_REFPTR_H_ +#define MSP_CORE_REFPTR_H_ + +namespace Msp { + +template +class RefPtr +{ +public: + RefPtr(): data(0), count(0) { } + RefPtr(T *d): data(d), count(0) { if(data) count=new unsigned(1); } + RefPtr(const RefPtr &p): data(p.data), count(p.count) { incref(); } + ~RefPtr() { decref(); } + + RefPtr &operator=(const RefPtr &p) + { + decref(); + data=p.data; + count=p.count; + incref(); + return *this; + } + + T *get() const { return data; } + T &operator*() const { return *data; } + T *operator->() const { return data; } + operator bool() const { return data!=0; } + + template + static RefPtr cast_dynamic(const RefPtr &p) { return RefPtr(dynamic_cast(p.get()), p.count); } + template friend class RefPtr; +private: + T *data; + unsigned *count; + + RefPtr(T *d, unsigned *c): data(d), count(c) { incref(); } + + void incref() + { + if(!count) return; + ++*count; + } + + void decref() + { + if(!count) return; + --*count; + if(!*count) + { + delete data; + delete count; + data=0; + count=0; + } + } +}; + +} // namespace Msp + +#endif diff --git a/source/core/semaphore.cpp b/source/core/semaphore.cpp index 9107a76..b9e7080 100644 --- a/source/core/semaphore.cpp +++ b/source/core/semaphore.cpp @@ -1,4 +1,5 @@ -/* +/* $Id$ + This file is part of libmspcore Copyright © 2006 Mikko Rasa, Mikkosoft Productions Distributed under the LGPL @@ -12,6 +13,63 @@ Distributed under the LGPL namespace Msp { +Semaphore::Semaphore(): + mutex(new Mutex), + own_mutex(true) +{ + init(); +} + +Semaphore::Semaphore(Mutex &m): + mutex(&m), + own_mutex(false) +{ + init(); +} + +#ifdef WIN32 +int Semaphore::signal() +{ + if(count==0) + return 0; + + int ret=!ReleaseSemaphore(sem, 1, 0); + + unsigned old_count=count; + mutex->unlock(); + while(count==old_count) + Sleep(0); + mutex->lock(); + + return ret; +} + +int Semaphore::broadcast() +{ + if(count==0) + return 0; + int ret=!ReleaseSemaphore(sem, count, 0); + + mutex->unlock(); + while(count) + Sleep(0); + mutex->lock(); + + return ret; +} + +int Semaphore::wait() +{ + ++count; + mutex->unlock(); + DWORD ret=WaitForSingleObject(sem, INFINITE); + mutex->lock(); + --count; + + return ret==WAIT_OBJECT_0; +} +#endif + int Semaphore::wait(const Time::TimeDelta &d) { #ifndef WIN32 @@ -21,15 +79,40 @@ int Semaphore::wait(const Time::TimeDelta &d) timeout.tv_sec=ts.raw()/1000000; timeout.tv_nsec=(ts.raw()%1000000)*1000; - MutexLock l(mutex); - int r=pthread_cond_timedwait(&sem, &mutex.mutex, &timeout); + int r=pthread_cond_timedwait(&sem, &mutex->mutex, &timeout); if(r==ETIMEDOUT) return 1; else if(r) return -1; return 0; #else - return WaitForSingleObject(sem, (DWORD)(d/Time::usec))==WAIT_OBJECT_0; + ++count; + mutex->lock(); + DWORD ret=WaitForSingleObject(sem, (DWORD)(d/Time::usec)); + mutex->unlock(); + --count; + return ret==WAIT_OBJECT_0; +#endif +} + +Semaphore::~Semaphore() +{ + if(own_mutex) + delete mutex; +#ifdef WIN32 + CloseHandle(sem); +#else + pthread_cond_destroy(&sem); +#endif +} + +void Semaphore::init() +{ +#ifdef WIN32 + count=0; + sem=CreateSemaphore(0, 0, 32, 0); +#else + pthread_cond_init(&sem, 0); #endif } diff --git a/source/core/semaphore.h b/source/core/semaphore.h index 1cf3cd6..c55553a 100644 --- a/source/core/semaphore.h +++ b/source/core/semaphore.h @@ -1,10 +1,11 @@ -/* +/* $Id$ + This file is part of libmspcore Copyright © 2006 Mikko Rasa, Mikkosoft Productions Distributed under the LGPL */ -#ifndef MSP_FRAMEWORK_SEMAPHORE_H_ -#define MSP_FRAMEWORK_SEMAPHORE_H_ +#ifndef MSP_CORE_SEMAPHORE_H_ +#define MSP_CORE_SEMAPHORE_H_ #include "mutex.h" #include "types.h" @@ -15,28 +16,36 @@ namespace Msp { class Semaphore { public: -#ifndef WIN32 - Semaphore() { pthread_cond_init(&sem, 0); } - int signal() { MutexLock l(mutex); return pthread_cond_signal(&sem); } - int broadcast() { MutexLock l(mutex); return pthread_cond_broadcast(&sem); } - int wait() { MutexLock l(mutex); return pthread_cond_wait(&sem, &mutex.mutex); } + Semaphore(); + Semaphore(Mutex &); + int signal(); + int broadcast(); + int wait(); int wait(const Time::TimeDelta &); - ~Semaphore() { pthread_cond_destroy(&sem); } -#else - Semaphore() { sem=CreateSemaphore(0, 0, 32, 0); } - int signal() { return !ReleaseSemaphore(sem, 1, 0); } - int broadcast() { return !ReleaseSemaphore(sem, 32, 0); } - int wait() { return WaitForSingleObject(sem, INFINITE)==WAIT_OBJECT_0; } - int wait(const Time::TimeDelta &); - ~Semaphore() { CloseHandle(sem); } -#endif + Mutex &get_mutex() { return *mutex; } + ~Semaphore(); private: -#ifndef WIN32 - Mutex mutex; -#endif + Mutex *mutex; + bool own_mutex; SemaphoreHandle sem; +#ifdef WIN32 + unsigned count; +#endif + + void init(); }; +#ifndef WIN32 +inline int Semaphore::signal() +{ return pthread_cond_signal(&sem); } + +inline int Semaphore::broadcast() +{ return pthread_cond_broadcast(&sem); } + +inline int Semaphore::wait() +{ return pthread_cond_wait(&sem, &mutex->mutex); } +#endif + } #endif diff --git a/source/core/thread.cpp b/source/core/thread.cpp index c7981cc..8e1134b 100644 --- a/source/core/thread.cpp +++ b/source/core/thread.cpp @@ -1,4 +1,5 @@ -/* +/* $Id$ + This file is part of libmspcore Copyright © 2006 Mikko Rasa, Mikkosoft Productions Distributed under the LGPL diff --git a/source/core/thread.h b/source/core/thread.h index 937d161..60a2e83 100644 --- a/source/core/thread.h +++ b/source/core/thread.h @@ -1,10 +1,11 @@ -/* +/* $Id$ + This file is part of libmspcore Copyright © 2006 Mikko Rasa, Mikkosoft Productions Distributed under the LGPL */ -#ifndef MSP_FRAMEWORK_THREAD_H_ -#define MSP_FRAMEWORK_THREAD_H_ +#ifndef MSP_CORE_THREAD_H_ +#define MSP_CORE_THREAD_H_ #include "types.h" @@ -36,13 +37,13 @@ private: Thread(const Thread &); Thread &operator=(const Thread &); + static #ifdef WIN32 -# define THREAD_RETURN_ DWORD WINAPI + DWORD WINAPI #else -# define THREAD_RETURN_ void * + void * #endif - static THREAD_RETURN_ main_(void *t) { ((Thread *)t)->main(); return 0; } -#undef THREAD_RETURN_ + main_(void *t) { ((Thread *)t)->main(); return 0; } }; } // namespace Msp diff --git a/source/core/types.h b/source/core/types.h index 885c523..0dace5a 100644 --- a/source/core/types.h +++ b/source/core/types.h @@ -1,10 +1,11 @@ -/* +/* $Id$ + This file is part of libmspcore Copyright © 2006 Mikko Rasa, Mikkosoft Productions Distributed under the LGPL */ -#ifndef MSP_FRAMEWORK_TYPES_H_ -#define MSP_FRAMEWORK_TYPES_H_ +#ifndef MSP_CORE_TYPES_H_ +#define MSP_CORE_TYPES_H_ #ifdef WIN32 #include diff --git a/source/debug/backtrace.cpp b/source/debug/backtrace.cpp new file mode 100644 index 0000000..2078996 --- /dev/null +++ b/source/debug/backtrace.cpp @@ -0,0 +1,45 @@ +/* $Id$ + +This file is part of libmspcore +Copyright © 2007 Mikko Rasa, Mikkosoft Productions +Distributed under the LGPL +*/ +#include +#include "backtrace.h" + +using namespace std; + +namespace Msp { +namespace Debug { + +Backtrace Backtrace::create() +{ +#ifndef WIN32 + void *addresses[50]; + int count=::backtrace(addresses, 50); + + char **symbols=backtrace_symbols(addresses, count); + + Backtrace bt; + for(int i=0; iaddress<<" in "<symbol<<'\n'; + + return out; +} + +} // namespace Debug +} // namespace Msp diff --git a/source/debug/backtrace.h b/source/debug/backtrace.h new file mode 100644 index 0000000..c570ce5 --- /dev/null +++ b/source/debug/backtrace.h @@ -0,0 +1,41 @@ +/* $Id$ + +This file is part of libmspcore +Copyright © 2007 Mikko Rasa, Mikkosoft Productions +Distributed under the LGPL +*/ +#ifndef MSP_DEBUG_BACKTRACE_H_ +#define MSP_DEBUG_BACKTRACE_H_ + +#include +#include +#include + +namespace Msp { +namespace Debug { + +class Backtrace +{ +public: + struct StackFrame + { + void *address; + std::string symbol; + + StackFrame(void *a, const std::string &s): address(a), symbol(s) { } + }; + typedef std::list FrameSeq; + + const FrameSeq &get_frames() const { return frames; } + + static Backtrace create(); +private: + FrameSeq frames; +}; + +std::ostream &operator<<(std::ostream &, const Backtrace &); + +} // namespace Debug +} // namespace Msp + +#endif diff --git a/source/debug/demangle.cpp b/source/debug/demangle.cpp new file mode 100644 index 0000000..58e05ce --- /dev/null +++ b/source/debug/demangle.cpp @@ -0,0 +1,50 @@ +/* $Id$ + +This file is part of libmspcore +Copyright © 2007 Mikko Rasa, Mikkosoft Productions +Distributed under the LGPL +*/ +#include "demangle.h" + +using namespace std; + +namespace Msp { +namespace Debug { + +string demangle_gcc3(const string &sym) +{ + string result; + + if(sym.compare(0, 2, "_Z")) + return result; + + string::const_iterator i=sym.begin()+2; + + bool nested=(*i=='N'); + bool first=true; + while(first || (nested && *i!='E')) + { + unsigned len=0; + for(; isdigit(*i); ++i) + len=len*10+(*i-'0'); + string::const_iterator j=i+len; + + if(!first) + result.append("::"); + result.append(i, j); + + first=false; + } + + if(nested) + ++i; + + for(; i!=sym.end(); ++i) + { + bool ref=(*i=='R'); + if(ref) ++i; + } +} + +} // namespace Debug +} // namespace Msp diff --git a/source/debug/demangle.h b/source/debug/demangle.h new file mode 100644 index 0000000..f8cab96 --- /dev/null +++ b/source/debug/demangle.h @@ -0,0 +1,20 @@ +/* $Id$ + +This file is part of libmspcore +Copyright © 2007 Mikko Rasa, Mikkosoft Productions +Distributed under the LGPL +*/ +#ifndef MSP_DEBUG_DEMANGLE_H_ +#define MSP_DEBUG_DEMANGLE_H_ + +#include + +namespace Msp { +namespace Debug { + +std::string demangle_gcc3(const std::string &); + +} // namespace Debug +} // namespace Msp + +#endif diff --git a/source/time/datetime.cpp b/source/time/datetime.cpp index 4fcec96..d74fc6f 100644 --- a/source/time/datetime.cpp +++ b/source/time/datetime.cpp @@ -1,7 +1,7 @@ /* $Id$ */ #include #include -#include +#include "../core/error.h" #include "datetime.h" #include "timestamp.h" @@ -40,9 +40,6 @@ inline int cmp_(T a, T b) } -#include -using namespace std; - namespace Msp { namespace Time { @@ -68,12 +65,32 @@ DateTime::DateTime(int32_t y, uint8_t m, uint8_t d): usec(0) { } +DateTime::DateTime(int32_t y, uint8_t m, uint8_t d, uint8_t h, uint8_t n, uint8_t s): + year(y), + month(m), + mday(d), + hour(h), + minute(n), + second(s), + usec(0) +{ } + +DateTime::DateTime(int32_t y, uint8_t m, uint8_t d, uint8_t h, uint8_t n, uint8_t s, uint32_t u): + year(y), + month(m), + mday(d), + hour(h), + minute(n), + second(s), + usec(u) +{ } + void DateTime::add_days(int32_t days) { unsigned new_year=year; /* Leap years have a 400 year cycle, so any 400 consecutive years have a - constant number of days */ + constant number of days (400*365+97=146097) */ new_year+=days/146097*400; days%=146097; diff --git a/source/time/timedelta.cpp b/source/time/timedelta.cpp index f7b037e..7d3d4bb 100644 --- a/source/time/timedelta.cpp +++ b/source/time/timedelta.cpp @@ -14,7 +14,7 @@ namespace { void print_part(ostream &out, int64_t &value, int64_t unit, char sep, bool &first) { - if(!value || (value - TimeDelta operator*(T a) const { return TimeDelta((int64_t)(usec*a)); } + TimeDelta operator*(T a) const { return TimeDelta(int64_t(usec*a)); } template - TimeDelta &operator*=(T a) { usec=(int64_t)(usec*a); return *this; } + TimeDelta &operator*=(T a) { usec=int64_t(usec*a); return *this; } template - TimeDelta operator/(T a) const { return TimeDelta((int64_t)(usec/a)); } + TimeDelta operator/(T a) const { return TimeDelta(int64_t(usec/a)); } template - TimeDelta &operator/=(T a) { usec=(int64_t)(usec/a); return *this; } + TimeDelta &operator/=(T a) { usec=int64_t(usec/a); return *this; } - double operator/(const TimeDelta &t) const { return (double)usec/t.usec; } + double operator/(const TimeDelta &t) const { return double(usec)/t.usec; } bool operator>(const TimeDelta &t) const { return usec>t.usec; } bool operator>=(const TimeDelta &t) const { return usec>=t.usec; } diff --git a/source/time/utils.cpp b/source/time/utils.cpp index ad0d245..f4a5379 100644 --- a/source/time/utils.cpp +++ b/source/time/utils.cpp @@ -44,12 +44,12 @@ TimeStamp now() FILETIME ft; SystemTimeToFileTime(&st, &ft); - epoch=(ft.dwLowDateTime+(int64_t)ft.dwHighDateTime<<32)/10; + epoch=(ft.dwLowDateTime+((int64_t)ft.dwHighDateTime<<32))/10; } FILETIME ft; GetSystemTimeAsFileTime(&ft); - return TimeStamp((ft.dwLowDateTime+(int64_t)ft.dwHighDateTime<<32)/10-epoch); + return TimeStamp((ft.dwLowDateTime+((int64_t)ft.dwHighDateTime<<32))/10-epoch); #endif } diff --git a/source/time/utils.h b/source/time/utils.h index bc04bad..59fe0c2 100644 --- a/source/time/utils.h +++ b/source/time/utils.h @@ -6,6 +6,8 @@ Distributed under the LGPL #ifndef MSP_TIME_UTILS_H_ #define MSP_TIME_UTILS_H_ +#include + namespace Msp { namespace Time {