Move most platform-specific code into overlay directories
authorMikko Rasa <tdb@tdb.fi>
Wed, 24 Apr 2013 13:22:18 +0000 (16:22 +0300)
committerMikko Rasa <tdb@tdb.fi>
Wed, 24 Apr 2013 13:22:18 +0000 (16:22 +0300)
A few things, in particular FS::Path, were not trivial to split.  I'm not
certain what to do with features like zlib either.

90 files changed:
Build
source/core/application.cpp
source/core/application.h
source/core/main.cpp [deleted file]
source/core/mutex.cpp [deleted file]
source/core/mutex_private.h
source/core/semaphore.cpp [deleted file]
source/core/systemerror.cpp
source/core/thread.cpp
source/core/thread.h
source/core/thread_private.h [new file with mode: 0644]
source/core/unix/application.cpp [new file with mode: 0644]
source/core/unix/main.cpp [new file with mode: 0644]
source/core/unix/mutex.cpp [new file with mode: 0644]
source/core/unix/mutex_platform.h [new file with mode: 0644]
source/core/unix/semaphore.cpp [new file with mode: 0644]
source/core/unix/systemerror.cpp [new file with mode: 0644]
source/core/unix/thread.cpp [new file with mode: 0644]
source/core/unix/thread_platform.h [new file with mode: 0644]
source/core/windows/application.cpp [new file with mode: 0644]
source/core/windows/main.cpp [new file with mode: 0644]
source/core/windows/mutex.cpp [new file with mode: 0644]
source/core/windows/mutex_platform.h [new file with mode: 0644]
source/core/windows/semaphore.cpp [new file with mode: 0644]
source/core/windows/systemerror.cpp [new file with mode: 0644]
source/core/windows/thread.cpp [new file with mode: 0644]
source/core/windows/thread_platform.h [new file with mode: 0644]
source/fs/dir.cpp
source/fs/stat.cpp
source/fs/stat_private.h [new file with mode: 0644]
source/fs/unix/dir.cpp [new file with mode: 0644]
source/fs/unix/stat.cpp [new file with mode: 0644]
source/fs/unix/stat_platform.h [new file with mode: 0644]
source/fs/unix/utils.cpp [new file with mode: 0644]
source/fs/utils.cpp
source/fs/windows/dir.cpp [new file with mode: 0644]
source/fs/windows/stat.cpp [new file with mode: 0644]
source/fs/windows/stat_platform.h [new file with mode: 0644]
source/fs/windows/utils.cpp [new file with mode: 0644]
source/io/console.cpp
source/io/console.h
source/io/eventreader.cpp [deleted file]
source/io/file.cpp
source/io/file.h
source/io/handle.cpp
source/io/handle.h
source/io/handle_private.h
source/io/pipe.cpp
source/io/pipe.h
source/io/poll.cpp
source/io/poll.h
source/io/seekable.cpp
source/io/serial.cpp
source/io/serial.h
source/io/serial_private.h [new file with mode: 0644]
source/io/unix/console.cpp [new file with mode: 0644]
source/io/unix/eventreader.cpp [new file with mode: 0644]
source/io/unix/file.cpp [new file with mode: 0644]
source/io/unix/handle.cpp [new file with mode: 0644]
source/io/unix/handle_platform.h [new file with mode: 0644]
source/io/unix/pipe.cpp [new file with mode: 0644]
source/io/unix/poll.cpp [new file with mode: 0644]
source/io/unix/poll_platform.h [new file with mode: 0644]
source/io/unix/seekable.cpp [new file with mode: 0644]
source/io/unix/serial.cpp [new file with mode: 0644]
source/io/unix/serial_platform.h [new file with mode: 0644]
source/io/windows/console.cpp [new file with mode: 0644]
source/io/windows/eventreader.cpp [new file with mode: 0644]
source/io/windows/file.cpp [new file with mode: 0644]
source/io/windows/handle.cpp [new file with mode: 0644]
source/io/windows/handle_platform.h [new file with mode: 0644]
source/io/windows/pipe.cpp [new file with mode: 0644]
source/io/windows/poll.cpp [new file with mode: 0644]
source/io/windows/poll_platform.h [new file with mode: 0644]
source/io/windows/seekable.cpp [new file with mode: 0644]
source/io/windows/serial.cpp [new file with mode: 0644]
source/io/windows/serial_platform.h [new file with mode: 0644]
source/time/rawtime.cpp [deleted file]
source/time/rawtime_private.h
source/time/timezone.cpp
source/time/timezone.h
source/time/unix/rawtime.cpp [new file with mode: 0644]
source/time/unix/rawtime_platform.h [new file with mode: 0644]
source/time/unix/timezone.cpp [new file with mode: 0644]
source/time/unix/utils.cpp [new file with mode: 0644]
source/time/utils.cpp
source/time/windows/rawtime.cpp [new file with mode: 0644]
source/time/windows/rawtime_platform.h [new file with mode: 0644]
source/time/windows/timezone.cpp [new file with mode: 0644]
source/time/windows/utils.cpp [new file with mode: 0644]

