};
};
+ if_arch "darwin"
+ {
+ build_info
+ {
+ library "Foundation.framework";
+ };
+ };
+
feature "zlib" "Support compression with zlib"
{
default "yes";
}
}
+JavaVM *MainThread::get_java_vm() const
+{
+ if(!activity)
+ return 0;
+
+ return activity->vm;
+}
+
void MainThread::set_window_flags(unsigned set, unsigned clear)
{
ANativeActivity_setWindowFlags(activity, set, clear);
void wait_for_app_created();
void resume_startup();
+ JavaVM *get_java_vm() const;
AAssetManager *get_asset_manager() const { return asset_manager; }
const FS::Path &get_internal_data_path() const { return int_data_path; }
#define MSP_CORE_APPLICATION_H_
#include <stdexcept>
+#include <string>
namespace Msp {
Private *priv;
+ Mutex(const Mutex &);
+ Mutex &operator=(const Mutex &);
public:
Mutex();
~Mutex();
namespace Msp {
-Thread::Thread():
+Thread::Thread(const string &name):
priv_(new Private),
+ name_(name),
state_(PENDING)
{ }
ThreadReturn THREAD_CALL Thread::Private::main_wrapper(void *arg)
{
Thread *thread = reinterpret_cast<Thread *>(arg);
+ thread->platform_setname();
thread->main();
thread->state_ = FINISHED;
return 0;
#ifndef MSP_CORE_THREAD_H_
#define MSP_CORE_THREAD_H_
+#include <string>
+
namespace Msp {
/**
};
Private *priv_;
+ std::string name_;
State state_;
protected:
- Thread();
+ Thread(const std::string & = std::string());
private:
Thread(const Thread &);
Thread &operator=(const Thread &);
public:
virtual ~Thread();
+ const std::string &get_name() const { return name_; }
+
/** Indicates whether the thread has finished running. */
bool is_finished() { return state_>=FINISHED; }
void platform_join();
void platform_kill();
void platform_launch();
+ void platform_setname();
protected:
virtual void main() = 0;
pthread_create(&priv_->handle, 0, &Private::main_wrapper, this);
}
+void Thread::platform_setname()
+{
+ if(!name_.empty())
+ pthread_setname_np(priv_->handle, name_.c_str());
+}
+
} // namespace Msp
priv_->handle = CreateThread(0, 0, &Private::main_wrapper, this, 0, &dummy);
}
+void Thread::platform_setname()
+{
+ // TODO: https://msdn.microsoft.com/en-us/library/xcb2z8hs.aspx
+}
+
} // namespace Msp
// Must include something to test for glibc
#include <cstdlib>
-#if !defined(WIN32) && defined(__GLIBC__)
+#if !defined(_WIN32) && defined(__GLIBC__)
#include <dlfcn.h>
#include <execinfo.h>
#endif
Backtrace Backtrace::create()
{
-#if !defined(WIN32) && defined(__GLIBC__)
+#if !defined(_WIN32) && defined(__GLIBC__)
void *addresses[50];
int count = ::backtrace(addresses, 50);
enum
{
-#ifdef WIN32
+#ifdef _WIN32
ITEMSEP = ';'
#else
ITEMSEP = ':'
for(Path::Iterator i=path.begin(); i!=path.end(); ++i)
{
p /= *i;
-#ifdef WIN32
+#ifdef _WIN32
if(p.size()==1 && p.is_absolute())
continue;
#endif
--- /dev/null
+#import <Foundation/NSPathUtilities.h>
+
+unsigned get_home_dir(char *buf, unsigned size)
+{
+ NSString *path = NSHomeDirectory();
+ if(![path getCString:buf maxLength:size encoding:NSUTF8StringEncoding])
+ return 0;
+
+ return [path lengthOfBytesUsingEncoding:NSUTF8StringEncoding];
+}
+
+unsigned get_application_support_dir(char *buf, unsigned size)
+{
+ NSArray *dirs = NSSearchPathForDirectoriesInDomains(NSApplicationSupportDirectory, NSUserDomainMask, YES);
+ if(![dirs count])
+ return 0;
+
+ NSString *path = [dirs objectAtIndex:0];
+ if(![path getCString:buf maxLength:size encoding:NSUTF8StringEncoding])
+ return 0;
+
+ return [path lengthOfBytesUsingEncoding:NSUTF8StringEncoding];
+}
--- /dev/null
+#include "dir.h"
+
+using namespace std;
+
+extern "C" unsigned get_home_dir(char *, unsigned);
+extern "C" unsigned get_application_support_dir(char *, unsigned);
+
+namespace Msp {
+namespace FS {
+
+Path get_home_dir()
+{
+ char buf[1024];
+ unsigned len = ::get_home_dir(buf, sizeof(buf));
+ if(len)
+ return string(buf, len);
+
+ const char *home = getenv("HOME");
+ if(home)
+ return home;
+
+ return ".";
+}
+
+Path get_user_data_dir(const string &appname)
+{
+ char buf[1024];
+ unsigned len = get_application_support_dir(buf, sizeof(buf));
+ if(len)
+ return Path(string(buf, len))/appname;
+ return get_home_dir()/"Library"/"Application Support"/appname;
+}
+
+} // namespace FS
+} // namespace Msp
namespace {
-#ifdef WIN32
+#ifdef _WIN32
inline bool is_windows_drive(const std::string &p)
{ return (p.size()==2 && ((p[0]>='A' && p[0]<='Z') || (p[0]>='a' && p[0]<='z')) && p[1]==':'); }
#endif
bool Path::is_absolute() const
{
-#ifdef WIN32
+#ifdef _WIN32
if(is_windows_drive((*this)[0]))
return true;
#endif
if(comp.size()==1 && (comp[0]=='/' || comp[0]=='\\'))
{
// Replace the path with the root directory
-#ifdef WIN32
+#ifdef _WIN32
string::size_type slash = (separators.empty() ? string::npos : separators.front());
if(is_windows_drive(path.substr(0, slash)))
{
separators.push_back(0);
}
}
-#ifdef WIN32
+#ifdef _WIN32
else if(is_windows_drive(comp))
{
path = comp;
// .. in root directory is a no-op
else if(path.size()==1 && path[0]==DIRSEP)
;
-#ifdef WIN32
+#ifdef _WIN32
else if(is_windows_drive(path))
;
#endif
bool Path::operator==(const Path &other) const
{
-#ifdef WIN32
+#ifdef _WIN32
return strcasecmp(path, other.path)==0;
#else
return path==other.path;
bool Path::operator<(const Path &other) const
{
-#ifdef WIN32
+#ifdef _WIN32
return strcasecmp(path, other.path)<0;
#else
return path<other.path;
bool Path::operator>(const Path &other) const
{
-#ifdef WIN32
+#ifdef _WIN32
return strcasecmp(path, other.path)>0;
#else
return path>other.path;
enum
{
-#ifdef WIN32
+#ifdef _WIN32
DIRSEP = '\\'
#else
DIRSEP = '/'
Private(const Private &);
~Private();
-#ifndef WIN32
+#ifndef _WIN32
/* This is here because it needs access to private members of Stat, but we
can't expose the system stat struct in the public header */
static Stat from_struct_stat(const struct stat &);
/**
Common interface for all I/O objects.
-
-A derived class must call set_events(P_NONE) before it is destroyed to avoid
-leaving stale pointers in an EventDispatcher.
*/
class Base
{
if(size==0)
return 0;
-#ifdef WIN32
+#ifdef _WIN32
if(mode&M_APPEND)
seek(0, S_END);
#endif
}
else if(ev)
{
-#ifdef WIN32
+#ifdef _WIN32
if(objects.size()>=MAXIMUM_WAIT_OBJECTS)
throw logic_error("Maximum number of wait objects reached");
#endif
namespace Msp {
namespace IO {
+/* Android libc does not recognize _FILE_OFFSET_BITS so this hack is necessary
+to get 64-bit seeks. */
+#ifdef __ANDROID__
+#define off_t off64_t
+#define lseek lseek64
+#endif
+
SeekOffset sys_seek(Handle &handle, SeekOffset offset, SeekType type)
{
off_t ret = lseek(*handle, offset, sys_seek_type(type));
#include <cstdlib>
#include <stdexcept>
#include <msp/strings/format.h>
+#include <msp/strings/regex.h>
#include "datetime.h"
#include "timestamp.h"
throw out_of_range("DateTime::DateTime mday");
}
+DateTime DateTime::parse_rfc3339(const string &str)
+{
+ static Regex re("^([0-9]{4})-([0-9]{2})-([0-9]{2})T([0-9]{2}):([0-9]{2}):([0-9]{2})(Z|[-+]([0-9]{2}):([0-9]{2}))$");
+
+ RegMatch m = re.match(str);
+ if(!m)
+ throw invalid_argument("DateTime::parse_rfc3339");
+
+ unsigned year = lexical_cast<unsigned>(m[1].str);
+ unsigned month = lexical_cast<unsigned>(m[2].str);
+ unsigned mday = lexical_cast<unsigned>(m[3].str);
+ unsigned hr = lexical_cast<unsigned>(m[4].str);
+ unsigned minute = lexical_cast<unsigned>(m[5].str);
+ unsigned second = lexical_cast<unsigned>(m[6].str);
+
+ DateTime result = DateTime(year, month, mday, hr, minute, second);
+
+ int tzoff = 0;
+ if(m[7].str!="Z")
+ {
+ tzoff = lexical_cast<unsigned>(m[8].str)*60+lexical_cast<unsigned>(m[9].str);
+ if(m[7].str[0]=='-')
+ tzoff = -tzoff;
+ }
+
+ result.set_timezone(tzoff);
+
+ return result;
+}
+
void DateTime::add_days(int days)
{
int new_year = year;
void init(int, unsigned char, unsigned char, unsigned char, unsigned char, unsigned char, unsigned);
public:
+ static DateTime parse_rfc3339(const std::string &);
+
int get_year() const { return year; }
unsigned char get_month() const { return month; }
unsigned char get_mday() const { return mday; }
inline void operator<<(LexicalConverter &c, const DateTime &d)
{ c.result(d.format_rfc3339()); }
+inline void operator>>(const LexicalConverter &c, DateTime &d)
+{ d = DateTime::parse_rfc3339(c.get()); }
+
} // namespace Time
} // namespace Msp
#include <algorithm>
+#include <msp/core/raii.h>
#include "timer.h"
#include "utils.h"
void Timer::tick(bool block)
{
+ if(block)
+ tick();
+ else
+ tick(zero);
+}
+
+void Timer::tick()
+{
+ do_tick(-sec);
+}
+
+void Timer::tick(const TimeDelta &timeout)
+{
+ if(timeout<zero)
+ throw invalid_argument("Timer::tick");
+
+ do_tick(timeout);
+}
+
+void Timer::do_tick(const TimeDelta &timeout)
+{
+ TimeStamp deadline;
+ if(timeout>=zero)
+ deadline = now()+timeout;
+
Slot *next = 0;
{
MutexLock l(mutex);
while(1)
{
- if(slots.empty())
+ TimeStamp stamp;
+ TimeStamp t = now();
+ if(!slots.empty())
{
- if(block)
- {
- blocking = true;
- mutex.unlock();
- sem.wait();
- mutex.lock();
- }
- else
- return;
+ next = slots.begin()->slot;
+ stamp = next->get_timeout();
+ if(stamp<=t)
+ break;
}
- next = slots.begin()->slot;
- const TimeStamp &stamp = next->get_timeout();
- const TimeStamp t = now();
- if(stamp<=t)
- break;
- else if(block)
+ if(timeout && (!deadline || t<deadline))
{
- blocking = true;
+ SetFlag setf(blocking);
mutex.unlock();
- sem.wait(stamp-t);
+ if(stamp && (!deadline || stamp<deadline))
+ sem.wait(stamp-t);
+ else if(deadline)
+ sem.wait(deadline-t);
+ else
+ sem.wait();
mutex.lock();
+ // The slots may have changed while waiting so check again
+ continue;
}
else
return;
/** Cancels a previously added timer. */
void cancel(Slot &);
- /** Checks all timers, executing any that have timed out. If block is true,
- waits until one times out.
+ /** Deprecated. Use one of the other overloads. */
+ void tick(bool block);
- Note: If there are no active timers when a blocking tick is executed, it
- won't return until a timer is added from another thread. */
- void tick(bool block = true);
+ /** Waits until a timer expires, then executes it. If no timers have been
+ set, blocks until one is added from another thread. */
+ void tick();
+ /** Waits until a timer expires but at most the specified amount of time.
+ If a timer did expire before the timeout, it is executed. */
+ void tick(const TimeDelta &);
+
+private:
+ void do_tick(const TimeDelta &);
+
+public:
TimeStamp get_next_timeout() const;
};