From: Mikko Rasa Date: Wed, 24 Apr 2013 13:22:18 +0000 (+0300) Subject: Move most platform-specific code into overlay directories X-Git-Url: http://git.tdb.fi/?a=commitdiff_plain;h=609c9a508cfdc7b42c46c4f21d17639204165a00;p=libs%2Fcore.git Move most platform-specific code into overlay directories A few things, in particular FS::Path, were not trivial to split. I'm not certain what to do with features like zlib either. --- diff --git a/Build b/Build index be4d039..c01f693 100644 --- a/Build +++ b/Build @@ -37,6 +37,14 @@ package "mspcore" source "source/stringcodec"; source "source/io"; source "source/fs"; + if_arch "windows" + { + overlay "windows"; + }; + if_arch "!windows" + { + overlay "unix"; + }; install true; install_map { diff --git a/source/core/application.cpp b/source/core/application.cpp index 51f013e..36621e9 100644 --- a/source/core/application.cpp +++ b/source/core/application.cpp @@ -1,9 +1,4 @@ -#ifdef WIN32 -#include -#endif #include -#include -#include #include #include "application.h" #include "getopt.h" @@ -68,14 +63,7 @@ int Application::run(int argc, char **argv, void *data) { delete app_; -#ifdef WIN32 - string msg = Debug::demangle(typeid(e).name())+":\n"+e.what(); - MessageBoxA(0, msg.c_str(), "Uncaught exception", MB_OK|MB_ICONERROR); -#else - IO::print(IO::cerr, "An uncaught exception occurred.\n"); - IO::print(IO::cerr, " type: %s\n", Debug::demangle(typeid(e).name())); - IO::print(IO::cerr, " what(): %s\n", e.what()); -#endif + display_exception(e); return 124; } diff --git a/source/core/application.h b/source/core/application.h index 08393b7..7dfea8a 100644 --- a/source/core/application.h +++ b/source/core/application.h @@ -1,6 +1,8 @@ #ifndef MSP_CORE_APPLICATION_H_ #define MSP_CORE_APPLICATION_H_ +#include + namespace Msp { /** @@ -45,6 +47,8 @@ protected: virtual void sighandler(int) { } private: static void sighandler_(int); + + static void display_exception(const std::exception &); }; diff --git a/source/core/main.cpp b/source/core/main.cpp deleted file mode 100644 index fa28c1f..0000000 --- a/source/core/main.cpp +++ /dev/null @@ -1,45 +0,0 @@ -#ifdef WIN32 -#include -#include -#include -#endif -#include "application.h" - -#ifdef WIN32 -using namespace std; -using namespace Msp; - -int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE /*hPrevInstance*/, LPSTR /*lpCmdLine*/, int /*nCmdShow*/) -{ - int argc = 0; - LPWSTR *argv_w = CommandLineToArgvW(GetCommandLineW(), &argc); - - unsigned max_size = 0; - for(int i=0; i(argv_buf); - char *argv_ptr = argv_buf+(argc+1)*sizeof(char *); - for(int i=0; i(argv_w[i]), wcslen(argv_w[i])*2); - arg = StringCodec::transcode(arg); - copy(arg.begin(), arg.end(), argv_ptr); - argv_ptr += arg.size(); - *argv_ptr++ = 0; - } - - LocalFree(argv_w); - int exit_code = Msp::Application::run(argc, argv, hInstance); - delete[] argv_buf; - return exit_code; -} - -#else -int main(int argc, char **argv) -{ - return Msp::Application::run(argc, argv); -} -#endif diff --git a/source/core/mutex.cpp b/source/core/mutex.cpp deleted file mode 100644 index 4f830c5..0000000 --- a/source/core/mutex.cpp +++ /dev/null @@ -1,62 +0,0 @@ -#ifndef WIN32 -#include -#endif -#include "mutex.h" -#include "mutex_private.h" -#include "systemerror.h" - -namespace Msp { - -Mutex::Mutex(): - priv(new Private) -{ -#ifdef WIN32 - InitializeCriticalSection(&priv->crit); -#else - pthread_mutex_init(&priv->mutex, 0); -#endif -} - -Mutex::~Mutex() -{ -#ifdef WIN32 - DeleteCriticalSection(&priv->crit); -#else - pthread_mutex_destroy(&priv->mutex); -#endif - delete priv; -} - -void Mutex::lock() -{ -#ifdef WIN32 - EnterCriticalSection(&priv->crit); -#else - if(int err = pthread_mutex_lock(&priv->mutex)) - throw system_error("pthread_mutex_lock", err); -#endif -} - -bool Mutex::trylock() -{ -#ifdef WIN32 - return TryEnterCriticalSection(&priv->crit); -#else - int err = pthread_mutex_trylock(&priv->mutex); - if(err && err!=EBUSY) - throw system_error("pthread_mutex_trylock", err); - return !err; -#endif -} - -void Mutex::unlock() -{ -#ifdef WIN32 - LeaveCriticalSection(&priv->crit); -#else - if(int err = pthread_mutex_unlock(&priv->mutex)) - throw system_error("pthread_mutex_unlock", err); -#endif -} - -} // namespace Msp diff --git a/source/core/mutex_private.h b/source/core/mutex_private.h index 0b092da..615b255 100644 --- a/source/core/mutex_private.h +++ b/source/core/mutex_private.h @@ -1,22 +1,14 @@ #ifndef MSP_CORE_MUTEX_PRIVATE_H_ #define MSP_CORE_MUTEX_PRIVATE_H_ -#ifdef WIN32 -#include -#else -#include -#endif #include "mutex.h" +#include "mutex_platform.h" namespace Msp { struct Mutex::Private { -#ifdef WIN32 - CRITICAL_SECTION crit; -#else - pthread_mutex_t mutex; -#endif + PlatformMutex mutex; }; } // namespace Msp diff --git a/source/core/semaphore.cpp b/source/core/semaphore.cpp deleted file mode 100644 index 4bfd303..0000000 --- a/source/core/semaphore.cpp +++ /dev/null @@ -1,97 +0,0 @@ -#ifdef WIN32 -#include -#else -#include -#include -#endif -#include -#include -#include -#include "mutex_private.h" -#include "semaphore.h" -#include "systemerror.h" - -namespace Msp { - -struct Semaphore::Private -{ -#ifdef WIN32 - HANDLE handle; -#else - Mutex mutex; - pthread_cond_t cond; - unsigned limit; - unsigned count; -#endif -}; - - -Semaphore::Semaphore(unsigned limit): - priv(new Private) -{ -#ifdef WIN32 - priv->handle = CreateSemaphore(0, 0, limit, 0); -#else - pthread_cond_init(&priv->cond, 0); - priv->limit = limit; - priv->count = 0; -#endif -} - -Semaphore::~Semaphore() -{ -#ifdef WIN32 - CloseHandle(priv->handle); -#else - pthread_cond_destroy(&priv->cond); -#endif - delete priv; -} - -void Semaphore::signal() -{ -#ifdef WIN32 - if(!ReleaseSemaphore(priv->handle, 1, 0)) - throw system_error("ReleaseSemaphore"); -#else - MutexLock mlock(priv->mutex); - if(priv->countlimit) - ++priv->count; - if(int err = pthread_cond_signal(&priv->cond)) - throw system_error("pthread_cond_signal", err); -#endif -} - -void Semaphore::wait() -{ -#ifdef WIN32 - DWORD ret = WaitForSingleObject(priv->handle, INFINITE); - if(ret==WAIT_FAILED) - throw system_error("WaitForSingleObject"); -#else - MutexLock mlock(priv->mutex); - while(!priv->count) - if(int err = pthread_cond_wait(&priv->cond, &priv->mutex.priv->mutex)) - throw system_error("pthread_cond_wait", err); - --priv->count; -#endif -} - -bool Semaphore::wait(const Time::TimeDelta &d) -{ -#ifdef WIN32 - DWORD ret = WaitForSingleObject(priv->handle, (DWORD)(d/Time::usec)); - if(ret==WAIT_FAILED) - throw system_error("WaitForSingleObject"); - return ret==WAIT_OBJECT_0; -#else - timespec timeout = Time::rawtime_to_timespec((Time::now()+d).raw()); - - int err = pthread_cond_timedwait(&priv->cond, &priv->mutex.priv->mutex, &timeout); - if(err && err!=ETIMEDOUT) - throw system_error("pthread_cond_timedwait", err); - return err==0; -#endif -} - -} // namespace Msp diff --git a/source/core/systemerror.cpp b/source/core/systemerror.cpp index 1ccee74..5424ef0 100644 --- a/source/core/systemerror.cpp +++ b/source/core/systemerror.cpp @@ -1,10 +1,3 @@ -#ifdef WIN32 -#include -#include -#else -#include -#include -#endif #include #include "systemerror.h" @@ -22,23 +15,4 @@ system_error::system_error(const string &w, const string &e): code_(numeric_limits::min()) { } -string system_error::get_message(int c) -{ -#ifdef WIN32 - if(c==-1) - c = GetLastError(); - - char msg[1024]; - if(FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM, 0, c, 0, msg, sizeof(msg), 0)) - return msg; - else - return lexical_cast(c, Fmt().hex()); -#else - if(c==-1) - c = errno; - - return strerror(c); -#endif -} - } // namespace Msp diff --git a/source/core/thread.cpp b/source/core/thread.cpp index 6c542e6..d2451a0 100644 --- a/source/core/thread.cpp +++ b/source/core/thread.cpp @@ -1,41 +1,11 @@ -#ifdef WIN32 -#include -#else -#include -#include -#endif #include #include "thread.h" +#include "thread_private.h" using namespace std; namespace Msp { -struct Thread::Private -{ -#ifdef WIN32 - HANDLE handle; -#else - pthread_t handle; -#endif - - Private(): handle(0) { } - -#ifdef WIN32 - static DWORD WINAPI -#else - static void * -#endif - main_wrapper(void *a) - { - Thread *t = reinterpret_cast(a); - t->main(); - t->state_ = FINISHED; - return 0; - } -}; - - Thread::Thread(): priv_(new Private), state_(PENDING) @@ -53,11 +23,7 @@ void Thread::join() if(state_>=JOINED) return; -#ifdef WIN32 - WaitForSingleObject(priv_->handle, INFINITE); -#else - pthread_join(priv_->handle, 0); -#endif + platform_join(); state_ = JOINED; } @@ -66,11 +32,7 @@ void Thread::kill() if(state_!=RUNNING) return; -#ifdef WIN32 - TerminateThread(priv_->handle, 0); -#else - pthread_kill(priv_->handle, SIGKILL); -#endif + platform_kill(); state_ = KILLED; } @@ -79,13 +41,16 @@ void Thread::launch() if(state_>=RUNNING) throw logic_error("already launched"); -#ifdef WIN32 - DWORD dummy; // Win9x needs the lpTthreadId parameter - priv_->handle = CreateThread(0, 0, &Private::main_wrapper, this, 0, &dummy); -#else - pthread_create(&priv_->handle, 0, &Private::main_wrapper, this); -#endif + platform_launch(); state_ = RUNNING; } +ThreadReturn THREAD_CALL Thread::Private::main_wrapper(void *arg) +{ + Thread *thread = reinterpret_cast(arg); + thread->main(); + thread->state_ = FINISHED; + return 0; +} + } // namespace Msp diff --git a/source/core/thread.h b/source/core/thread.h index 81494ea..1fff362 100644 --- a/source/core/thread.h +++ b/source/core/thread.h @@ -50,6 +50,12 @@ protected: /** Starts the thread. Can only be called once for each Thread instance. */ void launch(); +private: + void platform_join(); + void platform_kill(); + void platform_launch(); + +protected: virtual void main() = 0; }; diff --git a/source/core/thread_private.h b/source/core/thread_private.h new file mode 100644 index 0000000..f64c582 --- /dev/null +++ b/source/core/thread_private.h @@ -0,0 +1,19 @@ +#ifndef MSP_CORE_THREAD_PRIVATE_H_ +#define MSP_CORE_THREAD_PRIVATE_H_ + +#include "thread_platform.h" + +namespace Msp { + +struct Thread::Private +{ + ThreadHandle handle; + + Private(): handle(0) { } + + static ThreadReturn THREAD_CALL main_wrapper(void *); +}; + +} // namespace Msp + +#endif diff --git a/source/core/unix/application.cpp b/source/core/unix/application.cpp new file mode 100644 index 0000000..7f45fbc --- /dev/null +++ b/source/core/unix/application.cpp @@ -0,0 +1,17 @@ +#include +#include +#include +#include "application.h" + +using namespace std; + +namespace Msp { + +void Application::display_exception(const exception &e) +{ + IO::print(IO::cerr, "An uncaught exception occurred.\n"); + IO::print(IO::cerr, " type: %s\n", Debug::demangle(typeid(e).name())); + IO::print(IO::cerr, " what(): %s\n", e.what()); +} + +} // namespace Msp diff --git a/source/core/unix/main.cpp b/source/core/unix/main.cpp new file mode 100644 index 0000000..601ddb6 --- /dev/null +++ b/source/core/unix/main.cpp @@ -0,0 +1,6 @@ +#include "application.h" + +int main(int argc, char **argv) +{ + return Msp::Application::run(argc, argv); +} diff --git a/source/core/unix/mutex.cpp b/source/core/unix/mutex.cpp new file mode 100644 index 0000000..15e5c9a --- /dev/null +++ b/source/core/unix/mutex.cpp @@ -0,0 +1,41 @@ +#include +#include +#include "mutex.h" +#include "mutex_private.h" +#include "systemerror.h" + +namespace Msp { + +Mutex::Mutex(): + priv(new Private) +{ + pthread_mutex_init(&priv->mutex, 0); +} + +Mutex::~Mutex() +{ + pthread_mutex_destroy(&priv->mutex); + delete priv; +} + +void Mutex::lock() +{ + if(int err = pthread_mutex_lock(&priv->mutex)) + throw system_error("pthread_mutex_lock", err); +} + +bool Mutex::trylock() +{ + int err = pthread_mutex_trylock(&priv->mutex); + if(err && err!=EBUSY) + throw system_error("pthread_mutex_trylock", err); + return !err; +} + +void Mutex::unlock() +{ + if(int err = pthread_mutex_unlock(&priv->mutex)) + throw system_error("pthread_mutex_unlock", err); +} + +} // namespace Msp diff --git a/source/core/unix/mutex_platform.h b/source/core/unix/mutex_platform.h new file mode 100644 index 0000000..2eee8bc --- /dev/null +++ b/source/core/unix/mutex_platform.h @@ -0,0 +1,12 @@ +#ifndef MSP_CORE_MUTEX_PLATFORM_H_ +#define MSP_CORE_MUTEX_PLATFORM_H_ + +#include + +namespace Msp { + +typedef pthread_mutex_t PlatformMutex; + +} // namespace Msp + +#endif diff --git a/source/core/unix/semaphore.cpp b/source/core/unix/semaphore.cpp new file mode 100644 index 0000000..8149258 --- /dev/null +++ b/source/core/unix/semaphore.cpp @@ -0,0 +1,64 @@ +#include +#include +#include +#include +#include +#include +#include "mutex.h" +#include "mutex_private.h" +#include "semaphore.h" + +namespace Msp { + +struct Semaphore::Private +{ + Mutex mutex; + pthread_cond_t cond; + unsigned limit; + unsigned count; +}; + + +Semaphore::Semaphore(unsigned limit): + priv(new Private) +{ + pthread_cond_init(&priv->cond, 0); + priv->limit = limit; + priv->count = 0; +} + +Semaphore::~Semaphore() +{ + pthread_cond_destroy(&priv->cond); + delete priv; +} + +void Semaphore::signal() +{ + MutexLock mlock(priv->mutex); + if(priv->countlimit) + ++priv->count; + if(int err = pthread_cond_signal(&priv->cond)) + throw system_error("pthread_cond_signal", err); +} + +void Semaphore::wait() +{ + MutexLock mlock(priv->mutex); + while(!priv->count) + if(int err = pthread_cond_wait(&priv->cond, &priv->mutex.priv->mutex)) + throw system_error("pthread_cond_wait", err); + --priv->count; +} + +bool Semaphore::wait(const Time::TimeDelta &d) +{ + timespec timeout = Time::rawtime_to_timespec((Time::now()+d).raw()); + + int err = pthread_cond_timedwait(&priv->cond, &priv->mutex.priv->mutex, &timeout); + if(err && err!=ETIMEDOUT) + throw system_error("pthread_cond_timedwait", err); + return err==0; +} + +} // namespace Msp diff --git a/source/core/unix/systemerror.cpp b/source/core/unix/systemerror.cpp new file mode 100644 index 0000000..a8eb5a6 --- /dev/null +++ b/source/core/unix/systemerror.cpp @@ -0,0 +1,17 @@ +#include +#include +#include "systemerror.h" + +using namespace std; + +namespace Msp { + +string system_error::get_message(int c) +{ + if(c==-1) + c = errno; + + return strerror(c); +} + +} // namespace Msp diff --git a/source/core/unix/thread.cpp b/source/core/unix/thread.cpp new file mode 100644 index 0000000..e7d7f58 --- /dev/null +++ b/source/core/unix/thread.cpp @@ -0,0 +1,25 @@ +#include +#include +#include "thread.h" +#include "thread_private.h" + +using namespace std; + +namespace Msp { + +void Thread::platform_join() +{ + pthread_join(priv_->handle, 0); +} + +void Thread::platform_kill() +{ + pthread_kill(priv_->handle, SIGKILL); +} + +void Thread::platform_launch() +{ + pthread_create(&priv_->handle, 0, &Private::main_wrapper, this); +} + +} // namespace Msp diff --git a/source/core/unix/thread_platform.h b/source/core/unix/thread_platform.h new file mode 100644 index 0000000..0477a6d --- /dev/null +++ b/source/core/unix/thread_platform.h @@ -0,0 +1,15 @@ +#ifndef MSP_CORE_THREAD_PLATFORM_H_ +#define MSP_CORE_THREAD_PLATFORM_H_ + +#include + +namespace Msp { + +typedef pthread_t ThreadHandle; +typedef void *ThreadReturn; + +#define THREAD_CALL + +} // namespace Msp + +#endif diff --git a/source/core/windows/application.cpp b/source/core/windows/application.cpp new file mode 100644 index 0000000..ed8702a --- /dev/null +++ b/source/core/windows/application.cpp @@ -0,0 +1,16 @@ +#include +#include +#include +#include "application.h" + +using namespace std; + +namespace Msp { + +void Application::display_exception(const exception &e) +{ + string msg = Debug::demangle(typeid(e).name())+":\n"+e.what(); + MessageBoxA(0, msg.c_str(), "Uncaught exception", MB_OK|MB_ICONERROR); +} + +} // namespace Msp diff --git a/source/core/windows/main.cpp b/source/core/windows/main.cpp new file mode 100644 index 0000000..a0816a4 --- /dev/null +++ b/source/core/windows/main.cpp @@ -0,0 +1,35 @@ +#include +#include +#include +#include "application.h" + +using namespace std; +using namespace Msp; + +int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE /*hPrevInstance*/, LPSTR /*lpCmdLine*/, int /*nCmdShow*/) +{ + int argc = 0; + LPWSTR *argv_w = CommandLineToArgvW(GetCommandLineW(), &argc); + + unsigned max_size = 0; + for(int i=0; i(argv_buf); + char *argv_ptr = argv_buf+(argc+1)*sizeof(char *); + for(int i=0; i(argv_w[i]), wcslen(argv_w[i])*2); + arg = StringCodec::transcode(arg); + copy(arg.begin(), arg.end(), argv_ptr); + argv_ptr += arg.size(); + *argv_ptr++ = 0; + } + + LocalFree(argv_w); + int exit_code = Msp::Application::run(argc, argv, hInstance); + delete[] argv_buf; + return exit_code; +} diff --git a/source/core/windows/mutex.cpp b/source/core/windows/mutex.cpp new file mode 100644 index 0000000..e51fda4 --- /dev/null +++ b/source/core/windows/mutex.cpp @@ -0,0 +1,34 @@ +#include +#include "mutex.h" +#include "mutex_private.h" + +namespace Msp { + +Mutex::Mutex(): + priv(new Private) +{ + InitializeCriticalSection(&priv->mutex); +} + +Mutex::~Mutex() +{ + DeleteCriticalSection(&priv->mutex); + delete priv; +} + +void Mutex::lock() +{ + EnterCriticalSection(&priv->mutex); +} + +bool Mutex::trylock() +{ + return TryEnterCriticalSection(&priv->mutex); +} + +void Mutex::unlock() +{ + LeaveCriticalSection(&priv->mutex); +} + +} // namespace Msp diff --git a/source/core/windows/mutex_platform.h b/source/core/windows/mutex_platform.h new file mode 100644 index 0000000..fae5e85 --- /dev/null +++ b/source/core/windows/mutex_platform.h @@ -0,0 +1,12 @@ +#ifndef MSP_CORE_MUTEX_PLATFORM_H_ +#define MSP_CORE_MUTEX_PLATFORM_H_ + +#include + +namespace Msp { + +typedef CRITICAL_SECTION PlatformMutex; + +} // namespace Msp + +#endif diff --git a/source/core/windows/semaphore.cpp b/source/core/windows/semaphore.cpp new file mode 100644 index 0000000..aeb1709 --- /dev/null +++ b/source/core/windows/semaphore.cpp @@ -0,0 +1,47 @@ +#include +#include +#include +#include "semaphore.h" + +namespace Msp { + +struct Semaphore::Private +{ + HANDLE handle; +}; + + +Semaphore::Semaphore(unsigned limit): + priv(new Private) +{ + priv->handle = CreateSemaphore(0, 0, limit, 0); +} + +Semaphore::~Semaphore() +{ + CloseHandle(priv->handle); + delete priv; +} + +void Semaphore::signal() +{ + if(!ReleaseSemaphore(priv->handle, 1, 0)) + throw system_error("ReleaseSemaphore"); +} + +void Semaphore::wait() +{ + DWORD ret = WaitForSingleObject(priv->handle, INFINITE); + if(ret==WAIT_FAILED) + throw system_error("WaitForSingleObject"); +} + +bool Semaphore::wait(const Time::TimeDelta &d) +{ + DWORD ret = WaitForSingleObject(priv->handle, (DWORD)(d/Time::usec)); + if(ret==WAIT_FAILED) + throw system_error("WaitForSingleObject"); + return ret==WAIT_OBJECT_0; +} + +} // namespace Msp diff --git a/source/core/windows/systemerror.cpp b/source/core/windows/systemerror.cpp new file mode 100644 index 0000000..98eb9ed --- /dev/null +++ b/source/core/windows/systemerror.cpp @@ -0,0 +1,20 @@ +#include +#include +#include "systemerror.h" + +using namespace std; + +namespace Msp { +string system_error::get_message(int c) +{ + if(c==-1) + c = GetLastError(); + + char msg[1024]; + if(FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM, 0, c, 0, msg, sizeof(msg), 0)) + return msg; + else + return lexical_cast(c, Fmt().hex()); +} + +} // namespace Msp diff --git a/source/core/windows/thread.cpp b/source/core/windows/thread.cpp new file mode 100644 index 0000000..410141c --- /dev/null +++ b/source/core/windows/thread.cpp @@ -0,0 +1,25 @@ +#include +#include "thread.h" +#include "thread_private.h" + +using namespace std; + +namespace Msp { + +void Thread::platform_join() +{ + WaitForSingleObject(priv_->handle, INFINITE); +} + +void Thread::platform_kill() +{ + TerminateThread(priv_->handle, 0); +} + +void Thread::platform_launch() +{ + DWORD dummy; // Win9x needs the lpTthreadId parameter + priv_->handle = CreateThread(0, 0, &Private::main_wrapper, this, 0, &dummy); +} + +} // namespace Msp diff --git a/source/core/windows/thread_platform.h b/source/core/windows/thread_platform.h new file mode 100644 index 0000000..50b1a5e --- /dev/null +++ b/source/core/windows/thread_platform.h @@ -0,0 +1,15 @@ +#ifndef MSP_CORE_THREAD_PLATFORM_H_ +#define MSP_CORE_THREAD_PLATFORM_H_ + +#include + +namespace Msp { + +typedef HANDLE ThreadHandle; +typedef DWORD ThreadReturn; + +#define THREAD_CALL WINAPI + +} // namespace Msp + +#endif diff --git a/source/fs/dir.cpp b/source/fs/dir.cpp index f7f34f6..57fd936 100644 --- a/source/fs/dir.cpp +++ b/source/fs/dir.cpp @@ -1,12 +1,6 @@ #include -#include -#include -#ifdef WIN32 -#include -#else #include -#include -#endif +#include #include #include #include @@ -62,18 +56,6 @@ not_a_directory::not_a_directory(const Path &p): { } -void mkdir(const Path &path, int mode) -{ -#ifdef WIN32 - (void)mode; - if(!CreateDirectory(path.str().c_str(), NULL)) - throw system_error("CreateDirectory"); -#else - if(::mkdir(path.str().c_str(), mode)==-1) - throw system_error("mkdir"); -#endif -} - void mkpath(const Path &path, int mode) { Path p; @@ -95,17 +77,6 @@ void mkpath(const Path &path, int mode) } } -void rmdir(const Path &path) -{ -#ifdef WIN32 - if(!RemoveDirectory(path.str().c_str())) - throw system_error("RemoveDirectory"); -#else - if(::rmdir(path.str().c_str())==-1) - throw system_error("rmdir"); -#endif -} - void rmpath(const Path &path) { list files = list_files(path); @@ -154,32 +125,6 @@ Path getcwd() return ::getcwd(buf, sizeof(buf)); } -Path get_home_dir() -{ -#ifdef WIN32 - char home[MAX_PATH]; - if(SHGetFolderPath(0, CSIDL_PERSONAL, 0, 0, home)==S_OK) - return home; -#else - const char *home = getenv("HOME"); - if(home) - return home; -#endif - return "."; -} - -Path get_user_data_dir(const string &appname) -{ -#ifdef WIN32 - char datadir[MAX_PATH]; - if(SHGetFolderPath(0, CSIDL_LOCAL_APPDATA, 0, 0, datadir)==S_OK) - return Path(datadir)/appname; - return "."; -#else - return get_home_dir()/("."+appname); -#endif -} - Path get_sys_conf_dir(const string &argv0) { Path dir = get_bin_dir(argv0); diff --git a/source/fs/stat.cpp b/source/fs/stat.cpp index 85fead5..f4566ae 100644 --- a/source/fs/stat.cpp +++ b/source/fs/stat.cpp @@ -1,163 +1,17 @@ -#ifdef WIN32 -#include -#include -#else -#define _FILE_OFFSET_BITS 64 -#include -#include -#include -#include -#include -#endif -#include -#include -#include #include "path.h" #include "stat.h" +#include "stat_private.h" using namespace std; -namespace { - -#ifdef WIN32 -PSID copy_sid(PSID sid) -{ - if(!sid || !IsValidSid(sid)) - return 0; - DWORD len = GetLengthSid(sid); - PSID copy = reinterpret_cast(HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, len)); - if(!CopySid(len, copy, sid)) - { - DWORD err = GetLastError(); - HeapFree(GetProcessHeap(), 0, copy); - throw Msp::system_error("CopySid", err); - } - return copy; -} - -string get_account_name(PSID sid) -{ - char name[1024]; - DWORD nlen = sizeof(name); - char domain[1024]; - DWORD dlen = sizeof(domain); - SID_NAME_USE use; - if(!LookupAccountSid(0, sid, name, &nlen, domain, &dlen, &use)) - throw Msp::system_error("LookupAccountSid"); - return Msp::format("%s/%s", name, domain); -} -#endif - -} - - namespace Msp { namespace FS { -struct Stat::Private -{ -#ifdef WIN32 - PSID owner_id; - PSID group_id; -#else - uid_t owner_id; - gid_t group_id; -#endif - - Private(); - Private(const Private &); - ~Private(); - -#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 &); -#endif - - void fill_owner_info(Stat::OwnerInfo &); -}; - Stat::Private::Private(): owner_id(0), group_id(0) { } -Stat::Private::Private(const Private &other): -#ifdef WIN32 - owner_id(copy_sid(other.owner_id)), - group_id(copy_sid(other.group_id)) -#else - owner_id(other.owner_id), - group_id(other.group_id) -#endif -{ } - -Stat::Private::~Private() -{ -#ifdef WIN32 - if(owner_id) - HeapFree(GetProcessHeap(), 0, owner_id); - if(group_id) - HeapFree(GetProcessHeap(), 0, group_id); -#endif -} - -#ifndef WIN32 -Stat Stat::Private::from_struct_stat(const struct stat &st) -{ - Stat result; - result.exists = true; - if(S_ISREG(st.st_mode)) - result.type = REGULAR; - else if(S_ISDIR(st.st_mode)) - result.type = DIRECTORY; - else if(S_ISLNK(st.st_mode)) - result.type = SYMLINK; - else - result.type = UNKNOWN; - result.size = st.st_size; - result.alloc_size = st.st_blocks*512; - result.mtime = Time::TimeStamp::from_unixtime(st.st_mtime); - - result.priv = new Private; - result.priv->owner_id = st.st_uid; - result.priv->group_id = st.st_gid; - - return result; -} -#endif - -void Stat::Private::fill_owner_info(Stat::OwnerInfo &result) -{ -#ifdef WIN32 - if(owner_id) - result.owner = get_account_name(owner_id); - else - result.owner = "None"; - - if(group_id) - result.group = get_account_name(group_id); - else - result.group = "None"; -#else - char buf[1024]; - - struct passwd pw; - struct passwd *owner; - if(!getpwuid_r(owner_id, &pw, buf, sizeof(buf), &owner) && owner) - result.owner = owner->pw_name; - else - result.owner = format("%d", owner_id); - - struct group gr; - struct group *group; - if(!getgrgid_r(group_id, &gr, buf, sizeof(buf), &group) && group) - result.group = group->gr_name; - else - result.group = format("%d", group_id); -#endif -} - Stat::Stat(): exists(false), @@ -196,72 +50,6 @@ Stat::~Stat() delete priv; } -Stat Stat::stat(const Path &path) -{ -#ifdef WIN32 - HANDLE handle; - handle = CreateFile(path.str().c_str(), READ_CONTROL, FILE_SHARE_READ, 0, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL|FILE_FLAG_BACKUP_SEMANTICS, 0); - if(handle==INVALID_HANDLE_VALUE) - { - DWORD err = GetLastError(); - if(err==ERROR_FILE_NOT_FOUND) - return Stat(); - else - throw system_error("CreateFile", err); - } - - BY_HANDLE_FILE_INFORMATION info; - if(!GetFileInformationByHandle(handle, &info)) - { - CloseHandle(handle); - throw system_error("GetFileInformationByHandle"); - } - - Stat result; - if(info.dwFileAttributes&FILE_ATTRIBUTE_DIRECTORY) - result.type = DIRECTORY; - else - result.type = REGULAR; - - result.size = FileSize(info.nFileSizeHigh)<<32 | info.nFileSizeLow; - result.alloc_size = (result.size+511)&~511; - result.mtime = Time::TimeStamp(Time::filetime_to_rawtime(info.ftLastWriteTime)); - - PSECURITY_DESCRIPTOR sec_desc; - PSID owner = 0; - PSID group = 0; - const SECURITY_INFORMATION sec_info = OWNER_SECURITY_INFORMATION|GROUP_SECURITY_INFORMATION; - DWORD err = GetSecurityInfo(handle, SE_FILE_OBJECT, sec_info, &owner, &group, 0, 0, &sec_desc); - if(err) - { - CloseHandle(handle); - throw system_error("GetSecurityInfo", err); - } - - result.priv = new Private; - result.priv->owner_id = copy_sid(owner); - result.priv->group_id = copy_sid(group); - - LocalFree(sec_desc); - - CloseHandle(handle); - - return result; -#else - struct stat st; - int ret = ::stat(path.str().c_str(), &st); - if(ret==-1) - { - if(errno==ENOENT) - return Stat(); - else - throw system_error("stat"); - } - - return Private::from_struct_stat(st); -#endif -} - const std::string &Stat::get_owner() const { if(priv && owner_info.owner.empty()) @@ -276,33 +64,5 @@ const std::string &Stat::get_group() const return owner_info.group; } -Stat Stat::lstat(const Path &path) -{ -#ifdef WIN32 - return stat(path); -#else - struct stat st; - int ret = ::lstat(path.str().c_str(), &st); - if(ret==-1) - { - if(errno==ENOENT) - return Stat(); - else - throw system_error("lstat"); - } - - return Private::from_struct_stat(st); -#endif -} - -bool exists(const Path &path) -{ -#ifdef WIN32 - return GetFileAttributes(path.str().c_str())!=INVALID_FILE_ATTRIBUTES; -#else - return access(path.str().c_str(), F_OK)==0; -#endif -} - } // namespace FS } // namespace Msp diff --git a/source/fs/stat_private.h b/source/fs/stat_private.h new file mode 100644 index 0000000..c80d151 --- /dev/null +++ b/source/fs/stat_private.h @@ -0,0 +1,30 @@ +#ifndef MSP_FS_STAT_PRIVATE_H_ +#define MSP_FS_STAT_PRIVATE_H_ + +#include "stat_platform.h" + +namespace Msp { +namespace FS { + +struct Stat::Private +{ + UserID owner_id; + GroupID group_id; + + Private(); + Private(const Private &); + ~Private(); + +#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 &); +#endif + + void fill_owner_info(Stat::OwnerInfo &); +}; + +} // namespace FS +} // namespace Msp + +#endif diff --git a/source/fs/unix/dir.cpp b/source/fs/unix/dir.cpp new file mode 100644 index 0000000..93aaeab --- /dev/null +++ b/source/fs/unix/dir.cpp @@ -0,0 +1,38 @@ +#include +#include +#include +#include +#include "dir.h" + +using namespace std; + +namespace Msp { +namespace FS { + +void mkdir(const Path &path, int mode) +{ + if(::mkdir(path.str().c_str(), mode)==-1) + throw system_error("mkdir"); +} + +void rmdir(const Path &path) +{ + if(::rmdir(path.str().c_str())==-1) + throw system_error("rmdir"); +} + +Path get_home_dir() +{ + const char *home = getenv("HOME"); + if(home) + return home; + return "."; +} + +Path get_user_data_dir(const string &appname) +{ + return get_home_dir()/("."+appname); +} + +} // namespace FS +} // namespace Msp diff --git a/source/fs/unix/stat.cpp b/source/fs/unix/stat.cpp new file mode 100644 index 0000000..1404fed --- /dev/null +++ b/source/fs/unix/stat.cpp @@ -0,0 +1,102 @@ +#define _FILE_OFFSET_BITS 64 +#include +#include +#include +#include +#include +#include +#include +#include "stat.h" +#include "stat_private.h" + +namespace Msp { +namespace FS { + +Stat::Private::Private(const Private &other): + owner_id(other.owner_id), + group_id(other.group_id) +{ } + +Stat::Private::~Private() +{ } + +Stat Stat::Private::from_struct_stat(const struct stat &st) +{ + Stat result; + result.exists = true; + if(S_ISREG(st.st_mode)) + result.type = REGULAR; + else if(S_ISDIR(st.st_mode)) + result.type = DIRECTORY; + else if(S_ISLNK(st.st_mode)) + result.type = SYMLINK; + else + result.type = UNKNOWN; + result.size = st.st_size; + result.alloc_size = st.st_blocks*512; + result.mtime = Time::TimeStamp::from_unixtime(st.st_mtime); + + result.priv = new Private; + result.priv->owner_id = st.st_uid; + result.priv->group_id = st.st_gid; + + return result; +} + +void Stat::Private::fill_owner_info(Stat::OwnerInfo &result) +{ + char buf[1024]; + + struct passwd pw; + struct passwd *owner; + if(!getpwuid_r(owner_id, &pw, buf, sizeof(buf), &owner) && owner) + result.owner = owner->pw_name; + else + result.owner = format("%d", owner_id); + + struct group gr; + struct group *group; + if(!getgrgid_r(group_id, &gr, buf, sizeof(buf), &group) && group) + result.group = group->gr_name; + else + result.group = format("%d", group_id); +} + + +Stat Stat::stat(const Path &path) +{ + struct stat st; + int ret = ::stat(path.str().c_str(), &st); + if(ret==-1) + { + if(errno==ENOENT) + return Stat(); + else + throw system_error("stat"); + } + + return Private::from_struct_stat(st); +} + +Stat Stat::lstat(const Path &path) +{ + struct stat st; + int ret = ::lstat(path.str().c_str(), &st); + if(ret==-1) + { + if(errno==ENOENT) + return Stat(); + else + throw system_error("lstat"); + } + + return Private::from_struct_stat(st); +} + +bool exists(const Path &path) +{ + return access(path.str().c_str(), F_OK)==0; +} + +} // namespace FS +} // namespace Msp diff --git a/source/fs/unix/stat_platform.h b/source/fs/unix/stat_platform.h new file mode 100644 index 0000000..cc3f095 --- /dev/null +++ b/source/fs/unix/stat_platform.h @@ -0,0 +1,15 @@ +#ifndef MSP_FS_STAT_PLATFORM_H_ +#define MSP_FS_STAT_PLATFORM_H_ + +#include + +namespace Msp { +namespace FS { + +typedef uid_t UserID; +typedef gid_t GroupID; + +} // namespace FS +} // namespace Msp + +#endif diff --git a/source/fs/unix/utils.cpp b/source/fs/unix/utils.cpp new file mode 100644 index 0000000..c832343 --- /dev/null +++ b/source/fs/unix/utils.cpp @@ -0,0 +1,65 @@ +#include +#include +#include +#include "dir.h" +#include "stat.h" +#include "utils.h" + +using namespace std; + +namespace Msp { +namespace FS { + +Path readlink(const Path &link) +{ + char buf[4096]; + int len = ::readlink(link.c_str(), buf, sizeof(buf)); + if(len==-1) + throw system_error("readlink"); + return string(buf, len); +} + +Path realpath(const Path &path) +{ + list queue(path.begin(), path.end()); + if(!path.is_absolute()) + { + Path cwd = getcwd(); + queue.insert(queue.begin(), cwd.begin(), cwd.end()); + } + + Path real; + unsigned n_links = 0; + while(!queue.empty()) + { + Path next = real/queue.front(); + queue.pop_front(); + + if(is_link(next)) + { + if(++n_links>64) + throw runtime_error("too many symbolic links"); + Path link = readlink(next); + queue.insert(queue.begin(), link.begin(), link.end()); + } + else + real = next; + } + + return real; +} + +void rename(const Path &from, const Path &to) +{ + if(::rename(from.c_str(), to.c_str())==-1) + throw system_error("rename"); +} + +void unlink(const Path &path) +{ + if(::unlink(path.c_str())==-1) + throw system_error("unlink"); +} + +} // namespace FS +} // namespace Msp diff --git a/source/fs/utils.cpp b/source/fs/utils.cpp index 9a98025..2bfd1bf 100644 --- a/source/fs/utils.cpp +++ b/source/fs/utils.cpp @@ -1,14 +1,5 @@ -#include -#ifdef WIN32 -#include -#else -#include -#endif -#include #include #include "dir.h" -#include "path.h" -#include "stat.h" #include "utils.h" using namespace std; @@ -78,79 +69,6 @@ Path fix_case(const Path &path) return result; } -Path readlink(const Path &link) -{ -#ifdef WIN32 - (void)link; - throw logic_error("no symbolic links on win32"); -#else - char buf[4096]; - int len = ::readlink(link.str().c_str(), buf, sizeof(buf)); - if(len==-1) - throw system_error("readlink"); - return string(buf, len); -#endif -} - -Path realpath(const Path &path) -{ -#ifdef WIN32 - if(path.is_absolute()) - return path; - else - return getcwd()/path; -#else - list queue(path.begin(), path.end()); - if(!path.is_absolute()) - { - Path cwd = getcwd(); - queue.insert(queue.begin(), cwd.begin(), cwd.end()); - } - - Path real; - unsigned n_links = 0; - while(!queue.empty()) - { - Path next = real/queue.front(); - queue.pop_front(); - - if(is_link(next)) - { - if(++n_links>64) - throw runtime_error("too many symbolic links"); - Path link = readlink(next); - queue.insert(queue.begin(), link.begin(), link.end()); - } - else - real = next; - } - - return real; -#endif -} - -void rename(const Path &from, const Path &to) -{ -#ifdef WIN32 - if(!MoveFileEx(from.c_str(), to.c_str(), MOVEFILE_REPLACE_EXISTING)) - throw system_error("MoveFileEx"); -#else - if(::rename(from.str().c_str(), to.str().c_str())==-1) - throw system_error("rename"); -#endif -} - -void unlink(const Path &path) -{ -#ifdef WIN32 - if(!DeleteFile(path.c_str())) - throw system_error("DeleteFile"); -#else - if(::unlink(path.str().c_str())==-1) - throw system_error("unlink"); -#endif -} - Path relative(const Path &path, const Path &base) { Path::Iterator i = path.begin(); diff --git a/source/fs/windows/dir.cpp b/source/fs/windows/dir.cpp new file mode 100644 index 0000000..6adddec --- /dev/null +++ b/source/fs/windows/dir.cpp @@ -0,0 +1,39 @@ +#include +#include +#include "dir.h" + +using namespace std; + +namespace Msp { +namespace FS { + +void mkdir(const Path &path, int) +{ + if(!CreateDirectory(path.str().c_str(), NULL)) + throw system_error("CreateDirectory"); +} + +void rmdir(const Path &path) +{ + if(!RemoveDirectory(path.str().c_str())) + throw system_error("RemoveDirectory"); +} + +Path get_home_dir() +{ + char home[MAX_PATH]; + if(SHGetFolderPath(0, CSIDL_PERSONAL, 0, 0, home)==S_OK) + return home; + return "."; +} + +Path get_user_data_dir(const string &appname) +{ + char datadir[MAX_PATH]; + if(SHGetFolderPath(0, CSIDL_LOCAL_APPDATA, 0, 0, datadir)==S_OK) + return Path(datadir)/appname; + return "."; +} + +} // namespace FS +} // namespace Msp diff --git a/source/fs/windows/stat.cpp b/source/fs/windows/stat.cpp new file mode 100644 index 0000000..f0cbdb6 --- /dev/null +++ b/source/fs/windows/stat.cpp @@ -0,0 +1,136 @@ +#include +#include +#include +#include +#include +#include "stat.h" +#include "stat_private.h" + +using namespace std; + +namespace { + +PSID copy_sid(PSID sid) +{ + if(!sid || !IsValidSid(sid)) + return 0; + DWORD len = GetLengthSid(sid); + PSID copy = reinterpret_cast(HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, len)); + if(!CopySid(len, copy, sid)) + { + DWORD err = GetLastError(); + HeapFree(GetProcessHeap(), 0, copy); + throw Msp::system_error("CopySid", err); + } + return copy; +} + +string get_account_name(PSID sid) +{ + char name[1024]; + DWORD nlen = sizeof(name); + char domain[1024]; + DWORD dlen = sizeof(domain); + SID_NAME_USE use; + if(!LookupAccountSid(0, sid, name, &nlen, domain, &dlen, &use)) + throw Msp::system_error("LookupAccountSid"); + return Msp::format("%s/%s", name, domain); +} + +} + + +namespace Msp { +namespace FS { + +Stat::Private::Private(const Private &other): + owner_id(copy_sid(other.owner_id)), + group_id(copy_sid(other.group_id)) +{ } + +Stat::Private::~Private() +{ + if(owner_id) + HeapFree(GetProcessHeap(), 0, owner_id); + if(group_id) + HeapFree(GetProcessHeap(), 0, group_id); +} + +void Stat::Private::fill_owner_info(Stat::OwnerInfo &result) +{ + if(owner_id) + result.owner = get_account_name(owner_id); + else + result.owner = "None"; + + if(group_id) + result.group = get_account_name(group_id); + else + result.group = "None"; +} + + +Stat Stat::stat(const Path &path) +{ + HANDLE handle; + handle = CreateFile(path.str().c_str(), READ_CONTROL, FILE_SHARE_READ, 0, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL|FILE_FLAG_BACKUP_SEMANTICS, 0); + if(handle==INVALID_HANDLE_VALUE) + { + DWORD err = GetLastError(); + if(err==ERROR_FILE_NOT_FOUND) + return Stat(); + else + throw system_error("CreateFile", err); + } + + BY_HANDLE_FILE_INFORMATION info; + if(!GetFileInformationByHandle(handle, &info)) + { + CloseHandle(handle); + throw system_error("GetFileInformationByHandle"); + } + + Stat result; + if(info.dwFileAttributes&FILE_ATTRIBUTE_DIRECTORY) + result.type = DIRECTORY; + else + result.type = REGULAR; + + result.size = FileSize(info.nFileSizeHigh)<<32 | info.nFileSizeLow; + result.alloc_size = (result.size+511)&~511; + result.mtime = Time::TimeStamp(Time::filetime_to_rawtime(info.ftLastWriteTime)); + + PSECURITY_DESCRIPTOR sec_desc; + PSID owner = 0; + PSID group = 0; + const SECURITY_INFORMATION sec_info = OWNER_SECURITY_INFORMATION|GROUP_SECURITY_INFORMATION; + DWORD err = GetSecurityInfo(handle, SE_FILE_OBJECT, sec_info, &owner, &group, 0, 0, &sec_desc); + if(err) + { + CloseHandle(handle); + throw system_error("GetSecurityInfo", err); + } + + result.priv = new Private; + result.priv->owner_id = copy_sid(owner); + result.priv->group_id = copy_sid(group); + + LocalFree(sec_desc); + + CloseHandle(handle); + + return result; +} + +Stat Stat::lstat(const Path &path) +{ + return stat(path); +} + +bool exists(const Path &path) +{ + return GetFileAttributes(path.str().c_str())!=INVALID_FILE_ATTRIBUTES; +} + +} // namespace FS +} // namespace Msp diff --git a/source/fs/windows/stat_platform.h b/source/fs/windows/stat_platform.h new file mode 100644 index 0000000..4e8cfbc --- /dev/null +++ b/source/fs/windows/stat_platform.h @@ -0,0 +1,15 @@ +#ifndef MSP_FS_STAT_PLATFORM_H_ +#define MSP_FS_STAT_PLATFORM_H_ + +#include + +namespace Msp { +namespace FS { + +typedef PSID UserID; +typedef PSID GroupID; + +} // namespace FS +} // namespace Msp + +#endif diff --git a/source/fs/windows/utils.cpp b/source/fs/windows/utils.cpp new file mode 100644 index 0000000..ca9e7aa --- /dev/null +++ b/source/fs/windows/utils.cpp @@ -0,0 +1,38 @@ +#include +#include +#include "dir.h" +#include "utils.h" + +using namespace std; + +namespace Msp { +namespace FS { + +Path readlink(const Path &link) +{ + (void)link; + throw logic_error("no symbolic links on win32"); +} + +Path realpath(const Path &path) +{ + if(path.is_absolute()) + return path; + else + return getcwd()/path; +} + +void rename(const Path &from, const Path &to) +{ + if(!MoveFileEx(from.c_str(), to.c_str(), MOVEFILE_REPLACE_EXISTING)) + throw system_error("MoveFileEx"); +} + +void unlink(const Path &path) +{ + if(!DeleteFile(path.c_str())) + throw system_error("DeleteFile"); +} + +} // namespace FS +} // namespace Msp diff --git a/source/io/console.cpp b/source/io/console.cpp index a03ad20..d50d72d 100644 --- a/source/io/console.cpp +++ b/source/io/console.cpp @@ -1,36 +1,7 @@ -#ifndef WIN32 -#include -#include -#include -#include -#include -#endif -#include #include "console.h" -#include "handle_private.h" using namespace std; -namespace { - -#ifdef WIN32 -DWORD stream_to_sys(Msp::IO::Console::Stream stream) -{ - switch(stream) - { - case Msp::IO::Console::CIN: return STD_INPUT_HANDLE; - case Msp::IO::Console::COUT: return STD_OUTPUT_HANDLE; - case Msp::IO::Console::CERR: return STD_ERROR_HANDLE; - default: throw invalid_argument("stream_to_sys"); - } -} - -#else -termios orig_attr; -#endif - -} // namespace - namespace Msp { namespace IO { @@ -39,114 +10,15 @@ Console::Console(Stream s): { mode = (stream==CIN ? M_READ : M_WRITE); -#ifdef WIN32 - *handle = GetStdHandle(stream_to_sys(stream)); -#else - *handle = stream; - - if(stream==CIN) - tcgetattr(*handle, &orig_attr); -#endif + platform_init(); if(stream==CIN) set_events(P_INPUT); } -Console::~Console() -{ -#ifndef WIN32 - if(stream==CIN) - tcsetattr(*handle, TCSADRAIN, &orig_attr); -#endif -} - void Console::set_block(bool b) { -#ifdef WIN32 - // XXX Dunno how to do this in win32 - (void)b; -#else - int flags = fcntl(*handle, F_GETFL); - flags = (flags&~O_NONBLOCK) | (b?0:O_NONBLOCK); - fcntl(*handle, F_SETFL, flags); -#endif -} - -void Console::set_local_echo(bool e) -{ - check_access(M_READ); - -#ifdef WIN32 - DWORD m; - GetConsoleMode(*handle, &m); - SetConsoleMode(*handle, (m&~ENABLE_ECHO_INPUT) | (e?ENABLE_ECHO_INPUT:0)); -#else - termios t; - tcgetattr(*handle, &t); - t.c_lflag = (t.c_lflag&~ECHO) | (e?ECHO:0); - tcsetattr(*handle, TCSADRAIN, &t); -#endif -} - -void Console::set_line_buffer(bool l) -{ - check_access(M_READ); - -#ifdef WIN32 - DWORD m; - if(!GetConsoleMode(*handle, &m)) - throw system_error("GetConsoleMode"); - if(!SetConsoleMode(*handle, (m&~ENABLE_LINE_INPUT) | (l?ENABLE_LINE_INPUT:0))) - throw system_error("SetConsoleMode"); -#else - termios t; - if(tcgetattr(*handle, &t)==-1) - throw system_error("tcgetattr"); - t.c_lflag = (t.c_lflag&~ICANON) | (l?ICANON:0); - // man termios warns that VMIN and VTIME may share indices with VEOF and VEOL - if(l) - { - t.c_cc[VEOF] = orig_attr.c_cc[VEOF]; - t.c_cc[VEOL] = orig_attr.c_cc[VEOL]; - } - else - { - t.c_cc[VMIN] = 1; - t.c_cc[VTIME] = 0; - } - if(tcsetattr(*handle, TCSADRAIN, &t)==-1) - throw system_error("tcsetattr"); -#endif -} - -void Console::get_size(unsigned &rows, unsigned &cols) -{ - check_access(M_WRITE); - -#ifdef WIN32 - CONSOLE_SCREEN_BUFFER_INFO sbi; - if(!GetConsoleScreenBufferInfo(*handle, &sbi)) - throw system_error("GetConsoleScreenBufferInfo"); - // Right/bottom coords are inclusive - rows = sbi.srWindow.Bottom+1-sbi.srWindow.Top; - cols = sbi.srWindow.Right+1-sbi.srWindow.Left; -#else - struct winsize wsz; - if(ioctl(*handle, TIOCGWINSZ, &wsz)==-1) - throw system_error("ioctl TIOCGWINSZ"); - rows = wsz.ws_row; - cols = wsz.ws_col; -#endif -} - -void Console::redirect(Base &other) -{ - Handle other_handle = other.get_handle(mode&M_RDWR); -#ifdef WIN32 - SetStdHandle(stream_to_sys(stream), *other_handle); -#else - dup2(*other_handle, *handle); -#endif + sys_set_blocking(handle, b); } unsigned Console::do_write(const char *buf, unsigned len) diff --git a/source/io/console.h b/source/io/console.h index 7b7887b..5cb5f17 100644 --- a/source/io/console.h +++ b/source/io/console.h @@ -27,6 +27,7 @@ private: Handle handle; Console(Stream); + void platform_init(); public: ~Console(); diff --git a/source/io/eventreader.cpp b/source/io/eventreader.cpp deleted file mode 100644 index 370ddf2..0000000 --- a/source/io/eventreader.cpp +++ /dev/null @@ -1,139 +0,0 @@ -#ifdef WIN32 -#include -#endif -#include -#include -#include "eventreader.h" -#include "handle_private.h" - -using namespace std; - -namespace Msp { -namespace IO { - -struct EventReader::Private -{ -#ifdef WIN32 - OVERLAPPED *overlapped; - Handle event; - unsigned buf_size; - char *buffer; - unsigned buf_avail; - char *buf_next; -#endif -}; - - -EventReader::EventReader(Handle &h, unsigned size): - handle(h), - priv(0) -{ -#ifdef WIN32 - priv = new Private; - - priv->overlapped = 0; - *priv->event = CreateEvent(0, true, false, 0); - priv->buf_size = size; - priv->buffer = new char[priv->buf_size]; - priv->buf_avail = 0; - priv->buf_next = priv->buffer; -#else - (void)size; -#endif -} - -EventReader::~EventReader() -{ -#ifdef WIN32 - CloseHandle(*priv->event); - delete priv->overlapped; - delete[] priv->buffer; -#endif - delete priv; -} - -const Handle &EventReader::get_event() -{ -#ifdef WIN32 - start(); - return priv->event; -#else - return handle; -#endif -} - -void EventReader::start() -{ -#ifdef WIN32 - if(priv->buf_avail || priv->overlapped) - return; - - priv->overlapped = new OVERLAPPED; - memset(priv->overlapped, 0, sizeof(OVERLAPPED)); - priv->overlapped->hEvent = *priv->event; - - DWORD ret; - priv->buf_next = priv->buffer; - if(!ReadFile(*handle, priv->buffer, priv->buf_size, &ret, priv->overlapped)) - { - unsigned err = GetLastError(); - if(err!=ERROR_IO_PENDING) - throw system_error("ReadFile"); - } - else - { - priv->buf_avail = ret; - delete priv->overlapped; - priv->overlapped = 0; - SetEvent(*priv->event); - } -#endif -} - -void EventReader::wait() -{ -#ifdef WIN32 - if(!priv->overlapped) - return; - - DWORD ret; - if(!GetOverlappedResult(*handle, priv->overlapped, &ret, true)) - throw system_error("GetOverlappedResult"); - else - { - priv->buf_avail = ret; - delete priv->overlapped; - priv->overlapped = 0; - } -#endif -} - -unsigned EventReader::read(char *buf, unsigned len) -{ -#ifdef WIN32 - if(!priv->buf_avail) - { - // No data in buffer, try to get some - start(); - wait(); - } - - len = min(len, priv->buf_avail); - memcpy(buf, priv->buf_next, len); - priv->buf_next += len; - priv->buf_avail -= len; - - if(!priv->buf_avail) - { - ResetEvent(*priv->event); - start(); - } - - return len; -#else - return sys_read(handle, buf, len); -#endif -} - -} // namespace IO -} // namespace Msp diff --git a/source/io/file.cpp b/source/io/file.cpp index 805a9e8..9069432 100644 --- a/source/io/file.cpp +++ b/source/io/file.cpp @@ -1,10 +1,3 @@ -#ifndef WIN32 -#include -#include -#include -#endif -#include -#include #include "file.h" #include "handle_private.h" @@ -24,77 +17,7 @@ File::File(const string &fn, Mode m, CreateMode cm) mode = m; -#ifdef WIN32 - int flags = 0; - int share_flags = 0; - int create_flags = OPEN_EXISTING; - - if(mode&M_READ) - flags |= GENERIC_READ; - - if(mode&M_WRITE) - { - flags |= GENERIC_WRITE; - - switch(static_cast(cm)) - { - case C_NONE: create_flags = OPEN_EXISTING; break; - case C_CREATE: create_flags = OPEN_ALWAYS; break; - case C_TRUNCATE: create_flags = TRUNCATE_EXISTING; break; - case C_OVERWRITE: create_flags = CREATE_ALWAYS; break; - case C_NEW: create_flags = CREATE_NEW; break; - } - } - else - share_flags = FILE_SHARE_READ; - - *handle = CreateFile(fn.c_str(), flags, share_flags, 0, create_flags, FILE_ATTRIBUTE_NORMAL, 0); - if(!handle) - { - int err = GetLastError(); - if(err==ERROR_FILE_NOT_FOUND) - throw file_not_found(fn); - else if(err==ERROR_FILE_EXISTS) - throw file_already_exists(fn); - else - throw system_error(format("CreateFile(%s)", fn), err); - } -#else - int flags = 0; - switch(mode&M_RDWR) - { - case M_READ: flags |= O_RDONLY; break; - case M_WRITE: flags |= O_WRONLY; break; - case M_RDWR: flags |= O_RDWR; break; - default:; - } - - if(mode&M_WRITE) - { - if(cm&C_CREATE) - flags |= O_CREAT; - if(cm&C_TRUNCATE) - flags |= O_TRUNC; - if(cm&C_EXCLUSIVE) - flags |= O_EXCL; - } - if(mode&M_APPEND) - flags |= O_APPEND; - if(mode&M_NONBLOCK) - flags |= O_NONBLOCK; - - *handle = ::open(fn.c_str(), flags, 0666); - if(!handle) - { - int err = errno; - if(err==ENOENT) - throw file_not_found(fn); - else if(err==EEXIST) - throw file_already_exists(fn); - else - throw system_error(format("open(%s)", fn), err); - } -#endif + platform_init(fn, cm); } File::~File() @@ -105,13 +28,8 @@ File::~File() void File::set_block(bool b) { - mode = (mode&~M_NONBLOCK); - if(b) - mode = (mode|M_NONBLOCK); -#ifndef WIN32 - int flags = fcntl(*handle, F_GETFD); - fcntl(*handle, F_SETFL, (flags&O_NONBLOCK)|(b?0:O_NONBLOCK)); -#endif + mode = b?(mode&~M_NONBLOCK):(mode|M_NONBLOCK); + sys_set_blocking(handle, b); } unsigned File::do_write(const char *buf, unsigned size) @@ -143,15 +61,6 @@ unsigned File::do_read(char *buf, unsigned size) return ret; } -void File::sync() -{ -#ifndef WIN32 - signal_flush_required.emit(); - - fsync(*handle); -#endif -} - SeekOffset File::seek(SeekOffset off, SeekType type) { signal_flush_required.emit(); diff --git a/source/io/file.h b/source/io/file.h index 90a1041..d106561 100644 --- a/source/io/file.h +++ b/source/io/file.h @@ -52,6 +52,9 @@ public: write access is requested and the file does exist, it is created. Otherwise a missing file is an error. */ File(const std::string &, Mode = M_READ, CreateMode = C_OVERWRITE); +private: + void platform_init(const std::string &, CreateMode); +public: virtual ~File(); void set_block(bool); diff --git a/source/io/handle.cpp b/source/io/handle.cpp index 0e9b82a..c20f067 100644 --- a/source/io/handle.cpp +++ b/source/io/handle.cpp @@ -1,6 +1,3 @@ -#include -#include -#include #include "handle.h" #include "handle_private.h" @@ -28,79 +25,16 @@ Handle::~Handle() delete priv; } -Handle::operator const void *() const -{ -#ifdef WIN32 - return priv->handle!=INVALID_HANDLE_VALUE ? this : 0; -#else - return priv->handle!=-1 ? this : 0; -#endif -} - Handle::Private::Private(): -#ifdef WIN32 handle(INVALID_HANDLE_VALUE) -#else - handle(-1) -#endif { } -Handle::Private &Handle::Private::operator=(H h) +Handle::Private &Handle::Private::operator=(PlatformHandle h) { handle = h; return *this; } - -unsigned sys_read(Handle &handle, char *buf, unsigned size) -{ -#ifdef WIN32 - DWORD ret; - if(ReadFile(*handle, buf, size, &ret, 0)==0) - throw system_error("ReadFile"); -#else - int ret = read(*handle, buf, size); - if(ret==-1) - { - if(errno==EAGAIN) - return 0; - else - throw system_error("read"); - } -#endif - - return ret; -} - -unsigned sys_write(Handle &handle, const char *buf, unsigned size) -{ -#ifdef WIN32 - DWORD ret; - if(WriteFile(*handle, buf, size, &ret, 0)==0) - throw system_error("WriteFile"); -#else - int ret = write(*handle, buf, size); - if(ret==-1) - { - if(errno==EAGAIN) - return 0; - else - throw system_error("write"); - } -#endif - - return ret; -} - -void sys_close(Handle &handle) -{ -#ifdef WIN32 - CloseHandle(*handle); -#else - close(*handle); -#endif -} - } // namespace IO } // namespace Msp diff --git a/source/io/handle.h b/source/io/handle.h index 24b9ee6..8a9db50 100644 --- a/source/io/handle.h +++ b/source/io/handle.h @@ -28,6 +28,7 @@ public: }; +void sys_set_blocking(Handle &, bool); unsigned sys_read(Handle &, char *, unsigned); unsigned sys_write(Handle &, const char *, unsigned); void sys_close(Handle &); diff --git a/source/io/handle_private.h b/source/io/handle_private.h index d73a2b8..4fa690a 100644 --- a/source/io/handle_private.h +++ b/source/io/handle_private.h @@ -1,28 +1,20 @@ #ifndef MSP_IO_HANDLE_PRIVATE_H_ #define MSP_IO_HANDLE_PRIVATE_H_ -#ifdef WIN32 -#include -#endif #include "handle.h" +#include "handle_platform.h" namespace Msp { namespace IO { struct Handle::Private { -#ifdef WIN32 - typedef HANDLE H; -#else - typedef int H; -#endif - - H handle; + PlatformHandle handle; Private(); - Private &operator=(H); - operator H() const { return handle; } + Private &operator=(PlatformHandle); + operator PlatformHandle() const { return handle; } }; } // namespace IO diff --git a/source/io/pipe.cpp b/source/io/pipe.cpp index 0f20698..831076f 100644 --- a/source/io/pipe.cpp +++ b/source/io/pipe.cpp @@ -1,11 +1,3 @@ -#ifndef WIN32 -#include -#include -#include -#endif -#include -#include -#include "handle_private.h" #include "pipe.h" using namespace std; @@ -18,27 +10,7 @@ Pipe::Pipe(): { mode = M_RDWR; -#ifdef WIN32 - string name = format("\\\\.\\pipe\\%u.%p", GetCurrentProcessId(), this); - *read_handle = CreateNamedPipe(name.c_str(), PIPE_ACCESS_INBOUND|FILE_FLAG_OVERLAPPED, PIPE_TYPE_BYTE, 1, 1024, 1024, 0, 0); - if(!read_handle) - throw system_error("CreateNamedPipe"); - - *write_handle = CreateFile(name.c_str(), GENERIC_WRITE, 0, 0, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, 0); - if(!write_handle) - { - unsigned err = GetLastError(); - CloseHandle(*read_handle); - throw system_error(format("CreateFile(%s)", name), err); - } -#else - int pipe_fd[2]; - if(pipe(pipe_fd)==-1) - throw system_error("pipe"); - - *read_handle = pipe_fd[0]; - *write_handle = pipe_fd[1]; -#endif + platform_init(); set_events(P_INPUT); } @@ -58,12 +30,8 @@ void Pipe::set_block(bool b) if(b) mode = (mode|M_NONBLOCK); -#ifndef WIN32 - int flags = fcntl(*read_handle, F_GETFD); - fcntl(*read_handle, F_SETFL, (flags&O_NONBLOCK)|(b?0:O_NONBLOCK)); - flags = fcntl(*write_handle, F_GETFD); - fcntl(*write_handle, F_SETFL, (flags&O_NONBLOCK)|(b?0:O_NONBLOCK)); -#endif + sys_set_blocking(read_handle, b); + sys_set_blocking(write_handle, b); } unsigned Pipe::do_write(const char *buf, unsigned size) diff --git a/source/io/pipe.h b/source/io/pipe.h index d1508b2..50da5e5 100644 --- a/source/io/pipe.h +++ b/source/io/pipe.h @@ -17,6 +17,9 @@ private: public: Pipe(); +private: + void platform_init(); +public: ~Pipe(); void set_block(bool); diff --git a/source/io/poll.cpp b/source/io/poll.cpp index a580907..0356a00 100644 --- a/source/io/poll.cpp +++ b/source/io/poll.cpp @@ -1,106 +1,13 @@ -#include #include -#ifndef WIN32 -#include -#endif -#include -#include #include "eventobject.h" -#include "handle.h" -#include "handle_private.h" #include "poll.h" +#include "poll_platform.h" using namespace std; -namespace { - -using namespace Msp; -using namespace Msp::IO; - -inline short int sys_poll_event(PollEvent event) -{ - int result = 0; - - if(event&~(P_INPUT|P_PRIO|P_OUTPUT)) - throw invalid_argument("sys_poll_event"); - -#ifndef WIN32 - if(event&P_INPUT) - result |= POLLIN; - if(event&P_PRIO) - result |= POLLPRI; - if(event&P_OUTPUT) - result |= POLLOUT; -#endif - - return result; -} - -inline PollEvent poll_event_from_sys(int event) -{ - PollEvent result = P_NONE; - -#ifdef WIN32 - (void)event; -#else - if(event&POLLIN) - result = result|P_INPUT; - if(event&POLLPRI) - result = result|P_PRIO; - if(event&POLLOUT) - result = result|P_OUTPUT; - if(event&POLLERR) - result = result|P_ERROR; -#endif - - return result; -} - -inline PollEvent do_poll(EventObject &obj, PollEvent pe, int timeout) -{ -#ifdef WIN32 - if(timeout<0) - timeout = INFINITE; - - DWORD ret = WaitForSingleObject(*obj.get_event_handle(), timeout); - if(ret==WAIT_OBJECT_0) - return pe; - else if(ret==WAIT_FAILED) - throw system_error("WaitForSingleObject"); - - return P_NONE; -#else - pollfd pfd = { *obj.get_event_handle(), sys_poll_event(pe), 0 }; - - int ret = ::poll(&pfd, 1, timeout); - if(ret==-1) - { - if(errno==EINTR) - return P_NONE; - else - throw system_error("poll"); - } - - return poll_event_from_sys(pfd.revents); -#endif -} - -} - - namespace Msp { namespace IO { -struct Poller::Private -{ -#ifdef WIN32 - vector handles; -#else - vector pfd; -#endif -}; - - Poller::Poller(): priv(new Private), objs_changed(false) @@ -152,28 +59,6 @@ int Poller::poll(const Time::TimeDelta &timeout) return do_poll(static_cast(timeout/Time::msec)); } -void Poller::rebuild_array() -{ -#ifdef WIN32 - priv->handles.clear(); - - for(EventMap::iterator i=objects.begin(); i!=objects.end(); ++i) - priv->handles.push_back(*i->first->get_event_handle()); -#else - priv->pfd.clear(); - - for(EventMap::iterator i=objects.begin(); i!=objects.end(); ++i) - { - pollfd p; - p.fd = *i->first->get_event_handle(); - p.events = sys_poll_event(i->second); - priv->pfd.push_back(p); - } -#endif - - objs_changed = false; -} - int Poller::do_poll(int timeout) { if(objs_changed) @@ -181,50 +66,18 @@ int Poller::do_poll(int timeout) poll_result.clear(); -#ifdef WIN32 - if(timeout<0) - timeout = INFINITE; - - DWORD ret = WaitForMultipleObjects(priv->handles.size(), &priv->handles.front(), false, timeout); - if(/*ret>=WAIT_OBJECT_0 &&*/ rethandles.size()) - { - EventMap::iterator i = objects.begin(); - advance(i, ret-WAIT_OBJECT_0); - poll_result.push_back(Slot(i->first, i->second)); - - return 1; - } - else if(ret==WAIT_FAILED) - throw system_error("WaitForMultipleObjects"); + platform_poll(timeout); - return 0; -#else - int ret = ::poll(&priv->pfd.front(), priv->pfd.size(), timeout); - if(ret==-1) - { - if(errno==EINTR) - return 0; - else - throw system_error("poll"); - } + return poll_result.size(); +} - int n = ret; - EventMap::iterator j = objects.begin(); - for(vector::iterator i=priv->pfd.begin(); (i!=priv->pfd.end() && n>0); ++i, ++j) - if(i->revents) - { - poll_result.push_back(Slot(j->first, poll_event_from_sys(i->revents))); - --n; - } - return ret; -#endif -} +PollEvent platform_poll(EventObject &, PollEvent, int); PollEvent poll(EventObject &obj, PollEvent pe) { - return do_poll(obj, pe, -1); + return platform_poll(obj, pe, -1); } PollEvent poll(EventObject &obj, PollEvent pe, const Time::TimeDelta &timeout) @@ -232,7 +85,7 @@ PollEvent poll(EventObject &obj, PollEvent pe, const Time::TimeDelta &timeout) if(timeout(timeout/Time::msec)); + return platform_poll(obj, pe, static_cast(timeout/Time::msec)); } } // namespace IO diff --git a/source/io/poll.h b/source/io/poll.h index d7823aa..09e00e5 100644 --- a/source/io/poll.h +++ b/source/io/poll.h @@ -62,6 +62,7 @@ public: private: void rebuild_array(); int do_poll(int); + void platform_poll(int); public: const SlotList &get_result() const { return poll_result; } }; diff --git a/source/io/seekable.cpp b/source/io/seekable.cpp index 35ab5a0..6bc8485 100644 --- a/source/io/seekable.cpp +++ b/source/io/seekable.cpp @@ -1,46 +1,8 @@ -#ifndef WIN32 -#define _LARGEFILE64_SOURCE -#include -#include -#else -#include -#endif -#include #include -#include "handle.h" -#include "handle_private.h" #include "seekable.h" using namespace std; -namespace { - -using namespace Msp::IO; - -int sys_seek_type(SeekType st) -{ -#ifdef WIN32 - if(st==S_BEG) - return FILE_BEGIN; - else if(st==S_CUR) - return FILE_CURRENT; - else if(st==S_END) - return FILE_END; -#else - if(st==S_BEG) - return SEEK_SET; - else if(st==S_CUR) - return SEEK_CUR; - else if(st==S_END) - return SEEK_END; -#endif - - throw invalid_argument("sys_seek_type"); -} - -} // namespace - - namespace Msp { namespace IO { @@ -51,33 +13,5 @@ bad_seek::bad_seek(SeekOffset offset, SeekType type): format("SeekType(%d)", type)) { } - -SeekOffset sys_seek(Handle &handle, SeekOffset offset, SeekType type) -{ -#ifdef WIN32 - LONG high = offset>>32; - DWORD ret = SetFilePointer(*handle, offset, &high, sys_seek_type(type)); - if(ret==INVALID_SET_FILE_POINTER) - { - DWORD err = GetLastError(); - if(err!=NO_ERROR) - throw system_error("SetFilePointer"); - } - - return (SeekOffset(high)<<32) | ret; -#else - off64_t ret = lseek64(*handle, offset, sys_seek_type(type)); - if(ret==(off64_t)-1) - { - if(errno==EINVAL) - throw bad_seek(offset, type); - else - throw system_error("lseek64"); - } - - return ret; -#endif -} - } // namespace IO } // namespace Msp diff --git a/source/io/serial.cpp b/source/io/serial.cpp index dc623e2..cf2c695 100644 --- a/source/io/serial.cpp +++ b/source/io/serial.cpp @@ -1,196 +1,18 @@ -#ifdef WIN32 -#include -#else -#include -#include -#include -#endif -#include -#include -#include "handle_private.h" #include "serial.h" +#include "serial_private.h" using namespace std; namespace Msp { namespace IO { -struct Serial::DeviceState -{ -#ifdef WIN32 - DCB state; -#else - termios state; -#endif - - void get_from(const Handle &); - void apply_to(const Handle &); - void set_baud_rate(unsigned); - void set_data_bits(unsigned); - void set_parity(Parity); - void set_stop_bits(unsigned); -}; - -void Serial::DeviceState::get_from(const Handle &handle) -{ -#ifdef WIN32 - GetCommState(*handle, &state); -#else - tcgetattr(*handle, &state); -#endif -} - -void Serial::DeviceState::apply_to(const Handle &handle) -{ -#ifdef WIN32 - if(SetCommState(*handle, &state)==0) - throw system_error("SetCommState"); -#else - if(tcsetattr(*handle, TCSADRAIN, &state)==-1) - throw system_error("tcsetattr"); -#endif -} - -void Serial::DeviceState::set_baud_rate(unsigned baud) -{ -#ifdef WIN32 - state.BaudRate = baud; -#else - speed_t speed; - switch(baud) - { - case 0: speed = B0; break; - case 50: speed = B50; break; - case 75: speed = B75; break; - case 110: speed = B110; break; - case 134: speed = B134; break; - case 150: speed = B150; break; - case 200: speed = B200; break; - case 300: speed = B300; break; - case 600: speed = B600; break; - case 1200: speed = B1200; break; - case 1800: speed = B1800; break; - case 2400: speed = B2400; break; - case 4800: speed = B4800; break; - case 9600: speed = B9600; break; - case 19200: speed = B19200; break; - case 38400: speed = B38400; break; - case 57600: speed = B57600; break; - case 115200: speed = B115200; break; - case 230400: speed = B230400; break; - default: throw invalid_argument("set_baud_rate"); - } - - cfsetospeed(&state, speed); - cfsetispeed(&state, speed); -#endif -} - -void Serial::DeviceState::set_data_bits(unsigned bits) -{ -#ifdef WIN32 - state.ByteSize = bits; -#else - tcflag_t flag; - switch(bits) - { - case 5: flag = CS5; break; - case 6: flag = CS6; break; - case 7: flag = CS7; break; - case 8: flag = CS8; break; - default: throw invalid_argument("set_data_bits"); - } - - state.c_cflag = (state.c_cflag&~CSIZE)|flag; -#endif -} - -void Serial::DeviceState::set_parity(Serial::Parity par) -{ -#ifdef WIN32 - switch(par) - { - case Serial::NONE: state.Parity = NOPARITY; break; - case Serial::EVEN: state.Parity = EVENPARITY; break; - case Serial::ODD: state.Parity = ODDPARITY; break; - default: throw invalid_argument("set_parity"); - } -#else - tcflag_t flag; - switch(par) - { - case Serial::NONE: flag = 0; break; - case Serial::EVEN: flag = PARENB; break; - case Serial::ODD: flag = PARENB|PARODD; break; - default: throw invalid_argument("set_parity"); - } - - state.c_cflag = (state.c_cflag&~(PARENB|PARODD))|flag; -#endif -} - -void Serial::DeviceState::set_stop_bits(unsigned bits) -{ -#ifdef WIN32 - switch(bits) - { - case 1: state.StopBits = ONESTOPBIT; break; - case 2: state.StopBits = TWOSTOPBITS; break; - default: throw invalid_argument("set_stop_bits"); - } -#else - tcflag_t flag; - switch(bits) - { - case 1: flag = 0; break; - case 2: flag = CSTOPB; break; - default: throw invalid_argument("set_stop_bits"); - } - - state.c_cflag = (state.c_cflag&~CSTOPB)|flag; -#endif -} - - Serial::Serial(const string &descr): reader(handle, 1024) { string::size_type comma = descr.find(','); string port = descr.substr(0, comma); -#ifdef WIN32 - port = "\\\\.\\"+port; - - *handle = CreateFile(port.c_str(), GENERIC_READ|GENERIC_WRITE, 0, 0, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL|FILE_FLAG_OVERLAPPED, 0); - if(!handle) - throw system_error(format("CreateFile(%s)", port)); - mode = M_READ|M_WRITE; - - COMMTIMEOUTS timeouts; - timeouts.ReadIntervalTimeout = MAXDWORD; - timeouts.ReadTotalTimeoutMultiplier = MAXDWORD; - timeouts.ReadTotalTimeoutConstant = MAXDWORD-1; - timeouts.WriteTotalTimeoutMultiplier = 0; - timeouts.WriteTotalTimeoutConstant = 0; - SetCommTimeouts(*handle, &timeouts); -#else - if(port.compare(0, 5, "/dev/")) - port = "/dev/"+port; - - *handle = open(port.c_str(), O_RDWR); - if(!handle) - throw system_error(format("open(%s)", port)); - mode = M_READ|M_WRITE; - - termios t; - tcgetattr(*handle, &t); - t.c_iflag &= ~(ISTRIP|INLCR|IGNCR|ICRNL|IXON); - t.c_lflag &= ~(ECHO|ICANON|ISIG|IEXTEN); - t.c_oflag &= ~(OPOST|OCRNL|ONOCR|ONLRET); - t.c_cc[VMIN] = 1; - t.c_cc[VTIME] = 0; - tcsetattr(*handle, TCSADRAIN, &t); -#endif + platform_init(port); if(comma!=string::npos) { @@ -220,15 +42,8 @@ void Serial::close() void Serial::set_block(bool b) { - if(b) - mode = mode|M_NONBLOCK; - else - mode = mode&~M_NONBLOCK; - -#ifndef WIN32 - int flags = fcntl(*handle, F_GETFD); - fcntl(*handle, F_SETFL, (flags&O_NONBLOCK)|(b?0:O_NONBLOCK)); -#endif + mode = b?(mode&~M_NONBLOCK):(mode|M_NONBLOCK); + sys_set_blocking(handle, b); } void Serial::set_baud_rate(unsigned rate) diff --git a/source/io/serial.h b/source/io/serial.h index 49ecefb..1c91e60 100644 --- a/source/io/serial.h +++ b/source/io/serial.h @@ -26,6 +26,9 @@ private: public: Serial(const std::string &); +private: + void platform_init(const std::string &); +public: virtual ~Serial(); private: diff --git a/source/io/serial_private.h b/source/io/serial_private.h new file mode 100644 index 0000000..1b497be --- /dev/null +++ b/source/io/serial_private.h @@ -0,0 +1,25 @@ +#ifndef MSP_IO_SERIAL_PRIVATE_H_ +#define MSP_IO_SERIAL_PRIVATE_H_ + +#include "serial.h" +#include "serial_platform.h" + +namespace Msp { +namespace IO { + +struct Serial::DeviceState +{ + PlatformSerialDeviceState state; + + void get_from(const Handle &); + void apply_to(const Handle &); + void set_baud_rate(unsigned); + void set_data_bits(unsigned); + void set_parity(Serial::Parity); + void set_stop_bits(unsigned); +}; + +} // namespace IO +} // namespace Msp + +#endif diff --git a/source/io/unix/console.cpp b/source/io/unix/console.cpp new file mode 100644 index 0000000..d38d0bb --- /dev/null +++ b/source/io/unix/console.cpp @@ -0,0 +1,83 @@ +#include +#include +#include +#include +#include +#include "console.h" +#include "handle_private.h" + +namespace { + +termios orig_attr; + +} + + +namespace Msp { +namespace IO { + +void Console::platform_init() +{ + *handle = stream; + + if(stream==CIN) + tcgetattr(*handle, &orig_attr); +} + +Console::~Console() +{ + if(stream==CIN) + tcsetattr(*handle, TCSADRAIN, &orig_attr); +} + +void Console::set_local_echo(bool e) +{ + check_access(M_READ); + + termios t; + tcgetattr(*handle, &t); + t.c_lflag = (t.c_lflag&~ECHO) | (e?ECHO:0); + tcsetattr(*handle, TCSADRAIN, &t); +} + +void Console::set_line_buffer(bool l) +{ + check_access(M_READ); + + termios t; + if(tcgetattr(*handle, &t)==-1) + throw system_error("tcgetattr"); + t.c_lflag = (t.c_lflag&~ICANON) | (l?ICANON:0); + // man termios warns that VMIN and VTIME may share indices with VEOF and VEOL + if(l) + { + t.c_cc[VEOF] = orig_attr.c_cc[VEOF]; + t.c_cc[VEOL] = orig_attr.c_cc[VEOL]; + } + else + { + t.c_cc[VMIN] = 1; + t.c_cc[VTIME] = 0; + } + if(tcsetattr(*handle, TCSADRAIN, &t)==-1) + throw system_error("tcsetattr"); +} + +void Console::get_size(unsigned &rows, unsigned &cols) +{ + check_access(M_WRITE); + + struct winsize wsz; + if(ioctl(*handle, TIOCGWINSZ, &wsz)==-1) + throw system_error("ioctl TIOCGWINSZ"); + rows = wsz.ws_row; + cols = wsz.ws_col; +} + +void Console::redirect(Base &other) +{ + dup2(*other.get_handle(mode), *handle); +} + +} // namespace IO +} // namespace Msp diff --git a/source/io/unix/eventreader.cpp b/source/io/unix/eventreader.cpp new file mode 100644 index 0000000..fcbc892 --- /dev/null +++ b/source/io/unix/eventreader.cpp @@ -0,0 +1,31 @@ +#include "eventreader.h" + +namespace Msp { +namespace IO { + +EventReader::EventReader(Handle &h, unsigned): + handle(h), + priv(0) +{ } + +EventReader::~EventReader() +{ } + +const Handle &EventReader::get_event() +{ + return handle; +} + +void EventReader::start() +{ } + +void EventReader::wait() +{ } + +unsigned EventReader::read(char *buf, unsigned len) +{ + return sys_read(handle, buf, len); +} + +} // namespace IO +} // namespace Msp diff --git a/source/io/unix/file.cpp b/source/io/unix/file.cpp new file mode 100644 index 0000000..b2c9089 --- /dev/null +++ b/source/io/unix/file.cpp @@ -0,0 +1,60 @@ +#include +#include +#include +#include +#include +#include "file.h" +#include "handle_private.h" + +using namespace std; + +namespace Msp { +namespace IO { + +void File::platform_init(const string &fn, CreateMode cm) +{ + int flags = 0; + switch(mode&M_RDWR) + { + case M_READ: flags |= O_RDONLY; break; + case M_WRITE: flags |= O_WRONLY; break; + case M_RDWR: flags |= O_RDWR; break; + default:; + } + + if(mode&M_WRITE) + { + if(cm&C_CREATE) + flags |= O_CREAT; + if(cm&C_TRUNCATE) + flags |= O_TRUNC; + if(cm&C_EXCLUSIVE) + flags |= O_EXCL; + } + if(mode&M_APPEND) + flags |= O_APPEND; + if(mode&M_NONBLOCK) + flags |= O_NONBLOCK; + + *handle = ::open(fn.c_str(), flags, 0666); + if(!handle) + { + int err = errno; + if(err==ENOENT) + throw file_not_found(fn); + else if(err==EEXIST) + throw file_already_exists(fn); + else + throw system_error(format("open(%s)", fn), err); + } +} + +void File::sync() +{ + signal_flush_required.emit(); + + fsync(*handle); +} + +} // namespace IO +} // namespace Msp diff --git a/source/io/unix/handle.cpp b/source/io/unix/handle.cpp new file mode 100644 index 0000000..9546df9 --- /dev/null +++ b/source/io/unix/handle.cpp @@ -0,0 +1,57 @@ +#include +#include +#include +#include +#include "handle.h" +#include "handle_private.h" + +namespace Msp { +namespace IO { + +Handle::operator const void *() const +{ + return priv->handle!=-1 ? this : 0; +} + + +void sys_set_blocking(Handle &handle, bool b) +{ + int flags = fcntl(*handle, F_GETFD); + fcntl(*handle, F_SETFL, (flags&~O_NONBLOCK)|(b?0:O_NONBLOCK)); +} + +unsigned sys_read(Handle &handle, char *buf, unsigned size) +{ + int ret = read(*handle, buf, size); + if(ret==-1) + { + if(errno==EAGAIN) + return 0; + else + throw system_error("read"); + } + + return ret; +} + +unsigned sys_write(Handle &handle, const char *buf, unsigned size) +{ + int ret = write(*handle, buf, size); + if(ret==-1) + { + if(errno==EAGAIN) + return 0; + else + throw system_error("write"); + } + + return ret; +} + +void sys_close(Handle &handle) +{ + close(*handle); +} + +} // namespace IO +} // namespace Msp diff --git a/source/io/unix/handle_platform.h b/source/io/unix/handle_platform.h new file mode 100644 index 0000000..b241669 --- /dev/null +++ b/source/io/unix/handle_platform.h @@ -0,0 +1,14 @@ +#ifndef MSP_IO_HANDLE_PLATFORM_H_ +#define MSP_IO_HANDLE_PLATFORM_H_ + +namespace Msp { +namespace IO { + +typedef int PlatformHandle; + +#define INVALID_HANDLE_VALUE -1 + +} // namespace IO +} // namespace Msp + +#endif diff --git a/source/io/unix/pipe.cpp b/source/io/unix/pipe.cpp new file mode 100644 index 0000000..de93f82 --- /dev/null +++ b/source/io/unix/pipe.cpp @@ -0,0 +1,20 @@ +#include +#include +#include "handle_private.h" +#include "pipe.h" + +namespace Msp { +namespace IO { + +void Pipe::platform_init() +{ + int pipe_fd[2]; + if(pipe(pipe_fd)==-1) + throw system_error("pipe"); + + *read_handle = pipe_fd[0]; + *write_handle = pipe_fd[1]; +} + +} // namespace IO +} // namespace Msp diff --git a/source/io/unix/poll.cpp b/source/io/unix/poll.cpp new file mode 100644 index 0000000..650f226 --- /dev/null +++ b/source/io/unix/poll.cpp @@ -0,0 +1,109 @@ +#include +#include +#include +#include "eventobject.h" +#include "handle.h" +#include "handle_private.h" +#include "poll.h" +#include "poll_platform.h" + +using namespace std; + +namespace { + +using namespace Msp; +using namespace Msp::IO; + +inline short int sys_poll_event(PollEvent event) +{ + int result = 0; + + if(event&~(P_INPUT|P_PRIO|P_OUTPUT)) + throw invalid_argument("sys_poll_event"); + + if(event&P_INPUT) + result |= POLLIN; + if(event&P_PRIO) + result |= POLLPRI; + if(event&P_OUTPUT) + result |= POLLOUT; + + return result; +} + +inline PollEvent poll_event_from_sys(int event) +{ + PollEvent result = P_NONE; + + if(event&POLLIN) + result = result|P_INPUT; + if(event&POLLPRI) + result = result|P_PRIO; + if(event&POLLOUT) + result = result|P_OUTPUT; + if(event&POLLERR) + result = result|P_ERROR; + + return result; +} + +} + + +namespace Msp { +namespace IO { + +void Poller::rebuild_array() +{ + priv->pfd.clear(); + + for(EventMap::iterator i=objects.begin(); i!=objects.end(); ++i) + { + pollfd p; + p.fd = *i->first->get_event_handle(); + p.events = sys_poll_event(i->second); + priv->pfd.push_back(p); + } + + objs_changed = false; +} + +void Poller::platform_poll(int timeout) +{ + int ret = ::poll(&priv->pfd.front(), priv->pfd.size(), timeout); + if(ret==-1) + { + if(errno==EINTR) + return; + else + throw system_error("poll"); + } + + EventMap::iterator j = objects.begin(); + for(vector::iterator i=priv->pfd.begin(); (i!=priv->pfd.end() && ret>0); ++i, ++j) + if(i->revents) + { + poll_result.push_back(Slot(j->first, poll_event_from_sys(i->revents))); + --ret; + } +} + + +PollEvent platform_poll(EventObject &obj, PollEvent pe, int timeout) +{ + pollfd pfd = { *obj.get_event_handle(), sys_poll_event(pe), 0 }; + + int ret = ::poll(&pfd, 1, timeout); + if(ret==-1) + { + if(errno==EINTR) + return P_NONE; + else + throw system_error("poll"); + } + + return poll_event_from_sys(pfd.revents); +} + +} // namespace IO +} // namespace Msp diff --git a/source/io/unix/poll_platform.h b/source/io/unix/poll_platform.h new file mode 100644 index 0000000..bfd83da --- /dev/null +++ b/source/io/unix/poll_platform.h @@ -0,0 +1,18 @@ +#ifndef MSP_IO_POLL_PLATFORM_H_ +#define MSP_IO_POLL_PLATFORM_H_ + +#include +#include + +namespace Msp { +namespace IO { + +struct Poller::Private +{ + std::vector pfd; +}; + +} // namespace IO +} // namespace Msp + +#endif diff --git a/source/io/unix/seekable.cpp b/source/io/unix/seekable.cpp new file mode 100644 index 0000000..2c17114 --- /dev/null +++ b/source/io/unix/seekable.cpp @@ -0,0 +1,47 @@ +#define _LARGEFILE64_SOURCE +#include +#include +#include +#include "handle.h" +#include "handle_private.h" +#include "seekable.h" + +using namespace std; + +namespace { + +using namespace Msp::IO; + +int sys_seek_type(SeekType st) +{ + if(st==S_BEG) + return SEEK_SET; + else if(st==S_CUR) + return SEEK_CUR; + else if(st==S_END) + return SEEK_END; + + throw invalid_argument("sys_seek_type"); +} + +} + +namespace Msp { +namespace IO { + +SeekOffset sys_seek(Handle &handle, SeekOffset offset, SeekType type) +{ + off64_t ret = lseek64(*handle, offset, sys_seek_type(type)); + if(ret==(off64_t)-1) + { + if(errno==EINVAL) + throw bad_seek(offset, type); + else + throw system_error("lseek64"); + } + + return ret; +} + +} // namespace IO +} // namespace Msp diff --git a/source/io/unix/serial.cpp b/source/io/unix/serial.cpp new file mode 100644 index 0000000..49d9e9c --- /dev/null +++ b/source/io/unix/serial.cpp @@ -0,0 +1,121 @@ +#include +#include +#include +#include +#include "handle_private.h" +#include "serial.h" +#include "serial_private.h" + +using namespace std; + +namespace Msp { +namespace IO { + +void Serial::platform_init(const string &port) +{ + string fn = port; + if(fn.compare(0, 5, "/dev/")) + fn = "/dev/"+fn; + + *handle = open(fn.c_str(), O_RDWR); + if(!handle) + throw system_error(format("open(%s)", port)); + mode = M_READ|M_WRITE; + + termios t; + tcgetattr(*handle, &t); + t.c_iflag &= ~(ISTRIP|INLCR|IGNCR|ICRNL|IXON); + t.c_lflag &= ~(ECHO|ICANON|ISIG|IEXTEN); + t.c_oflag &= ~(OPOST|OCRNL|ONOCR|ONLRET); + t.c_cc[VMIN] = 1; + t.c_cc[VTIME] = 0; + tcsetattr(*handle, TCSADRAIN, &t); +} + + +void Serial::DeviceState::get_from(const Handle &handle) +{ + tcgetattr(*handle, &state); +} + +void Serial::DeviceState::apply_to(const Handle &handle) +{ + if(tcsetattr(*handle, TCSADRAIN, &state)==-1) + throw system_error("tcsetattr"); +} + +void Serial::DeviceState::set_baud_rate(unsigned baud) +{ + speed_t speed; + switch(baud) + { + case 0: speed = B0; break; + case 50: speed = B50; break; + case 75: speed = B75; break; + case 110: speed = B110; break; + case 134: speed = B134; break; + case 150: speed = B150; break; + case 200: speed = B200; break; + case 300: speed = B300; break; + case 600: speed = B600; break; + case 1200: speed = B1200; break; + case 1800: speed = B1800; break; + case 2400: speed = B2400; break; + case 4800: speed = B4800; break; + case 9600: speed = B9600; break; + case 19200: speed = B19200; break; + case 38400: speed = B38400; break; + case 57600: speed = B57600; break; + case 115200: speed = B115200; break; + case 230400: speed = B230400; break; + default: throw invalid_argument("set_baud_rate"); + } + + cfsetospeed(&state, speed); + cfsetispeed(&state, speed); +} + +void Serial::DeviceState::set_data_bits(unsigned bits) +{ + tcflag_t flag; + switch(bits) + { + case 5: flag = CS5; break; + case 6: flag = CS6; break; + case 7: flag = CS7; break; + case 8: flag = CS8; break; + default: throw invalid_argument("set_data_bits"); + } + + state.c_cflag = (state.c_cflag&~CSIZE)|flag; +} + +void Serial::DeviceState::set_parity(Serial::Parity par) +{ + tcflag_t flag; + switch(par) + { + case Serial::NONE: flag = 0; break; + case Serial::EVEN: flag = PARENB; break; + case Serial::ODD: flag = PARENB|PARODD; break; + default: throw invalid_argument("set_parity"); + } + + state.c_cflag = (state.c_cflag&~(PARENB|PARODD))|flag; +} + +void Serial::DeviceState::set_stop_bits(unsigned bits) +{ + tcflag_t flag; + switch(bits) + { + case 1: flag = 0; break; + case 2: flag = CSTOPB; break; + default: throw invalid_argument("set_stop_bits"); + } + + state.c_cflag = (state.c_cflag&~CSTOPB)|flag; +} + +} // namespace IO +} // namespace MSp diff --git a/source/io/unix/serial_platform.h b/source/io/unix/serial_platform.h new file mode 100644 index 0000000..e7de712 --- /dev/null +++ b/source/io/unix/serial_platform.h @@ -0,0 +1,14 @@ +#ifndef MSP_IO_SERIAL_PLATFORM_H_ +#define MSP_IO_SERIAL_PLATFORM_H_ + +#include + +namespace Msp { +namespace IO { + +typedef termios PlatformSerialDeviceState; + +} // namespace IO +} // namespace Msp + +#endif diff --git a/source/io/windows/console.cpp b/source/io/windows/console.cpp new file mode 100644 index 0000000..a331133 --- /dev/null +++ b/source/io/windows/console.cpp @@ -0,0 +1,72 @@ +#include +#include "console.h" +#include "handle_private.h" + +using namespace std; + +namespace { + +DWORD stream_to_sys(Msp::IO::Console::Stream stream) +{ + switch(stream) + { + case Msp::IO::Console::CIN: return STD_INPUT_HANDLE; + case Msp::IO::Console::COUT: return STD_OUTPUT_HANDLE; + case Msp::IO::Console::CERR: return STD_ERROR_HANDLE; + default: throw invalid_argument("stream_to_sys"); + } +} + +} // namespace + + +namespace Msp { +namespace IO { + +void Console::platform_init() +{ + *handle = GetStdHandle(stream_to_sys(stream)); +} + +Console::~Console() +{ } + +void Console::set_local_echo(bool e) +{ + check_access(M_READ); + + DWORD m; + GetConsoleMode(*handle, &m); + SetConsoleMode(*handle, (m&~ENABLE_ECHO_INPUT) | (e?ENABLE_ECHO_INPUT:0)); +} + +void Console::set_line_buffer(bool l) +{ + check_access(M_READ); + + DWORD m; + if(!GetConsoleMode(*handle, &m)) + throw system_error("GetConsoleMode"); + if(!SetConsoleMode(*handle, (m&~ENABLE_LINE_INPUT) | (l?ENABLE_LINE_INPUT:0))) + throw system_error("SetConsoleMode"); +} + +void Console::get_size(unsigned &rows, unsigned &cols) +{ + check_access(M_WRITE); + + CONSOLE_SCREEN_BUFFER_INFO sbi; + if(!GetConsoleScreenBufferInfo(*handle, &sbi)) + throw system_error("GetConsoleScreenBufferInfo"); + // Right/bottom coords are inclusive + rows = sbi.srWindow.Bottom+1-sbi.srWindow.Top; + cols = sbi.srWindow.Right+1-sbi.srWindow.Left; +} + +void Console::redirect(Base &other) +{ + SetStdHandle(stream_to_sys(stream), *other.get_handle(mode)); +} + +} // namespace IO +} // namespace Msp diff --git a/source/io/windows/eventreader.cpp b/source/io/windows/eventreader.cpp new file mode 100644 index 0000000..62c9763 --- /dev/null +++ b/source/io/windows/eventreader.cpp @@ -0,0 +1,115 @@ +#include +#include +#include +#include "eventreader.h" +#include "handle_private.h" + +using namespace std; + +namespace Msp { +namespace IO { + +struct EventReader::Private +{ + OVERLAPPED *overlapped; + Handle event; + unsigned buf_size; + char *buffer; + unsigned buf_avail; + char *buf_next; +}; + + +EventReader::EventReader(Handle &h, unsigned size): + handle(h), + priv(new Private) +{ + priv->overlapped = 0; + *priv->event = CreateEvent(0, true, false, 0); + priv->buf_size = size; + priv->buffer = new char[priv->buf_size]; + priv->buf_avail = 0; + priv->buf_next = priv->buffer; +} + +EventReader::~EventReader() +{ + CloseHandle(*priv->event); + delete priv->overlapped; + delete[] priv->buffer; + delete priv; +} + +const Handle &EventReader::get_event() +{ + start(); + return priv->event; +} + +void EventReader::start() +{ + if(priv->buf_avail || priv->overlapped) + return; + + priv->overlapped = new OVERLAPPED; + memset(priv->overlapped, 0, sizeof(OVERLAPPED)); + priv->overlapped->hEvent = *priv->event; + + DWORD ret; + priv->buf_next = priv->buffer; + if(!ReadFile(*handle, priv->buffer, priv->buf_size, &ret, priv->overlapped)) + { + unsigned err = GetLastError(); + if(err!=ERROR_IO_PENDING) + throw system_error("ReadFile"); + } + else + { + priv->buf_avail = ret; + delete priv->overlapped; + priv->overlapped = 0; + SetEvent(*priv->event); + } +} + +void EventReader::wait() +{ + if(!priv->overlapped) + return; + + DWORD ret; + if(!GetOverlappedResult(*handle, priv->overlapped, &ret, true)) + throw system_error("GetOverlappedResult"); + else + { + priv->buf_avail = ret; + delete priv->overlapped; + priv->overlapped = 0; + } +} + +unsigned EventReader::read(char *buf, unsigned len) +{ + if(!priv->buf_avail) + { + // No data in buffer, try to get some + start(); + wait(); + } + + len = min(len, priv->buf_avail); + memcpy(buf, priv->buf_next, len); + priv->buf_next += len; + priv->buf_avail -= len; + + if(!priv->buf_avail) + { + ResetEvent(*priv->event); + start(); + } + + return len; +} + +} // namespace IO +} // namespace Msp diff --git a/source/io/windows/file.cpp b/source/io/windows/file.cpp new file mode 100644 index 0000000..b973375 --- /dev/null +++ b/source/io/windows/file.cpp @@ -0,0 +1,54 @@ +#include +#include +#include "file.h" +#include "handle_private.h" + +using namespace std; + +namespace Msp { +namespace IO { + +void File::platform_init(const string &fn, CreateMode cm) +{ + int flags = 0; + int share_flags = 0; + int create_flags = OPEN_EXISTING; + + if(mode&M_READ) + flags |= GENERIC_READ; + + if(mode&M_WRITE) + { + flags |= GENERIC_WRITE; + + switch(static_cast(cm)) + { + case C_NONE: create_flags = OPEN_EXISTING; break; + case C_CREATE: create_flags = OPEN_ALWAYS; break; + case C_TRUNCATE: create_flags = TRUNCATE_EXISTING; break; + case C_OVERWRITE: create_flags = CREATE_ALWAYS; break; + case C_NEW: create_flags = CREATE_NEW; break; + } + } + else + share_flags = FILE_SHARE_READ; + + *handle = CreateFile(fn.c_str(), flags, share_flags, 0, create_flags, FILE_ATTRIBUTE_NORMAL, 0); + if(!handle) + { + int err = GetLastError(); + if(err==ERROR_FILE_NOT_FOUND) + throw file_not_found(fn); + else if(err==ERROR_FILE_EXISTS) + throw file_already_exists(fn); + else + throw system_error(format("CreateFile(%s)", fn), err); + } +} + +void File::sync() +{ +} + +} // namespace IO +} // namespace Msp diff --git a/source/io/windows/handle.cpp b/source/io/windows/handle.cpp new file mode 100644 index 0000000..5b1d933 --- /dev/null +++ b/source/io/windows/handle.cpp @@ -0,0 +1,42 @@ +#include +#include "handle.h" +#include "handle_private.h" + +namespace Msp { +namespace IO { + +Handle::operator const void *() const +{ + return priv->handle!=INVALID_HANDLE_VALUE ? this : 0; +} + + +void sys_set_blocking(Handle &, bool) +{ +} + +unsigned sys_read(Handle &handle, char *buf, unsigned size) +{ + DWORD ret; + if(ReadFile(*handle, buf, size, &ret, 0)==0) + throw system_error("ReadFile"); + + return ret; +} + +unsigned sys_write(Handle &handle, const char *buf, unsigned size) +{ + DWORD ret; + if(WriteFile(*handle, buf, size, &ret, 0)==0) + throw system_error("WriteFile"); + + return ret; +} + +void sys_close(Handle &handle) +{ + CloseHandle(*handle); +} + +} // namespace IO +} // namespace Msp diff --git a/source/io/windows/handle_platform.h b/source/io/windows/handle_platform.h new file mode 100644 index 0000000..f12e5f7 --- /dev/null +++ b/source/io/windows/handle_platform.h @@ -0,0 +1,14 @@ +#ifndef MSP_IO_HANDLE_PLATFORM_H_ +#define MSP_IO_HANDLE_PLATFORM_H_ + +#include + +namespace Msp { +namespace IO { + +typedef HANDLE PlatformHandle; + +} // namespace IO +} // namespace Msp + +#endif diff --git a/source/io/windows/pipe.cpp b/source/io/windows/pipe.cpp new file mode 100644 index 0000000..02d7f33 --- /dev/null +++ b/source/io/windows/pipe.cpp @@ -0,0 +1,28 @@ +#include +#include +#include "handle_private.h" +#include "pipe.h" + +using namespace std; + +namespace Msp { +namespace IO { + +void Pipe::platform_init() +{ + string name = format("\\\\.\\pipe\\%u.%p", GetCurrentProcessId(), this); + *read_handle = CreateNamedPipe(name.c_str(), PIPE_ACCESS_INBOUND|FILE_FLAG_OVERLAPPED, PIPE_TYPE_BYTE, 1, 1024, 1024, 0, 0); + if(!read_handle) + throw system_error("CreateNamedPipe"); + + *write_handle = CreateFile(name.c_str(), GENERIC_WRITE, 0, 0, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, 0); + if(!write_handle) + { + unsigned err = GetLastError(); + CloseHandle(*read_handle); + throw system_error(format("CreateFile(%s)", name), err); + } +} + +} // namespace IO +} // namespace Msp diff --git a/source/io/windows/poll.cpp b/source/io/windows/poll.cpp new file mode 100644 index 0000000..e672258 --- /dev/null +++ b/source/io/windows/poll.cpp @@ -0,0 +1,53 @@ +#include +#include "eventobject.h" +#include "handle.h" +#include "handle_private.h" +#include "poll.h" +#include "poll_platform.h" + +namespace Msp { +namespace IO { + +void Poller::rebuild_array() +{ + priv->handles.clear(); + + for(EventMap::iterator i=objects.begin(); i!=objects.end(); ++i) + priv->handles.push_back(*i->first->get_event_handle()); + + objs_changed = false; +} + +void Poller::platform_poll(int timeout) +{ + if(timeout<0) + timeout = INFINITE; + + DWORD ret = WaitForMultipleObjects(priv->handles.size(), &priv->handles.front(), false, timeout); + if(/*ret>=WAIT_OBJECT_0 &&*/ rethandles.size()) + { + EventMap::iterator i = objects.begin(); + advance(i, ret-WAIT_OBJECT_0); + poll_result.push_back(Slot(i->first, i->second)); + } + else if(ret==WAIT_FAILED) + throw system_error("WaitForMultipleObjects"); +} + + +PollEvent platform_poll(EventObject &obj, PollEvent pe, int timeout) +{ + if(timeout<0) + timeout = INFINITE; + + DWORD ret = WaitForSingleObject(*obj.get_event_handle(), timeout); + if(ret==WAIT_OBJECT_0) + return pe; + else if(ret==WAIT_FAILED) + throw system_error("WaitForSingleObject"); + + return P_NONE; +} + +} // namespace IO +} // namespace Msp diff --git a/source/io/windows/poll_platform.h b/source/io/windows/poll_platform.h new file mode 100644 index 0000000..ccf92c3 --- /dev/null +++ b/source/io/windows/poll_platform.h @@ -0,0 +1,18 @@ +#ifndef MSP_IO_POLL_PLATFORM_H_ +#define MSP_IO_POLL_PLATFORM_H_ + +#include +#include + +namespace Msp { +namespace IO { + +struct Poller::Private +{ + std::vector handles; +}; + +} // namespace IO +} // namespace Msp + +#endif diff --git a/source/io/windows/seekable.cpp b/source/io/windows/seekable.cpp new file mode 100644 index 0000000..73c5cc5 --- /dev/null +++ b/source/io/windows/seekable.cpp @@ -0,0 +1,45 @@ +#include +#include +#include "handle.h" +#include "handle_private.h" +#include "seekable.h" + +using namespace std; + +namespace { + +using namespace Msp::IO; + +int sys_seek_type(SeekType st) +{ + if(st==S_BEG) + return FILE_BEGIN; + else if(st==S_CUR) + return FILE_CURRENT; + else if(st==S_END) + return FILE_END; + + throw invalid_argument("sys_seek_type"); +} + +} + +namespace Msp { +namespace IO { + +SeekOffset sys_seek(Handle &handle, SeekOffset offset, SeekType type) +{ + LONG high = offset>>32; + DWORD ret = SetFilePointer(*handle, offset, &high, sys_seek_type(type)); + if(ret==INVALID_SET_FILE_POINTER) + { + DWORD err = GetLastError(); + if(err!=NO_ERROR) + throw system_error("SetFilePointer"); + } + + return (SeekOffset(high)<<32) | ret; +} + +} // namespace IO +} // namespace Msp diff --git a/source/io/windows/serial.cpp b/source/io/windows/serial.cpp new file mode 100644 index 0000000..0092754 --- /dev/null +++ b/source/io/windows/serial.cpp @@ -0,0 +1,74 @@ +#include +#include +#include "handle_private.h" +#include "serial.h" +#include "serial_private.h" + +using namespace std; + +namespace Msp { +namespace IO { + +void Serial::platform_init(const string &port) +{ + string name = "\\\\.\\"+port; + + *handle = CreateFile(name.c_str(), GENERIC_READ|GENERIC_WRITE, 0, 0, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL|FILE_FLAG_OVERLAPPED, 0); + if(!handle) + throw system_error(format("CreateFile(%s)", port)); + mode = M_READ|M_WRITE; + + COMMTIMEOUTS timeouts; + timeouts.ReadIntervalTimeout = MAXDWORD; + timeouts.ReadTotalTimeoutMultiplier = MAXDWORD; + timeouts.ReadTotalTimeoutConstant = MAXDWORD-1; + timeouts.WriteTotalTimeoutMultiplier = 0; + timeouts.WriteTotalTimeoutConstant = 0; + SetCommTimeouts(*handle, &timeouts); +} + + +void Serial::DeviceState::get_from(const Handle &handle) +{ + GetCommState(*handle, &state); +} + +void Serial::DeviceState::apply_to(const Handle &handle) +{ + if(SetCommState(*handle, &state)==0) + throw system_error("SetCommState"); +} + +void Serial::DeviceState::set_baud_rate(unsigned baud) +{ + state.BaudRate = baud; +} + +void Serial::DeviceState::set_data_bits(unsigned bits) +{ + state.ByteSize = bits; +} + +void Serial::DeviceState::set_parity(Serial::Parity par) +{ + switch(par) + { + case Serial::NONE: state.Parity = NOPARITY; break; + case Serial::EVEN: state.Parity = EVENPARITY; break; + case Serial::ODD: state.Parity = ODDPARITY; break; + default: throw invalid_argument("set_parity"); + } +} + +void Serial::DeviceState::set_stop_bits(unsigned bits) +{ + switch(bits) + { + case 1: state.StopBits = ONESTOPBIT; break; + case 2: state.StopBits = TWOSTOPBITS; break; + default: throw invalid_argument("set_stop_bits"); + } +} + +} // namespace IO +} // namespace MSp diff --git a/source/io/windows/serial_platform.h b/source/io/windows/serial_platform.h new file mode 100644 index 0000000..dd7dd50 --- /dev/null +++ b/source/io/windows/serial_platform.h @@ -0,0 +1,14 @@ +#ifndef MSP_IO_SERIAL_PLATFORM_H_ +#define MSP_IO_SERIAL_PLATFORM_H_ + +#include + +namespace Msp { +namespace IO { + +typedef DCB PlatformSerialDeviceState; + +} // namespace IO +} // namespace Msp + +#endif diff --git a/source/time/rawtime.cpp b/source/time/rawtime.cpp deleted file mode 100644 index a299246..0000000 --- a/source/time/rawtime.cpp +++ /dev/null @@ -1,62 +0,0 @@ -#include "rawtime.h" -#include "rawtime_private.h" - -namespace { - -#ifdef WIN32 -/// Returns the unixtime epoch as filetime -Msp::Time::RawTime get_epoch() -{ - SYSTEMTIME st; - st.wYear = 1970; - st.wMonth = 1; - st.wDay = 1; - st.wHour = 0; - st.wMinute = 0; - st.wSecond = 0; - st.wMilliseconds = 0; - - FILETIME ft; - SystemTimeToFileTime(&st, &ft); - return (ft.dwLowDateTime+(static_cast(ft.dwHighDateTime)<<32))/10; -} -#endif - -} - - -namespace Msp { -namespace Time { - -#ifdef WIN32 -RawTime filetime_to_rawtime(const FILETIME &ft) -{ - static RawTime epoch = get_epoch(); - - return (ft.dwLowDateTime+(static_cast(ft.dwHighDateTime)<<32))/10-epoch; -} -#else -timeval rawtime_to_timeval(RawTime raw) -{ - timeval tv; - tv.tv_sec = raw/1000000; - tv.tv_usec = raw%1000000; - return tv; -} - -timespec rawtime_to_timespec(RawTime raw) -{ - timespec ts; - ts.tv_sec = raw/1000000; - ts.tv_nsec = (raw%1000000)*1000; - return ts; -} - -RawTime timeval_to_rawtime(const timeval &tv) -{ - return tv.tv_sec*1000000LL+tv.tv_usec; -} -#endif - -} // namespace Time -} // namespace Msp diff --git a/source/time/rawtime_private.h b/source/time/rawtime_private.h index 846a712..e0cbb2e 100644 --- a/source/time/rawtime_private.h +++ b/source/time/rawtime_private.h @@ -1,25 +1,6 @@ #ifndef MSP_TIME_RAWTIME_PRIVATE_H_ #define MSP_TIME_RAWTIME_PRIVATE_H_ -#ifdef WIN32 -#include -#else -#include -#endif -#include "rawtime.h" - -namespace Msp { -namespace Time { - -#ifdef WIN32 -RawTime filetime_to_rawtime(const FILETIME &); -#else -timeval rawtime_to_timeval(RawTime); -timespec rawtime_to_timespec(RawTime); -RawTime timeval_to_rawtime(const timeval &); -#endif - -} // namespace Time -} // namespace Msp +#include "rawtime_platform.h" #endif diff --git a/source/time/timezone.cpp b/source/time/timezone.cpp index 7baf494..76c3fb2 100644 --- a/source/time/timezone.cpp +++ b/source/time/timezone.cpp @@ -1,108 +1,9 @@ #include -#ifdef WIN32 -#include -#else -#include -#include -#endif #include -#include -#include "timestamp.h" #include "timezone.h" -#include "utils.h" using namespace std; -namespace { - -using Msp::Time::TimeZone; - -#ifndef WIN32 -long get_long(char *&ptr) -{ - long result = 0; - for(unsigned i=0; i<4; ++i) - result = (result<<8)+static_cast(*ptr++); - return result; -} -#endif - -TimeZone get_local_timezone() -{ -#ifdef WIN32 - TIME_ZONE_INFORMATION tzinfo; - DWORD dst = GetTimeZoneInformation(&tzinfo); - if(dst==TIME_ZONE_ID_INVALID) - throw Msp::system_error("GetTimeZoneInformation"); - - int offset = tzinfo.Bias; - if(dst==TIME_ZONE_ID_STANDARD) - offset += tzinfo.StandardBias; - else if(dst==TIME_ZONE_ID_DAYLIGHT) - offset += tzinfo.DaylightBias; - - return TimeZone(offset); -#else - int fd = open("/etc/localtime", O_RDONLY); - if(fd!=-1) - { - char hdr[44]; - int len = read(fd, hdr, sizeof(hdr)); - long gmtoff = -1; - string name; - if(len==44 && hdr[0]=='T' && hdr[1]=='Z' && hdr[2]=='i' && hdr[3]=='f') - { - char *ptr = hdr+20; - long isgmtcnt = get_long(ptr); - long isstdcnt = get_long(ptr); - long leapcnt = get_long(ptr); - long timecnt = get_long(ptr); - long typecnt = get_long(ptr); - long charcnt = get_long(ptr); - int size = timecnt*5+typecnt*6+isgmtcnt+isstdcnt+leapcnt*8+charcnt; - char *buf = new char[size]; - len = read(fd, buf, size); - if(len==size) - { - ptr = buf; - int index = -1; - time_t cur_time = Msp::Time::now().to_unixtime(); - for(int i=0; i0) - index = ptr[index]; - ptr += timecnt; - - int abbrind = 0; - for(int i=0; i=0 && i==index) || (index<0 && !ptr[4] && gmtoff==-1)) - { - gmtoff = get_long(ptr); - ++ptr; - abbrind = *ptr++; - } - else - ptr += 6; - } - - name = ptr+abbrind; - } - delete[] buf; - } - close(fd); - - if(gmtoff!=-1) - return TimeZone(gmtoff/60, name); - } - return TimeZone(); -#endif -} - -} - namespace Msp { namespace Time { @@ -137,7 +38,7 @@ const TimeZone &TimeZone::utc() const TimeZone &TimeZone::local() { - static TimeZone tz = get_local_timezone(); + static TimeZone tz = platform_get_local_timezone(); return tz; } diff --git a/source/time/timezone.h b/source/time/timezone.h index 28feb16..3fbeb54 100644 --- a/source/time/timezone.h +++ b/source/time/timezone.h @@ -22,6 +22,8 @@ public: static const TimeZone &utc(); static const TimeZone &local(); +private: + static TimeZone platform_get_local_timezone(); }; } // namespace Time diff --git a/source/time/unix/rawtime.cpp b/source/time/unix/rawtime.cpp new file mode 100644 index 0000000..2b8bc6d --- /dev/null +++ b/source/time/unix/rawtime.cpp @@ -0,0 +1,29 @@ +#include "rawtime.h" +#include "rawtime_private.h" + +namespace Msp { +namespace Time { + +timeval rawtime_to_timeval(RawTime raw) +{ + timeval tv; + tv.tv_sec = raw/1000000; + tv.tv_usec = raw%1000000; + return tv; +} + +timespec rawtime_to_timespec(RawTime raw) +{ + timespec ts; + ts.tv_sec = raw/1000000; + ts.tv_nsec = (raw%1000000)*1000; + return ts; +} + +RawTime timeval_to_rawtime(const timeval &tv) +{ + return tv.tv_sec*1000000LL+tv.tv_usec; +} + +} // namespace Time +} // namespace Msp diff --git a/source/time/unix/rawtime_platform.h b/source/time/unix/rawtime_platform.h new file mode 100644 index 0000000..8f9f633 --- /dev/null +++ b/source/time/unix/rawtime_platform.h @@ -0,0 +1,17 @@ +#ifndef MSP_TIME_RAWTIME_PLATFORM_H_ +#define MSP_TIME_RAWTIME_PLATFORM_H_ + +#include +#include "rawtime.h" + +namespace Msp { +namespace Time { + +timeval rawtime_to_timeval(RawTime); +timespec rawtime_to_timespec(RawTime); +RawTime timeval_to_rawtime(const timeval &); + +} // namespace Time +} // namespace Msp + +#endif diff --git a/source/time/unix/timezone.cpp b/source/time/unix/timezone.cpp new file mode 100644 index 0000000..e55969c --- /dev/null +++ b/source/time/unix/timezone.cpp @@ -0,0 +1,85 @@ +#include +#include +#include "timestamp.h" +#include "timezone.h" +#include "utils.h" + +using namespace std; + +namespace { + +long get_long(char *&ptr) +{ + long result = 0; + for(unsigned i=0; i<4; ++i) + result = (result<<8)+static_cast(*ptr++); + return result; +} + +} + + +namespace Msp { +namespace Time { + +TimeZone TimeZone::platform_get_local_timezone() +{ + int fd = open("/etc/localtime", O_RDONLY); + if(fd!=-1) + { + char hdr[44]; + int len = read(fd, hdr, sizeof(hdr)); + long gmtoff = -1; + string name; + if(len==44 && hdr[0]=='T' && hdr[1]=='Z' && hdr[2]=='i' && hdr[3]=='f') + { + char *ptr = hdr+20; + long isgmtcnt = get_long(ptr); + long isstdcnt = get_long(ptr); + long leapcnt = get_long(ptr); + long timecnt = get_long(ptr); + long typecnt = get_long(ptr); + long charcnt = get_long(ptr); + int size = timecnt*5+typecnt*6+isgmtcnt+isstdcnt+leapcnt*8+charcnt; + char *buf = new char[size]; + len = read(fd, buf, size); + if(len==size) + { + ptr = buf; + int index = -1; + time_t cur_time = Msp::Time::now().to_unixtime(); + for(int i=0; i0) + index = ptr[index]; + ptr += timecnt; + + int abbrind = 0; + for(int i=0; i=0 && i==index) || (index<0 && !ptr[4] && gmtoff==-1)) + { + gmtoff = get_long(ptr); + ++ptr; + abbrind = *ptr++; + } + else + ptr += 6; + } + + name = ptr+abbrind; + } + delete[] buf; + } + close(fd); + + if(gmtoff!=-1) + return TimeZone(gmtoff/60, name); + } + return TimeZone(); +} + +} // namespace Time +} // namespace Msp diff --git a/source/time/unix/utils.cpp b/source/time/unix/utils.cpp new file mode 100644 index 0000000..029c75b --- /dev/null +++ b/source/time/unix/utils.cpp @@ -0,0 +1,36 @@ +#include +#include +#include +#include +#include "rawtime_private.h" +#include "timedelta.h" +#include "timestamp.h" +#include "utils.h" + +namespace Msp { +namespace Time { + +TimeStamp now() +{ + timeval tv; + gettimeofday(&tv, 0); + return TimeStamp(timeval_to_rawtime(tv)); +} + +TimeDelta get_cpu_time() +{ + rusage ru; + getrusage(RUSAGE_SELF, &ru); + return (ru.ru_utime.tv_sec+ru.ru_stime.tv_sec)*sec + (ru.ru_utime.tv_usec+ru.ru_stime.tv_usec)*usec; +} + +void sleep(const TimeDelta &d) +{ + timespec ts = rawtime_to_timespec(d.raw()); + while(nanosleep(&ts, 0)==-1) + if(errno!=EINTR) + throw system_error("nanosleep"); +} + +} // namespace Time +} // namespace Msp diff --git a/source/time/utils.cpp b/source/time/utils.cpp index 9c643cf..52c8934 100644 --- a/source/time/utils.cpp +++ b/source/time/utils.cpp @@ -1,14 +1,4 @@ -#ifdef WIN32 -#include -#else -#include -#include -#include -#endif -#include #include "datetime.h" -#include "rawtime_private.h" -#include "timedelta.h" #include "timestamp.h" #include "utils.h" @@ -17,47 +7,10 @@ using namespace std; namespace Msp { namespace Time { -TimeStamp now() -{ -#ifndef WIN32 - timeval tv; - gettimeofday(&tv, 0); - return TimeStamp(timeval_to_rawtime(tv)); -#else - FILETIME ft; - GetSystemTimeAsFileTime(&ft); - return TimeStamp(filetime_to_rawtime(ft)); -#endif -} - string format_now(const string &fmt) { return DateTime(now()).format(fmt); } -TimeDelta get_cpu_time() -{ -#ifndef WIN32 - rusage ru; - getrusage(RUSAGE_SELF, &ru); - return (ru.ru_utime.tv_sec+ru.ru_stime.tv_sec)*sec + (ru.ru_utime.tv_usec+ru.ru_stime.tv_usec)*usec; -#else - //XXX Figure out the function to use on Win32 - return TimeDelta(); -#endif -} - -void sleep(const TimeDelta &d) -{ -#ifndef WIN32 - timespec ts = rawtime_to_timespec(d.raw()); - while(nanosleep(&ts, 0)==-1) - if(errno!=EINTR) - throw system_error("nanosleep"); -#else - Sleep((DWORD)(d/msec)); -#endif -} - } // namespace Time } // namespace Msp diff --git a/source/time/windows/rawtime.cpp b/source/time/windows/rawtime.cpp new file mode 100644 index 0000000..b6276f0 --- /dev/null +++ b/source/time/windows/rawtime.cpp @@ -0,0 +1,36 @@ +#include "rawtime.h" +#include "rawtime_private.h" + +namespace { + +/// Returns the unixtime epoch as filetime +Msp::Time::RawTime get_epoch() +{ + SYSTEMTIME st; + st.wYear = 1970; + st.wMonth = 1; + st.wDay = 1; + st.wHour = 0; + st.wMinute = 0; + st.wSecond = 0; + st.wMilliseconds = 0; + + FILETIME ft; + SystemTimeToFileTime(&st, &ft); + return (ft.dwLowDateTime+(static_cast(ft.dwHighDateTime)<<32))/10; +} + +} + +namespace Msp { +namespace Time { + +RawTime filetime_to_rawtime(const FILETIME &ft) +{ + static RawTime epoch = get_epoch(); + + return (ft.dwLowDateTime+(static_cast(ft.dwHighDateTime)<<32))/10-epoch; +} + +} // namespace Time +} // namespace Msp diff --git a/source/time/windows/rawtime_platform.h b/source/time/windows/rawtime_platform.h new file mode 100644 index 0000000..60a9a59 --- /dev/null +++ b/source/time/windows/rawtime_platform.h @@ -0,0 +1,15 @@ +#ifndef MSP_TIME_RAWTIME_PLATFORM_H_ +#define MSP_TIME_RAWTIME_PLATFORM_H_ + +#include +#include "rawtime.h" + +namespace Msp { +namespace Time { + +RawTime filetime_to_rawtime(const FILETIME &); + +} // namespace Time +} // namespace Msp + +#endif diff --git a/source/time/windows/timezone.cpp b/source/time/windows/timezone.cpp new file mode 100644 index 0000000..570c679 --- /dev/null +++ b/source/time/windows/timezone.cpp @@ -0,0 +1,25 @@ +#include +#include +#include "timezone.h" + +namespace Msp { +namespace Time { + +TimeZone TimeZone::platform_get_local_timezone() +{ + TIME_ZONE_INFORMATION tzinfo; + DWORD dst = GetTimeZoneInformation(&tzinfo); + if(dst==TIME_ZONE_ID_INVALID) + throw Msp::system_error("GetTimeZoneInformation"); + + int offset = tzinfo.Bias; + if(dst==TIME_ZONE_ID_STANDARD) + offset += tzinfo.StandardBias; + else if(dst==TIME_ZONE_ID_DAYLIGHT) + offset += tzinfo.DaylightBias; + + return TimeZone(offset); +} + +} // namespace Time +} // namespace Msp diff --git a/source/time/windows/utils.cpp b/source/time/windows/utils.cpp new file mode 100644 index 0000000..2150a10 --- /dev/null +++ b/source/time/windows/utils.cpp @@ -0,0 +1,29 @@ +#include +#include "rawtime_private.h" +#include "timedelta.h" +#include "timestamp.h" +#include "utils.h" + +namespace Msp { +namespace Time { + +TimeStamp now() +{ + FILETIME ft; + GetSystemTimeAsFileTime(&ft); + return TimeStamp(filetime_to_rawtime(ft)); +} + +TimeDelta get_cpu_time() +{ + //XXX Figure out the function to use on Win32 + return TimeDelta(); +} + +void sleep(const TimeDelta &d) +{ + Sleep((DWORD)(d/msec)); +} + +} // namespace Time +} // namespace Msp