diff --git a/Build b/Build
index be4d039a96c97f01102222115c0ed7baa82e7694..c01f693c8a310a6261aa895991bccbd644cef9f3 100644 (file)
--- 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
                {
index 51f013e72c3cb5876429035d2604c95eb1a1f578..36621e92ae99af9b74a2726263fd3b8176cbd020 100644 (file)
@@ -1,9 +1,4 @@
-#ifdef WIN32
-#include <windows.h>
-#endif
 #include <signal.h>
-#include <typeinfo>
-#include <msp/debug/demangle.h>
 #include <msp/io/print.h>
 #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;
        }
index 08393b724b486077452e9ffb940bd9822fc6578c..7dfea8a0ad13abaa05d3102ace97a0962e957fd4 100644 (file)
@@ -1,6 +1,8 @@
 #ifndef MSP_CORE_APPLICATION_H_
 #define MSP_CORE_APPLICATION_H_
 
+#include <stdexcept>
+
 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 (file)
index fa28c1f..0000000
+++ /dev/null
@@ -1,45 +0,0 @@
-#ifdef WIN32
-#include <windows.h>
-#include <msp/stringcodec/utf16.h>
-#include <msp/stringcodec/utf8.h>
-#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<argc; ++i)
-               max_size += wcslen(argv_w[i])*4+1;
-
-       char *argv_buf = new char[max_size+(argc+1)*sizeof(char *)];
-       char **argv = reinterpret_cast<char **>(argv_buf);
-       char *argv_ptr = argv_buf+(argc+1)*sizeof(char *);
-       for(int i=0; i<argc; ++i)
-       {
-               argv[i] = argv_ptr;
-               string arg(reinterpret_cast<char *>(argv_w[i]), wcslen(argv_w[i])*2);
-               arg = StringCodec::transcode<StringCodec::Utf16Le, StringCodec::Utf8>(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 (file)
index 4f830c5..0000000
+++ /dev/null
@@ -1,62 +0,0 @@
-#ifndef WIN32
-#include <cerrno>
-#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
index 0b092dad9e441d8e9e5563d50a6b7b7c280326f6..615b25548b84200b7919e1a5cb4cd457780192a7 100644 (file)
@@ -1,22 +1,14 @@
 #ifndef MSP_CORE_MUTEX_PRIVATE_H_
 #define MSP_CORE_MUTEX_PRIVATE_H_
 
-#ifdef WIN32
-#include <windows.h>
-#else
-#include <pthread.h>
-#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 (file)
index 4bfd303..0000000
+++ /dev/null
@@ -1,97 +0,0 @@
-#ifdef WIN32
-#include <windows.h>
-#else
-#include <sys/time.h>
-#include <cerrno>
-#endif
-#include <msp/time/rawtime_private.h>
-#include <msp/time/timestamp.h>
-#include <msp/time/utils.h>
-#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->count<priv->limit)
-               ++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
index 1ccee74ed4a80139c77e1e013567465f4325906e..5424ef0ee647d564a624eb4e190553d7a808f88e 100644 (file)
@@ -1,10 +1,3 @@
-#ifdef WIN32
-#include <windows.h>
-#include <msp/strings/lexicalcast.h>
-#else
-#include <cerrno>
-#include <cstring>
-#endif
 #include <limits>
 #include "systemerror.h"
 
@@ -22,23 +15,4 @@ system_error::system_error(const string &w, const string &e):
        code_(numeric_limits<int>::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<string>(c, Fmt().hex());
-#else
-       if(c==-1)
-               c = errno;
-
-       return strerror(c);
-#endif
-}
-
 } // namespace Msp
index 6c542e6a6712d4e19323fbd779c401abd7ea4215..d2451a0d819187e67f0ea41340720e62ac7f3a4a 100644 (file)
@@ -1,41 +1,11 @@
-#ifdef WIN32
-#include <windows.h>
-#else
-#include <pthread.h>
-#include <signal.h>
-#endif
 #include <stdexcept>
 #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<Thread *>(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<Thread *>(arg);
+       thread->main();
+       thread->state_ = FINISHED;
+       return 0;
+}
+
 } // namespace Msp
