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"
{
-/*
+/* $Id$
+
This file is part of libmspcore
Copyright © 2006 Mikko Rasa, Mikkosoft Productions
Distributed under the LGPL
-/*
+/* $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"
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:
--- /dev/null
+/* $Id$
+
+This file is part of libmspcore
+Copyright © 2006-2007 Mikko Rasa, Mikkosoft Productions
+Distributed under the LGPL
+*/
+#include <sstream>
+#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<<w<<": ";
+#ifdef WIN32
+ buf<<e;
+#else
+ buf<<strerror(e);
+#endif
+ return buf.str();
+}
+
+} // namespace Msp
-/*
+/* $Id$
+
This file is part of libmspcore
-Copyright © 2006 Mikko Rasa, Mikkosoft Productions
+Copyright © 2006-2007 Mikko Rasa, Mikkosoft Productions
Distributed under the LGPL
*/
-#ifndef MSP_FRAMEWORK_ERRORS_H_
-#define MSP_FRAMEWORK_ERRORS_H_
+#ifndef MSP_CORE_ERROR_H_
+#define MSP_CORE_ERROR_H_
-#include <msp/error.h>
+#include <exception>
+#include <string>
+#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) { }
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
--- /dev/null
+/* $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<<argv0;
+ for(list<OptBase *>::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<OptBase *>::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<argc;)
+ {
+ if(argv[i][0]=='-')
+ {
+ if(argv[i][1]=='-')
+ {
+ if(!argv[i][2])
+ break;
+
+ i+=process_long(argv+i);
+ }
+ else
+ i+=process_short(argv+i);
+ }
+ else
+ args.push_back(argv[i++]);
+ }
+
+ for(; i<argc; ++i)
+ args.push_back(argv[i]);
+}
+
+GetOpt::~GetOpt()
+{
+ for(list<OptBase *>::iterator i=opts.begin(); i!=opts.end(); ++i)
+ delete *i;
+}
+
+GetOpt::OptBase &GetOpt::get_option(char s)
+{
+ for(list<OptBase *>::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<OptBase *>::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
--- /dev/null
+/* $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 <list>
+#include <sstream>
+#include <string>
+#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<std::string> &get_args() const { return args; }
+
+ template<typename T>
+ OptBase &add_option(char s, const std::string &l, T &d, ArgType a=NO_ARG)
+ { opts.push_back(new Option<T>(s, l, d, a)); return *opts.back(); }
+
+ template<typename T>
+ OptBase &add_option(char s, const std::string &l, std::list<T> &d, ArgType a=REQUIRED_ARG)
+ { opts.push_back(new ListOption<std::list<T> >(s, l, d, a)); return *opts.back(); }
+
+ template<typename T>
+ 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<typename T>
+ 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<typename T>
+ 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<OptBase *> opts;
+ std::list<std::string> 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<bool>::process_() { data=true; }
+template<> inline void GetOpt::Option<unsigned>::process_() { ++data; }
+
+} // namespace Msp
+
+#endif
-/*
+/* $Id$
+
This file is part of libmspcore
Copyright © 2006 Mikko Rasa, Mikkosoft Productions
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
-/*
+/* $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 <msp/refcount.h>
+#include "refptr.h"
#include "types.h"
namespace Msp {
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;
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<typename T>
+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<MutexLock> mutex;
+ T *data;
+};
+
+/*template<typename T>
class MutexPtr: public RefCount
{
public:
}
return true;
}
-};
+};*/
}
--- /dev/null
+/* $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<typename T>
+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<typename U>
+ static RefPtr<T> cast_dynamic(const RefPtr<U> &p) { return RefPtr<T>(dynamic_cast<T *>(p.get()), p.count); }
+ template<typename U> 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
-/*
+/* $Id$
+
This file is part of libmspcore
Copyright © 2006 Mikko Rasa, Mikkosoft Productions
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
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
}
-/*
+/* $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"
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
-/*
+/* $Id$
+
This file is part of libmspcore
Copyright © 2006 Mikko Rasa, Mikkosoft Productions
Distributed under the LGPL
-/*
+/* $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"
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
-/*
+/* $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 <windows.h>
--- /dev/null
+/* $Id$
+
+This file is part of libmspcore
+Copyright © 2007 Mikko Rasa, Mikkosoft Productions
+Distributed under the LGPL
+*/
+#include <execinfo.h>
+#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; i<count; ++i)
+ bt.frames.push_back(StackFrame(addresses[i], symbols[i]));
+
+ free(symbols);
+
+ return bt;
+#else
+ return Backtrace();
+#endif
+}
+
+ostream &operator<<(ostream &out, const Backtrace &bt)
+{
+ const Backtrace::FrameSeq &frames=bt.get_frames();
+ for(Backtrace::FrameSeq::const_iterator i=frames.begin(); i!=frames.end(); ++i)
+ out<<i->address<<" in "<<i->symbol<<'\n';
+
+ return out;
+}
+
+} // namespace Debug
+} // namespace Msp
--- /dev/null
+/* $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 <list>
+#include <ostream>
+#include <string>
+
+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<StackFrame> 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
--- /dev/null
+/* $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
--- /dev/null
+/* $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 <string>
+
+namespace Msp {
+namespace Debug {
+
+std::string demangle_gcc3(const std::string &);
+
+} // namespace Debug
+} // namespace Msp
+
+#endif
/* $Id$ */
#include <sstream>
#include <iomanip>
-#include <msp/error.h>
+#include "../core/error.h"
#include "datetime.h"
#include "timestamp.h"
}
-#include <iostream>
-using namespace std;
-
namespace Msp {
namespace Time {
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;
void print_part(ostream &out, int64_t &value, int64_t unit, char sep, bool &first)
{
- if(!value || (value<unit && first))
+ if(value<unit && first)
return;
if(!first)
TimeDelta &operator-=(const TimeDelta &t) { usec-=t.usec; return *this; }
template<typename T>
- TimeDelta operator*(T a) const { return TimeDelta((int64_t)(usec*a)); }
+ TimeDelta operator*(T a) const { return TimeDelta(int64_t(usec*a)); }
template<typename T>
- TimeDelta &operator*=(T a) { usec=(int64_t)(usec*a); return *this; }
+ TimeDelta &operator*=(T a) { usec=int64_t(usec*a); return *this; }
template<typename T>
- TimeDelta operator/(T a) const { return TimeDelta((int64_t)(usec/a)); }
+ TimeDelta operator/(T a) const { return TimeDelta(int64_t(usec/a)); }
template<typename T>
- 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; }
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
}
#ifndef MSP_TIME_UTILS_H_
#define MSP_TIME_UTILS_H_
+#include <string>
+
namespace Msp {
namespace Time {