From: Mikko Rasa Date: Wed, 27 Jul 2016 15:49:16 +0000 (+0300) Subject: Merge agouti:prog/core X-Git-Url: http://git.tdb.fi/?p=libs%2Fcore.git;a=commitdiff_plain;h=1a563cfd722a5571428562259790b4948980dd4f;hp=970a9aee41d1e0b7aecdd972583e7396433a739f Merge agouti:prog/core --- diff --git a/Build b/Build index d940f4a..12e3114 100644 --- a/Build +++ b/Build @@ -24,6 +24,14 @@ package "mspcore" }; }; + if_arch "darwin" + { + build_info + { + library "Foundation.framework"; + }; + }; + feature "zlib" "Support compression with zlib" { default "yes"; diff --git a/source/core/android/mainthread.cpp b/source/core/android/mainthread.cpp index 255eaa3..8ce484a 100644 --- a/source/core/android/mainthread.cpp +++ b/source/core/android/mainthread.cpp @@ -51,6 +51,14 @@ void MainThread::resume_startup() } } +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); diff --git a/source/core/android/mainthread.h b/source/core/android/mainthread.h index 22309ee..609300f 100644 --- a/source/core/android/mainthread.h +++ b/source/core/android/mainthread.h @@ -34,6 +34,7 @@ public: 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; } diff --git a/source/core/application.h b/source/core/application.h index 6b3ec1a..d0985be 100644 --- a/source/core/application.h +++ b/source/core/application.h @@ -2,6 +2,7 @@ #define MSP_CORE_APPLICATION_H_ #include +#include namespace Msp { diff --git a/source/core/mutex.h b/source/core/mutex.h index 0fe9e82..71fbdf0 100644 --- a/source/core/mutex.h +++ b/source/core/mutex.h @@ -18,6 +18,8 @@ private: Private *priv; + Mutex(const Mutex &); + Mutex &operator=(const Mutex &); public: Mutex(); ~Mutex(); diff --git a/source/core/thread.cpp b/source/core/thread.cpp index d2451a0..721e8cf 100644 --- a/source/core/thread.cpp +++ b/source/core/thread.cpp @@ -6,8 +6,9 @@ using namespace std; namespace Msp { -Thread::Thread(): +Thread::Thread(const string &name): priv_(new Private), + name_(name), state_(PENDING) { } @@ -48,6 +49,7 @@ void Thread::launch() ThreadReturn THREAD_CALL Thread::Private::main_wrapper(void *arg) { Thread *thread = reinterpret_cast(arg); + thread->platform_setname(); thread->main(); thread->state_ = FINISHED; return 0; diff --git a/source/core/thread.h b/source/core/thread.h index 1fff362..7cf17b8 100644 --- a/source/core/thread.h +++ b/source/core/thread.h @@ -1,6 +1,8 @@ #ifndef MSP_CORE_THREAD_H_ #define MSP_CORE_THREAD_H_ +#include + namespace Msp { /** @@ -25,16 +27,19 @@ private: }; 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; } @@ -54,6 +59,7 @@ private: void platform_join(); void platform_kill(); void platform_launch(); + void platform_setname(); protected: virtual void main() = 0; diff --git a/source/core/unix/thread.cpp b/source/core/unix/thread.cpp index 26afeef..3c17a9a 100644 --- a/source/core/unix/thread.cpp +++ b/source/core/unix/thread.cpp @@ -20,4 +20,10 @@ void Thread::platform_launch() 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 diff --git a/source/core/windows/thread.cpp b/source/core/windows/thread.cpp index 7c43618..ab02c4d 100644 --- a/source/core/windows/thread.cpp +++ b/source/core/windows/thread.cpp @@ -20,4 +20,9 @@ void Thread::platform_launch() 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 diff --git a/source/debug/backtrace.cpp b/source/debug/backtrace.cpp index 1fda155..f9057dc 100644 --- a/source/debug/backtrace.cpp +++ b/source/debug/backtrace.cpp @@ -1,6 +1,6 @@ // Must include something to test for glibc #include -#if !defined(WIN32) && defined(__GLIBC__) +#if !defined(_WIN32) && defined(__GLIBC__) #include #include #endif @@ -14,7 +14,7 @@ namespace Debug { Backtrace Backtrace::create() { -#if !defined(WIN32) && defined(__GLIBC__) +#if !defined(_WIN32) && defined(__GLIBC__) void *addresses[50]; int count = ::backtrace(addresses, 50); diff --git a/source/fs/dir.cpp b/source/fs/dir.cpp index 9c6a97a..717c11c 100644 --- a/source/fs/dir.cpp +++ b/source/fs/dir.cpp @@ -20,7 +20,7 @@ namespace enum { -#ifdef WIN32 +#ifdef _WIN32 ITEMSEP = ';' #else ITEMSEP = ':' @@ -73,7 +73,7 @@ void mkpath(const Path &path, int mode) 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 diff --git a/source/fs/osx/cfdir.m b/source/fs/osx/cfdir.m new file mode 100644 index 0000000..4dd4b4b --- /dev/null +++ b/source/fs/osx/cfdir.m @@ -0,0 +1,23 @@ +#import + +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]; +} diff --git a/source/fs/osx/dir_location.cpp b/source/fs/osx/dir_location.cpp new file mode 100644 index 0000000..7ce89f7 --- /dev/null +++ b/source/fs/osx/dir_location.cpp @@ -0,0 +1,35 @@ +#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 diff --git a/source/fs/path.cpp b/source/fs/path.cpp index 0fe95d6..d68595b 100644 --- a/source/fs/path.cpp +++ b/source/fs/path.cpp @@ -7,7 +7,7 @@ using namespace std; 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 @@ -58,7 +58,7 @@ unsigned Path::size() const bool Path::is_absolute() const { -#ifdef WIN32 +#ifdef _WIN32 if(is_windows_drive((*this)[0])) return true; #endif @@ -103,7 +103,7 @@ void Path::add_component(const string &comp) 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))) { @@ -118,7 +118,7 @@ void Path::add_component(const string &comp) separators.push_back(0); } } -#ifdef WIN32 +#ifdef _WIN32 else if(is_windows_drive(comp)) { path = comp; @@ -132,7 +132,7 @@ void Path::add_component(const string &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 @@ -192,7 +192,7 @@ string Path::operator[](int n) const bool Path::operator==(const Path &other) const { -#ifdef WIN32 +#ifdef _WIN32 return strcasecmp(path, other.path)==0; #else return path==other.path; @@ -201,7 +201,7 @@ bool Path::operator==(const Path &other) const bool Path::operator<(const Path &other) const { -#ifdef WIN32 +#ifdef _WIN32 return strcasecmp(path, other.path)<0; #else return path(const Path &other) const { -#ifdef WIN32 +#ifdef _WIN32 return strcasecmp(path, other.path)>0; #else return path>other.path; diff --git a/source/fs/path.h b/source/fs/path.h index 3cbfb16..82600dc 100644 --- a/source/fs/path.h +++ b/source/fs/path.h @@ -10,7 +10,7 @@ namespace FS { enum { -#ifdef WIN32 +#ifdef _WIN32 DIRSEP = '\\' #else DIRSEP = '/' diff --git a/source/fs/stat_private.h b/source/fs/stat_private.h index c80d151..7b20638 100644 --- a/source/fs/stat_private.h +++ b/source/fs/stat_private.h @@ -15,7 +15,7 @@ struct Stat::Private 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 &); diff --git a/source/io/base.h b/source/io/base.h index c58be90..8d29caf 100644 --- a/source/io/base.h +++ b/source/io/base.h @@ -12,9 +12,6 @@ namespace IO { /** 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 { diff --git a/source/io/file.cpp b/source/io/file.cpp index 666b1ed..1b4a738 100644 --- a/source/io/file.cpp +++ b/source/io/file.cpp @@ -39,7 +39,7 @@ unsigned File::do_write(const char *buf, unsigned size) if(size==0) return 0; -#ifdef WIN32 +#ifdef _WIN32 if(mode&M_APPEND) seek(0, S_END); #endif diff --git a/source/io/poll.cpp b/source/io/poll.cpp index 0356a00..6da777c 100644 --- a/source/io/poll.cpp +++ b/source/io/poll.cpp @@ -36,7 +36,7 @@ void Poller::set_object(EventObject &obj, PollEvent ev) } else if(ev) { -#ifdef WIN32 +#ifdef _WIN32 if(objects.size()>=MAXIMUM_WAIT_OBJECTS) throw logic_error("Maximum number of wait objects reached"); #endif diff --git a/source/io/unix/seekable.cpp b/source/io/unix/seekable.cpp index 93a6e86..a402742 100644 --- a/source/io/unix/seekable.cpp +++ b/source/io/unix/seekable.cpp @@ -29,6 +29,13 @@ int sys_seek_type(SeekType st) 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)); diff --git a/source/time/datetime.cpp b/source/time/datetime.cpp index c77796f..26bd7cd 100644 --- a/source/time/datetime.cpp +++ b/source/time/datetime.cpp @@ -1,6 +1,7 @@ #include #include #include +#include #include "datetime.h" #include "timestamp.h" @@ -104,6 +105,36 @@ void DateTime::init(int y, unsigned char m, unsigned char d, unsigned char h, un 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(m[1].str); + unsigned month = lexical_cast(m[2].str); + unsigned mday = lexical_cast(m[3].str); + unsigned hr = lexical_cast(m[4].str); + unsigned minute = lexical_cast(m[5].str); + unsigned second = lexical_cast(m[6].str); + + DateTime result = DateTime(year, month, mday, hr, minute, second); + + int tzoff = 0; + if(m[7].str!="Z") + { + tzoff = lexical_cast(m[8].str)*60+lexical_cast(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; diff --git a/source/time/datetime.h b/source/time/datetime.h index f065d32..b7f578c 100644 --- a/source/time/datetime.h +++ b/source/time/datetime.h @@ -43,6 +43,8 @@ private: 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; } @@ -80,6 +82,9 @@ private: 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 diff --git a/source/time/timer.cpp b/source/time/timer.cpp index f26900b..e0af57c 100644 --- a/source/time/timer.cpp +++ b/source/time/timer.cpp @@ -1,4 +1,5 @@ #include +#include #include "timer.h" #include "utils.h" @@ -55,35 +56,59 @@ void Timer::cancel(Slot &slot) 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) + 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