index 81494eaf5e47a007d6bd6207293a972920277362..1fff3627b037287aac89cb8e68e77f15d5543b47 100644 (file)
@@ -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 (file)
index 0000000..f64c582
--- /dev/null
@@ -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 (file)
index 0000000..7f45fbc
--- /dev/null
@@ -0,0 +1,17 @@
+#include <typeinfo>
+#include <msp/debug/demangle.h>
+#include <msp/io/print.h>
+#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 (file)
index 0000000..601ddb6
--- /dev/null
@@ -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 (file)
index 0000000..15e5c9a
--- /dev/null
@@ -0,0 +1,41 @@
+#include <cerrno>
+#include <pthread.h>
+#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 (file)
index 0000000..2eee8bc
--- /dev/null
@@ -0,0 +1,12 @@
+#ifndef MSP_CORE_MUTEX_PLATFORM_H_
+#define MSP_CORE_MUTEX_PLATFORM_H_
+
+#include <pthread.h>
+
+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 (file)
index 0000000..8149258
--- /dev/null
@@ -0,0 +1,64 @@
+#include <sys/time.h>
+#include <cerrno>
+#include <msp/core/systemerror.h>
+#include <msp/time/rawtime_private.h>
+#include <msp/time/timestamp.h>
+#include <msp/time/utils.h>
+#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->count<priv->limit)
+               ++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 (file)
index 0000000..a8eb5a6
--- /dev/null
@@ -0,0 +1,17 @@
+#include <cerrno>
+#include <cstring>
+#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 (file)
index 0000000..e7d7f58
--- /dev/null
@@ -0,0 +1,25 @@
+#include <pthread.h>
+#include <signal.h>
+#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 (file)
index 0000000..0477a6d
--- /dev/null
@@ -0,0 +1,15 @@
+#ifndef MSP_CORE_THREAD_PLATFORM_H_
+#define MSP_CORE_THREAD_PLATFORM_H_
+
+#include <pthread.h>
+
+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 (file)
index 0000000..ed8702a
--- /dev/null
@@ -0,0 +1,16 @@
+#include <windows.h>
+#include <typeinfo>
+#include <msp/debug/demangle.h>
+#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 (file)
index 0000000..a0816a4
--- /dev/null
@@ -0,0 +1,35 @@
+#include <windows.h>
+#include <msp/stringcodec/utf16.h>
+#include <msp/stringcodec/utf8.h>
+#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<argc; ++i)
+               max_size += wcslen(argv_w[i])*4+1;
+
+       char *argv_buf = new char[max_size+(argc+1)*sizeof(char *)];
+       char **argv = reinterpret_cast<char **>(argv_buf);
+       char *argv_ptr = argv_buf+(argc+1)*sizeof(char *);
+       for(int i=0; i<argc; ++i)
+       {
+               argv[i] = argv_ptr;
+               string arg(reinterpret_cast<char *>(argv_w[i]), wcslen(argv_w[i])*2);
+               arg = StringCodec::transcode<StringCodec::Utf16Le, StringCodec::Utf8>(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 (file)
index 0000000..e51fda4
--- /dev/null
@@ -0,0 +1,34 @@
+#include <windows.h>
+#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 (file)
index 0000000..fae5e85
--- /dev/null
@@ -0,0 +1,12 @@
+#ifndef MSP_CORE_MUTEX_PLATFORM_H_
+#define MSP_CORE_MUTEX_PLATFORM_H_
+
+#include <windows.h>
+
+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 (file)
index 0000000..aeb1709
--- /dev/null
@@ -0,0 +1,47 @@
+#include <windows.h>
+#include <msp/core/systemerror.h>
+#include <msp/time/units.h>
+#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 (file)
index 0000000..98eb9ed
--- /dev/null
@@ -0,0 +1,20 @@
+#include <windows.h>
+#include <msp/strings/lexicalcast.h>
+#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<string>(c, Fmt().hex());
+}
+
+} // namespace Msp
diff --git a/source/core/windows/thread.cpp b/source/core/windows/thread.cpp
new file mode 100644 (file)
index 0000000..410141c
--- /dev/null
@@ -0,0 +1,25 @@
+#include <windows.h>
+#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 (file)
index 0000000..50b1a5e
--- /dev/null
@@ -0,0 +1,15 @@
+#ifndef MSP_CORE_THREAD_PLATFORM_H_
+#define MSP_CORE_THREAD_PLATFORM_H_
+
+#include <windows.h>
+
+namespace Msp {
+
+typedef HANDLE ThreadHandle;
+typedef DWORD ThreadReturn;
+
+#define THREAD_CALL WINAPI
+
+} // namespace Msp
+
+#endif
index f7f34f668492383087c78ddb4f2627a4e551e38e..57fd9368f2b311da99ea1cb3a2fc1ccdaf286510 100644 (file)
@@ -1,12 +1,6 @@
 #include <cstdlib>
