From eeb6b89120ab259702f103da01bfd8c06f285e7b Mon Sep 17 00:00:00 2001 From: Mikko Rasa Date: Wed, 24 Apr 2013 16:08:45 +0300 Subject: [PATCH 01/16] Use UInt64 for FileSize The MSVC define was incorrect anyway. --- source/fs/stat.h | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/source/fs/stat.h b/source/fs/stat.h index 8c05771..3f056a5 100644 --- a/source/fs/stat.h +++ b/source/fs/stat.h @@ -2,6 +2,7 @@ #define MSP_FS_STAT_H_ #include +#include #include #include "path.h" @@ -16,11 +17,7 @@ enum FileType SYMLINK }; -#ifdef MSVC -typedef __uint64 FileSize; -#else -typedef unsigned long long FileSize; -#endif +typedef UInt64 FileSize; /** Holds file information. -- 2.45.2 From b4806214e905752617691f851717033fd3f266c2 Mon Sep 17 00:00:00 2001 From: Mikko Rasa Date: Wed, 24 Apr 2013 16:11:11 +0300 Subject: [PATCH 02/16] Clean up after the timedelta.h/units.h merge Quite a few files were still including units.h, and documentation for TimeDelta contained a reference to it. --- source/core/semaphore.cpp | 1 - source/debug/profiler.cpp | 1 - source/io/eventdispatcher.cpp | 1 - source/io/eventdispatcher.h | 1 + source/io/poll.cpp | 1 - source/time/datetime.cpp | 1 - source/time/timedelta.cpp | 1 - source/time/timedelta.h | 3 +-- source/time/timezone.cpp | 1 - source/time/utils.cpp | 1 - 10 files changed, 2 insertions(+), 10 deletions(-) diff --git a/source/core/semaphore.cpp b/source/core/semaphore.cpp index 06e8435..4bfd303 100644 --- a/source/core/semaphore.cpp +++ b/source/core/semaphore.cpp @@ -6,7 +6,6 @@ #endif #include #include -#include #include #include "mutex_private.h" #include "semaphore.h" diff --git a/source/debug/profiler.cpp b/source/debug/profiler.cpp index 38681ed..c33aebf 100644 --- a/source/debug/profiler.cpp +++ b/source/debug/profiler.cpp @@ -1,5 +1,4 @@ #include -#include #include "profiler.h" #include "profilingscope.h" diff --git a/source/io/eventdispatcher.cpp b/source/io/eventdispatcher.cpp index 8660b5b..3a3baa6 100644 --- a/source/io/eventdispatcher.cpp +++ b/source/io/eventdispatcher.cpp @@ -1,4 +1,3 @@ -#include #include "base.h" #include "eventdispatcher.h" #include "eventobject.h" diff --git a/source/io/eventdispatcher.h b/source/io/eventdispatcher.h index 16dd62b..04d037e 100644 --- a/source/io/eventdispatcher.h +++ b/source/io/eventdispatcher.h @@ -3,6 +3,7 @@ #include #include +#include #include "poll.h" namespace Msp { diff --git a/source/io/poll.cpp b/source/io/poll.cpp index e8c5804..a580907 100644 --- a/source/io/poll.cpp +++ b/source/io/poll.cpp @@ -5,7 +5,6 @@ #endif #include #include -#include #include "eventobject.h" #include "handle.h" #include "handle_private.h" diff --git a/source/time/datetime.cpp b/source/time/datetime.cpp index bf82411..c77796f 100644 --- a/source/time/datetime.cpp +++ b/source/time/datetime.cpp @@ -3,7 +3,6 @@ #include #include "datetime.h" #include "timestamp.h" -#include "units.h" using namespace std; diff --git a/source/time/timedelta.cpp b/source/time/timedelta.cpp index a4e5db1..a56e0fe 100644 --- a/source/time/timedelta.cpp +++ b/source/time/timedelta.cpp @@ -1,6 +1,5 @@ #include #include "timedelta.h" -#include "units.h" using namespace std; diff --git a/source/time/timedelta.h b/source/time/timedelta.h index 9be491e..c73529b 100644 --- a/source/time/timedelta.h +++ b/source/time/timedelta.h @@ -21,8 +21,7 @@ public: TimeDelta(): usec(0) { } /** Constructs a TimeDelta from a plain number. The purpose of this is to - allow serialization together with the raw() function. For creating - TimeDeltas with a specific length, see units.h. */ + allow serialization together with the raw() function. */ explicit TimeDelta(RawTime u): usec(u) { } /** Returns the raw number stored inside the TimeDelta. This should only be used diff --git a/source/time/timezone.cpp b/source/time/timezone.cpp index a2cd7a3..7baf494 100644 --- a/source/time/timezone.cpp +++ b/source/time/timezone.cpp @@ -9,7 +9,6 @@ #include #include "timestamp.h" #include "timezone.h" -#include "units.h" #include "utils.h" using namespace std; diff --git a/source/time/utils.cpp b/source/time/utils.cpp index 8b57695..9c643cf 100644 --- a/source/time/utils.cpp +++ b/source/time/utils.cpp @@ -10,7 +10,6 @@ #include "rawtime_private.h" #include "timedelta.h" #include "timestamp.h" -#include "units.h" #include "utils.h" using namespace std; -- 2.45.2 From 609c9a508cfdc7b42c46c4f21d17639204165a00 Mon Sep 17 00:00:00 2001 From: Mikko Rasa Date: Wed, 24 Apr 2013 16:22:18 +0300 Subject: [PATCH 03/16] Move most platform-specific code into overlay directories A few things, in particular FS::Path, were not trivial to split. I'm not certain what to do with features like zlib either. --- Build | 8 + source/core/application.cpp | 14 +- source/core/application.h | 4 + source/core/mutex_private.h | 12 +- source/core/systemerror.cpp | 26 --- source/core/thread.cpp | 59 ++---- source/core/thread.h | 6 + source/core/thread_private.h | 19 ++ source/core/unix/application.cpp | 17 ++ source/core/unix/main.cpp | 6 + source/core/{ => unix}/mutex.cpp | 23 +-- source/core/unix/mutex_platform.h | 12 ++ source/core/{ => unix}/semaphore.cpp | 37 +--- source/core/unix/systemerror.cpp | 17 ++ source/core/unix/thread.cpp | 25 +++ source/core/unix/thread_platform.h | 15 ++ source/core/windows/application.cpp | 16 ++ source/core/{ => windows}/main.cpp | 10 - source/core/windows/mutex.cpp | 34 ++++ source/core/windows/mutex_platform.h | 12 ++ source/core/windows/semaphore.cpp | 47 +++++ source/core/windows/systemerror.cpp | 20 ++ source/core/windows/thread.cpp | 25 +++ source/core/windows/thread_platform.h | 15 ++ source/fs/dir.cpp | 57 +----- source/fs/stat.cpp | 242 +----------------------- source/fs/stat_private.h | 30 +++ source/fs/unix/dir.cpp | 38 ++++ source/fs/unix/stat.cpp | 102 ++++++++++ source/fs/unix/stat_platform.h | 15 ++ source/fs/unix/utils.cpp | 65 +++++++ source/fs/utils.cpp | 82 -------- source/fs/windows/dir.cpp | 39 ++++ source/fs/windows/stat.cpp | 136 +++++++++++++ source/fs/windows/stat_platform.h | 15 ++ source/fs/windows/utils.cpp | 38 ++++ source/io/console.cpp | 132 +------------ source/io/console.h | 1 + source/io/file.cpp | 97 +--------- source/io/file.h | 3 + source/io/handle.cpp | 68 +------ source/io/handle.h | 1 + source/io/handle_private.h | 16 +- source/io/pipe.cpp | 38 +--- source/io/pipe.h | 3 + source/io/poll.cpp | 161 +--------------- source/io/poll.h | 1 + source/io/seekable.cpp | 66 ------- source/io/serial.cpp | 193 +------------------ source/io/serial.h | 3 + source/io/serial_private.h | 25 +++ source/io/unix/console.cpp | 83 ++++++++ source/io/unix/eventreader.cpp | 31 +++ source/io/unix/file.cpp | 60 ++++++ source/io/unix/handle.cpp | 57 ++++++ source/io/unix/handle_platform.h | 14 ++ source/io/unix/pipe.cpp | 20 ++ source/io/unix/poll.cpp | 109 +++++++++++ source/io/unix/poll_platform.h | 18 ++ source/io/unix/seekable.cpp | 47 +++++ source/io/unix/serial.cpp | 121 ++++++++++++ source/io/unix/serial_platform.h | 14 ++ source/io/windows/console.cpp | 72 +++++++ source/io/{ => windows}/eventreader.cpp | 26 +-- source/io/windows/file.cpp | 54 ++++++ source/io/windows/handle.cpp | 42 ++++ source/io/windows/handle_platform.h | 14 ++ source/io/windows/pipe.cpp | 28 +++ source/io/windows/poll.cpp | 53 ++++++ source/io/windows/poll_platform.h | 18 ++ source/io/windows/seekable.cpp | 45 +++++ source/io/windows/serial.cpp | 74 ++++++++ source/io/windows/serial_platform.h | 14 ++ source/time/rawtime_private.h | 21 +- source/time/timezone.cpp | 101 +--------- source/time/timezone.h | 2 + source/time/unix/rawtime.cpp | 29 +++ source/time/unix/rawtime_platform.h | 17 ++ source/time/unix/timezone.cpp | 85 +++++++++ source/time/unix/utils.cpp | 36 ++++ source/time/utils.cpp | 47 ----- source/time/{ => windows}/rawtime.cpp | 26 --- source/time/windows/rawtime_platform.h | 15 ++ source/time/windows/timezone.cpp | 25 +++ source/time/windows/utils.cpp | 29 +++ 85 files changed, 2086 insertions(+), 1507 deletions(-) create mode 100644 source/core/thread_private.h create mode 100644 source/core/unix/application.cpp create mode 100644 source/core/unix/main.cpp rename source/core/{ => unix}/mutex.cpp (66%) create mode 100644 source/core/unix/mutex_platform.h rename source/core/{ => unix}/semaphore.cpp (64%) create mode 100644 source/core/unix/systemerror.cpp create mode 100644 source/core/unix/thread.cpp create mode 100644 source/core/unix/thread_platform.h create mode 100644 source/core/windows/application.cpp rename source/core/{ => windows}/main.cpp (89%) create mode 100644 source/core/windows/mutex.cpp create mode 100644 source/core/windows/mutex_platform.h create mode 100644 source/core/windows/semaphore.cpp create mode 100644 source/core/windows/systemerror.cpp create mode 100644 source/core/windows/thread.cpp create mode 100644 source/core/windows/thread_platform.h create mode 100644 source/fs/stat_private.h create mode 100644 source/fs/unix/dir.cpp create mode 100644 source/fs/unix/stat.cpp create mode 100644 source/fs/unix/stat_platform.h create mode 100644 source/fs/unix/utils.cpp create mode 100644 source/fs/windows/dir.cpp create mode 100644 source/fs/windows/stat.cpp create mode 100644 source/fs/windows/stat_platform.h create mode 100644 source/fs/windows/utils.cpp create mode 100644 source/io/serial_private.h create mode 100644 source/io/unix/console.cpp create mode 100644 source/io/unix/eventreader.cpp create mode 100644 source/io/unix/file.cpp create mode 100644 source/io/unix/handle.cpp create mode 100644 source/io/unix/handle_platform.h create mode 100644 source/io/unix/pipe.cpp create mode 100644 source/io/unix/poll.cpp create mode 100644 source/io/unix/poll_platform.h create mode 100644 source/io/unix/seekable.cpp create mode 100644 source/io/unix/serial.cpp create mode 100644 source/io/unix/serial_platform.h create mode 100644 source/io/windows/console.cpp rename source/io/{ => windows}/eventreader.cpp (87%) create mode 100644 source/io/windows/file.cpp create mode 100644 source/io/windows/handle.cpp create mode 100644 source/io/windows/handle_platform.h create mode 100644 source/io/windows/pipe.cpp create mode 100644 source/io/windows/poll.cpp create mode 100644 source/io/windows/poll_platform.h create mode 100644 source/io/windows/seekable.cpp create mode 100644 source/io/windows/serial.cpp create mode 100644 source/io/windows/serial_platform.h create mode 100644 source/time/unix/rawtime.cpp create mode 100644 source/time/unix/rawtime_platform.h create mode 100644 source/time/unix/timezone.cpp create mode 100644 source/time/unix/utils.cpp rename source/time/{ => windows}/rawtime.cpp (62%) create mode 100644 source/time/windows/rawtime_platform.h create mode 100644 source/time/windows/timezone.cpp create mode 100644 source/time/windows/utils.cpp diff --git a/Build b/Build index be4d039..c01f693 100644 --- a/Build +++ b/Build @@ -37,6 +37,14 @@ package "mspcore" source "source/stringcodec"; source "source/io"; source "source/fs"; + if_arch "windows" + { + overlay "windows"; + }; + if_arch "!windows" + { + overlay "unix"; + }; install true; install_map { diff --git a/source/core/application.cpp b/source/core/application.cpp index 51f013e..36621e9 100644 --- a/source/core/application.cpp +++ b/source/core/application.cpp @@ -1,9 +1,4 @@ -#ifdef WIN32 -#include -#endif #include -#include -#include #include #include "application.h" #include "getopt.h" @@ -68,14 +63,7 @@ int Application::run(int argc, char **argv, void *data) { delete app_; -#ifdef WIN32 - string msg = Debug::demangle(typeid(e).name())+":\n"+e.what(); - MessageBoxA(0, msg.c_str(), "Uncaught exception", MB_OK|MB_ICONERROR); -#else - IO::print(IO::cerr, "An uncaught exception occurred.\n"); - IO::print(IO::cerr, " type: %s\n", Debug::demangle(typeid(e).name())); - IO::print(IO::cerr, " what(): %s\n", e.what()); -#endif + display_exception(e); return 124; } diff --git a/source/core/application.h b/source/core/application.h index 08393b7..7dfea8a 100644 --- a/source/core/application.h +++ b/source/core/application.h @@ -1,6 +1,8 @@ #ifndef MSP_CORE_APPLICATION_H_ #define MSP_CORE_APPLICATION_H_ +#include + namespace Msp { /** @@ -45,6 +47,8 @@ protected: virtual void sighandler(int) { } private: static void sighandler_(int); + + static void display_exception(const std::exception &); }; diff --git a/source/core/mutex_private.h b/source/core/mutex_private.h index 0b092da..615b255 100644 --- a/source/core/mutex_private.h +++ b/source/core/mutex_private.h @@ -1,22 +1,14 @@ #ifndef MSP_CORE_MUTEX_PRIVATE_H_ #define MSP_CORE_MUTEX_PRIVATE_H_ -#ifdef WIN32 -#include -#else -#include -#endif #include "mutex.h" +#include "mutex_platform.h" namespace Msp { struct Mutex::Private { -#ifdef WIN32 - CRITICAL_SECTION crit; -#else - pthread_mutex_t mutex; -#endif + PlatformMutex mutex; }; } // namespace Msp diff --git a/source/core/systemerror.cpp b/source/core/systemerror.cpp index 1ccee74..5424ef0 100644 --- a/source/core/systemerror.cpp +++ b/source/core/systemerror.cpp @@ -1,10 +1,3 @@ -#ifdef WIN32 -#include -#include -#else -#include -#include -#endif #include #include "systemerror.h" @@ -22,23 +15,4 @@ system_error::system_error(const string &w, const string &e): code_(numeric_limits::min()) { } -string system_error::get_message(int c) -{ -#ifdef WIN32 - if(c==-1) - c = GetLastError(); - - char msg[1024]; - if(FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM, 0, c, 0, msg, sizeof(msg), 0)) - return msg; - else - return lexical_cast(c, Fmt().hex()); -#else - if(c==-1) - c = errno; - - return strerror(c); -#endif -} - } // namespace Msp diff --git a/source/core/thread.cpp b/source/core/thread.cpp index 6c542e6..d2451a0 100644 --- a/source/core/thread.cpp +++ b/source/core/thread.cpp @@ -1,41 +1,11 @@ -#ifdef WIN32 -#include -#else -#include -#include -#endif #include #include "thread.h" +#include "thread_private.h" using namespace std; namespace Msp { -struct Thread::Private -{ -#ifdef WIN32 - HANDLE handle; -#else - pthread_t handle; -#endif - - Private(): handle(0) { } - -#ifdef WIN32 - static DWORD WINAPI -#else - static void * -#endif - main_wrapper(void *a) - { - Thread *t = reinterpret_cast(a); - t->main(); - t->state_ = FINISHED; - return 0; - } -}; - - Thread::Thread(): priv_(new Private), state_(PENDING) @@ -53,11 +23,7 @@ void Thread::join() if(state_>=JOINED) return; -#ifdef WIN32 - WaitForSingleObject(priv_->handle, INFINITE); -#else - pthread_join(priv_->handle, 0); -#endif + platform_join(); state_ = JOINED; } @@ -66,11 +32,7 @@ void Thread::kill() if(state_!=RUNNING) return; -#ifdef WIN32 - TerminateThread(priv_->handle, 0); -#else - pthread_kill(priv_->handle, SIGKILL); -#endif + platform_kill(); state_ = KILLED; } @@ -79,13 +41,16 @@ void Thread::launch() if(state_>=RUNNING) throw logic_error("already launched"); -#ifdef WIN32 - DWORD dummy; // Win9x needs the lpTthreadId parameter - priv_->handle = CreateThread(0, 0, &Private::main_wrapper, this, 0, &dummy); -#else - pthread_create(&priv_->handle, 0, &Private::main_wrapper, this); -#endif + platform_launch(); state_ = RUNNING; } +ThreadReturn THREAD_CALL Thread::Private::main_wrapper(void *arg) +{ + Thread *thread = reinterpret_cast(arg); + thread->main(); + thread->state_ = FINISHED; + return 0; +} + } // namespace Msp diff --git a/source/core/thread.h b/source/core/thread.h index 81494ea..1fff362 100644 --- a/source/core/thread.h +++ b/source/core/thread.h @@ -50,6 +50,12 @@ protected: /** Starts the thread. Can only be called once for each Thread instance. */ void launch(); +private: + void platform_join(); + void platform_kill(); + void platform_launch(); + +protected: virtual void main() = 0; }; diff --git a/source/core/thread_private.h b/source/core/thread_private.h new file mode 100644 index 0000000..f64c582 --- /dev/null +++ b/source/core/thread_private.h @@ -0,0 +1,19 @@ +#ifndef MSP_CORE_THREAD_PRIVATE_H_ +#define MSP_CORE_THREAD_PRIVATE_H_ + +#include "thread_platform.h" + +namespace Msp { + +struct Thread::Private +{ + ThreadHandle handle; + + Private(): handle(0) { } + + static ThreadReturn THREAD_CALL main_wrapper(void *); +}; + +} // namespace Msp + +#endif diff --git a/source/core/unix/application.cpp b/source/core/unix/application.cpp new file mode 100644 index 0000000..7f45fbc --- /dev/null +++ b/source/core/unix/application.cpp @@ -0,0 +1,17 @@ +#include +#include +#include +#include "application.h" + +using namespace std; + +namespace Msp { + +void Application::display_exception(const exception &e) +{ + IO::print(IO::cerr, "An uncaught exception occurred.\n"); + IO::print(IO::cerr, " type: %s\n", Debug::demangle(typeid(e).name())); + IO::print(IO::cerr, " what(): %s\n", e.what()); +} + +} // namespace Msp diff --git a/source/core/unix/main.cpp b/source/core/unix/main.cpp new file mode 100644 index 0000000..601ddb6 --- /dev/null +++ b/source/core/unix/main.cpp @@ -0,0 +1,6 @@ +#include "application.h" + +int main(int argc, char **argv) +{ + return Msp::Application::run(argc, argv); +} diff --git a/source/core/mutex.cpp b/source/core/unix/mutex.cpp similarity index 66% rename from source/core/mutex.cpp rename to source/core/unix/mutex.cpp index 4f830c5..15e5c9a 100644 --- a/source/core/mutex.cpp +++ b/source/core/unix/mutex.cpp @@ -1,6 +1,5 @@ -#ifndef WIN32 #include -#endif +#include #include "mutex.h" #include "mutex_private.h" #include "systemerror.h" @@ -10,53 +9,33 @@ namespace Msp { Mutex::Mutex(): priv(new Private) { -#ifdef WIN32 - InitializeCriticalSection(&priv->crit); -#else pthread_mutex_init(&priv->mutex, 0); -#endif } Mutex::~Mutex() { -#ifdef WIN32 - DeleteCriticalSection(&priv->crit); -#else pthread_mutex_destroy(&priv->mutex); -#endif delete priv; } void Mutex::lock() { -#ifdef WIN32 - EnterCriticalSection(&priv->crit); -#else if(int err = pthread_mutex_lock(&priv->mutex)) throw system_error("pthread_mutex_lock", err); -#endif } bool Mutex::trylock() { -#ifdef WIN32 - return TryEnterCriticalSection(&priv->crit); -#else int err = pthread_mutex_trylock(&priv->mutex); if(err && err!=EBUSY) throw system_error("pthread_mutex_trylock", err); return !err; -#endif } void Mutex::unlock() { -#ifdef WIN32 - LeaveCriticalSection(&priv->crit); -#else if(int err = pthread_mutex_unlock(&priv->mutex)) throw system_error("pthread_mutex_unlock", err); -#endif } } // namespace Msp diff --git a/source/core/unix/mutex_platform.h b/source/core/unix/mutex_platform.h new file mode 100644 index 0000000..2eee8bc --- /dev/null +++ b/source/core/unix/mutex_platform.h @@ -0,0 +1,12 @@ +#ifndef MSP_CORE_MUTEX_PLATFORM_H_ +#define MSP_CORE_MUTEX_PLATFORM_H_ + +#include + +namespace Msp { + +typedef pthread_mutex_t PlatformMutex; + +} // namespace Msp + +#endif diff --git a/source/core/semaphore.cpp b/source/core/unix/semaphore.cpp similarity index 64% rename from source/core/semaphore.cpp rename to source/core/unix/semaphore.cpp index 4bfd303..8149258 100644 --- a/source/core/semaphore.cpp +++ b/source/core/unix/semaphore.cpp @@ -1,97 +1,64 @@ -#ifdef WIN32 -#include -#else #include #include -#endif +#include #include #include #include +#include "mutex.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->countlimit) ++priv->count; if(int err = pthread_cond_signal(&priv->cond)) throw system_error("pthread_cond_signal", err); -#endif } void Semaphore::wait() { -#ifdef WIN32 - DWORD ret = WaitForSingleObject(priv->handle, INFINITE); - if(ret==WAIT_FAILED) - throw system_error("WaitForSingleObject"); -#else MutexLock mlock(priv->mutex); while(!priv->count) if(int err = pthread_cond_wait(&priv->cond, &priv->mutex.priv->mutex)) throw system_error("pthread_cond_wait", err); --priv->count; -#endif } bool Semaphore::wait(const Time::TimeDelta &d) { -#ifdef WIN32 - DWORD ret = WaitForSingleObject(priv->handle, (DWORD)(d/Time::usec)); - if(ret==WAIT_FAILED) - throw system_error("WaitForSingleObject"); - return ret==WAIT_OBJECT_0; -#else timespec timeout = Time::rawtime_to_timespec((Time::now()+d).raw()); int err = pthread_cond_timedwait(&priv->cond, &priv->mutex.priv->mutex, &timeout); if(err && err!=ETIMEDOUT) throw system_error("pthread_cond_timedwait", err); return err==0; -#endif } } // namespace Msp diff --git a/source/core/unix/systemerror.cpp b/source/core/unix/systemerror.cpp new file mode 100644 index 0000000..a8eb5a6 --- /dev/null +++ b/source/core/unix/systemerror.cpp @@ -0,0 +1,17 @@ +#include +#include +#include "systemerror.h" + +using namespace std; + +namespace Msp { + +string system_error::get_message(int c) +{ + if(c==-1) + c = errno; + + return strerror(c); +} + +} // namespace Msp diff --git a/source/core/unix/thread.cpp b/source/core/unix/thread.cpp new file mode 100644 index 0000000..e7d7f58 --- /dev/null +++ b/source/core/unix/thread.cpp @@ -0,0 +1,25 @@ +#include +#include +#include "thread.h" +#include "thread_private.h" + +using namespace std; + +namespace Msp { + +void Thread::platform_join() +{ + pthread_join(priv_->handle, 0); +} + +void Thread::platform_kill() +{ + pthread_kill(priv_->handle, SIGKILL); +} + +void Thread::platform_launch() +{ + pthread_create(&priv_->handle, 0, &Private::main_wrapper, this); +} + +} // namespace Msp diff --git a/source/core/unix/thread_platform.h b/source/core/unix/thread_platform.h new file mode 100644 index 0000000..0477a6d --- /dev/null +++ b/source/core/unix/thread_platform.h @@ -0,0 +1,15 @@ +#ifndef MSP_CORE_THREAD_PLATFORM_H_ +#define MSP_CORE_THREAD_PLATFORM_H_ + +#include + +namespace Msp { + +typedef pthread_t ThreadHandle; +typedef void *ThreadReturn; + +#define THREAD_CALL + +} // namespace Msp + +#endif diff --git a/source/core/windows/application.cpp b/source/core/windows/application.cpp new file mode 100644 index 0000000..ed8702a --- /dev/null +++ b/source/core/windows/application.cpp @@ -0,0 +1,16 @@ +#include +#include +#include +#include "application.h" + +using namespace std; + +namespace Msp { + +void Application::display_exception(const exception &e) +{ + string msg = Debug::demangle(typeid(e).name())+":\n"+e.what(); + MessageBoxA(0, msg.c_str(), "Uncaught exception", MB_OK|MB_ICONERROR); +} + +} // namespace Msp diff --git a/source/core/main.cpp b/source/core/windows/main.cpp similarity index 89% rename from source/core/main.cpp rename to source/core/windows/main.cpp index fa28c1f..a0816a4 100644 --- a/source/core/main.cpp +++ b/source/core/windows/main.cpp @@ -1,11 +1,8 @@ -#ifdef WIN32 #include #include #include -#endif #include "application.h" -#ifdef WIN32 using namespace std; using namespace Msp; @@ -36,10 +33,3 @@ int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE /*hPrevInstance*/, LPSTR /*l 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/windows/mutex.cpp b/source/core/windows/mutex.cpp new file mode 100644 index 0000000..e51fda4 --- /dev/null +++ b/source/core/windows/mutex.cpp @@ -0,0 +1,34 @@ +#include +#include "mutex.h" +#include "mutex_private.h" + +namespace Msp { + +Mutex::Mutex(): + priv(new Private) +{ + InitializeCriticalSection(&priv->mutex); +} + +Mutex::~Mutex() +{ + DeleteCriticalSection(&priv->mutex); + delete priv; +} + +void Mutex::lock() +{ + EnterCriticalSection(&priv->mutex); +} + +bool Mutex::trylock() +{ + return TryEnterCriticalSection(&priv->mutex); +} + +void Mutex::unlock() +{ + LeaveCriticalSection(&priv->mutex); +} + +} // namespace Msp diff --git a/source/core/windows/mutex_platform.h b/source/core/windows/mutex_platform.h new file mode 100644 index 0000000..fae5e85 --- /dev/null +++ b/source/core/windows/mutex_platform.h @@ -0,0 +1,12 @@ +#ifndef MSP_CORE_MUTEX_PLATFORM_H_ +#define MSP_CORE_MUTEX_PLATFORM_H_ + +#include + +namespace Msp { + +typedef CRITICAL_SECTION PlatformMutex; + +} // namespace Msp + +#endif diff --git a/source/core/windows/semaphore.cpp b/source/core/windows/semaphore.cpp new file mode 100644 index 0000000..aeb1709 --- /dev/null +++ b/source/core/windows/semaphore.cpp @@ -0,0 +1,47 @@ +#include +#include +#include +#include "semaphore.h" + +namespace Msp { + +struct Semaphore::Private +{ + HANDLE handle; +}; + + +Semaphore::Semaphore(unsigned limit): + priv(new Private) +{ + priv->handle = CreateSemaphore(0, 0, limit, 0); +} + +Semaphore::~Semaphore() +{ + CloseHandle(priv->handle); + delete priv; +} + +void Semaphore::signal() +{ + if(!ReleaseSemaphore(priv->handle, 1, 0)) + throw system_error("ReleaseSemaphore"); +} + +void Semaphore::wait() +{ + DWORD ret = WaitForSingleObject(priv->handle, INFINITE); + if(ret==WAIT_FAILED) + throw system_error("WaitForSingleObject"); +} + +bool Semaphore::wait(const Time::TimeDelta &d) +{ + DWORD ret = WaitForSingleObject(priv->handle, (DWORD)(d/Time::usec)); + if(ret==WAIT_FAILED) + throw system_error("WaitForSingleObject"); + return ret==WAIT_OBJECT_0; +} + +} // namespace Msp diff --git a/source/core/windows/systemerror.cpp b/source/core/windows/systemerror.cpp new file mode 100644 index 0000000..98eb9ed --- /dev/null +++ b/source/core/windows/systemerror.cpp @@ -0,0 +1,20 @@ +#include +#include +#include "systemerror.h" + +using namespace std; + +namespace Msp { +string system_error::get_message(int c) +{ + if(c==-1) + c = GetLastError(); + + char msg[1024]; + if(FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM, 0, c, 0, msg, sizeof(msg), 0)) + return msg; + else + return lexical_cast(c, Fmt().hex()); +} + +} // namespace Msp diff --git a/source/core/windows/thread.cpp b/source/core/windows/thread.cpp new file mode 100644 index 0000000..410141c --- /dev/null +++ b/source/core/windows/thread.cpp @@ -0,0 +1,25 @@ +#include +#include "thread.h" +#include "thread_private.h" + +using namespace std; + +namespace Msp { + +void Thread::platform_join() +{ + WaitForSingleObject(priv_->handle, INFINITE); +} + +void Thread::platform_kill() +{ + TerminateThread(priv_->handle, 0); +} + +void Thread::platform_launch() +{ + DWORD dummy; // Win9x needs the lpTthreadId parameter + priv_->handle = CreateThread(0, 0, &Private::main_wrapper, this, 0, &dummy); +} + +} // namespace Msp diff --git a/source/core/windows/thread_platform.h b/source/core/windows/thread_platform.h new file mode 100644 index 0000000..50b1a5e --- /dev/null +++ b/source/core/windows/thread_platform.h @@ -0,0 +1,15 @@ +#ifndef MSP_CORE_THREAD_PLATFORM_H_ +#define MSP_CORE_THREAD_PLATFORM_H_ + +#include + +namespace Msp { + +typedef HANDLE ThreadHandle; +typedef DWORD ThreadReturn; + +#define THREAD_CALL WINAPI + +} // namespace Msp + +#endif diff --git a/source/fs/dir.cpp b/source/fs/dir.cpp index f7f34f6..57fd936 100644 --- a/source/fs/dir.cpp +++ b/source/fs/dir.cpp @@ -1,12 +1,6 @@ #include -#include -#include -#ifdef WIN32 -#include -#else #include -#include -#endif +#include #include #include #include @@ -62,18 +56,6 @@ not_a_directory::not_a_directory(const Path &p): { } -void mkdir(const Path &path, int mode) -{ -#ifdef WIN32 - (void)mode; - if(!CreateDirectory(path.str().c_str(), NULL)) - throw system_error("CreateDirectory"); -#else - if(::mkdir(path.str().c_str(), mode)==-1) - throw system_error("mkdir"); -#endif -} - void mkpath(const Path &path, int mode) { Path p; @@ -95,17 +77,6 @@ void mkpath(const Path &path, int mode) } } -void rmdir(const Path &path) -{ -#ifdef WIN32 - if(!RemoveDirectory(path.str().c_str())) - throw system_error("RemoveDirectory"); -#else - if(::rmdir(path.str().c_str())==-1) - throw system_error("rmdir"); -#endif -} - void rmpath(const Path &path) { list files = list_files(path); @@ -154,32 +125,6 @@ Path getcwd() return ::getcwd(buf, sizeof(buf)); } -Path get_home_dir() -{ -#ifdef WIN32 - char home[MAX_PATH]; - if(SHGetFolderPath(0, CSIDL_PERSONAL, 0, 0, home)==S_OK) - return home; -#else - const char *home = getenv("HOME"); - if(home) - return home; -#endif - return "."; -} - -Path get_user_data_dir(const string &appname) -{ -#ifdef WIN32 - char datadir[MAX_PATH]; - if(SHGetFolderPath(0, CSIDL_LOCAL_APPDATA, 0, 0, datadir)==S_OK) - return Path(datadir)/appname; - return "."; -#else - return get_home_dir()/("."+appname); -#endif -} - Path get_sys_conf_dir(const string &argv0) { Path dir = get_bin_dir(argv0); diff --git a/source/fs/stat.cpp b/source/fs/stat.cpp index 85fead5..f4566ae 100644 --- a/source/fs/stat.cpp +++ b/source/fs/stat.cpp @@ -1,163 +1,17 @@ -#ifdef WIN32 -#include -#include -#else -#define _FILE_OFFSET_BITS 64 -#include -#include -#include -#include -#include -#endif -#include -#include -#include #include "path.h" #include "stat.h" +#include "stat_private.h" using namespace std; -namespace { - -#ifdef WIN32 -PSID copy_sid(PSID sid) -{ - if(!sid || !IsValidSid(sid)) - return 0; - DWORD len = GetLengthSid(sid); - PSID copy = reinterpret_cast(HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, len)); - if(!CopySid(len, copy, sid)) - { - DWORD err = GetLastError(); - HeapFree(GetProcessHeap(), 0, copy); - throw Msp::system_error("CopySid", err); - } - return copy; -} - -string get_account_name(PSID sid) -{ - char name[1024]; - DWORD nlen = sizeof(name); - char domain[1024]; - DWORD dlen = sizeof(domain); - SID_NAME_USE use; - if(!LookupAccountSid(0, sid, name, &nlen, domain, &dlen, &use)) - throw Msp::system_error("LookupAccountSid"); - return Msp::format("%s/%s", name, domain); -} -#endif - -} - - namespace Msp { namespace FS { -struct Stat::Private -{ -#ifdef WIN32 - PSID owner_id; - PSID group_id; -#else - uid_t owner_id; - gid_t group_id; -#endif - - Private(); - Private(const Private &); - ~Private(); - -#ifndef WIN32 - /* This is here because it needs access to private members of Stat, but we - can't expose the system stat struct in the public header */ - static Stat from_struct_stat(const struct stat &); -#endif - - void fill_owner_info(Stat::OwnerInfo &); -}; - Stat::Private::Private(): owner_id(0), group_id(0) { } -Stat::Private::Private(const Private &other): -#ifdef WIN32 - owner_id(copy_sid(other.owner_id)), - group_id(copy_sid(other.group_id)) -#else - owner_id(other.owner_id), - group_id(other.group_id) -#endif -{ } - -Stat::Private::~Private() -{ -#ifdef WIN32 - if(owner_id) - HeapFree(GetProcessHeap(), 0, owner_id); - if(group_id) - HeapFree(GetProcessHeap(), 0, group_id); -#endif -} - -#ifndef WIN32 -Stat Stat::Private::from_struct_stat(const struct stat &st) -{ - Stat result; - result.exists = true; - if(S_ISREG(st.st_mode)) - result.type = REGULAR; - else if(S_ISDIR(st.st_mode)) - result.type = DIRECTORY; - else if(S_ISLNK(st.st_mode)) - result.type = SYMLINK; - else - result.type = UNKNOWN; - result.size = st.st_size; - result.alloc_size = st.st_blocks*512; - result.mtime = Time::TimeStamp::from_unixtime(st.st_mtime); - - result.priv = new Private; - result.priv->owner_id = st.st_uid; - result.priv->group_id = st.st_gid; - - return result; -} -#endif - -void Stat::Private::fill_owner_info(Stat::OwnerInfo &result) -{ -#ifdef WIN32 - if(owner_id) - result.owner = get_account_name(owner_id); - else - result.owner = "None"; - - if(group_id) - result.group = get_account_name(group_id); - else - result.group = "None"; -#else - char buf[1024]; - - struct passwd pw; - struct passwd *owner; - if(!getpwuid_r(owner_id, &pw, buf, sizeof(buf), &owner) && owner) - result.owner = owner->pw_name; - else - result.owner = format("%d", owner_id); - - struct group gr; - struct group *group; - if(!getgrgid_r(group_id, &gr, buf, sizeof(buf), &group) && group) - result.group = group->gr_name; - else - result.group = format("%d", group_id); -#endif -} - Stat::Stat(): exists(false), @@ -196,72 +50,6 @@ Stat::~Stat() delete priv; } -Stat Stat::stat(const Path &path) -{ -#ifdef WIN32 - HANDLE handle; - handle = CreateFile(path.str().c_str(), READ_CONTROL, FILE_SHARE_READ, 0, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL|FILE_FLAG_BACKUP_SEMANTICS, 0); - if(handle==INVALID_HANDLE_VALUE) - { - DWORD err = GetLastError(); - if(err==ERROR_FILE_NOT_FOUND) - return Stat(); - else - throw system_error("CreateFile", err); - } - - BY_HANDLE_FILE_INFORMATION info; - if(!GetFileInformationByHandle(handle, &info)) - { - CloseHandle(handle); - throw system_error("GetFileInformationByHandle"); - } - - Stat result; - if(info.dwFileAttributes&FILE_ATTRIBUTE_DIRECTORY) - result.type = DIRECTORY; - else - result.type = REGULAR; - - result.size = FileSize(info.nFileSizeHigh)<<32 | info.nFileSizeLow; - result.alloc_size = (result.size+511)&~511; - result.mtime = Time::TimeStamp(Time::filetime_to_rawtime(info.ftLastWriteTime)); - - PSECURITY_DESCRIPTOR sec_desc; - PSID owner = 0; - PSID group = 0; - const SECURITY_INFORMATION sec_info = OWNER_SECURITY_INFORMATION|GROUP_SECURITY_INFORMATION; - DWORD err = GetSecurityInfo(handle, SE_FILE_OBJECT, sec_info, &owner, &group, 0, 0, &sec_desc); - if(err) - { - CloseHandle(handle); - throw system_error("GetSecurityInfo", err); - } - - result.priv = new Private; - result.priv->owner_id = copy_sid(owner); - result.priv->group_id = copy_sid(group); - - LocalFree(sec_desc); - - CloseHandle(handle); - - return result; -#else - struct stat st; - int ret = ::stat(path.str().c_str(), &st); - if(ret==-1) - { - if(errno==ENOENT) - return Stat(); - else - throw system_error("stat"); - } - - return Private::from_struct_stat(st); -#endif -} - const std::string &Stat::get_owner() const { if(priv && owner_info.owner.empty()) @@ -276,33 +64,5 @@ const std::string &Stat::get_group() const return owner_info.group; } -Stat Stat::lstat(const Path &path) -{ -#ifdef WIN32 - return stat(path); -#else - struct stat st; - int ret = ::lstat(path.str().c_str(), &st); - if(ret==-1) - { - if(errno==ENOENT) - return Stat(); - else - throw system_error("lstat"); - } - - return Private::from_struct_stat(st); -#endif -} - -bool exists(const Path &path) -{ -#ifdef WIN32 - return GetFileAttributes(path.str().c_str())!=INVALID_FILE_ATTRIBUTES; -#else - return access(path.str().c_str(), F_OK)==0; -#endif -} - } // namespace FS } // namespace Msp diff --git a/source/fs/stat_private.h b/source/fs/stat_private.h new file mode 100644 index 0000000..c80d151 --- /dev/null +++ b/source/fs/stat_private.h @@ -0,0 +1,30 @@ +#ifndef MSP_FS_STAT_PRIVATE_H_ +#define MSP_FS_STAT_PRIVATE_H_ + +#include "stat_platform.h" + +namespace Msp { +namespace FS { + +struct Stat::Private +{ + UserID owner_id; + GroupID group_id; + + Private(); + Private(const Private &); + ~Private(); + +#ifndef WIN32 + /* This is here because it needs access to private members of Stat, but we + can't expose the system stat struct in the public header */ + static Stat from_struct_stat(const struct stat &); +#endif + + void fill_owner_info(Stat::OwnerInfo &); +}; + +} // namespace FS +} // namespace Msp + +#endif diff --git a/source/fs/unix/dir.cpp b/source/fs/unix/dir.cpp new file mode 100644 index 0000000..93aaeab --- /dev/null +++ b/source/fs/unix/dir.cpp @@ -0,0 +1,38 @@ +#include +#include +#include +#include +#include "dir.h" + +using namespace std; + +namespace Msp { +namespace FS { + +void mkdir(const Path &path, int mode) +{ + if(::mkdir(path.str().c_str(), mode)==-1) + throw system_error("mkdir"); +} + +void rmdir(const Path &path) +{ + if(::rmdir(path.str().c_str())==-1) + throw system_error("rmdir"); +} + +Path get_home_dir() +{ + const char *home = getenv("HOME"); + if(home) + return home; + return "."; +} + +Path get_user_data_dir(const string &appname) +{ + return get_home_dir()/("."+appname); +} + +} // namespace FS +} // namespace Msp diff --git a/source/fs/unix/stat.cpp b/source/fs/unix/stat.cpp new file mode 100644 index 0000000..1404fed --- /dev/null +++ b/source/fs/unix/stat.cpp @@ -0,0 +1,102 @@ +#define _FILE_OFFSET_BITS 64 +#include +#include +#include +#include +#include +#include +#include +#include "stat.h" +#include "stat_private.h" + +namespace Msp { +namespace FS { + +Stat::Private::Private(const Private &other): + owner_id(other.owner_id), + group_id(other.group_id) +{ } + +Stat::Private::~Private() +{ } + +Stat Stat::Private::from_struct_stat(const struct stat &st) +{ + Stat result; + result.exists = true; + if(S_ISREG(st.st_mode)) + result.type = REGULAR; + else if(S_ISDIR(st.st_mode)) + result.type = DIRECTORY; + else if(S_ISLNK(st.st_mode)) + result.type = SYMLINK; + else + result.type = UNKNOWN; + result.size = st.st_size; + result.alloc_size = st.st_blocks*512; + result.mtime = Time::TimeStamp::from_unixtime(st.st_mtime); + + result.priv = new Private; + result.priv->owner_id = st.st_uid; + result.priv->group_id = st.st_gid; + + return result; +} + +void Stat::Private::fill_owner_info(Stat::OwnerInfo &result) +{ + char buf[1024]; + + struct passwd pw; + struct passwd *owner; + if(!getpwuid_r(owner_id, &pw, buf, sizeof(buf), &owner) && owner) + result.owner = owner->pw_name; + else + result.owner = format("%d", owner_id); + + struct group gr; + struct group *group; + if(!getgrgid_r(group_id, &gr, buf, sizeof(buf), &group) && group) + result.group = group->gr_name; + else + result.group = format("%d", group_id); +} + + +Stat Stat::stat(const Path &path) +{ + struct stat st; + int ret = ::stat(path.str().c_str(), &st); + if(ret==-1) + { + if(errno==ENOENT) + return Stat(); + else + throw system_error("stat"); + } + + return Private::from_struct_stat(st); +} + +Stat Stat::lstat(const Path &path) +{ + struct stat st; + int ret = ::lstat(path.str().c_str(), &st); + if(ret==-1) + { + if(errno==ENOENT) + return Stat(); + else + throw system_error("lstat"); + } + + return Private::from_struct_stat(st); +} + +bool exists(const Path &path) +{ + return access(path.str().c_str(), F_OK)==0; +} + +} // namespace FS +} // namespace Msp diff --git a/source/fs/unix/stat_platform.h b/source/fs/unix/stat_platform.h new file mode 100644 index 0000000..cc3f095 --- /dev/null +++ b/source/fs/unix/stat_platform.h @@ -0,0 +1,15 @@ +#ifndef MSP_FS_STAT_PLATFORM_H_ +#define MSP_FS_STAT_PLATFORM_H_ + +#include + +namespace Msp { +namespace FS { + +typedef uid_t UserID; +typedef gid_t GroupID; + +} // namespace FS +} // namespace Msp + +#endif diff --git a/source/fs/unix/utils.cpp b/source/fs/unix/utils.cpp new file mode 100644 index 0000000..c832343 --- /dev/null +++ b/source/fs/unix/utils.cpp @@ -0,0 +1,65 @@ +#include +#include +#include +#include "dir.h" +#include "stat.h" +#include "utils.h" + +using namespace std; + +namespace Msp { +namespace FS { + +Path readlink(const Path &link) +{ + char buf[4096]; + int len = ::readlink(link.c_str(), buf, sizeof(buf)); + if(len==-1) + throw system_error("readlink"); + return string(buf, len); +} + +Path realpath(const Path &path) +{ + list queue(path.begin(), path.end()); + if(!path.is_absolute()) + { + Path cwd = getcwd(); + queue.insert(queue.begin(), cwd.begin(), cwd.end()); + } + + Path real; + unsigned n_links = 0; + while(!queue.empty()) + { + Path next = real/queue.front(); + queue.pop_front(); + + if(is_link(next)) + { + if(++n_links>64) + throw runtime_error("too many symbolic links"); + Path link = readlink(next); + queue.insert(queue.begin(), link.begin(), link.end()); + } + else + real = next; + } + + return real; +} + +void rename(const Path &from, const Path &to) +{ + if(::rename(from.c_str(), to.c_str())==-1) + throw system_error("rename"); +} + +void unlink(const Path &path) +{ + if(::unlink(path.c_str())==-1) + throw system_error("unlink"); +} + +} // namespace FS +} // namespace Msp diff --git a/source/fs/utils.cpp b/source/fs/utils.cpp index 9a98025..2bfd1bf 100644 --- a/source/fs/utils.cpp +++ b/source/fs/utils.cpp @@ -1,14 +1,5 @@ -#include -#ifdef WIN32 -#include -#else -#include -#endif -#include #include #include "dir.h" -#include "path.h" -#include "stat.h" #include "utils.h" using namespace std; @@ -78,79 +69,6 @@ Path fix_case(const Path &path) return result; } -Path readlink(const Path &link) -{ -#ifdef WIN32 - (void)link; - throw logic_error("no symbolic links on win32"); -#else - char buf[4096]; - int len = ::readlink(link.str().c_str(), buf, sizeof(buf)); - if(len==-1) - throw system_error("readlink"); - return string(buf, len); -#endif -} - -Path realpath(const Path &path) -{ -#ifdef WIN32 - if(path.is_absolute()) - return path; - else - return getcwd()/path; -#else - list queue(path.begin(), path.end()); - if(!path.is_absolute()) - { - Path cwd = getcwd(); - queue.insert(queue.begin(), cwd.begin(), cwd.end()); - } - - Path real; - unsigned n_links = 0; - while(!queue.empty()) - { - Path next = real/queue.front(); - queue.pop_front(); - - if(is_link(next)) - { - if(++n_links>64) - throw runtime_error("too many symbolic links"); - Path link = readlink(next); - queue.insert(queue.begin(), link.begin(), link.end()); - } - else - real = next; - } - - return real; -#endif -} - -void rename(const Path &from, const Path &to) -{ -#ifdef WIN32 - if(!MoveFileEx(from.c_str(), to.c_str(), MOVEFILE_REPLACE_EXISTING)) - throw system_error("MoveFileEx"); -#else - if(::rename(from.str().c_str(), to.str().c_str())==-1) - throw system_error("rename"); -#endif -} - -void unlink(const Path &path) -{ -#ifdef WIN32 - if(!DeleteFile(path.c_str())) - throw system_error("DeleteFile"); -#else - if(::unlink(path.str().c_str())==-1) - throw system_error("unlink"); -#endif -} - Path relative(const Path &path, const Path &base) { Path::Iterator i = path.begin(); diff --git a/source/fs/windows/dir.cpp b/source/fs/windows/dir.cpp new file mode 100644 index 0000000..6adddec --- /dev/null +++ b/source/fs/windows/dir.cpp @@ -0,0 +1,39 @@ +#include +#include +#include "dir.h" + +using namespace std; + +namespace Msp { +namespace FS { + +void mkdir(const Path &path, int) +{ + if(!CreateDirectory(path.str().c_str(), NULL)) + throw system_error("CreateDirectory"); +} + +void rmdir(const Path &path) +{ + if(!RemoveDirectory(path.str().c_str())) + throw system_error("RemoveDirectory"); +} + +Path get_home_dir() +{ + char home[MAX_PATH]; + if(SHGetFolderPath(0, CSIDL_PERSONAL, 0, 0, home)==S_OK) + return home; + return "."; +} + +Path get_user_data_dir(const string &appname) +{ + char datadir[MAX_PATH]; + if(SHGetFolderPath(0, CSIDL_LOCAL_APPDATA, 0, 0, datadir)==S_OK) + return Path(datadir)/appname; + return "."; +} + +} // namespace FS +} // namespace Msp diff --git a/source/fs/windows/stat.cpp b/source/fs/windows/stat.cpp new file mode 100644 index 0000000..f0cbdb6 --- /dev/null +++ b/source/fs/windows/stat.cpp @@ -0,0 +1,136 @@ +#include +#include +#include +#include +#include +#include "stat.h" +#include "stat_private.h" + +using namespace std; + +namespace { + +PSID copy_sid(PSID sid) +{ + if(!sid || !IsValidSid(sid)) + return 0; + DWORD len = GetLengthSid(sid); + PSID copy = reinterpret_cast(HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, len)); + if(!CopySid(len, copy, sid)) + { + DWORD err = GetLastError(); + HeapFree(GetProcessHeap(), 0, copy); + throw Msp::system_error("CopySid", err); + } + return copy; +} + +string get_account_name(PSID sid) +{ + char name[1024]; + DWORD nlen = sizeof(name); + char domain[1024]; + DWORD dlen = sizeof(domain); + SID_NAME_USE use; + if(!LookupAccountSid(0, sid, name, &nlen, domain, &dlen, &use)) + throw Msp::system_error("LookupAccountSid"); + return Msp::format("%s/%s", name, domain); +} + +} + + +namespace Msp { +namespace FS { + +Stat::Private::Private(const Private &other): + owner_id(copy_sid(other.owner_id)), + group_id(copy_sid(other.group_id)) +{ } + +Stat::Private::~Private() +{ + if(owner_id) + HeapFree(GetProcessHeap(), 0, owner_id); + if(group_id) + HeapFree(GetProcessHeap(), 0, group_id); +} + +void Stat::Private::fill_owner_info(Stat::OwnerInfo &result) +{ + if(owner_id) + result.owner = get_account_name(owner_id); + else + result.owner = "None"; + + if(group_id) + result.group = get_account_name(group_id); + else + result.group = "None"; +} + + +Stat Stat::stat(const Path &path) +{ + HANDLE handle; + handle = CreateFile(path.str().c_str(), READ_CONTROL, FILE_SHARE_READ, 0, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL|FILE_FLAG_BACKUP_SEMANTICS, 0); + if(handle==INVALID_HANDLE_VALUE) + { + DWORD err = GetLastError(); + if(err==ERROR_FILE_NOT_FOUND) + return Stat(); + else + throw system_error("CreateFile", err); + } + + BY_HANDLE_FILE_INFORMATION info; + if(!GetFileInformationByHandle(handle, &info)) + { + CloseHandle(handle); + throw system_error("GetFileInformationByHandle"); + } + + Stat result; + if(info.dwFileAttributes&FILE_ATTRIBUTE_DIRECTORY) + result.type = DIRECTORY; + else + result.type = REGULAR; + + result.size = FileSize(info.nFileSizeHigh)<<32 | info.nFileSizeLow; + result.alloc_size = (result.size+511)&~511; + result.mtime = Time::TimeStamp(Time::filetime_to_rawtime(info.ftLastWriteTime)); + + PSECURITY_DESCRIPTOR sec_desc; + PSID owner = 0; + PSID group = 0; + const SECURITY_INFORMATION sec_info = OWNER_SECURITY_INFORMATION|GROUP_SECURITY_INFORMATION; + DWORD err = GetSecurityInfo(handle, SE_FILE_OBJECT, sec_info, &owner, &group, 0, 0, &sec_desc); + if(err) + { + CloseHandle(handle); + throw system_error("GetSecurityInfo", err); + } + + result.priv = new Private; + result.priv->owner_id = copy_sid(owner); + result.priv->group_id = copy_sid(group); + + LocalFree(sec_desc); + + CloseHandle(handle); + + return result; +} + +Stat Stat::lstat(const Path &path) +{ + return stat(path); +} + +bool exists(const Path &path) +{ + return GetFileAttributes(path.str().c_str())!=INVALID_FILE_ATTRIBUTES; +} + +} // namespace FS +} // namespace Msp diff --git a/source/fs/windows/stat_platform.h b/source/fs/windows/stat_platform.h new file mode 100644 index 0000000..4e8cfbc --- /dev/null +++ b/source/fs/windows/stat_platform.h @@ -0,0 +1,15 @@ +#ifndef MSP_FS_STAT_PLATFORM_H_ +#define MSP_FS_STAT_PLATFORM_H_ + +#include + +namespace Msp { +namespace FS { + +typedef PSID UserID; +typedef PSID GroupID; + +} // namespace FS +} // namespace Msp + +#endif diff --git a/source/fs/windows/utils.cpp b/source/fs/windows/utils.cpp new file mode 100644 index 0000000..ca9e7aa --- /dev/null +++ b/source/fs/windows/utils.cpp @@ -0,0 +1,38 @@ +#include +#include +#include "dir.h" +#include "utils.h" + +using namespace std; + +namespace Msp { +namespace FS { + +Path readlink(const Path &link) +{ + (void)link; + throw logic_error("no symbolic links on win32"); +} + +Path realpath(const Path &path) +{ + if(path.is_absolute()) + return path; + else + return getcwd()/path; +} + +void rename(const Path &from, const Path &to) +{ + if(!MoveFileEx(from.c_str(), to.c_str(), MOVEFILE_REPLACE_EXISTING)) + throw system_error("MoveFileEx"); +} + +void unlink(const Path &path) +{ + if(!DeleteFile(path.c_str())) + throw system_error("DeleteFile"); +} + +} // namespace FS +} // namespace Msp diff --git a/source/io/console.cpp b/source/io/console.cpp index a03ad20..d50d72d 100644 --- a/source/io/console.cpp +++ b/source/io/console.cpp @@ -1,36 +1,7 @@ -#ifndef WIN32 -#include -#include -#include -#include -#include -#endif -#include #include "console.h" -#include "handle_private.h" using namespace std; -namespace { - -#ifdef WIN32 -DWORD stream_to_sys(Msp::IO::Console::Stream stream) -{ - switch(stream) - { - case Msp::IO::Console::CIN: return STD_INPUT_HANDLE; - case Msp::IO::Console::COUT: return STD_OUTPUT_HANDLE; - case Msp::IO::Console::CERR: return STD_ERROR_HANDLE; - default: throw invalid_argument("stream_to_sys"); - } -} - -#else -termios orig_attr; -#endif - -} // namespace - namespace Msp { namespace IO { @@ -39,114 +10,15 @@ Console::Console(Stream s): { mode = (stream==CIN ? M_READ : M_WRITE); -#ifdef WIN32 - *handle = GetStdHandle(stream_to_sys(stream)); -#else - *handle = stream; - - if(stream==CIN) - tcgetattr(*handle, &orig_attr); -#endif + platform_init(); if(stream==CIN) set_events(P_INPUT); } -Console::~Console() -{ -#ifndef WIN32 - if(stream==CIN) - tcsetattr(*handle, TCSADRAIN, &orig_attr); -#endif -} - void Console::set_block(bool b) { -#ifdef WIN32 - // XXX Dunno how to do this in win32 - (void)b; -#else - int flags = fcntl(*handle, F_GETFL); - flags = (flags&~O_NONBLOCK) | (b?0:O_NONBLOCK); - fcntl(*handle, F_SETFL, flags); -#endif -} - -void Console::set_local_echo(bool e) -{ - check_access(M_READ); - -#ifdef WIN32 - DWORD m; - GetConsoleMode(*handle, &m); - SetConsoleMode(*handle, (m&~ENABLE_ECHO_INPUT) | (e?ENABLE_ECHO_INPUT:0)); -#else - termios t; - tcgetattr(*handle, &t); - t.c_lflag = (t.c_lflag&~ECHO) | (e?ECHO:0); - tcsetattr(*handle, TCSADRAIN, &t); -#endif -} - -void Console::set_line_buffer(bool l) -{ - check_access(M_READ); - -#ifdef WIN32 - DWORD m; - if(!GetConsoleMode(*handle, &m)) - throw system_error("GetConsoleMode"); - if(!SetConsoleMode(*handle, (m&~ENABLE_LINE_INPUT) | (l?ENABLE_LINE_INPUT:0))) - throw system_error("SetConsoleMode"); -#else - termios t; - if(tcgetattr(*handle, &t)==-1) - throw system_error("tcgetattr"); - t.c_lflag = (t.c_lflag&~ICANON) | (l?ICANON:0); - // man termios warns that VMIN and VTIME may share indices with VEOF and VEOL - if(l) - { - t.c_cc[VEOF] = orig_attr.c_cc[VEOF]; - t.c_cc[VEOL] = orig_attr.c_cc[VEOL]; - } - else - { - t.c_cc[VMIN] = 1; - t.c_cc[VTIME] = 0; - } - if(tcsetattr(*handle, TCSADRAIN, &t)==-1) - throw system_error("tcsetattr"); -#endif -} - -void Console::get_size(unsigned &rows, unsigned &cols) -{ - check_access(M_WRITE); - -#ifdef WIN32 - CONSOLE_SCREEN_BUFFER_INFO sbi; - if(!GetConsoleScreenBufferInfo(*handle, &sbi)) - throw system_error("GetConsoleScreenBufferInfo"); - // Right/bottom coords are inclusive - rows = sbi.srWindow.Bottom+1-sbi.srWindow.Top; - cols = sbi.srWindow.Right+1-sbi.srWindow.Left; -#else - struct winsize wsz; - if(ioctl(*handle, TIOCGWINSZ, &wsz)==-1) - throw system_error("ioctl TIOCGWINSZ"); - rows = wsz.ws_row; - cols = wsz.ws_col; -#endif -} - -void Console::redirect(Base &other) -{ - Handle other_handle = other.get_handle(mode&M_RDWR); -#ifdef WIN32 - SetStdHandle(stream_to_sys(stream), *other_handle); -#else - dup2(*other_handle, *handle); -#endif + sys_set_blocking(handle, b); } unsigned Console::do_write(const char *buf, unsigned len) diff --git a/source/io/console.h b/source/io/console.h index 7b7887b..5cb5f17 100644 --- a/source/io/console.h +++ b/source/io/console.h @@ -27,6 +27,7 @@ private: Handle handle; Console(Stream); + void platform_init(); public: ~Console(); diff --git a/source/io/file.cpp b/source/io/file.cpp index 805a9e8..9069432 100644 --- a/source/io/file.cpp +++ b/source/io/file.cpp @@ -1,10 +1,3 @@ -#ifndef WIN32 -#include -#include -#include -#endif -#include -#include #include "file.h" #include "handle_private.h" @@ -24,77 +17,7 @@ File::File(const string &fn, Mode m, CreateMode cm) mode = m; -#ifdef WIN32 - int flags = 0; - int share_flags = 0; - int create_flags = OPEN_EXISTING; - - if(mode&M_READ) - flags |= GENERIC_READ; - - if(mode&M_WRITE) - { - flags |= GENERIC_WRITE; - - switch(static_cast(cm)) - { - case C_NONE: create_flags = OPEN_EXISTING; break; - case C_CREATE: create_flags = OPEN_ALWAYS; break; - case C_TRUNCATE: create_flags = TRUNCATE_EXISTING; break; - case C_OVERWRITE: create_flags = CREATE_ALWAYS; break; - case C_NEW: create_flags = CREATE_NEW; break; - } - } - else - share_flags = FILE_SHARE_READ; - - *handle = CreateFile(fn.c_str(), flags, share_flags, 0, create_flags, FILE_ATTRIBUTE_NORMAL, 0); - if(!handle) - { - int err = GetLastError(); - if(err==ERROR_FILE_NOT_FOUND) - throw file_not_found(fn); - else if(err==ERROR_FILE_EXISTS) - throw file_already_exists(fn); - else - throw system_error(format("CreateFile(%s)", fn), err); - } -#else - int flags = 0; - switch(mode&M_RDWR) - { - case M_READ: flags |= O_RDONLY; break; - case M_WRITE: flags |= O_WRONLY; break; - case M_RDWR: flags |= O_RDWR; break; - default:; - } - - if(mode&M_WRITE) - { - if(cm&C_CREATE) - flags |= O_CREAT; - if(cm&C_TRUNCATE) - flags |= O_TRUNC; - if(cm&C_EXCLUSIVE) - flags |= O_EXCL; - } - if(mode&M_APPEND) - flags |= O_APPEND; - if(mode&M_NONBLOCK) - flags |= O_NONBLOCK; - - *handle = ::open(fn.c_str(), flags, 0666); - if(!handle) - { - int err = errno; - if(err==ENOENT) - throw file_not_found(fn); - else if(err==EEXIST) - throw file_already_exists(fn); - else - throw system_error(format("open(%s)", fn), err); - } -#endif + platform_init(fn, cm); } File::~File() @@ -105,13 +28,8 @@ File::~File() void File::set_block(bool b) { - mode = (mode&~M_NONBLOCK); - if(b) - mode = (mode|M_NONBLOCK); -#ifndef WIN32 - int flags = fcntl(*handle, F_GETFD); - fcntl(*handle, F_SETFL, (flags&O_NONBLOCK)|(b?0:O_NONBLOCK)); -#endif + mode = b?(mode&~M_NONBLOCK):(mode|M_NONBLOCK); + sys_set_blocking(handle, b); } unsigned File::do_write(const char *buf, unsigned size) @@ -143,15 +61,6 @@ unsigned File::do_read(char *buf, unsigned size) return ret; } -void File::sync() -{ -#ifndef WIN32 - signal_flush_required.emit(); - - fsync(*handle); -#endif -} - SeekOffset File::seek(SeekOffset off, SeekType type) { signal_flush_required.emit(); diff --git a/source/io/file.h b/source/io/file.h index 90a1041..d106561 100644 --- a/source/io/file.h +++ b/source/io/file.h @@ -52,6 +52,9 @@ public: write access is requested and the file does exist, it is created. Otherwise a missing file is an error. */ File(const std::string &, Mode = M_READ, CreateMode = C_OVERWRITE); +private: + void platform_init(const std::string &, CreateMode); +public: virtual ~File(); void set_block(bool); diff --git a/source/io/handle.cpp b/source/io/handle.cpp index 0e9b82a..c20f067 100644 --- a/source/io/handle.cpp +++ b/source/io/handle.cpp @@ -1,6 +1,3 @@ -#include -#include -#include #include "handle.h" #include "handle_private.h" @@ -28,79 +25,16 @@ Handle::~Handle() delete priv; } -Handle::operator const void *() const -{ -#ifdef WIN32 - return priv->handle!=INVALID_HANDLE_VALUE ? this : 0; -#else - return priv->handle!=-1 ? this : 0; -#endif -} - Handle::Private::Private(): -#ifdef WIN32 handle(INVALID_HANDLE_VALUE) -#else - handle(-1) -#endif { } -Handle::Private &Handle::Private::operator=(H h) +Handle::Private &Handle::Private::operator=(PlatformHandle h) { handle = h; return *this; } - -unsigned sys_read(Handle &handle, char *buf, unsigned size) -{ -#ifdef WIN32 - DWORD ret; - if(ReadFile(*handle, buf, size, &ret, 0)==0) - throw system_error("ReadFile"); -#else - int ret = read(*handle, buf, size); - if(ret==-1) - { - if(errno==EAGAIN) - return 0; - else - throw system_error("read"); - } -#endif - - return ret; -} - -unsigned sys_write(Handle &handle, const char *buf, unsigned size) -{ -#ifdef WIN32 - DWORD ret; - if(WriteFile(*handle, buf, size, &ret, 0)==0) - throw system_error("WriteFile"); -#else - int ret = write(*handle, buf, size); - if(ret==-1) - { - if(errno==EAGAIN) - return 0; - else - throw system_error("write"); - } -#endif - - return ret; -} - -void sys_close(Handle &handle) -{ -#ifdef WIN32 - CloseHandle(*handle); -#else - close(*handle); -#endif -} - } // namespace IO } // namespace Msp diff --git a/source/io/handle.h b/source/io/handle.h index 24b9ee6..8a9db50 100644 --- a/source/io/handle.h +++ b/source/io/handle.h @@ -28,6 +28,7 @@ public: }; +void sys_set_blocking(Handle &, bool); unsigned sys_read(Handle &, char *, unsigned); unsigned sys_write(Handle &, const char *, unsigned); void sys_close(Handle &); diff --git a/source/io/handle_private.h b/source/io/handle_private.h index d73a2b8..4fa690a 100644 --- a/source/io/handle_private.h +++ b/source/io/handle_private.h @@ -1,28 +1,20 @@ #ifndef MSP_IO_HANDLE_PRIVATE_H_ #define MSP_IO_HANDLE_PRIVATE_H_ -#ifdef WIN32 -#include -#endif #include "handle.h" +#include "handle_platform.h" namespace Msp { namespace IO { struct Handle::Private { -#ifdef WIN32 - typedef HANDLE H; -#else - typedef int H; -#endif - - H handle; + PlatformHandle handle; Private(); - Private &operator=(H); - operator H() const { return handle; } + Private &operator=(PlatformHandle); + operator PlatformHandle() const { return handle; } }; } // namespace IO diff --git a/source/io/pipe.cpp b/source/io/pipe.cpp index 0f20698..831076f 100644 --- a/source/io/pipe.cpp +++ b/source/io/pipe.cpp @@ -1,11 +1,3 @@ -#ifndef WIN32 -#include -#include -#include -#endif -#include -#include -#include "handle_private.h" #include "pipe.h" using namespace std; @@ -18,27 +10,7 @@ Pipe::Pipe(): { mode = M_RDWR; -#ifdef WIN32 - string name = format("\\\\.\\pipe\\%u.%p", GetCurrentProcessId(), this); - *read_handle = CreateNamedPipe(name.c_str(), PIPE_ACCESS_INBOUND|FILE_FLAG_OVERLAPPED, PIPE_TYPE_BYTE, 1, 1024, 1024, 0, 0); - if(!read_handle) - throw system_error("CreateNamedPipe"); - - *write_handle = CreateFile(name.c_str(), GENERIC_WRITE, 0, 0, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, 0); - if(!write_handle) - { - unsigned err = GetLastError(); - CloseHandle(*read_handle); - throw system_error(format("CreateFile(%s)", name), err); - } -#else - int pipe_fd[2]; - if(pipe(pipe_fd)==-1) - throw system_error("pipe"); - - *read_handle = pipe_fd[0]; - *write_handle = pipe_fd[1]; -#endif + platform_init(); set_events(P_INPUT); } @@ -58,12 +30,8 @@ void Pipe::set_block(bool b) if(b) mode = (mode|M_NONBLOCK); -#ifndef WIN32 - int flags = fcntl(*read_handle, F_GETFD); - fcntl(*read_handle, F_SETFL, (flags&O_NONBLOCK)|(b?0:O_NONBLOCK)); - flags = fcntl(*write_handle, F_GETFD); - fcntl(*write_handle, F_SETFL, (flags&O_NONBLOCK)|(b?0:O_NONBLOCK)); -#endif + sys_set_blocking(read_handle, b); + sys_set_blocking(write_handle, b); } unsigned Pipe::do_write(const char *buf, unsigned size) diff --git a/source/io/pipe.h b/source/io/pipe.h index d1508b2..50da5e5 100644 --- a/source/io/pipe.h +++ b/source/io/pipe.h @@ -17,6 +17,9 @@ private: public: Pipe(); +private: + void platform_init(); +public: ~Pipe(); void set_block(bool); diff --git a/source/io/poll.cpp b/source/io/poll.cpp index a580907..0356a00 100644 --- a/source/io/poll.cpp +++ b/source/io/poll.cpp @@ -1,106 +1,13 @@ -#include #include -#ifndef WIN32 -#include -#endif -#include -#include #include "eventobject.h" -#include "handle.h" -#include "handle_private.h" #include "poll.h" +#include "poll_platform.h" using namespace std; -namespace { - -using namespace Msp; -using namespace Msp::IO; - -inline short int sys_poll_event(PollEvent event) -{ - int result = 0; - - if(event&~(P_INPUT|P_PRIO|P_OUTPUT)) - throw invalid_argument("sys_poll_event"); - -#ifndef WIN32 - if(event&P_INPUT) - result |= POLLIN; - if(event&P_PRIO) - result |= POLLPRI; - if(event&P_OUTPUT) - result |= POLLOUT; -#endif - - return result; -} - -inline PollEvent poll_event_from_sys(int event) -{ - PollEvent result = P_NONE; - -#ifdef WIN32 - (void)event; -#else - if(event&POLLIN) - result = result|P_INPUT; - if(event&POLLPRI) - result = result|P_PRIO; - if(event&POLLOUT) - result = result|P_OUTPUT; - if(event&POLLERR) - result = result|P_ERROR; -#endif - - return result; -} - -inline PollEvent do_poll(EventObject &obj, PollEvent pe, int timeout) -{ -#ifdef WIN32 - if(timeout<0) - timeout = INFINITE; - - DWORD ret = WaitForSingleObject(*obj.get_event_handle(), timeout); - if(ret==WAIT_OBJECT_0) - return pe; - else if(ret==WAIT_FAILED) - throw system_error("WaitForSingleObject"); - - return P_NONE; -#else - pollfd pfd = { *obj.get_event_handle(), sys_poll_event(pe), 0 }; - - int ret = ::poll(&pfd, 1, timeout); - if(ret==-1) - { - if(errno==EINTR) - return P_NONE; - else - throw system_error("poll"); - } - - return poll_event_from_sys(pfd.revents); -#endif -} - -} - - namespace Msp { namespace IO { -struct Poller::Private -{ -#ifdef WIN32 - vector handles; -#else - vector pfd; -#endif -}; - - Poller::Poller(): priv(new Private), objs_changed(false) @@ -152,28 +59,6 @@ int Poller::poll(const Time::TimeDelta &timeout) return do_poll(static_cast(timeout/Time::msec)); } -void Poller::rebuild_array() -{ -#ifdef WIN32 - priv->handles.clear(); - - for(EventMap::iterator i=objects.begin(); i!=objects.end(); ++i) - priv->handles.push_back(*i->first->get_event_handle()); -#else - priv->pfd.clear(); - - for(EventMap::iterator i=objects.begin(); i!=objects.end(); ++i) - { - pollfd p; - p.fd = *i->first->get_event_handle(); - p.events = sys_poll_event(i->second); - priv->pfd.push_back(p); - } -#endif - - objs_changed = false; -} - int Poller::do_poll(int timeout) { if(objs_changed) @@ -181,50 +66,18 @@ int Poller::do_poll(int timeout) poll_result.clear(); -#ifdef WIN32 - if(timeout<0) - timeout = INFINITE; - - DWORD ret = WaitForMultipleObjects(priv->handles.size(), &priv->handles.front(), false, timeout); - if(/*ret>=WAIT_OBJECT_0 &&*/ rethandles.size()) - { - EventMap::iterator i = objects.begin(); - advance(i, ret-WAIT_OBJECT_0); - poll_result.push_back(Slot(i->first, i->second)); - - return 1; - } - else if(ret==WAIT_FAILED) - throw system_error("WaitForMultipleObjects"); + platform_poll(timeout); - return 0; -#else - int ret = ::poll(&priv->pfd.front(), priv->pfd.size(), timeout); - if(ret==-1) - { - if(errno==EINTR) - return 0; - else - throw system_error("poll"); - } + return poll_result.size(); +} - int n = ret; - EventMap::iterator j = objects.begin(); - for(vector::iterator i=priv->pfd.begin(); (i!=priv->pfd.end() && n>0); ++i, ++j) - if(i->revents) - { - poll_result.push_back(Slot(j->first, poll_event_from_sys(i->revents))); - --n; - } - return ret; -#endif -} +PollEvent platform_poll(EventObject &, PollEvent, int); PollEvent poll(EventObject &obj, PollEvent pe) { - return do_poll(obj, pe, -1); + return platform_poll(obj, pe, -1); } PollEvent poll(EventObject &obj, PollEvent pe, const Time::TimeDelta &timeout) @@ -232,7 +85,7 @@ PollEvent poll(EventObject &obj, PollEvent pe, const Time::TimeDelta &timeout) if(timeout(timeout/Time::msec)); + return platform_poll(obj, pe, static_cast(timeout/Time::msec)); } } // namespace IO diff --git a/source/io/poll.h b/source/io/poll.h index d7823aa..09e00e5 100644 --- a/source/io/poll.h +++ b/source/io/poll.h @@ -62,6 +62,7 @@ public: private: void rebuild_array(); int do_poll(int); + void platform_poll(int); public: const SlotList &get_result() const { return poll_result; } }; diff --git a/source/io/seekable.cpp b/source/io/seekable.cpp index 35ab5a0..6bc8485 100644 --- a/source/io/seekable.cpp +++ b/source/io/seekable.cpp @@ -1,46 +1,8 @@ -#ifndef WIN32 -#define _LARGEFILE64_SOURCE -#include -#include -#else -#include -#endif -#include #include -#include "handle.h" -#include "handle_private.h" #include "seekable.h" using namespace std; -namespace { - -using namespace Msp::IO; - -int sys_seek_type(SeekType st) -{ -#ifdef WIN32 - if(st==S_BEG) - return FILE_BEGIN; - else if(st==S_CUR) - return FILE_CURRENT; - else if(st==S_END) - return FILE_END; -#else - if(st==S_BEG) - return SEEK_SET; - else if(st==S_CUR) - return SEEK_CUR; - else if(st==S_END) - return SEEK_END; -#endif - - throw invalid_argument("sys_seek_type"); -} - -} // namespace - - namespace Msp { namespace IO { @@ -51,33 +13,5 @@ bad_seek::bad_seek(SeekOffset offset, SeekType type): format("SeekType(%d)", type)) { } - -SeekOffset sys_seek(Handle &handle, SeekOffset offset, SeekType type) -{ -#ifdef WIN32 - LONG high = offset>>32; - DWORD ret = SetFilePointer(*handle, offset, &high, sys_seek_type(type)); - if(ret==INVALID_SET_FILE_POINTER) - { - DWORD err = GetLastError(); - if(err!=NO_ERROR) - throw system_error("SetFilePointer"); - } - - return (SeekOffset(high)<<32) | ret; -#else - off64_t ret = lseek64(*handle, offset, sys_seek_type(type)); - if(ret==(off64_t)-1) - { - if(errno==EINVAL) - throw bad_seek(offset, type); - else - throw system_error("lseek64"); - } - - return ret; -#endif -} - } // namespace IO } // namespace Msp diff --git a/source/io/serial.cpp b/source/io/serial.cpp index dc623e2..cf2c695 100644 --- a/source/io/serial.cpp +++ b/source/io/serial.cpp @@ -1,196 +1,18 @@ -#ifdef WIN32 -#include -#else -#include -#include -#include -#endif -#include -#include -#include "handle_private.h" #include "serial.h" +#include "serial_private.h" using namespace std; namespace Msp { namespace IO { -struct Serial::DeviceState -{ -#ifdef WIN32 - DCB state; -#else - termios state; -#endif - - void get_from(const Handle &); - void apply_to(const Handle &); - void set_baud_rate(unsigned); - void set_data_bits(unsigned); - void set_parity(Parity); - void set_stop_bits(unsigned); -}; - -void Serial::DeviceState::get_from(const Handle &handle) -{ -#ifdef WIN32 - GetCommState(*handle, &state); -#else - tcgetattr(*handle, &state); -#endif -} - -void Serial::DeviceState::apply_to(const Handle &handle) -{ -#ifdef WIN32 - if(SetCommState(*handle, &state)==0) - throw system_error("SetCommState"); -#else - if(tcsetattr(*handle, TCSADRAIN, &state)==-1) - throw system_error("tcsetattr"); -#endif -} - -void Serial::DeviceState::set_baud_rate(unsigned baud) -{ -#ifdef WIN32 - state.BaudRate = baud; -#else - speed_t speed; - switch(baud) - { - case 0: speed = B0; break; - case 50: speed = B50; break; - case 75: speed = B75; break; - case 110: speed = B110; break; - case 134: speed = B134; break; - case 150: speed = B150; break; - case 200: speed = B200; break; - case 300: speed = B300; break; - case 600: speed = B600; break; - case 1200: speed = B1200; break; - case 1800: speed = B1800; break; - case 2400: speed = B2400; break; - case 4800: speed = B4800; break; - case 9600: speed = B9600; break; - case 19200: speed = B19200; break; - case 38400: speed = B38400; break; - case 57600: speed = B57600; break; - case 115200: speed = B115200; break; - case 230400: speed = B230400; break; - default: throw invalid_argument("set_baud_rate"); - } - - cfsetospeed(&state, speed); - cfsetispeed(&state, speed); -#endif -} - -void Serial::DeviceState::set_data_bits(unsigned bits) -{ -#ifdef WIN32 - state.ByteSize = bits; -#else - tcflag_t flag; - switch(bits) - { - case 5: flag = CS5; break; - case 6: flag = CS6; break; - case 7: flag = CS7; break; - case 8: flag = CS8; break; - default: throw invalid_argument("set_data_bits"); - } - - state.c_cflag = (state.c_cflag&~CSIZE)|flag; -#endif -} - -void Serial::DeviceState::set_parity(Serial::Parity par) -{ -#ifdef WIN32 - switch(par) - { - case Serial::NONE: state.Parity = NOPARITY; break; - case Serial::EVEN: state.Parity = EVENPARITY; break; - case Serial::ODD: state.Parity = ODDPARITY; break; - default: throw invalid_argument("set_parity"); - } -#else - tcflag_t flag; - switch(par) - { - case Serial::NONE: flag = 0; break; - case Serial::EVEN: flag = PARENB; break; - case Serial::ODD: flag = PARENB|PARODD; break; - default: throw invalid_argument("set_parity"); - } - - state.c_cflag = (state.c_cflag&~(PARENB|PARODD))|flag; -#endif -} - -void Serial::DeviceState::set_stop_bits(unsigned bits) -{ -#ifdef WIN32 - switch(bits) - { - case 1: state.StopBits = ONESTOPBIT; break; - case 2: state.StopBits = TWOSTOPBITS; break; - default: throw invalid_argument("set_stop_bits"); - } -#else - tcflag_t flag; - switch(bits) - { - case 1: flag = 0; break; - case 2: flag = CSTOPB; break; - default: throw invalid_argument("set_stop_bits"); - } - - state.c_cflag = (state.c_cflag&~CSTOPB)|flag; -#endif -} - - Serial::Serial(const string &descr): reader(handle, 1024) { string::size_type comma = descr.find(','); string port = descr.substr(0, comma); -#ifdef WIN32 - port = "\\\\.\\"+port; - - *handle = CreateFile(port.c_str(), GENERIC_READ|GENERIC_WRITE, 0, 0, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL|FILE_FLAG_OVERLAPPED, 0); - if(!handle) - throw system_error(format("CreateFile(%s)", port)); - mode = M_READ|M_WRITE; - - COMMTIMEOUTS timeouts; - timeouts.ReadIntervalTimeout = MAXDWORD; - timeouts.ReadTotalTimeoutMultiplier = MAXDWORD; - timeouts.ReadTotalTimeoutConstant = MAXDWORD-1; - timeouts.WriteTotalTimeoutMultiplier = 0; - timeouts.WriteTotalTimeoutConstant = 0; - SetCommTimeouts(*handle, &timeouts); -#else - if(port.compare(0, 5, "/dev/")) - port = "/dev/"+port; - - *handle = open(port.c_str(), O_RDWR); - if(!handle) - throw system_error(format("open(%s)", port)); - mode = M_READ|M_WRITE; - - termios t; - tcgetattr(*handle, &t); - t.c_iflag &= ~(ISTRIP|INLCR|IGNCR|ICRNL|IXON); - t.c_lflag &= ~(ECHO|ICANON|ISIG|IEXTEN); - t.c_oflag &= ~(OPOST|OCRNL|ONOCR|ONLRET); - t.c_cc[VMIN] = 1; - t.c_cc[VTIME] = 0; - tcsetattr(*handle, TCSADRAIN, &t); -#endif + platform_init(port); if(comma!=string::npos) { @@ -220,15 +42,8 @@ void Serial::close() void Serial::set_block(bool b) { - if(b) - mode = mode|M_NONBLOCK; - else - mode = mode&~M_NONBLOCK; - -#ifndef WIN32 - int flags = fcntl(*handle, F_GETFD); - fcntl(*handle, F_SETFL, (flags&O_NONBLOCK)|(b?0:O_NONBLOCK)); -#endif + mode = b?(mode&~M_NONBLOCK):(mode|M_NONBLOCK); + sys_set_blocking(handle, b); } void Serial::set_baud_rate(unsigned rate) diff --git a/source/io/serial.h b/source/io/serial.h index 49ecefb..1c91e60 100644 --- a/source/io/serial.h +++ b/source/io/serial.h @@ -26,6 +26,9 @@ private: public: Serial(const std::string &); +private: + void platform_init(const std::string &); +public: virtual ~Serial(); private: diff --git a/source/io/serial_private.h b/source/io/serial_private.h new file mode 100644 index 0000000..1b497be --- /dev/null +++ b/source/io/serial_private.h @@ -0,0 +1,25 @@ +#ifndef MSP_IO_SERIAL_PRIVATE_H_ +#define MSP_IO_SERIAL_PRIVATE_H_ + +#include "serial.h" +#include "serial_platform.h" + +namespace Msp { +namespace IO { + +struct Serial::DeviceState +{ + PlatformSerialDeviceState state; + + void get_from(const Handle &); + void apply_to(const Handle &); + void set_baud_rate(unsigned); + void set_data_bits(unsigned); + void set_parity(Serial::Parity); + void set_stop_bits(unsigned); +}; + +} // namespace IO +} // namespace Msp + +#endif diff --git a/source/io/unix/console.cpp b/source/io/unix/console.cpp new file mode 100644 index 0000000..d38d0bb --- /dev/null +++ b/source/io/unix/console.cpp @@ -0,0 +1,83 @@ +#include +#include +#include +#include +#include +#include "console.h" +#include "handle_private.h" + +namespace { + +termios orig_attr; + +} + + +namespace Msp { +namespace IO { + +void Console::platform_init() +{ + *handle = stream; + + if(stream==CIN) + tcgetattr(*handle, &orig_attr); +} + +Console::~Console() +{ + if(stream==CIN) + tcsetattr(*handle, TCSADRAIN, &orig_attr); +} + +void Console::set_local_echo(bool e) +{ + check_access(M_READ); + + termios t; + tcgetattr(*handle, &t); + t.c_lflag = (t.c_lflag&~ECHO) | (e?ECHO:0); + tcsetattr(*handle, TCSADRAIN, &t); +} + +void Console::set_line_buffer(bool l) +{ + check_access(M_READ); + + termios t; + if(tcgetattr(*handle, &t)==-1) + throw system_error("tcgetattr"); + t.c_lflag = (t.c_lflag&~ICANON) | (l?ICANON:0); + // man termios warns that VMIN and VTIME may share indices with VEOF and VEOL + if(l) + { + t.c_cc[VEOF] = orig_attr.c_cc[VEOF]; + t.c_cc[VEOL] = orig_attr.c_cc[VEOL]; + } + else + { + t.c_cc[VMIN] = 1; + t.c_cc[VTIME] = 0; + } + if(tcsetattr(*handle, TCSADRAIN, &t)==-1) + throw system_error("tcsetattr"); +} + +void Console::get_size(unsigned &rows, unsigned &cols) +{ + check_access(M_WRITE); + + struct winsize wsz; + if(ioctl(*handle, TIOCGWINSZ, &wsz)==-1) + throw system_error("ioctl TIOCGWINSZ"); + rows = wsz.ws_row; + cols = wsz.ws_col; +} + +void Console::redirect(Base &other) +{ + dup2(*other.get_handle(mode), *handle); +} + +} // namespace IO +} // namespace Msp diff --git a/source/io/unix/eventreader.cpp b/source/io/unix/eventreader.cpp new file mode 100644 index 0000000..fcbc892 --- /dev/null +++ b/source/io/unix/eventreader.cpp @@ -0,0 +1,31 @@ +#include "eventreader.h" + +namespace Msp { +namespace IO { + +EventReader::EventReader(Handle &h, unsigned): + handle(h), + priv(0) +{ } + +EventReader::~EventReader() +{ } + +const Handle &EventReader::get_event() +{ + return handle; +} + +void EventReader::start() +{ } + +void EventReader::wait() +{ } + +unsigned EventReader::read(char *buf, unsigned len) +{ + return sys_read(handle, buf, len); +} + +} // namespace IO +} // namespace Msp diff --git a/source/io/unix/file.cpp b/source/io/unix/file.cpp new file mode 100644 index 0000000..b2c9089 --- /dev/null +++ b/source/io/unix/file.cpp @@ -0,0 +1,60 @@ +#include +#include +#include +#include +#include +#include "file.h" +#include "handle_private.h" + +using namespace std; + +namespace Msp { +namespace IO { + +void File::platform_init(const string &fn, CreateMode cm) +{ + int flags = 0; + switch(mode&M_RDWR) + { + case M_READ: flags |= O_RDONLY; break; + case M_WRITE: flags |= O_WRONLY; break; + case M_RDWR: flags |= O_RDWR; break; + default:; + } + + if(mode&M_WRITE) + { + if(cm&C_CREATE) + flags |= O_CREAT; + if(cm&C_TRUNCATE) + flags |= O_TRUNC; + if(cm&C_EXCLUSIVE) + flags |= O_EXCL; + } + if(mode&M_APPEND) + flags |= O_APPEND; + if(mode&M_NONBLOCK) + flags |= O_NONBLOCK; + + *handle = ::open(fn.c_str(), flags, 0666); + if(!handle) + { + int err = errno; + if(err==ENOENT) + throw file_not_found(fn); + else if(err==EEXIST) + throw file_already_exists(fn); + else + throw system_error(format("open(%s)", fn), err); + } +} + +void File::sync() +{ + signal_flush_required.emit(); + + fsync(*handle); +} + +} // namespace IO +} // namespace Msp diff --git a/source/io/unix/handle.cpp b/source/io/unix/handle.cpp new file mode 100644 index 0000000..9546df9 --- /dev/null +++ b/source/io/unix/handle.cpp @@ -0,0 +1,57 @@ +#include +#include +#include +#include +#include "handle.h" +#include "handle_private.h" + +namespace Msp { +namespace IO { + +Handle::operator const void *() const +{ + return priv->handle!=-1 ? this : 0; +} + + +void sys_set_blocking(Handle &handle, bool b) +{ + int flags = fcntl(*handle, F_GETFD); + fcntl(*handle, F_SETFL, (flags&~O_NONBLOCK)|(b?0:O_NONBLOCK)); +} + +unsigned sys_read(Handle &handle, char *buf, unsigned size) +{ + int ret = read(*handle, buf, size); + if(ret==-1) + { + if(errno==EAGAIN) + return 0; + else + throw system_error("read"); + } + + return ret; +} + +unsigned sys_write(Handle &handle, const char *buf, unsigned size) +{ + int ret = write(*handle, buf, size); + if(ret==-1) + { + if(errno==EAGAIN) + return 0; + else + throw system_error("write"); + } + + return ret; +} + +void sys_close(Handle &handle) +{ + close(*handle); +} + +} // namespace IO +} // namespace Msp diff --git a/source/io/unix/handle_platform.h b/source/io/unix/handle_platform.h new file mode 100644 index 0000000..b241669 --- /dev/null +++ b/source/io/unix/handle_platform.h @@ -0,0 +1,14 @@ +#ifndef MSP_IO_HANDLE_PLATFORM_H_ +#define MSP_IO_HANDLE_PLATFORM_H_ + +namespace Msp { +namespace IO { + +typedef int PlatformHandle; + +#define INVALID_HANDLE_VALUE -1 + +} // namespace IO +} // namespace Msp + +#endif diff --git a/source/io/unix/pipe.cpp b/source/io/unix/pipe.cpp new file mode 100644 index 0000000..de93f82 --- /dev/null +++ b/source/io/unix/pipe.cpp @@ -0,0 +1,20 @@ +#include +#include +#include "handle_private.h" +#include "pipe.h" + +namespace Msp { +namespace IO { + +void Pipe::platform_init() +{ + int pipe_fd[2]; + if(pipe(pipe_fd)==-1) + throw system_error("pipe"); + + *read_handle = pipe_fd[0]; + *write_handle = pipe_fd[1]; +} + +} // namespace IO +} // namespace Msp diff --git a/source/io/unix/poll.cpp b/source/io/unix/poll.cpp new file mode 100644 index 0000000..650f226 --- /dev/null +++ b/source/io/unix/poll.cpp @@ -0,0 +1,109 @@ +#include +#include +#include +#include "eventobject.h" +#include "handle.h" +#include "handle_private.h" +#include "poll.h" +#include "poll_platform.h" + +using namespace std; + +namespace { + +using namespace Msp; +using namespace Msp::IO; + +inline short int sys_poll_event(PollEvent event) +{ + int result = 0; + + if(event&~(P_INPUT|P_PRIO|P_OUTPUT)) + throw invalid_argument("sys_poll_event"); + + if(event&P_INPUT) + result |= POLLIN; + if(event&P_PRIO) + result |= POLLPRI; + if(event&P_OUTPUT) + result |= POLLOUT; + + return result; +} + +inline PollEvent poll_event_from_sys(int event) +{ + PollEvent result = P_NONE; + + if(event&POLLIN) + result = result|P_INPUT; + if(event&POLLPRI) + result = result|P_PRIO; + if(event&POLLOUT) + result = result|P_OUTPUT; + if(event&POLLERR) + result = result|P_ERROR; + + return result; +} + +} + + +namespace Msp { +namespace IO { + +void Poller::rebuild_array() +{ + priv->pfd.clear(); + + for(EventMap::iterator i=objects.begin(); i!=objects.end(); ++i) + { + pollfd p; + p.fd = *i->first->get_event_handle(); + p.events = sys_poll_event(i->second); + priv->pfd.push_back(p); + } + + objs_changed = false; +} + +void Poller::platform_poll(int timeout) +{ + int ret = ::poll(&priv->pfd.front(), priv->pfd.size(), timeout); + if(ret==-1) + { + if(errno==EINTR) + return; + else + throw system_error("poll"); + } + + EventMap::iterator j = objects.begin(); + for(vector::iterator i=priv->pfd.begin(); (i!=priv->pfd.end() && ret>0); ++i, ++j) + if(i->revents) + { + poll_result.push_back(Slot(j->first, poll_event_from_sys(i->revents))); + --ret; + } +} + + +PollEvent platform_poll(EventObject &obj, PollEvent pe, int timeout) +{ + pollfd pfd = { *obj.get_event_handle(), sys_poll_event(pe), 0 }; + + int ret = ::poll(&pfd, 1, timeout); + if(ret==-1) + { + if(errno==EINTR) + return P_NONE; + else + throw system_error("poll"); + } + + return poll_event_from_sys(pfd.revents); +} + +} // namespace IO +} // namespace Msp diff --git a/source/io/unix/poll_platform.h b/source/io/unix/poll_platform.h new file mode 100644 index 0000000..bfd83da --- /dev/null +++ b/source/io/unix/poll_platform.h @@ -0,0 +1,18 @@ +#ifndef MSP_IO_POLL_PLATFORM_H_ +#define MSP_IO_POLL_PLATFORM_H_ + +#include +#include + +namespace Msp { +namespace IO { + +struct Poller::Private +{ + std::vector pfd; +}; + +} // namespace IO +} // namespace Msp + +#endif diff --git a/source/io/unix/seekable.cpp b/source/io/unix/seekable.cpp new file mode 100644 index 0000000..2c17114 --- /dev/null +++ b/source/io/unix/seekable.cpp @@ -0,0 +1,47 @@ +#define _LARGEFILE64_SOURCE +#include +#include +#include +#include "handle.h" +#include "handle_private.h" +#include "seekable.h" + +using namespace std; + +namespace { + +using namespace Msp::IO; + +int sys_seek_type(SeekType st) +{ + if(st==S_BEG) + return SEEK_SET; + else if(st==S_CUR) + return SEEK_CUR; + else if(st==S_END) + return SEEK_END; + + throw invalid_argument("sys_seek_type"); +} + +} + +namespace Msp { +namespace IO { + +SeekOffset sys_seek(Handle &handle, SeekOffset offset, SeekType type) +{ + off64_t ret = lseek64(*handle, offset, sys_seek_type(type)); + if(ret==(off64_t)-1) + { + if(errno==EINVAL) + throw bad_seek(offset, type); + else + throw system_error("lseek64"); + } + + return ret; +} + +} // namespace IO +} // namespace Msp diff --git a/source/io/unix/serial.cpp b/source/io/unix/serial.cpp new file mode 100644 index 0000000..49d9e9c --- /dev/null +++ b/source/io/unix/serial.cpp @@ -0,0 +1,121 @@ +#include +#include +#include +#include +#include "handle_private.h" +#include "serial.h" +#include "serial_private.h" + +using namespace std; + +namespace Msp { +namespace IO { + +void Serial::platform_init(const string &port) +{ + string fn = port; + if(fn.compare(0, 5, "/dev/")) + fn = "/dev/"+fn; + + *handle = open(fn.c_str(), O_RDWR); + if(!handle) + throw system_error(format("open(%s)", port)); + mode = M_READ|M_WRITE; + + termios t; + tcgetattr(*handle, &t); + t.c_iflag &= ~(ISTRIP|INLCR|IGNCR|ICRNL|IXON); + t.c_lflag &= ~(ECHO|ICANON|ISIG|IEXTEN); + t.c_oflag &= ~(OPOST|OCRNL|ONOCR|ONLRET); + t.c_cc[VMIN] = 1; + t.c_cc[VTIME] = 0; + tcsetattr(*handle, TCSADRAIN, &t); +} + + +void Serial::DeviceState::get_from(const Handle &handle) +{ + tcgetattr(*handle, &state); +} + +void Serial::DeviceState::apply_to(const Handle &handle) +{ + if(tcsetattr(*handle, TCSADRAIN, &state)==-1) + throw system_error("tcsetattr"); +} + +void Serial::DeviceState::set_baud_rate(unsigned baud) +{ + speed_t speed; + switch(baud) + { + case 0: speed = B0; break; + case 50: speed = B50; break; + case 75: speed = B75; break; + case 110: speed = B110; break; + case 134: speed = B134; break; + case 150: speed = B150; break; + case 200: speed = B200; break; + case 300: speed = B300; break; + case 600: speed = B600; break; + case 1200: speed = B1200; break; + case 1800: speed = B1800; break; + case 2400: speed = B2400; break; + case 4800: speed = B4800; break; + case 9600: speed = B9600; break; + case 19200: speed = B19200; break; + case 38400: speed = B38400; break; + case 57600: speed = B57600; break; + case 115200: speed = B115200; break; + case 230400: speed = B230400; break; + default: throw invalid_argument("set_baud_rate"); + } + + cfsetospeed(&state, speed); + cfsetispeed(&state, speed); +} + +void Serial::DeviceState::set_data_bits(unsigned bits) +{ + tcflag_t flag; + switch(bits) + { + case 5: flag = CS5; break; + case 6: flag = CS6; break; + case 7: flag = CS7; break; + case 8: flag = CS8; break; + default: throw invalid_argument("set_data_bits"); + } + + state.c_cflag = (state.c_cflag&~CSIZE)|flag; +} + +void Serial::DeviceState::set_parity(Serial::Parity par) +{ + tcflag_t flag; + switch(par) + { + case Serial::NONE: flag = 0; break; + case Serial::EVEN: flag = PARENB; break; + case Serial::ODD: flag = PARENB|PARODD; break; + default: throw invalid_argument("set_parity"); + } + + state.c_cflag = (state.c_cflag&~(PARENB|PARODD))|flag; +} + +void Serial::DeviceState::set_stop_bits(unsigned bits) +{ + tcflag_t flag; + switch(bits) + { + case 1: flag = 0; break; + case 2: flag = CSTOPB; break; + default: throw invalid_argument("set_stop_bits"); + } + + state.c_cflag = (state.c_cflag&~CSTOPB)|flag; +} + +} // namespace IO +} // namespace MSp diff --git a/source/io/unix/serial_platform.h b/source/io/unix/serial_platform.h new file mode 100644 index 0000000..e7de712 --- /dev/null +++ b/source/io/unix/serial_platform.h @@ -0,0 +1,14 @@ +#ifndef MSP_IO_SERIAL_PLATFORM_H_ +#define MSP_IO_SERIAL_PLATFORM_H_ + +#include + +namespace Msp { +namespace IO { + +typedef termios PlatformSerialDeviceState; + +} // namespace IO +} // namespace Msp + +#endif diff --git a/source/io/windows/console.cpp b/source/io/windows/console.cpp new file mode 100644 index 0000000..a331133 --- /dev/null +++ b/source/io/windows/console.cpp @@ -0,0 +1,72 @@ +#include +#include "console.h" +#include "handle_private.h" + +using namespace std; + +namespace { + +DWORD stream_to_sys(Msp::IO::Console::Stream stream) +{ + switch(stream) + { + case Msp::IO::Console::CIN: return STD_INPUT_HANDLE; + case Msp::IO::Console::COUT: return STD_OUTPUT_HANDLE; + case Msp::IO::Console::CERR: return STD_ERROR_HANDLE; + default: throw invalid_argument("stream_to_sys"); + } +} + +} // namespace + + +namespace Msp { +namespace IO { + +void Console::platform_init() +{ + *handle = GetStdHandle(stream_to_sys(stream)); +} + +Console::~Console() +{ } + +void Console::set_local_echo(bool e) +{ + check_access(M_READ); + + DWORD m; + GetConsoleMode(*handle, &m); + SetConsoleMode(*handle, (m&~ENABLE_ECHO_INPUT) | (e?ENABLE_ECHO_INPUT:0)); +} + +void Console::set_line_buffer(bool l) +{ + check_access(M_READ); + + DWORD m; + if(!GetConsoleMode(*handle, &m)) + throw system_error("GetConsoleMode"); + if(!SetConsoleMode(*handle, (m&~ENABLE_LINE_INPUT) | (l?ENABLE_LINE_INPUT:0))) + throw system_error("SetConsoleMode"); +} + +void Console::get_size(unsigned &rows, unsigned &cols) +{ + check_access(M_WRITE); + + CONSOLE_SCREEN_BUFFER_INFO sbi; + if(!GetConsoleScreenBufferInfo(*handle, &sbi)) + throw system_error("GetConsoleScreenBufferInfo"); + // Right/bottom coords are inclusive + rows = sbi.srWindow.Bottom+1-sbi.srWindow.Top; + cols = sbi.srWindow.Right+1-sbi.srWindow.Left; +} + +void Console::redirect(Base &other) +{ + SetStdHandle(stream_to_sys(stream), *other.get_handle(mode)); +} + +} // namespace IO +} // namespace Msp diff --git a/source/io/eventreader.cpp b/source/io/windows/eventreader.cpp similarity index 87% rename from source/io/eventreader.cpp rename to source/io/windows/eventreader.cpp index 370ddf2..62c9763 100644 --- a/source/io/eventreader.cpp +++ b/source/io/windows/eventreader.cpp @@ -1,6 +1,4 @@ -#ifdef WIN32 #include -#endif #include #include #include "eventreader.h" @@ -13,58 +11,43 @@ 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) + priv(new Private) { -#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; @@ -87,12 +70,10 @@ void EventReader::start() priv->overlapped = 0; SetEvent(*priv->event); } -#endif } void EventReader::wait() { -#ifdef WIN32 if(!priv->overlapped) return; @@ -105,12 +86,10 @@ void EventReader::wait() 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 @@ -130,9 +109,6 @@ unsigned EventReader::read(char *buf, unsigned len) } return len; -#else - return sys_read(handle, buf, len); -#endif } } // namespace IO diff --git a/source/io/windows/file.cpp b/source/io/windows/file.cpp new file mode 100644 index 0000000..b973375 --- /dev/null +++ b/source/io/windows/file.cpp @@ -0,0 +1,54 @@ +#include +#include +#include "file.h" +#include "handle_private.h" + +using namespace std; + +namespace Msp { +namespace IO { + +void File::platform_init(const string &fn, CreateMode cm) +{ + int flags = 0; + int share_flags = 0; + int create_flags = OPEN_EXISTING; + + if(mode&M_READ) + flags |= GENERIC_READ; + + if(mode&M_WRITE) + { + flags |= GENERIC_WRITE; + + switch(static_cast(cm)) + { + case C_NONE: create_flags = OPEN_EXISTING; break; + case C_CREATE: create_flags = OPEN_ALWAYS; break; + case C_TRUNCATE: create_flags = TRUNCATE_EXISTING; break; + case C_OVERWRITE: create_flags = CREATE_ALWAYS; break; + case C_NEW: create_flags = CREATE_NEW; break; + } + } + else + share_flags = FILE_SHARE_READ; + + *handle = CreateFile(fn.c_str(), flags, share_flags, 0, create_flags, FILE_ATTRIBUTE_NORMAL, 0); + if(!handle) + { + int err = GetLastError(); + if(err==ERROR_FILE_NOT_FOUND) + throw file_not_found(fn); + else if(err==ERROR_FILE_EXISTS) + throw file_already_exists(fn); + else + throw system_error(format("CreateFile(%s)", fn), err); + } +} + +void File::sync() +{ +} + +} // namespace IO +} // namespace Msp diff --git a/source/io/windows/handle.cpp b/source/io/windows/handle.cpp new file mode 100644 index 0000000..5b1d933 --- /dev/null +++ b/source/io/windows/handle.cpp @@ -0,0 +1,42 @@ +#include +#include "handle.h" +#include "handle_private.h" + +namespace Msp { +namespace IO { + +Handle::operator const void *() const +{ + return priv->handle!=INVALID_HANDLE_VALUE ? this : 0; +} + + +void sys_set_blocking(Handle &, bool) +{ +} + +unsigned sys_read(Handle &handle, char *buf, unsigned size) +{ + DWORD ret; + if(ReadFile(*handle, buf, size, &ret, 0)==0) + throw system_error("ReadFile"); + + return ret; +} + +unsigned sys_write(Handle &handle, const char *buf, unsigned size) +{ + DWORD ret; + if(WriteFile(*handle, buf, size, &ret, 0)==0) + throw system_error("WriteFile"); + + return ret; +} + +void sys_close(Handle &handle) +{ + CloseHandle(*handle); +} + +} // namespace IO +} // namespace Msp diff --git a/source/io/windows/handle_platform.h b/source/io/windows/handle_platform.h new file mode 100644 index 0000000..f12e5f7 --- /dev/null +++ b/source/io/windows/handle_platform.h @@ -0,0 +1,14 @@ +#ifndef MSP_IO_HANDLE_PLATFORM_H_ +#define MSP_IO_HANDLE_PLATFORM_H_ + +#include + +namespace Msp { +namespace IO { + +typedef HANDLE PlatformHandle; + +} // namespace IO +} // namespace Msp + +#endif diff --git a/source/io/windows/pipe.cpp b/source/io/windows/pipe.cpp new file mode 100644 index 0000000..02d7f33 --- /dev/null +++ b/source/io/windows/pipe.cpp @@ -0,0 +1,28 @@ +#include +#include +#include "handle_private.h" +#include "pipe.h" + +using namespace std; + +namespace Msp { +namespace IO { + +void Pipe::platform_init() +{ + string name = format("\\\\.\\pipe\\%u.%p", GetCurrentProcessId(), this); + *read_handle = CreateNamedPipe(name.c_str(), PIPE_ACCESS_INBOUND|FILE_FLAG_OVERLAPPED, PIPE_TYPE_BYTE, 1, 1024, 1024, 0, 0); + if(!read_handle) + throw system_error("CreateNamedPipe"); + + *write_handle = CreateFile(name.c_str(), GENERIC_WRITE, 0, 0, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, 0); + if(!write_handle) + { + unsigned err = GetLastError(); + CloseHandle(*read_handle); + throw system_error(format("CreateFile(%s)", name), err); + } +} + +} // namespace IO +} // namespace Msp diff --git a/source/io/windows/poll.cpp b/source/io/windows/poll.cpp new file mode 100644 index 0000000..e672258 --- /dev/null +++ b/source/io/windows/poll.cpp @@ -0,0 +1,53 @@ +#include +#include "eventobject.h" +#include "handle.h" +#include "handle_private.h" +#include "poll.h" +#include "poll_platform.h" + +namespace Msp { +namespace IO { + +void Poller::rebuild_array() +{ + priv->handles.clear(); + + for(EventMap::iterator i=objects.begin(); i!=objects.end(); ++i) + priv->handles.push_back(*i->first->get_event_handle()); + + objs_changed = false; +} + +void Poller::platform_poll(int timeout) +{ + if(timeout<0) + timeout = INFINITE; + + DWORD ret = WaitForMultipleObjects(priv->handles.size(), &priv->handles.front(), false, timeout); + if(/*ret>=WAIT_OBJECT_0 &&*/ rethandles.size()) + { + EventMap::iterator i = objects.begin(); + advance(i, ret-WAIT_OBJECT_0); + poll_result.push_back(Slot(i->first, i->second)); + } + else if(ret==WAIT_FAILED) + throw system_error("WaitForMultipleObjects"); +} + + +PollEvent platform_poll(EventObject &obj, PollEvent pe, int timeout) +{ + if(timeout<0) + timeout = INFINITE; + + DWORD ret = WaitForSingleObject(*obj.get_event_handle(), timeout); + if(ret==WAIT_OBJECT_0) + return pe; + else if(ret==WAIT_FAILED) + throw system_error("WaitForSingleObject"); + + return P_NONE; +} + +} // namespace IO +} // namespace Msp diff --git a/source/io/windows/poll_platform.h b/source/io/windows/poll_platform.h new file mode 100644 index 0000000..ccf92c3 --- /dev/null +++ b/source/io/windows/poll_platform.h @@ -0,0 +1,18 @@ +#ifndef MSP_IO_POLL_PLATFORM_H_ +#define MSP_IO_POLL_PLATFORM_H_ + +#include +#include + +namespace Msp { +namespace IO { + +struct Poller::Private +{ + std::vector handles; +}; + +} // namespace IO +} // namespace Msp + +#endif diff --git a/source/io/windows/seekable.cpp b/source/io/windows/seekable.cpp new file mode 100644 index 0000000..73c5cc5 --- /dev/null +++ b/source/io/windows/seekable.cpp @@ -0,0 +1,45 @@ +#include +#include +#include "handle.h" +#include "handle_private.h" +#include "seekable.h" + +using namespace std; + +namespace { + +using namespace Msp::IO; + +int sys_seek_type(SeekType st) +{ + if(st==S_BEG) + return FILE_BEGIN; + else if(st==S_CUR) + return FILE_CURRENT; + else if(st==S_END) + return FILE_END; + + throw invalid_argument("sys_seek_type"); +} + +} + +namespace Msp { +namespace IO { + +SeekOffset sys_seek(Handle &handle, SeekOffset offset, SeekType type) +{ + LONG high = offset>>32; + DWORD ret = SetFilePointer(*handle, offset, &high, sys_seek_type(type)); + if(ret==INVALID_SET_FILE_POINTER) + { + DWORD err = GetLastError(); + if(err!=NO_ERROR) + throw system_error("SetFilePointer"); + } + + return (SeekOffset(high)<<32) | ret; +} + +} // namespace IO +} // namespace Msp diff --git a/source/io/windows/serial.cpp b/source/io/windows/serial.cpp new file mode 100644 index 0000000..0092754 --- /dev/null +++ b/source/io/windows/serial.cpp @@ -0,0 +1,74 @@ +#include +#include +#include "handle_private.h" +#include "serial.h" +#include "serial_private.h" + +using namespace std; + +namespace Msp { +namespace IO { + +void Serial::platform_init(const string &port) +{ + string name = "\\\\.\\"+port; + + *handle = CreateFile(name.c_str(), GENERIC_READ|GENERIC_WRITE, 0, 0, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL|FILE_FLAG_OVERLAPPED, 0); + if(!handle) + throw system_error(format("CreateFile(%s)", port)); + mode = M_READ|M_WRITE; + + COMMTIMEOUTS timeouts; + timeouts.ReadIntervalTimeout = MAXDWORD; + timeouts.ReadTotalTimeoutMultiplier = MAXDWORD; + timeouts.ReadTotalTimeoutConstant = MAXDWORD-1; + timeouts.WriteTotalTimeoutMultiplier = 0; + timeouts.WriteTotalTimeoutConstant = 0; + SetCommTimeouts(*handle, &timeouts); +} + + +void Serial::DeviceState::get_from(const Handle &handle) +{ + GetCommState(*handle, &state); +} + +void Serial::DeviceState::apply_to(const Handle &handle) +{ + if(SetCommState(*handle, &state)==0) + throw system_error("SetCommState"); +} + +void Serial::DeviceState::set_baud_rate(unsigned baud) +{ + state.BaudRate = baud; +} + +void Serial::DeviceState::set_data_bits(unsigned bits) +{ + state.ByteSize = bits; +} + +void Serial::DeviceState::set_parity(Serial::Parity par) +{ + switch(par) + { + case Serial::NONE: state.Parity = NOPARITY; break; + case Serial::EVEN: state.Parity = EVENPARITY; break; + case Serial::ODD: state.Parity = ODDPARITY; break; + default: throw invalid_argument("set_parity"); + } +} + +void Serial::DeviceState::set_stop_bits(unsigned bits) +{ + switch(bits) + { + case 1: state.StopBits = ONESTOPBIT; break; + case 2: state.StopBits = TWOSTOPBITS; break; + default: throw invalid_argument("set_stop_bits"); + } +} + +} // namespace IO +} // namespace MSp diff --git a/source/io/windows/serial_platform.h b/source/io/windows/serial_platform.h new file mode 100644 index 0000000..dd7dd50 --- /dev/null +++ b/source/io/windows/serial_platform.h @@ -0,0 +1,14 @@ +#ifndef MSP_IO_SERIAL_PLATFORM_H_ +#define MSP_IO_SERIAL_PLATFORM_H_ + +#include + +namespace Msp { +namespace IO { + +typedef DCB PlatformSerialDeviceState; + +} // namespace IO +} // namespace Msp + +#endif diff --git a/source/time/rawtime_private.h b/source/time/rawtime_private.h index 846a712..e0cbb2e 100644 --- a/source/time/rawtime_private.h +++ b/source/time/rawtime_private.h @@ -1,25 +1,6 @@ #ifndef MSP_TIME_RAWTIME_PRIVATE_H_ #define MSP_TIME_RAWTIME_PRIVATE_H_ -#ifdef WIN32 -#include -#else -#include -#endif -#include "rawtime.h" - -namespace Msp { -namespace Time { - -#ifdef WIN32 -RawTime filetime_to_rawtime(const FILETIME &); -#else -timeval rawtime_to_timeval(RawTime); -timespec rawtime_to_timespec(RawTime); -RawTime timeval_to_rawtime(const timeval &); -#endif - -} // namespace Time -} // namespace Msp +#include "rawtime_platform.h" #endif diff --git a/source/time/timezone.cpp b/source/time/timezone.cpp index 7baf494..76c3fb2 100644 --- a/source/time/timezone.cpp +++ b/source/time/timezone.cpp @@ -1,108 +1,9 @@ #include -#ifdef WIN32 -#include -#else -#include -#include -#endif #include -#include -#include "timestamp.h" #include "timezone.h" -#include "utils.h" using namespace std; -namespace { - -using Msp::Time::TimeZone; - -#ifndef WIN32 -long get_long(char *&ptr) -{ - long result = 0; - for(unsigned i=0; i<4; ++i) - result = (result<<8)+static_cast(*ptr++); - return result; -} -#endif - -TimeZone get_local_timezone() -{ -#ifdef WIN32 - TIME_ZONE_INFORMATION tzinfo; - DWORD dst = GetTimeZoneInformation(&tzinfo); - if(dst==TIME_ZONE_ID_INVALID) - throw Msp::system_error("GetTimeZoneInformation"); - - int offset = tzinfo.Bias; - if(dst==TIME_ZONE_ID_STANDARD) - offset += tzinfo.StandardBias; - else if(dst==TIME_ZONE_ID_DAYLIGHT) - offset += tzinfo.DaylightBias; - - return TimeZone(offset); -#else - int fd = open("/etc/localtime", O_RDONLY); - if(fd!=-1) - { - char hdr[44]; - int len = read(fd, hdr, sizeof(hdr)); - long gmtoff = -1; - string name; - if(len==44 && hdr[0]=='T' && hdr[1]=='Z' && hdr[2]=='i' && hdr[3]=='f') - { - char *ptr = hdr+20; - long isgmtcnt = get_long(ptr); - long isstdcnt = get_long(ptr); - long leapcnt = get_long(ptr); - long timecnt = get_long(ptr); - long typecnt = get_long(ptr); - long charcnt = get_long(ptr); - int size = timecnt*5+typecnt*6+isgmtcnt+isstdcnt+leapcnt*8+charcnt; - char *buf = new char[size]; - len = read(fd, buf, size); - if(len==size) - { - ptr = buf; - int index = -1; - time_t cur_time = Msp::Time::now().to_unixtime(); - for(int i=0; i0) - index = ptr[index]; - ptr += timecnt; - - int abbrind = 0; - for(int i=0; i=0 && i==index) || (index<0 && !ptr[4] && gmtoff==-1)) - { - gmtoff = get_long(ptr); - ++ptr; - abbrind = *ptr++; - } - else - ptr += 6; - } - - name = ptr+abbrind; - } - delete[] buf; - } - close(fd); - - if(gmtoff!=-1) - return TimeZone(gmtoff/60, name); - } - return TimeZone(); -#endif -} - -} - namespace Msp { namespace Time { @@ -137,7 +38,7 @@ const TimeZone &TimeZone::utc() const TimeZone &TimeZone::local() { - static TimeZone tz = get_local_timezone(); + static TimeZone tz = platform_get_local_timezone(); return tz; } diff --git a/source/time/timezone.h b/source/time/timezone.h index 28feb16..3fbeb54 100644 --- a/source/time/timezone.h +++ b/source/time/timezone.h @@ -22,6 +22,8 @@ public: static const TimeZone &utc(); static const TimeZone &local(); +private: + static TimeZone platform_get_local_timezone(); }; } // namespace Time diff --git a/source/time/unix/rawtime.cpp b/source/time/unix/rawtime.cpp new file mode 100644 index 0000000..2b8bc6d --- /dev/null +++ b/source/time/unix/rawtime.cpp @@ -0,0 +1,29 @@ +#include "rawtime.h" +#include "rawtime_private.h" + +namespace Msp { +namespace Time { + +timeval rawtime_to_timeval(RawTime raw) +{ + timeval tv; + tv.tv_sec = raw/1000000; + tv.tv_usec = raw%1000000; + return tv; +} + +timespec rawtime_to_timespec(RawTime raw) +{ + timespec ts; + ts.tv_sec = raw/1000000; + ts.tv_nsec = (raw%1000000)*1000; + return ts; +} + +RawTime timeval_to_rawtime(const timeval &tv) +{ + return tv.tv_sec*1000000LL+tv.tv_usec; +} + +} // namespace Time +} // namespace Msp diff --git a/source/time/unix/rawtime_platform.h b/source/time/unix/rawtime_platform.h new file mode 100644 index 0000000..8f9f633 --- /dev/null +++ b/source/time/unix/rawtime_platform.h @@ -0,0 +1,17 @@ +#ifndef MSP_TIME_RAWTIME_PLATFORM_H_ +#define MSP_TIME_RAWTIME_PLATFORM_H_ + +#include +#include "rawtime.h" + +namespace Msp { +namespace Time { + +timeval rawtime_to_timeval(RawTime); +timespec rawtime_to_timespec(RawTime); +RawTime timeval_to_rawtime(const timeval &); + +} // namespace Time +} // namespace Msp + +#endif diff --git a/source/time/unix/timezone.cpp b/source/time/unix/timezone.cpp new file mode 100644 index 0000000..e55969c --- /dev/null +++ b/source/time/unix/timezone.cpp @@ -0,0 +1,85 @@ +#include +#include +#include "timestamp.h" +#include "timezone.h" +#include "utils.h" + +using namespace std; + +namespace { + +long get_long(char *&ptr) +{ + long result = 0; + for(unsigned i=0; i<4; ++i) + result = (result<<8)+static_cast(*ptr++); + return result; +} + +} + + +namespace Msp { +namespace Time { + +TimeZone TimeZone::platform_get_local_timezone() +{ + int fd = open("/etc/localtime", O_RDONLY); + if(fd!=-1) + { + char hdr[44]; + int len = read(fd, hdr, sizeof(hdr)); + long gmtoff = -1; + string name; + if(len==44 && hdr[0]=='T' && hdr[1]=='Z' && hdr[2]=='i' && hdr[3]=='f') + { + char *ptr = hdr+20; + long isgmtcnt = get_long(ptr); + long isstdcnt = get_long(ptr); + long leapcnt = get_long(ptr); + long timecnt = get_long(ptr); + long typecnt = get_long(ptr); + long charcnt = get_long(ptr); + int size = timecnt*5+typecnt*6+isgmtcnt+isstdcnt+leapcnt*8+charcnt; + char *buf = new char[size]; + len = read(fd, buf, size); + if(len==size) + { + ptr = buf; + int index = -1; + time_t cur_time = Msp::Time::now().to_unixtime(); + for(int i=0; i0) + index = ptr[index]; + ptr += timecnt; + + int abbrind = 0; + for(int i=0; i=0 && i==index) || (index<0 && !ptr[4] && gmtoff==-1)) + { + gmtoff = get_long(ptr); + ++ptr; + abbrind = *ptr++; + } + else + ptr += 6; + } + + name = ptr+abbrind; + } + delete[] buf; + } + close(fd); + + if(gmtoff!=-1) + return TimeZone(gmtoff/60, name); + } + return TimeZone(); +} + +} // namespace Time +} // namespace Msp diff --git a/source/time/unix/utils.cpp b/source/time/unix/utils.cpp new file mode 100644 index 0000000..029c75b --- /dev/null +++ b/source/time/unix/utils.cpp @@ -0,0 +1,36 @@ +#include +#include +#include +#include +#include "rawtime_private.h" +#include "timedelta.h" +#include "timestamp.h" +#include "utils.h" + +namespace Msp { +namespace Time { + +TimeStamp now() +{ + timeval tv; + gettimeofday(&tv, 0); + return TimeStamp(timeval_to_rawtime(tv)); +} + +TimeDelta get_cpu_time() +{ + rusage ru; + getrusage(RUSAGE_SELF, &ru); + return (ru.ru_utime.tv_sec+ru.ru_stime.tv_sec)*sec + (ru.ru_utime.tv_usec+ru.ru_stime.tv_usec)*usec; +} + +void sleep(const TimeDelta &d) +{ + timespec ts = rawtime_to_timespec(d.raw()); + while(nanosleep(&ts, 0)==-1) + if(errno!=EINTR) + throw system_error("nanosleep"); +} + +} // namespace Time +} // namespace Msp diff --git a/source/time/utils.cpp b/source/time/utils.cpp index 9c643cf..52c8934 100644 --- a/source/time/utils.cpp +++ b/source/time/utils.cpp @@ -1,14 +1,4 @@ -#ifdef WIN32 -#include -#else -#include -#include -#include -#endif -#include #include "datetime.h" -#include "rawtime_private.h" -#include "timedelta.h" #include "timestamp.h" #include "utils.h" @@ -17,47 +7,10 @@ using namespace std; namespace Msp { namespace Time { -TimeStamp now() -{ -#ifndef WIN32 - timeval tv; - gettimeofday(&tv, 0); - return TimeStamp(timeval_to_rawtime(tv)); -#else - FILETIME ft; - GetSystemTimeAsFileTime(&ft); - return TimeStamp(filetime_to_rawtime(ft)); -#endif -} - string format_now(const string &fmt) { return DateTime(now()).format(fmt); } -TimeDelta get_cpu_time() -{ -#ifndef WIN32 - rusage ru; - getrusage(RUSAGE_SELF, &ru); - return (ru.ru_utime.tv_sec+ru.ru_stime.tv_sec)*sec + (ru.ru_utime.tv_usec+ru.ru_stime.tv_usec)*usec; -#else - //XXX Figure out the function to use on Win32 - return TimeDelta(); -#endif -} - -void sleep(const TimeDelta &d) -{ -#ifndef WIN32 - timespec ts = rawtime_to_timespec(d.raw()); - while(nanosleep(&ts, 0)==-1) - if(errno!=EINTR) - throw system_error("nanosleep"); -#else - Sleep((DWORD)(d/msec)); -#endif -} - } // namespace Time } // namespace Msp diff --git a/source/time/rawtime.cpp b/source/time/windows/rawtime.cpp similarity index 62% rename from source/time/rawtime.cpp rename to source/time/windows/rawtime.cpp index a299246..b6276f0 100644 --- a/source/time/rawtime.cpp +++ b/source/time/windows/rawtime.cpp @@ -3,7 +3,6 @@ namespace { -#ifdef WIN32 /// Returns the unixtime epoch as filetime Msp::Time::RawTime get_epoch() { @@ -20,43 +19,18 @@ Msp::Time::RawTime get_epoch() SystemTimeToFileTime(&st, &ft); return (ft.dwLowDateTime+(static_cast(ft.dwHighDateTime)<<32))/10; } -#endif } - namespace Msp { namespace Time { -#ifdef WIN32 RawTime filetime_to_rawtime(const FILETIME &ft) { static RawTime epoch = get_epoch(); return (ft.dwLowDateTime+(static_cast(ft.dwHighDateTime)<<32))/10-epoch; } -#else -timeval rawtime_to_timeval(RawTime raw) -{ - timeval tv; - tv.tv_sec = raw/1000000; - tv.tv_usec = raw%1000000; - return tv; -} - -timespec rawtime_to_timespec(RawTime raw) -{ - timespec ts; - ts.tv_sec = raw/1000000; - ts.tv_nsec = (raw%1000000)*1000; - return ts; -} - -RawTime timeval_to_rawtime(const timeval &tv) -{ - return tv.tv_sec*1000000LL+tv.tv_usec; -} -#endif } // namespace Time } // namespace Msp diff --git a/source/time/windows/rawtime_platform.h b/source/time/windows/rawtime_platform.h new file mode 100644 index 0000000..60a9a59 --- /dev/null +++ b/source/time/windows/rawtime_platform.h @@ -0,0 +1,15 @@ +#ifndef MSP_TIME_RAWTIME_PLATFORM_H_ +#define MSP_TIME_RAWTIME_PLATFORM_H_ + +#include +#include "rawtime.h" + +namespace Msp { +namespace Time { + +RawTime filetime_to_rawtime(const FILETIME &); + +} // namespace Time +} // namespace Msp + +#endif diff --git a/source/time/windows/timezone.cpp b/source/time/windows/timezone.cpp new file mode 100644 index 0000000..570c679 --- /dev/null +++ b/source/time/windows/timezone.cpp @@ -0,0 +1,25 @@ +#include +#include +#include "timezone.h" + +namespace Msp { +namespace Time { + +TimeZone TimeZone::platform_get_local_timezone() +{ + TIME_ZONE_INFORMATION tzinfo; + DWORD dst = GetTimeZoneInformation(&tzinfo); + if(dst==TIME_ZONE_ID_INVALID) + throw Msp::system_error("GetTimeZoneInformation"); + + int offset = tzinfo.Bias; + if(dst==TIME_ZONE_ID_STANDARD) + offset += tzinfo.StandardBias; + else if(dst==TIME_ZONE_ID_DAYLIGHT) + offset += tzinfo.DaylightBias; + + return TimeZone(offset); +} + +} // namespace Time +} // namespace Msp diff --git a/source/time/windows/utils.cpp b/source/time/windows/utils.cpp new file mode 100644 index 0000000..2150a10 --- /dev/null +++ b/source/time/windows/utils.cpp @@ -0,0 +1,29 @@ +#include +#include "rawtime_private.h" +#include "timedelta.h" +#include "timestamp.h" +#include "utils.h" + +namespace Msp { +namespace Time { + +TimeStamp now() +{ + FILETIME ft; + GetSystemTimeAsFileTime(&ft); + return TimeStamp(filetime_to_rawtime(ft)); +} + +TimeDelta get_cpu_time() +{ + //XXX Figure out the function to use on Win32 + return TimeDelta(); +} + +void sleep(const TimeDelta &d) +{ + Sleep((DWORD)(d/msec)); +} + +} // namespace Time +} // namespace Msp -- 2.45.2 From 87edba02a23b1338934e36fac407966b25fcf811 Mon Sep 17 00:00:00 2001 From: Mikko Rasa Date: Wed, 24 Apr 2013 16:40:27 +0300 Subject: [PATCH 04/16] Add missing terminator entries to some test data arrays --- tests/lexicalcast.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tests/lexicalcast.cpp b/tests/lexicalcast.cpp index 2a4a787..37439fc 100644 --- a/tests/lexicalcast.cpp +++ b/tests/lexicalcast.cpp @@ -99,6 +99,7 @@ void LexicalCastTests::oct_integers() { 012345, "%#08o", "00012345" }, { 012345, "%+#o", "+012345" }, { -012345, "%#o", "-012345" }, + { 0, 0, 0 } }; test_values(values); } @@ -114,6 +115,7 @@ void LexicalCastTests::bin_integers() { 0xcf3, "%#016b", "0b00110011110011" }, { 0xcf3, "%+#b", "+0b110011110011" }, { -0xcf3, "%#b", "-0b110011110011" }, + { 0, 0, 0 } }; test_values(values); } -- 2.45.2 From 9c6c946ed658abd50be9d597cb2c722592d660ae Mon Sep 17 00:00:00 2001 From: Mikko Rasa Date: Tue, 30 Apr 2013 15:57:45 +0300 Subject: [PATCH 05/16] Move GetOpt exception handling to the .cpp file --- source/core/getopt.cpp | 20 ++++++++++++++++++-- source/core/getopt.h | 22 ++-------------------- 2 files changed, 20 insertions(+), 22 deletions(-) diff --git a/source/core/getopt.cpp b/source/core/getopt.cpp index 34e5317..ad72644 100644 --- a/source/core/getopt.cpp +++ b/source/core/getopt.cpp @@ -257,22 +257,38 @@ void GetOpt::OptBase::process() { if(arg_type==REQUIRED_ARG) throw usage_error("--"+lng+" requires an argument"); + ++seen_count; if(ext_seen_count) *ext_seen_count = seen_count; - store(); + try + { + store(); + } + catch(const exception &e) + { + throw usage_error("Invalid argument for --"+lng+" ("+e.what()+")"); + } } void GetOpt::OptBase::process(const string &arg) { if(arg_type==NO_ARG) throw usage_error("--"+lng+" takes no argument"); + ++seen_count; if(ext_seen_count) *ext_seen_count = seen_count; - store(arg); + try + { + store(arg); + } + catch(const exception &e) + { + throw usage_error("Invalid argument for --"+lng+" ("+e.what()+")"); + } } } // namespace Msp diff --git a/source/core/getopt.h b/source/core/getopt.h index 2aaceef..53c9ddf 100644 --- a/source/core/getopt.h +++ b/source/core/getopt.h @@ -122,16 +122,7 @@ private: virtual void store() { } virtual void store(const std::string &a) - { - try - { - data = lexical_cast(a); - } - catch(const lexical_error &e) - { - throw usage_error("Invalid argument for --"+lng+" ("+e.what()+")"); - } - } + { data = lexical_cast(a); } }; template @@ -147,16 +138,7 @@ private: virtual void store() { } virtual void store(const std::string &a) - { - try - { - data.push_back(lexical_cast(a)); - } - catch(const lexical_error &e) - { - throw usage_error("Invalid argument for --"+lng+" ("+e.what()+")"); - } - } + { data.push_back(lexical_cast(a)); } }; bool help; -- 2.45.2 From 7e11b20594ae05177fe36701422a0faf6120c0b0 Mon Sep 17 00:00:00 2001 From: Mikko Rasa Date: Thu, 2 May 2013 12:58:36 +0300 Subject: [PATCH 06/16] Use a typedef for the option descriptor list --- source/core/getopt.cpp | 16 ++++++++-------- source/core/getopt.h | 4 +++- 2 files changed, 11 insertions(+), 9 deletions(-) diff --git a/source/core/getopt.cpp b/source/core/getopt.cpp index ad72644..2bbfebc 100644 --- a/source/core/getopt.cpp +++ b/source/core/getopt.cpp @@ -13,13 +13,13 @@ GetOpt::GetOpt(): GetOpt::~GetOpt() { - for(list::iterator i=opts.begin(); i!=opts.end(); ++i) + for(OptionList::iterator i=opts.begin(); i!=opts.end(); ++i) delete *i; } GetOpt::OptBase &GetOpt::add_option(OptBase *opt) { - for(list::iterator i=opts.begin(); i!=opts.end(); ) + for(OptionList::iterator i=opts.begin(); i!=opts.end(); ) { if((opt->get_short()!=0 && (*i)->get_short()==opt->get_short()) || (*i)->get_long()==opt->get_long()) { @@ -36,7 +36,7 @@ GetOpt::OptBase &GetOpt::add_option(OptBase *opt) GetOpt::OptBase &GetOpt::get_option(char s) { - for(list::iterator i=opts.begin(); i!=opts.end(); ++i) + for(OptionList::iterator i=opts.begin(); i!=opts.end(); ++i) if((*i)->get_short()==s) return **i; throw usage_error(string("Unknown option -")+s); @@ -44,7 +44,7 @@ GetOpt::OptBase &GetOpt::get_option(char s) GetOpt::OptBase &GetOpt::get_option(const string &l) { - for(list::iterator i=opts.begin(); i!=opts.end(); ++i) + for(OptionList::iterator i=opts.begin(); i!=opts.end(); ++i) if((*i)->get_long()==l) return **i; throw usage_error(string("Unknown option --")+l); @@ -149,7 +149,7 @@ unsigned GetOpt::process_short(const char *const *argp) string GetOpt::generate_usage(const string &argv0) const { string result = argv0; - for(list::const_iterator i=opts.begin(); i!=opts.end(); ++i) + for(OptionList::const_iterator i=opts.begin(); i!=opts.end(); ++i) { result += " ["; if((*i)->get_short()) @@ -180,12 +180,12 @@ string GetOpt::generate_usage(const string &argv0) const string GetOpt::generate_help() const { bool any_short = false; - for(list::const_iterator i=opts.begin(); (!any_short && i!=opts.end()); ++i) + for(OptionList::const_iterator i=opts.begin(); (!any_short && i!=opts.end()); ++i) any_short = (*i)->get_short(); string::size_type maxw = 0; list switches; - for(list::const_iterator i=opts.begin(); i!=opts.end(); ++i) + for(OptionList::const_iterator i=opts.begin(); i!=opts.end(); ++i) { string swtch; if((*i)->get_short()) @@ -215,7 +215,7 @@ string GetOpt::generate_help() const string result; list::const_iterator j = switches.begin(); - for(list::const_iterator i=opts.begin(); i!=opts.end(); ++i, ++j) + for(OptionList::const_iterator i=opts.begin(); i!=opts.end(); ++i, ++j) result += format(" %s%s%s\n", *j, string(maxw+2-j->size(), ' '), (*i)->get_help()); return result; diff --git a/source/core/getopt.h b/source/core/getopt.h index 53c9ddf..4f53cc2 100644 --- a/source/core/getopt.h +++ b/source/core/getopt.h @@ -141,8 +141,10 @@ private: { data.push_back(lexical_cast(a)); } }; + typedef std::list OptionList; + bool help; - std::list opts; + OptionList opts; std::vector args; public: -- 2.45.2 From b27a278d8ab85afbad191d14962cc33e894718d4 Mon Sep 17 00:00:00 2001 From: Mikko Rasa Date: Thu, 2 May 2013 14:21:19 +0300 Subject: [PATCH 07/16] Restructure internals of GetOpt Value storage is now handled by a separate class hierarchy, making it more reusable. --- source/core/getopt.cpp | 42 +++++++++++++++------------ source/core/getopt.h | 64 ++++++++++++++++++++++++++---------------- 2 files changed, 64 insertions(+), 42 deletions(-) diff --git a/source/core/getopt.cpp b/source/core/getopt.cpp index 2bbfebc..e909712 100644 --- a/source/core/getopt.cpp +++ b/source/core/getopt.cpp @@ -17,11 +17,14 @@ GetOpt::~GetOpt() delete *i; } -GetOpt::OptBase &GetOpt::add_option(OptBase *opt) +GetOpt::OptionImpl &GetOpt::add_option(char s, const string &l, const Store &t, ArgType a) { + if(l.empty()) + throw invalid_argument("GetOpt::add_option"); + for(OptionList::iterator i=opts.begin(); i!=opts.end(); ) { - if((opt->get_short()!=0 && (*i)->get_short()==opt->get_short()) || (*i)->get_long()==opt->get_long()) + if((s!=0 && (*i)->get_short()==s) || (*i)->get_long()==l) { delete *i; opts.erase(i++); @@ -30,11 +33,11 @@ GetOpt::OptBase &GetOpt::add_option(OptBase *opt) ++i; } - opts.push_back(opt); + opts.push_back(new OptionImpl(s, l, t, a)); return *opts.back(); } -GetOpt::OptBase &GetOpt::get_option(char s) +GetOpt::OptionImpl &GetOpt::get_option(char s) { for(OptionList::iterator i=opts.begin(); i!=opts.end(); ++i) if((*i)->get_short()==s) @@ -42,7 +45,7 @@ GetOpt::OptBase &GetOpt::get_option(char s) throw usage_error(string("Unknown option -")+s); } -GetOpt::OptBase &GetOpt::get_option(const string &l) +GetOpt::OptionImpl &GetOpt::get_option(const string &l) { for(OptionList::iterator i=opts.begin(); i!=opts.end(); ++i) if((*i)->get_long()==l) @@ -94,7 +97,7 @@ unsigned GetOpt::process_long(const char *const *argp) unsigned equals = 0; for(; arg[equals] && arg[equals]!='='; ++equals) ; - OptBase &opt = get_option(string(arg, equals)); + OptionImpl &opt = get_option(string(arg, equals)); if(arg[equals]) // Process the part after the = as option argument @@ -122,7 +125,7 @@ unsigned GetOpt::process_short(const char *const *argp) // Loop through all characters in the argument for(; *arg; ++arg) { - OptBase &opt = get_option(*arg); + OptionImpl &opt = get_option(*arg); if(arg[1] && opt.get_arg_type()!=NO_ARG) { @@ -222,38 +225,41 @@ string GetOpt::generate_help() const } -GetOpt::OptBase::OptBase(char s, const std::string &l, ArgType a): +GetOpt::OptionImpl::OptionImpl(char s, const std::string &l, const Store &t, ArgType a): shrt(s), lng(l), arg_type(a), seen_count(0), ext_seen_count(0), - metavar("ARG") + metavar("ARG"), + store(t.clone()) +{ } + +GetOpt::OptionImpl::~OptionImpl() { - if(lng.empty()) - throw invalid_argument("empty long option name"); + delete store; } -GetOpt::OptBase &GetOpt::OptBase::set_help(const string &h) +GetOpt::OptionImpl &GetOpt::OptionImpl::set_help(const string &h) { help = h; return *this; } -GetOpt::OptBase &GetOpt::OptBase::set_help(const string &h, const string &m) +GetOpt::OptionImpl &GetOpt::OptionImpl::set_help(const string &h, const string &m) { help = h; metavar = m; return *this; } -GetOpt::OptBase &GetOpt::OptBase::bind_seen_count(unsigned &c) +GetOpt::OptionImpl &GetOpt::OptionImpl::bind_seen_count(unsigned &c) { ext_seen_count = &c; return *this; } -void GetOpt::OptBase::process() +void GetOpt::OptionImpl::process() { if(arg_type==REQUIRED_ARG) throw usage_error("--"+lng+" requires an argument"); @@ -264,7 +270,7 @@ void GetOpt::OptBase::process() try { - store(); + store->store(); } catch(const exception &e) { @@ -272,7 +278,7 @@ void GetOpt::OptBase::process() } } -void GetOpt::OptBase::process(const string &arg) +void GetOpt::OptionImpl::process(const string &arg) { if(arg_type==NO_ARG) throw usage_error("--"+lng+" takes no argument"); @@ -283,7 +289,7 @@ void GetOpt::OptBase::process(const string &arg) try { - store(arg); + store->store(arg); } catch(const exception &e) { diff --git a/source/core/getopt.h b/source/core/getopt.h index 4f53cc2..911934a 100644 --- a/source/core/getopt.h +++ b/source/core/getopt.h @@ -79,7 +79,20 @@ public: }; private: - class OptBase: public Option + class Store + { + protected: + Store() { } + public: + virtual ~Store() { } + + virtual Store *clone() const = 0; + + virtual void store() = 0; + virtual void store(const std::string &) = 0; + }; + + class OptionImpl: public Option { protected: char shrt; @@ -89,14 +102,15 @@ private: unsigned *ext_seen_count; std::string help; std::string metavar; + Store *store; - OptBase(char, const std::string &, ArgType); public: - virtual ~OptBase() { } + OptionImpl(char, const std::string &, const Store &, ArgType); + virtual ~OptionImpl(); - virtual OptBase &set_help(const std::string &); - virtual OptBase &set_help(const std::string &, const std::string &); - virtual OptBase &bind_seen_count(unsigned &); + virtual OptionImpl &set_help(const std::string &); + virtual OptionImpl &set_help(const std::string &, const std::string &); + virtual OptionImpl &bind_seen_count(unsigned &); char get_short() const { return shrt; } const std::string &get_long() const { return lng; } ArgType get_arg_type() const { return arg_type; } @@ -105,19 +119,19 @@ private: virtual unsigned get_seen_count() const { return seen_count; } void process(); void process(const std::string &); - protected: - virtual void store() = 0; - virtual void store(const std::string &) = 0; }; template - class SimpleOption: public OptBase + class SimpleStore: public Store { private: T &data; public: - SimpleOption(char s, const std::string &l, T &d, ArgType a): OptBase(s, l, a), data(d) { } + SimpleStore(T &d): data(d) { } + + virtual SimpleStore *clone() const + { return new SimpleStore(data); } virtual void store() { } @@ -126,14 +140,16 @@ private: }; template - class ListOption: public OptBase + class ListStore: public Store { private: T &data; public: - ListOption(char s, const std::string &l, T &d, ArgType a): OptBase(s, l, a), data(d) - { if(arg_type!=REQUIRED_ARG) throw std::invalid_argument("ListOption arg_type!=REQUIRED"); } + ListStore(T &d): data(d) { } + + virtual ListStore *clone() const + { return new ListStore(data); } virtual void store() { } @@ -141,7 +157,7 @@ private: { data.push_back(lexical_cast(a)); } }; - typedef std::list OptionList; + typedef std::list OptionList; bool help; OptionList opts; @@ -161,14 +177,14 @@ public: and an unsigned will be incremented; any other type will be ignored. */ template Option &add_option(char s, const std::string &l, T &d, ArgType a = NO_ARG) - { return add_option(new SimpleOption(s, l, d, a)); } + { return add_option(s, l, SimpleStore(d), a); } /** Adds an option with both short and long forms. The option may be specified multiple times, and the argument from each occurrence is stored in the list. The argument type must be REQUIRED_ARG. */ template Option &add_option(char s, const std::string &l, std::list &d, ArgType a = REQUIRED_ARG) - { return add_option(new ListOption >(s, l, d, a)); } + { return add_option(s, l, ListStore >(d), a); } /** Adds an option with only a long form. */ template @@ -176,10 +192,10 @@ public: { return add_option(0, l, d, a); } private: - OptBase &add_option(OptBase *); + OptionImpl &add_option(char, const std::string &, const Store &, ArgType); - OptBase &get_option(char); - OptBase &get_option(const std::string &); + OptionImpl &get_option(char); + OptionImpl &get_option(const std::string &); public: /** Processes argc/argv style command line arguments. The contents of argv @@ -202,16 +218,16 @@ public: std::string generate_help() const; }; -template<> inline void GetOpt::SimpleOption::store() +template<> inline void GetOpt::SimpleStore::store() { data = true; } -template<> inline void GetOpt::SimpleOption::store() +template<> inline void GetOpt::SimpleStore::store() { ++data; } -template<> inline void GetOpt::SimpleOption::store(const std::string &a) +template<> inline void GetOpt::SimpleStore::store(const std::string &a) { data = a; } -template<> inline void GetOpt::ListOption >::store(const std::string &a) +template<> inline void GetOpt::ListStore >::store(const std::string &a) { data.push_back(a); } } // namespace Msp -- 2.45.2 From 6f0c4c39133e08c05ffb1f1d53141a7e80ba6351 Mon Sep 17 00:00:00 2001 From: Mikko Rasa Date: Fri, 3 May 2013 12:40:20 +0300 Subject: [PATCH 08/16] Restore the check that list options must take an argument --- source/core/getopt.cpp | 2 ++ source/core/getopt.h | 5 +++++ 2 files changed, 7 insertions(+) diff --git a/source/core/getopt.cpp b/source/core/getopt.cpp index e909712..fdeb2f8 100644 --- a/source/core/getopt.cpp +++ b/source/core/getopt.cpp @@ -21,6 +21,8 @@ GetOpt::OptionImpl &GetOpt::add_option(char s, const string &l, const Store &t, { if(l.empty()) throw invalid_argument("GetOpt::add_option"); + if(t.is_list() && a!=REQUIRED_ARG) + throw invalid_argument("GetOpt::add_option"); for(OptionList::iterator i=opts.begin(); i!=opts.end(); ) { diff --git a/source/core/getopt.h b/source/core/getopt.h index 911934a..70841cb 100644 --- a/source/core/getopt.h +++ b/source/core/getopt.h @@ -88,6 +88,7 @@ private: virtual Store *clone() const = 0; + virtual bool is_list() const = 0; virtual void store() = 0; virtual void store(const std::string &) = 0; }; @@ -133,6 +134,8 @@ private: virtual SimpleStore *clone() const { return new SimpleStore(data); } + virtual bool is_list() const { return false; } + virtual void store() { } virtual void store(const std::string &a) @@ -151,6 +154,8 @@ private: virtual ListStore *clone() const { return new ListStore(data); } + virtual bool is_list() const { return true; } + virtual void store() { } virtual void store(const std::string &a) -- 2.45.2 From 5305cabf0b20a99a82aff4bcef26f2be0a8fd757 Mon Sep 17 00:00:00 2001 From: Mikko Rasa Date: Fri, 3 May 2013 12:42:27 +0300 Subject: [PATCH 09/16] Add support for positional arguments in GetOpt This addresses the issue of any positional arguments recognized by an application not showing up in the generated help text. It also reduces the amount of processing and validation required from the application itself and provides consistent error messages. --- source/core/getopt.cpp | 116 ++++++++++++++++++++++++++++++++++++++++- source/core/getopt.h | 75 ++++++++++++++++++++++---- 2 files changed, 180 insertions(+), 11 deletions(-) diff --git a/source/core/getopt.cpp b/source/core/getopt.cpp index fdeb2f8..2561c9a 100644 --- a/source/core/getopt.cpp +++ b/source/core/getopt.cpp @@ -15,6 +15,8 @@ GetOpt::~GetOpt() { for(OptionList::iterator i=opts.begin(); i!=opts.end(); ++i) delete *i; + for(ArgumentList::iterator i=args.begin(); i!=args.end(); ++i) + delete *i; } GetOpt::OptionImpl &GetOpt::add_option(char s, const string &l, const Store &t, ArgType a) @@ -39,6 +41,30 @@ GetOpt::OptionImpl &GetOpt::add_option(char s, const string &l, const Store &t, return *opts.back(); } +GetOpt::ArgumentImpl &GetOpt::add_argument(const string &n, const Store &t, ArgType a) +{ + if(a==NO_ARG) + throw invalid_argument("GetOpt::add_argument"); + + bool have_list = false; + bool have_optional = false; + for(ArgumentList::const_iterator i=args.begin(); i!=args.end(); ++i) + { + if((*i)->is_list_store()) + have_list = true; + else if((*i)->get_type()==OPTIONAL_ARG) + have_optional = true; + } + + if(have_optional && (t.is_list() || a!=OPTIONAL_ARG)) + throw invalid_argument("GetOpt::add_argument"); + if(have_list && (t.is_list() || a==OPTIONAL_ARG)) + throw invalid_argument("GetOpt::add_argument"); + + args.push_back(new ArgumentImpl(n, t, a)); + return *args.back(); +} + GetOpt::OptionImpl &GetOpt::get_option(char s) { for(OptionList::iterator i=opts.begin(); i!=opts.end(); ++i) @@ -59,6 +85,8 @@ void GetOpt::operator()(unsigned argc, const char *const *argv) { try { + /* Arguments must first be collected into an array to handle the case + where a variable-length argument list is followed by fixed arguments. */ unsigned i = 1; for(; iis_list_store()) + { + unsigned end = args_raw.size(); + for(ArgumentList::const_iterator k=j; ++k!=args.end(); ) + --end; + if(i==end && (*j)->get_type()==REQUIRED_ARG) + throw usage_error((*j)->get_name()+" is required"); + for(; iprocess(args_raw[i]); + } + else + { + if(iprocess(args_raw[i++]); + else if((*j)->get_type()==REQUIRED_ARG) + throw usage_error((*j)->get_name()+" is required"); + } + } + + // XXX Enable this when get_args() is completely removed + /*if(iget_type()==OPTIONAL_ARG) + result += '['; + result += format("<%s>", (*i)->get_name()); + if((*i)->is_list_store()) + result += " ..."; + if((*i)->get_type()==OPTIONAL_ARG) + result += ']'; + } + return result; } @@ -218,10 +284,26 @@ string GetOpt::generate_help() const maxw = max(maxw, swtch.size()); } + list pargs; + for(ArgumentList::const_iterator i=args.begin(); i!=args.end(); ++i) + { + string parg = format("<%s>", (*i)->get_name()); + pargs.push_back(parg); + maxw = max(maxw, parg.size()); + } + string result; + result += "Options:\n"; list::const_iterator j = switches.begin(); for(OptionList::const_iterator i=opts.begin(); i!=opts.end(); ++i, ++j) result += format(" %s%s%s\n", *j, string(maxw+2-j->size(), ' '), (*i)->get_help()); + if(!pargs.empty()) + { + result += "\nArguments:\n"; + j = pargs.begin(); + for(ArgumentList::const_iterator i=args.begin(); i!=args.end(); ++i, ++j) + result += format(" %s%s%s\n", *j, string(maxw+2-j->size(), ' '), (*i)->get_help()); + } return result; } @@ -299,4 +381,34 @@ void GetOpt::OptionImpl::process(const string &arg) } } + +GetOpt::ArgumentImpl::ArgumentImpl(const string &n, const Store &t, ArgType a): + name(n), + type(a), + store(t.clone()) +{ } + +GetOpt::ArgumentImpl::~ArgumentImpl() +{ + delete store; +} + +GetOpt::ArgumentImpl &GetOpt::ArgumentImpl::set_help(const string &h) +{ + help = h; + return *this; +} + +void GetOpt::ArgumentImpl::process(const string &arg) +{ + try + { + store->store(arg); + } + catch(const exception &e) + { + throw usage_error("Invalid "+name+" ("+e.what()+")"); + } +} + } // namespace Msp diff --git a/source/core/getopt.h b/source/core/getopt.h index 70841cb..f4e318e 100644 --- a/source/core/getopt.h +++ b/source/core/getopt.h @@ -44,9 +44,19 @@ A single option may have both alternative forms, but must always have at least a long form. This is to encourage self-documenting options; it's much easier to remember words than letters. -A built-in --help option is provided and will output a list of options and -their associated help texts. An application may override this by providing -its own option with the same name. +Positional arguments are also supported. They are identified by an arbitrary +string, but the identifier is only used in help text and error messages. Any +number of the final arguments may be optional. + +To support applications that take an arbitrary amount of arguments, a single +positional argument list can be specified. Fixed positional arguments are +allowed together with a list, but they can't be optional. An application that +wants to do complex processing on the argument list can declare a list of +string arguments. + +A built-in --help option is provided and will output a list of options, +arguments and their associated help texts. An application may override this by +providing its own option with the same name. */ class GetOpt { @@ -78,6 +88,16 @@ public: virtual unsigned get_seen_count() const = 0; }; + class Argument + { + protected: + Argument() { } + public: + virtual ~Argument() { } + + virtual Argument &set_help(const std::string &) = 0; + }; + private: class Store { @@ -122,6 +142,26 @@ private: void process(const std::string &); }; + class ArgumentImpl: public Argument + { + private: + std::string name; + ArgType type; + std::string help; + Store *store; + + public: + ArgumentImpl(const std::string &, const Store &, ArgType); + virtual ~ArgumentImpl(); + + virtual ArgumentImpl &set_help(const std::string &); + const std::string &get_name() const { return name; } + ArgType get_type() const { return type; } + const std::string &get_help() const { return help; } + bool is_list_store() const { return store->is_list(); } + void process(const std::string &); + }; + template class SimpleStore: public Store { @@ -163,17 +203,20 @@ private: }; typedef std::list OptionList; + typedef std::list ArgumentList; bool help; OptionList opts; - std::vector args; + ArgumentList args; + std::vector args_raw; public: GetOpt(); ~GetOpt(); - /// Returns any non-option arguments encountered during processing. - const std::vector &get_args() const { return args; } + /** Returns any non-option arguments encountered during processing. + Deprecated. */ + const std::vector &get_args() const { return args_raw; } /** Adds an option with both short and long forms. Processing depends on the type of the destination variable and whether an argument is taken or @@ -196,8 +239,22 @@ public: Option &add_option(const std::string &l, T &d, ArgType a) { return add_option(0, l, d, a); } + /** Adds a positional argument. The value will be lexical_cast to the + appropriate type and stored in the destination. */ + template + Argument &add_argument(const std::string &n, T &d, ArgType a = REQUIRED_ARG) + { return add_argument(n, SimpleStore(d), a); } + + /** Adds a positional argument list. If the list is declared as required, + at least one element must be given; an optional list may be empty. Only one + list may be added, and optional fixed arguments can't be used with it. */ + template + Argument &add_argument(const std::string &n, std::list &d, ArgType a = REQUIRED_ARG) + { return add_argument(n, ListStore >(d), a); } + private: OptionImpl &add_option(char, const std::string &, const Store &, ArgType); + ArgumentImpl &add_argument(const std::string &, const Store &, ArgType); OptionImpl &get_option(char); OptionImpl &get_option(const std::string &); @@ -215,11 +272,11 @@ private: unsigned process_short(const char *const *); public: - /** Generates a single line that describes known options. */ + /** Generates a single line that describes known options and arguments. */ std::string generate_usage(const std::string &) const; - /** Generates help for known options in tabular format, one option per - line. The returned string will have a linefeed at the end. */ + /** Generates help for known options and arguments in tabular format, one + item per line. The returned string will have a linefeed at the end. */ std::string generate_help() const; }; -- 2.45.2 From 47750d0e06f00e46ea03eda334a4c777bf213d72 Mon Sep 17 00:00:00 2001 From: Mikko Rasa Date: Fri, 3 May 2013 12:46:49 +0300 Subject: [PATCH 10/16] Add new test cases to cover positional arguments --- tests/getopt.cpp | 111 ++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 105 insertions(+), 6 deletions(-) diff --git a/tests/getopt.cpp b/tests/getopt.cpp index cb5df62..e688868 100644 --- a/tests/getopt.cpp +++ b/tests/getopt.cpp @@ -15,11 +15,16 @@ private: void short_options(); void long_options(); void arguments(); - void non_options(); + void positional(); + void positional_list(); + void empty_list(); + void mixed(); void help(); void invalid_option(); void invalid_arg(); void missing_arg(); + void missing_positional(); + void missing_positional_list(); }; GetOptTests::GetOptTests() @@ -27,11 +32,16 @@ GetOptTests::GetOptTests() add(&GetOptTests::short_options, "Short options"); add(&GetOptTests::long_options, "Long options"); add(&GetOptTests::arguments, "Option arguments"); - add(&GetOptTests::non_options, "Non-options"); + add(&GetOptTests::positional, "Positional arguments"); + add(&GetOptTests::positional_list, "Positional argument list"); + add(&GetOptTests::empty_list, "Empty positional argument list"); + add(&GetOptTests::mixed, "Mixed options and positional arguments"); add(&GetOptTests::help, "Help").expect_throw(); add(&GetOptTests::invalid_option, "Invalid option").expect_throw(); - add(&GetOptTests::invalid_arg, "Invalid argument").expect_throw(); - add(&GetOptTests::missing_arg, "Missing argument").expect_throw(); + add(&GetOptTests::invalid_arg, "Invalid option argument").expect_throw(); + add(&GetOptTests::missing_arg, "Missing option argument").expect_throw(); + add(&GetOptTests::missing_positional, "Missing positional argument").expect_throw(); + add(&GetOptTests::missing_positional_list, "Missing positional argument list").expect_throw(); } void GetOptTests::short_options() @@ -88,20 +98,87 @@ void GetOptTests::arguments() EXPECT_EQUAL(bar, 69); } -void GetOptTests::non_options() +void GetOptTests::positional() +{ + static const char *argv[] = { "test", "foo", "42", "bar", 0 }; + + string first; + unsigned second = 0; + string third; + unsigned fourth = 13; + + GetOpt getopt; + getopt.add_argument("first", first); + getopt.add_argument("second", second); + getopt.add_argument("third", third); + getopt.add_argument("fourth", fourth, GetOpt::OPTIONAL_ARG); + getopt(4, argv); + + EXPECT_EQUAL(first, "foo"); + EXPECT_EQUAL(second, 42); + EXPECT_EQUAL(third, "bar"); + EXPECT_EQUAL(fourth, 13); +} + +void GetOptTests::positional_list() +{ + static const char *argv[] = { "test", "x", "y", "z", "foo", 0 }; + + list args; + string tail; + + GetOpt getopt; + getopt.add_argument("arg", args); + getopt.add_argument("tail", tail); + getopt(5, argv); + + EXPECT_EQUAL(args.size(), 3U); + EXPECT_EQUAL(args.front(), "x"); + EXPECT_EQUAL(args.back(), "z"); + EXPECT_EQUAL(tail, "foo"); +} + +void GetOptTests::empty_list() +{ + static const char *argv[] = { "test", "foo", "bar", 0 }; + + string head; + list mid; + string tail; + + GetOpt getopt; + getopt.add_argument("head", head); + getopt.add_argument("mid", mid, GetOpt::OPTIONAL_ARG); + getopt.add_argument("tail", tail); + getopt(3, argv); + + EXPECT_EQUAL(head, "foo"); + EXPECT(mid.empty()); + EXPECT_EQUAL(tail, "bar"); +} + +void GetOptTests::mixed() { static const char *argv[] = { "test", "-a", "foo", "-b", "bar", "baz", 0 }; bool a = false; bool b = false; + string first; + string second; + string third; GetOpt getopt; getopt.add_option('a', "a", a, GetOpt::NO_ARG); getopt.add_option('b', "b", b, GetOpt::NO_ARG); + getopt.add_argument("first", first); + getopt.add_argument("second", second); + getopt.add_argument("third", third); getopt(6, argv); EXPECT(a && b); - EXPECT_EQUAL(getopt.get_args().size(), 3U); + EXPECT_EQUAL(first, "foo"); + EXPECT_EQUAL(second, "bar"); + EXPECT_EQUAL(third, "baz"); } void GetOptTests::help() @@ -139,3 +216,25 @@ void GetOptTests::missing_arg() getopt.add_option("value", value, GetOpt::REQUIRED_ARG); getopt(2, argv); } + +void GetOptTests::missing_positional() +{ + static const char *argv[] = { "test", 0 }; + + string arg; + + GetOpt getopt; + getopt.add_argument("arg", arg); + getopt(1, argv); +} + +void GetOptTests::missing_positional_list() +{ + static const char *argv[] = { "test", 0 }; + + list args; + + GetOpt getopt; + getopt.add_argument("arg", args); + getopt(1, argv); +} -- 2.45.2 From b54e273fec47af51792955143e84417b638ad2b7 Mon Sep 17 00:00:00 2001 From: Mikko Rasa Date: Fri, 3 May 2013 12:47:24 +0300 Subject: [PATCH 11/16] Cosmetic fixes for comments and output --- source/core/getopt.cpp | 2 +- source/core/getopt.h | 10 +++++----- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/source/core/getopt.cpp b/source/core/getopt.cpp index 2561c9a..e42ceb2 100644 --- a/source/core/getopt.cpp +++ b/source/core/getopt.cpp @@ -141,7 +141,7 @@ void GetOpt::operator()(unsigned argc, const char *const *argv) } if(help) - throw usage_error(string("Help for ")+argv[0]+":", generate_help()); + throw usage_error(string("Help for ")+argv[0]+":", "\nUsage:\n "+generate_usage(argv[0])+"\n\n"+generate_help()); } unsigned GetOpt::process_long(const char *const *argp) diff --git a/source/core/getopt.h b/source/core/getopt.h index f4e318e..411515f 100644 --- a/source/core/getopt.h +++ b/source/core/getopt.h @@ -33,12 +33,12 @@ the string "-abc" could be interpreted as having the options 'a', 'b' and 'c'. If the option takes an argument and there are unused characters in the argv element, then those characters are interpreted as the argument. Otherwise the next element is taken as the argument. An optional argument must be given in -the same element. +the same element if it is given. Long options begin with a double dash and are identified by an arbitrary string. An argument can be specified either in the same argv element, separated by an equals sign, or in the next element. As with short options, -an optional argument must be in the same element. +an optional argument, if given, must be in the same element. A single option may have both alternative forms, but must always have at least a long form. This is to encourage self-documenting options; it's much easier @@ -220,9 +220,9 @@ public: /** Adds an option with both short and long forms. Processing depends on the type of the destination variable and whether an argument is taken or - not. With an argument, the value is lexical_cast to appropriate type and - stored in the destination. Without an argument, a bool will be set to true - and an unsigned will be incremented; any other type will be ignored. */ + not. With an argument, the value is lexical_cast to the appropriate type + and stored in the destination. Without an argument, a bool will be set to + true and an unsigned will be incremented; any other type will be ignored. */ template Option &add_option(char s, const std::string &l, T &d, ArgType a = NO_ARG) { return add_option(s, l, SimpleStore(d), a); } -- 2.45.2 From c4bebb877ec98d518bf02152ca81930e18eda6a7 Mon Sep 17 00:00:00 2001 From: Mikko Rasa Date: Fri, 3 May 2013 12:47:51 +0300 Subject: [PATCH 12/16] Throw an exception for nonsensical arguments in some FS functions --- source/fs/utils.cpp | 6 ++++++ source/fs/utils.h | 5 +++-- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/source/fs/utils.cpp b/source/fs/utils.cpp index 2bfd1bf..ed1ca0a 100644 --- a/source/fs/utils.cpp +++ b/source/fs/utils.cpp @@ -71,6 +71,9 @@ Path fix_case(const Path &path) Path relative(const Path &path, const Path &base) { + if(path.is_absolute()!=base.is_absolute()) + throw invalid_argument("FS::relative"); + Path::Iterator i = path.begin(); Path::Iterator j = base.begin(); for(; (i!=path.end() && j!=base.end() && *i==*j); ++i, ++j) ; @@ -96,6 +99,9 @@ Path common_ancestor(const Path &path1, const Path &path2) int descendant_depth(const Path &path, const Path &parent) { + if(path.is_absolute()!=parent.is_absolute()) + throw invalid_argument("FS::descendant_depth"); + Path::Iterator i = path.begin(); Path::Iterator j = parent.begin(); for(; (i!=path.end() && j!=parent.end() && *i==*j); ++i, ++j) ; diff --git a/source/fs/utils.h b/source/fs/utils.h index a52e37d..e518d35 100644 --- a/source/fs/utils.h +++ b/source/fs/utils.h @@ -35,14 +35,15 @@ void unlink(const Path &path); /// Renames a file. Existing file, if any, is overwritten. void rename(const Path &from, const Path &to); -/// Makes a path relative to some base path. That is, base/result==path. +/** Makes a path relative to some base path. That is, base/result==path. Both +paths must be either absolute or relative. */ Path relative(const Path &path, const Path &base); /// Returns the longest prefix shared by both paths. Path common_ancestor(const Path &, const Path &); /** Determines how many levels a path is below another. Returns -1 if path is -not a descendant of parent. */ +not a descendant of parent. Both paths must be either absolute or relative. */ int descendant_depth(const Path &path, const Path &parent); } // namespace FS -- 2.45.2 From 844da6227b2b703a2180eae759d02809c6036cce Mon Sep 17 00:00:00 2001 From: Mikko Rasa Date: Fri, 3 May 2013 12:49:14 +0300 Subject: [PATCH 13/16] Add test cases for path manipulation functions --- tests/fsutils.cpp | 80 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 80 insertions(+) create mode 100644 tests/fsutils.cpp diff --git a/tests/fsutils.cpp b/tests/fsutils.cpp new file mode 100644 index 0000000..a17b5f5 --- /dev/null +++ b/tests/fsutils.cpp @@ -0,0 +1,80 @@ +#include +#include + +using namespace std; +using namespace Msp; + +class FSUtilTests: public Test::RegisteredTest +{ +public: + FSUtilTests(); + + static const char *get_name() { return "fsutils"; } + +private: + void pathsplit(); + void fnsplit(); + void hierarchy(); + void bad_hierarchy(); +}; + +FSUtilTests::FSUtilTests() +{ + add(&FSUtilTests::pathsplit, "Path splitting"); + add(&FSUtilTests::fnsplit, "Filename splitting"); + add(&FSUtilTests::hierarchy, "Hierarchy"); + add(&FSUtilTests::bad_hierarchy, "Bad hierarchy").expect_throw(); +} + +void FSUtilTests::pathsplit() +{ + FS::Path path("/foo/bar/baz"); + FS::Path dir = FS::dirname(path); + EXPECT_EQUAL(dir.str(), "/foo/bar"); + string base = FS::basename(path); + EXPECT_EQUAL(base, "baz"); +} + +void FSUtilTests::fnsplit() +{ + string filename = "file.png"; + string base = FS::basepart(filename); + EXPECT_EQUAL(base, "file"); + string ext = FS::extpart(filename); + EXPECT_EQUAL(ext, ".png"); + + filename = "file.tar.gz"; + base = FS::basepart(filename); + EXPECT_EQUAL(base, "file.tar"); + ext = FS::extpart(filename); + EXPECT_EQUAL(ext, ".gz"); +} + +void FSUtilTests::hierarchy() +{ + FS::Path path1 = "/foo/bar"; + FS::Path path2 = "/foo/bar/quux/baz"; + int depth = FS::descendant_depth(path2, path1); + EXPECT_EQUAL(depth, 2); + FS::Path rel = FS::relative(path2, path1); + EXPECT_EQUAL(rel.str(), "./quux/baz"); + + path2 = "/foo/quux/baz"; + depth = FS::descendant_depth(path2, path1); + EXPECT_EQUAL(depth, -1); + rel = FS::relative(path2, path1); + EXPECT_EQUAL(rel.str(), "../quux/baz"); + FS::Path anc = FS::common_ancestor(path1, path2); + EXPECT_EQUAL(anc.str(), "/foo"); + + path2 = "bar/quux"; + anc = FS::common_ancestor(path1, path2); + EXPECT(anc.empty()); +} + +void FSUtilTests::bad_hierarchy() +{ + FS::Path path1 = "/foo"; + FS::Path path2 = "bar"; + FS::relative(path2, path1); +} -- 2.45.2 From 9be92503cda27dffd8c3219ec4cfadaee37b6369 Mon Sep 17 00:00:00 2001 From: Mikko Rasa Date: Tue, 7 May 2013 16:41:21 +0300 Subject: [PATCH 14/16] Don't output the list of options in usage with full help --- source/core/getopt.cpp | 45 +++++++++++++++++++++++------------------- source/core/getopt.h | 6 ++++-- 2 files changed, 29 insertions(+), 22 deletions(-) diff --git a/source/core/getopt.cpp b/source/core/getopt.cpp index e42ceb2..f88d4a9 100644 --- a/source/core/getopt.cpp +++ b/source/core/getopt.cpp @@ -141,7 +141,7 @@ void GetOpt::operator()(unsigned argc, const char *const *argv) } if(help) - throw usage_error(string("Help for ")+argv[0]+":", "\nUsage:\n "+generate_usage(argv[0])+"\n\n"+generate_help()); + throw usage_error(string("Help for ")+argv[0]+":", "\nUsage:\n "+generate_usage(argv[0], true)+"\n\n"+generate_help()); } unsigned GetOpt::process_long(const char *const *argp) @@ -205,32 +205,37 @@ unsigned GetOpt::process_short(const char *const *argp) return 1; } -string GetOpt::generate_usage(const string &argv0) const +string GetOpt::generate_usage(const string &argv0, bool compact) const { string result = argv0; - for(OptionList::const_iterator i=opts.begin(); i!=opts.end(); ++i) + if(compact) + result += " [options]"; + else { - result += " ["; - if((*i)->get_short()) + for(OptionList::const_iterator i=opts.begin(); i!=opts.end(); ++i) { - result += format("-%c", (*i)->get_short()); + result += " ["; + if((*i)->get_short()) + { + result += format("-%c", (*i)->get_short()); + if(!(*i)->get_long().empty()) + result += '|'; + else if((*i)->get_arg_type()==OPTIONAL_ARG) + result += format("[%s]", (*i)->get_metavar()); + else if((*i)->get_arg_type()==REQUIRED_ARG) + result += format(" %s", (*i)->get_metavar()); + } if(!(*i)->get_long().empty()) - result += '|'; - else if((*i)->get_arg_type()==OPTIONAL_ARG) - result += format("[%s]", (*i)->get_metavar()); - else if((*i)->get_arg_type()==REQUIRED_ARG) - result += format(" %s", (*i)->get_metavar()); - } - if(!(*i)->get_long().empty()) - { - result += format("--%s", (*i)->get_long()); + { + result += format("--%s", (*i)->get_long()); - if((*i)->get_arg_type()==OPTIONAL_ARG) - result += format("[=%s]", (*i)->get_metavar()); - else if((*i)->get_arg_type()==REQUIRED_ARG) - result += format("=%s", (*i)->get_metavar()); + if((*i)->get_arg_type()==OPTIONAL_ARG) + result += format("[=%s]", (*i)->get_metavar()); + else if((*i)->get_arg_type()==REQUIRED_ARG) + result += format("=%s", (*i)->get_metavar()); + } + result += ']'; } - result += ']'; } for(ArgumentList::const_iterator i=args.begin(); i!=args.end(); ++i) diff --git a/source/core/getopt.h b/source/core/getopt.h index 411515f..407d345 100644 --- a/source/core/getopt.h +++ b/source/core/getopt.h @@ -272,8 +272,10 @@ private: unsigned process_short(const char *const *); public: - /** Generates a single line that describes known options and arguments. */ - std::string generate_usage(const std::string &) const; + /** Generates a single line that describes known options and arguments. If + compact is true, the options list is replaced with a placeholder. This + provides cleaner output if full help text is printed. */ + std::string generate_usage(const std::string &, bool compact = false) const; /** Generates help for known options and arguments in tabular format, one item per line. The returned string will have a linefeed at the end. */ -- 2.45.2 From 18bd1fd8496eb6b07476f6782072a5d6bd23f4be Mon Sep 17 00:00:00 2001 From: Mikko Rasa Date: Fri, 24 May 2013 17:38:32 +0300 Subject: [PATCH 15/16] Use _FILE_OFFSET_BITS rather than _LARGEFILE64_SOURCE lseek64 and off64_t are non-portable. This makes the standard lseek use a 64-bit interface. --- source/io/unix/seekable.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/source/io/unix/seekable.cpp b/source/io/unix/seekable.cpp index 2c17114..93a6e86 100644 --- a/source/io/unix/seekable.cpp +++ b/source/io/unix/seekable.cpp @@ -1,4 +1,4 @@ -#define _LARGEFILE64_SOURCE +#define _FILE_OFFSET_BITS 64 #include #include #include @@ -31,8 +31,8 @@ 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) + off_t ret = lseek(*handle, offset, sys_seek_type(type)); + if(ret==(off_t)-1) { if(errno==EINVAL) throw bad_seek(offset, type); -- 2.45.2 From 7a493cb73ff5f5f820d4873d6c993d0e9c5a580a Mon Sep 17 00:00:00 2001 From: Mikko Rasa Date: Fri, 24 May 2013 17:42:09 +0300 Subject: [PATCH 16/16] Avoid a shadowing warning from clang It considers the handle member of the outer class to be shadowed by the parameter of an inner class member function. --- source/io/unix/serial.cpp | 8 ++++---- source/io/windows/serial.cpp | 8 ++++---- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/source/io/unix/serial.cpp b/source/io/unix/serial.cpp index 49d9e9c..69939a8 100644 --- a/source/io/unix/serial.cpp +++ b/source/io/unix/serial.cpp @@ -33,14 +33,14 @@ void Serial::platform_init(const string &port) } -void Serial::DeviceState::get_from(const Handle &handle) +void Serial::DeviceState::get_from(const Handle &h) { - tcgetattr(*handle, &state); + tcgetattr(*h, &state); } -void Serial::DeviceState::apply_to(const Handle &handle) +void Serial::DeviceState::apply_to(const Handle &h) { - if(tcsetattr(*handle, TCSADRAIN, &state)==-1) + if(tcsetattr(*h, TCSADRAIN, &state)==-1) throw system_error("tcsetattr"); } diff --git a/source/io/windows/serial.cpp b/source/io/windows/serial.cpp index 0092754..84a3175 100644 --- a/source/io/windows/serial.cpp +++ b/source/io/windows/serial.cpp @@ -28,14 +28,14 @@ void Serial::platform_init(const string &port) } -void Serial::DeviceState::get_from(const Handle &handle) +void Serial::DeviceState::get_from(const Handle &h) { - GetCommState(*handle, &state); + GetCommState(*h, &state); } -void Serial::DeviceState::apply_to(const Handle &handle) +void Serial::DeviceState::apply_to(const Handle &h) { - if(SetCommState(*handle, &state)==0) + if(SetCommState(*h, &state)==0) throw system_error("SetCommState"); } -- 2.45.2