-#include <cerrno>
-#include <dirent.h>
-#ifdef WIN32
-#include <shlobj.h>
-#else
 #include <unistd.h>
-#include <sys/stat.h>
-#endif
+#include <dirent.h>
 #include <msp/core/systemerror.h>
 #include <msp/strings/regex.h>
 #include <msp/strings/utils.h>
@@ -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<string> 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);
index 85fead5e7de1327eac1ade4c2e511d199badd8c8..f4566ae8b6ef8363cd68f709f2d66924137a58a2 100644 (file)
-#ifdef WIN32
-#include <windows.h>
-#include <aclapi.h>
-#else
-#define _FILE_OFFSET_BITS 64
-#include <cerrno>
-#include <unistd.h>
-#include <sys/stat.h>
-#include <grp.h>
-#include <pwd.h>
-#endif
-#include <msp/core/systemerror.h>
-#include <msp/strings/format.h>
-#include <msp/time/rawtime_private.h>
 #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<PSID>(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 (file)
index 0000000..c80d151
--- /dev/null
@@ -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 (file)
index 0000000..93aaeab
--- /dev/null
@@ -0,0 +1,38 @@
+#include <cstdlib>
+#include <unistd.h>
+#include <sys/stat.h>
+#include <msp/core/systemerror.h>
+#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 (file)
index 0000000..1404fed
--- /dev/null
@@ -0,0 +1,102 @@
+#define _FILE_OFFSET_BITS 64
+#include <cerrno>
+#include <unistd.h>
+#include <sys/stat.h>
+#include <grp.h>
+#include <pwd.h>
+#include <msp/core/systemerror.h>
+#include <msp/strings/format.h>
+#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 (file)
index 0000000..cc3f095
--- /dev/null
@@ -0,0 +1,15 @@
+#ifndef MSP_FS_STAT_PLATFORM_H_
+#define MSP_FS_STAT_PLATFORM_H_
+
+#include <unistd.h>
+
+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 (file)
index 0000000..c832343
--- /dev/null
@@ -0,0 +1,65 @@
+#include <cstdio>
+#include <unistd.h>
+#include <msp/core/systemerror.h>
+#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<string> 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
index 9a9802524399e53c8b21e723764f939a6fd9f8c1..2bfd1bf3ff4c63d9152084fe1ffdc0b802223aa5 100644 (file)
@@ -1,14 +1,5 @@
-#include <cstdio>
-#ifdef WIN32
-#include <windows.h>
-#else
-#include <unistd.h>
-#endif
-#include <msp/core/systemerror.h>
 #include <msp/strings/utils.h>
 #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<string> 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 (file)
index 0000000..6adddec
--- /dev/null
@@ -0,0 +1,39 @@
+#include <shlobj.h>
+#include <msp/core/systemerror.h>
+#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 (file)
index 0000000..f0cbdb6
--- /dev/null
@@ -0,0 +1,136 @@
+#include <windows.h>
+#include <aclapi.h>
+#include <msp/core/systemerror.h>
+#include <msp/strings/format.h>
+#include <msp/time/rawtime_private.h>
+#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<PSID>(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 (file)
index 0000000..4e8cfbc
--- /dev/null
@@ -0,0 +1,15 @@
+#ifndef MSP_FS_STAT_PLATFORM_H_
+#define MSP_FS_STAT_PLATFORM_H_
+
+#include <windows.h>
+
+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 (file)
index 0000000..ca9e7aa
--- /dev/null
@@ -0,0 +1,38 @@
+#include <windows.h>
+#include <msp/core/systemerror.h>
+#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
index a03ad20747bf251c40c57f682e027f760756cb7e..d50d72df89a5b8b3e353e5612feb8175703f4a93 100644 (file)
@@ -1,36 +1,7 @@
-#ifndef WIN32
-#include <errno.h>
-#include <unistd.h>
-#include <fcntl.h>
-#include <termios.h>
-#include <sys/ioctl.h>
-#endif
-#include <msp/core/systemerror.h>
 #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)
index 7b7887be80332fea89ddb24b320e7fc93a606e1a..5cb5f178e07f4279a465629dde4219ce514c833b 100644 (file)
@@ -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 (file)
index 370ddf2..0000000
+++ /dev/null
@@ -1,139 +0,0 @@
-#ifdef WIN32
-#include <windows.h>
-#endif
-#include <algorithm>
-#include <msp/core/systemerror.h>
-#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
index 805a9e8dba0072270d90a8cb695faa681e710e3a..90694324aa1d6e52f8c59b9f649135725926e031 100644 (file)
@@ -1,10 +1,3 @@
-#ifndef WIN32
-#include <errno.h>
-#include <fcntl.h>
-#include <unistd.h>
-#endif
-#include <msp/strings/format.h>
-#include <msp/core/systemerror.h>
 #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<int>(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();
index 90a1041ccda6520db5386b724f43fe6e936bfe85..d106561e5f599cc31367be5f3de9140a4d349cbf 100644 (file)
@@ -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);
index 0e9b82aa000c9382fe954b764f36d6614710934e..c20f067e5a6ca18b3d04c1c39b173d9ea7ccfe0b 100644 (file)
@@ -1,6 +1,3 @@
-#include <cerrno>
-#include <unistd.h>
-#include <msp/core/systemerror.h>
 #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
index 24b9ee6a9e9e192b63fb4eb2230cd66050577c4c..8a9db50b60ec5e85032fa5e1eb0741f9857cbdfe 100644 (file)
@@ -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 &);
index d73a2b88af6343a23690e461e519af4d5e623820..4fa690ab3c50a1bde134de16b69013a80e82aeba 100644 (file)
@@ -1,28 +1,20 @@
 #ifndef MSP_IO_HANDLE_PRIVATE_H_
 #define MSP_IO_HANDLE_PRIVATE_H_
 
-#ifdef WIN32
-#include <windows.h>
-#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
index 0f206981f11c6d1e205d127d281655965559187e..831076f0086b2ffd756ec9e86a3b1b1364e9b1cc 100644 (file)
@@ -1,11 +1,3 @@
-#ifndef WIN32
-#include <fcntl.h>
-#include <errno.h>
-#include <unistd.h>
-#endif
-#include <msp/core/systemerror.h>
-#include <msp/strings/format.h>
-#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)
index d1508b2097d743b244c03f89d4230cf59cad8608..50da5e53e1d6b49a9c1d599a319ae6fb5502c83f 100644 (file)
@@ -17,6 +17,9 @@ private:
 
 public:
        Pipe();
+private:
+       void platform_init();
+public:
        ~Pipe();
 
        void set_block(bool);
index a58090792fcb06cf9c4a2a9049159ac7324524a8..0356a00fdbe27ffe957f340fb25d82b5cf1d2c7a 100644 (file)
-#include <cerrno>
 #include <stdexcept>
-#ifndef WIN32
-#include <poll.h>
-#endif
-#include <msp/core/systemerror.h>
-#include <msp/strings/format.h>
 #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<HANDLE> handles;
-#else
-       vector<pollfd> 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<int>(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 &&*/ ret<WAIT_OBJECT_0+priv->handles.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<pollfd>::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<Time::zero)
                throw invalid_argument("poll");
 
-       return do_poll(obj, pe, static_cast<int>(timeout/Time::msec));
+       return platform_poll(obj, pe, static_cast<int>(timeout/Time::msec));
 }
 
 } // namespace IO
index d7823aa9108d8d16bd856fd2fbb4b35f41ac04fa..09e00e5bbedb6313bea0832d09eb0e451a5ffe3d 100644 (file)
@@ -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; }
 };
index 35ab5a05104fef55fbe625a3e55cdff2d1b18590..6bc84855541c6f0974eb3c8ba29405fb67d8febd 100644 (file)
@@ -1,46 +1,8 @@
-#ifndef WIN32
-#define _LARGEFILE64_SOURCE
-#include <cerrno>
-#include <unistd.h>
-#else
-#include <windows.h>
-#endif
-#include <msp/core/systemerror.h>
 #include <msp/strings/format.h>
-#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
index dc623e29cc47b82426816fa780a744f474c89eec..cf2c6952bf3d7e97eb52eb0102f5253549aa03da 100644 (file)
-#ifdef WIN32
-#include <windows.h>
-#else
-#include <termios.h>
-#include <fcntl.h>
-#include <errno.h>
-#endif
-#include <msp/strings/format.h>
-#include <msp/core/systemerror.h>
-#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)
index 49ecefbc8fd02f30dea512610cb40ae966781a06..1c91e600ea4503f7f7443769be4c5083c43bdc2e 100644 (file)
@@ -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 (file)
index 0000000..1b497be
--- /dev/null
@@ -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 (file)
index 0000000..d38d0bb
--- /dev/null
@@ -0,0 +1,83 @@
+#include <unistd.h>
+#include <fcntl.h>
+#include <termios.h>
+#include <sys/ioctl.h>
+#include <msp/core/systemerror.h>
+#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 (file)
index 0000000..fcbc892
--- /dev/null
@@ -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 (file)
index 0000000..b2c9089
--- /dev/null
@@ -0,0 +1,60 @@
+#include <errno.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <msp/core/systemerror.h>
+#include <msp/strings/format.h>
+#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 (file)
index 0000000..9546df9
--- /dev/null
@@ -0,0 +1,57 @@
+#include <cerrno>
+#include <unistd.h>
+#include <fcntl.h>
+#include <msp/core/systemerror.h>
+#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 (file)
index 0000000..b241669
--- /dev/null
@@ -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 (file)
index 0000000..de93f82
--- /dev/null
@@ -0,0 +1,20 @@
+#include <unistd.h>
+#include <msp/core/systemerror.h>
+#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 (file)
index 0000000..650f226
--- /dev/null
@@ -0,0 +1,109 @@
+#include <cerrno>
+#include <msp/core/systemerror.h>
+#include <poll.h>
+#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<pollfd>::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 (file)
index 0000000..bfd83da
--- /dev/null
@@ -0,0 +1,18 @@
+#ifndef MSP_IO_POLL_PLATFORM_H_
+#define MSP_IO_POLL_PLATFORM_H_
+
+#include <poll.h>
+#include <vector>
+
+namespace Msp {
+namespace IO {
+
+struct Poller::Private
+{
+       std::vector<pollfd> pfd;
+};
+
+} // namespace IO
+} // namespace Msp
+
+#endif
diff --git a/source/io/unix/seekable.cpp b/source/io/unix/seekable.cpp
new file mode 100644 (file)
index 0000000..2c17114
--- /dev/null
@@ -0,0 +1,47 @@
+#define _LARGEFILE64_SOURCE
+#include <cerrno>
+#include <unistd.h>
+#include <msp/core/systemerror.h>
+#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 (file)
index 0000000..49d9e9c
--- /dev/null
@@ -0,0 +1,121 @@
+#include <fcntl.h>
+#include <termios.h>
+#include <msp/core/systemerror.h>
+#include <msp/strings/format.h>
+#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 (file)
index 0000000..e7de712
--- /dev/null
@@ -0,0 +1,14 @@
+#ifndef MSP_IO_SERIAL_PLATFORM_H_
+#define MSP_IO_SERIAL_PLATFORM_H_
+
+#include <termios.h>
+
+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 (file)
index 0000000..a331133
--- /dev/null
@@ -0,0 +1,72 @@
+#include <msp/core/systemerror.h>
+#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 (file)
index 0000000..62c9763
--- /dev/null
@@ -0,0 +1,115 @@
+#include <windows.h>
+#include <algorithm>
+#include <msp/core/systemerror.h>
+#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 (file)
index 0000000..b973375
--- /dev/null
@@ -0,0 +1,54 @@
+#include <msp/core/systemerror.h>
+#include <msp/strings/format.h>
+#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<int>(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 (file)
index 0000000..5b1d933
--- /dev/null
@@ -0,0 +1,42 @@
+#include <msp/core/systemerror.h>
+#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 (file)
index 0000000..f12e5f7
--- /dev/null
@@ -0,0 +1,14 @@
+#ifndef MSP_IO_HANDLE_PLATFORM_H_
+#define MSP_IO_HANDLE_PLATFORM_H_
+
+#include <windows.h>
+
+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 (file)
index 0000000..02d7f33
--- /dev/null
@@ -0,0 +1,28 @@
+#include <msp/core/systemerror.h>
+#include <msp/strings/format.h>
+#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 (file)
index 0000000..e672258
--- /dev/null
@@ -0,0 +1,53 @@
+#include <msp/core/systemerror.h>
+#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 &&*/ ret<WAIT_OBJECT_0+priv->handles.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 (file)
index 0000000..ccf92c3
--- /dev/null
@@ -0,0 +1,18 @@
+#ifndef MSP_IO_POLL_PLATFORM_H_
+#define MSP_IO_POLL_PLATFORM_H_
+
+#include <windows.h>
+#include <vector>
+
+namespace Msp {
+namespace IO {
+
+struct Poller::Private
+{
+       std::vector<HANDLE> handles;
+};
+
+} // namespace IO
+} // namespace Msp
+
+#endif
diff --git a/source/io/windows/seekable.cpp b/source/io/windows/seekable.cpp
new file mode 100644 (file)
index 0000000..73c5cc5
--- /dev/null
@@ -0,0 +1,45 @@
+#include <windows.h>
+#include <msp/core/systemerror.h>
+#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 (file)
index 0000000..0092754
--- /dev/null
@@ -0,0 +1,74 @@
+#include <msp/core/systemerror.h>
+#include <msp/strings/format.h>
+#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 (file)
index 0000000..dd7dd50
--- /dev/null
@@ -0,0 +1,14 @@
+#ifndef MSP_IO_SERIAL_PLATFORM_H_
+#define MSP_IO_SERIAL_PLATFORM_H_
+
+#include <windows.h>
+
+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 (file)
index a299246..0000000
+++ /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<Msp::Time::RawTime>(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<RawTime>(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
index 846a712f70bb48614e300555510f4ec9a191b7bf..e0cbb2ecfa30db2a6984fe8813bb3676d6860fa1 100644 (file)
@@ -1,25 +1,6 @@
 #ifndef MSP_TIME_RAWTIME_PRIVATE_H_
 #define MSP_TIME_RAWTIME_PRIVATE_H_
 
-#ifdef WIN32
-#include <windows.h>
-#else
-#include <sys/time.h>
-#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
index 7baf4943bec4b436c479d06d4394c9004f91f2d3..76c3fb242463fe3f5f504c37e3f0a95a616d223c 100644 (file)
@@ -1,108 +1,9 @@
 #include <cstdlib>
-#ifdef WIN32
-#include <windows.h>
-#else
-#include <unistd.h>
-#include <fcntl.h>
-#endif
 #include <msp/strings/format.h>
-#include <msp/core/systemerror.h>
-#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<unsigned char >(*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; i<timecnt; ++i)
-                                       if(get_long(ptr)<=cur_time)
-                                               index = i;
-
-                               if(index>0)
-                                       index = ptr[index];
-                               ptr += timecnt;
-
-                               int abbrind = 0;
-                               for(int i=0; i<typecnt; ++i)
-                               {
-                                       if((index>=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;
 }
 
index 28feb16bf13ff958af044f4e2e0da1319688622c..3fbeb543a243e1a7abd8922e07617ea9cda83992 100644 (file)
@@ -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 (file)
index 0000000..2b8bc6d
--- /dev/null
@@ -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 (file)
index 0000000..8f9f633
--- /dev/null
@@ -0,0 +1,17 @@
+#ifndef MSP_TIME_RAWTIME_PLATFORM_H_
+#define MSP_TIME_RAWTIME_PLATFORM_H_
+
+#include <sys/time.h>
+#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 (file)
index 0000000..e55969c
--- /dev/null
@@ -0,0 +1,85 @@
+#include <unistd.h>
+#include <fcntl.h>
+#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<unsigned char >(*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; i<timecnt; ++i)
+                                       if(get_long(ptr)<=cur_time)
+                                               index = i;
+
+                               if(index>0)
+                                       index = ptr[index];
+                               ptr += timecnt;
+
+                               int abbrind = 0;
+                               for(int i=0; i<typecnt; ++i)
+                               {
+                                       if((index>=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 (file)
index 0000000..029c75b
--- /dev/null
@@ -0,0 +1,36 @@
+#include <sys/resource.h>
+#include <sys/time.h>
+#include <cerrno>
+#include <msp/core/systemerror.h>
+#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
index 9c643cf8b2dec5634c703474d5b3e976a58f3346..52c89342b29a4fbfbc0d2b71aec465f59264d319 100644 (file)
@@ -1,14 +1,4 @@
-#ifdef WIN32
-#include <windows.h>
-#else
-#include <sys/resource.h>
-#include <sys/time.h>
-#include <cerrno>
-#endif
-#include <msp/core/systemerror.h>
 #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 (file)
index 0000000..b6276f0
--- /dev/null
@@ -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<Msp::Time::RawTime>(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<RawTime>(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 (file)
index 0000000..60a9a59
--- /dev/null
@@ -0,0 +1,15 @@
+#ifndef MSP_TIME_RAWTIME_PLATFORM_H_
+#define MSP_TIME_RAWTIME_PLATFORM_H_
+
+#include <windows.h>
+#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 (file)
index 0000000..570c679
--- /dev/null
@@ -0,0 +1,25 @@
+#include <windows.h>
+#include <msp/core/systemerror.h>
+#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 (file)
index 0000000..2150a10
--- /dev/null
@@ -0,0 +1,29 @@
+#include <windows.h>
+#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