source "source/stringcodec";
source "source/io";
source "source/fs";
+ if_arch "windows"
+ {
+ overlay "windows";
+ };
+ if_arch "!windows"
+ {
+ overlay "unix";
+ };
install true;
install_map
{
-#ifdef WIN32
-#include <windows.h>
-#endif
#include <signal.h>
-#include <typeinfo>
-#include <msp/debug/demangle.h>
#include <msp/io/print.h>
#include "application.h"
#include "getopt.h"
{
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;
}
#ifndef MSP_CORE_APPLICATION_H_
#define MSP_CORE_APPLICATION_H_
+#include <stdexcept>
+
namespace Msp {
/**
virtual void sighandler(int) { }
private:
static void sighandler_(int);
+
+ static void display_exception(const std::exception &);
};
+++ /dev/null
-#ifdef WIN32
-#include <windows.h>
-#include <msp/stringcodec/utf16.h>
-#include <msp/stringcodec/utf8.h>
-#endif
-#include "application.h"
-
-#ifdef WIN32
-using namespace std;
-using namespace Msp;
-
-int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE /*hPrevInstance*/, LPSTR /*lpCmdLine*/, int /*nCmdShow*/)
-{
- int argc = 0;
- LPWSTR *argv_w = CommandLineToArgvW(GetCommandLineW(), &argc);
-
- unsigned max_size = 0;
- for(int i=0; i<argc; ++i)
- max_size += wcslen(argv_w[i])*4+1;
-
- char *argv_buf = new char[max_size+(argc+1)*sizeof(char *)];
- char **argv = reinterpret_cast<char **>(argv_buf);
- char *argv_ptr = argv_buf+(argc+1)*sizeof(char *);
- for(int i=0; i<argc; ++i)
- {
- argv[i] = argv_ptr;
- string arg(reinterpret_cast<char *>(argv_w[i]), wcslen(argv_w[i])*2);
- arg = StringCodec::transcode<StringCodec::Utf16Le, StringCodec::Utf8>(arg);
- copy(arg.begin(), arg.end(), argv_ptr);
- argv_ptr += arg.size();
- *argv_ptr++ = 0;
- }
-
- LocalFree(argv_w);
- int exit_code = Msp::Application::run(argc, argv, hInstance);
- delete[] argv_buf;
- return exit_code;
-}
-
-#else
-int main(int argc, char **argv)
-{
- return Msp::Application::run(argc, argv);
-}
-#endif
+++ /dev/null
-#ifndef WIN32
-#include <cerrno>
-#endif
-#include "mutex.h"
-#include "mutex_private.h"
-#include "systemerror.h"
-
-namespace Msp {
-
-Mutex::Mutex():
- priv(new Private)
-{
-#ifdef WIN32
- InitializeCriticalSection(&priv->crit);
-#else
- pthread_mutex_init(&priv->mutex, 0);
-#endif
-}
-
-Mutex::~Mutex()
-{
-#ifdef WIN32
- DeleteCriticalSection(&priv->crit);
-#else
- pthread_mutex_destroy(&priv->mutex);
-#endif
- delete priv;
-}
-
-void Mutex::lock()
-{
-#ifdef WIN32
- EnterCriticalSection(&priv->crit);
-#else
- if(int err = pthread_mutex_lock(&priv->mutex))
- throw system_error("pthread_mutex_lock", err);
-#endif
-}
-
-bool Mutex::trylock()
-{
-#ifdef WIN32
- return TryEnterCriticalSection(&priv->crit);
-#else
- int err = pthread_mutex_trylock(&priv->mutex);
- if(err && err!=EBUSY)
- throw system_error("pthread_mutex_trylock", err);
- return !err;
-#endif
-}
-
-void Mutex::unlock()
-{
-#ifdef WIN32
- LeaveCriticalSection(&priv->crit);
-#else
- if(int err = pthread_mutex_unlock(&priv->mutex))
- throw system_error("pthread_mutex_unlock", err);
-#endif
-}
-
-} // namespace Msp
#ifndef MSP_CORE_MUTEX_PRIVATE_H_
#define MSP_CORE_MUTEX_PRIVATE_H_
-#ifdef WIN32
-#include <windows.h>
-#else
-#include <pthread.h>
-#endif
#include "mutex.h"
+#include "mutex_platform.h"
namespace Msp {
struct Mutex::Private
{
-#ifdef WIN32
- CRITICAL_SECTION crit;
-#else
- pthread_mutex_t mutex;
-#endif
+ PlatformMutex mutex;
};
} // namespace Msp
+++ /dev/null
-#ifdef WIN32
-#include <windows.h>
-#else
-#include <sys/time.h>
-#include <cerrno>
-#endif
-#include <msp/time/rawtime_private.h>
-#include <msp/time/timestamp.h>
-#include <msp/time/utils.h>
-#include "mutex_private.h"
-#include "semaphore.h"
-#include "systemerror.h"
-
-namespace Msp {
-
-struct Semaphore::Private
-{
-#ifdef WIN32
- HANDLE handle;
-#else
- Mutex mutex;
- pthread_cond_t cond;
- unsigned limit;
- unsigned count;
-#endif
-};
-
-
-Semaphore::Semaphore(unsigned limit):
- priv(new Private)
-{
-#ifdef WIN32
- priv->handle = CreateSemaphore(0, 0, limit, 0);
-#else
- pthread_cond_init(&priv->cond, 0);
- priv->limit = limit;
- priv->count = 0;
-#endif
-}
-
-Semaphore::~Semaphore()
-{
-#ifdef WIN32
- CloseHandle(priv->handle);
-#else
- pthread_cond_destroy(&priv->cond);
-#endif
- delete priv;
-}
-
-void Semaphore::signal()
-{
-#ifdef WIN32
- if(!ReleaseSemaphore(priv->handle, 1, 0))
- throw system_error("ReleaseSemaphore");
-#else
- MutexLock mlock(priv->mutex);
- if(priv->count<priv->limit)
- ++priv->count;
- if(int err = pthread_cond_signal(&priv->cond))
- throw system_error("pthread_cond_signal", err);
-#endif
-}
-
-void Semaphore::wait()
-{
-#ifdef WIN32
- DWORD ret = WaitForSingleObject(priv->handle, INFINITE);
- if(ret==WAIT_FAILED)
- throw system_error("WaitForSingleObject");
-#else
- MutexLock mlock(priv->mutex);
- while(!priv->count)
- if(int err = pthread_cond_wait(&priv->cond, &priv->mutex.priv->mutex))
- throw system_error("pthread_cond_wait", err);
- --priv->count;
-#endif
-}
-
-bool Semaphore::wait(const Time::TimeDelta &d)
-{
-#ifdef WIN32
- DWORD ret = WaitForSingleObject(priv->handle, (DWORD)(d/Time::usec));
- if(ret==WAIT_FAILED)
- throw system_error("WaitForSingleObject");
- return ret==WAIT_OBJECT_0;
-#else
- timespec timeout = Time::rawtime_to_timespec((Time::now()+d).raw());
-
- int err = pthread_cond_timedwait(&priv->cond, &priv->mutex.priv->mutex, &timeout);
- if(err && err!=ETIMEDOUT)
- throw system_error("pthread_cond_timedwait", err);
- return err==0;
-#endif
-}
-
-} // namespace Msp
-#ifdef WIN32
-#include <windows.h>
-#include <msp/strings/lexicalcast.h>
-#else
-#include <cerrno>
-#include <cstring>
-#endif
#include <limits>
#include "systemerror.h"
code_(numeric_limits<int>::min())
{ }
-string system_error::get_message(int c)
-{
-#ifdef WIN32
- if(c==-1)
- c = GetLastError();
-
- char msg[1024];
- if(FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM, 0, c, 0, msg, sizeof(msg), 0))
- return msg;
- else
- return lexical_cast<string>(c, Fmt().hex());
-#else
- if(c==-1)
- c = errno;
-
- return strerror(c);
-#endif
-}
-
} // namespace Msp
-#ifdef WIN32
-#include <windows.h>
-#else
-#include <pthread.h>
-#include <signal.h>
-#endif
#include <stdexcept>
#include "thread.h"
+#include "thread_private.h"
using namespace std;
namespace Msp {
-struct Thread::Private
-{
-#ifdef WIN32
- HANDLE handle;
-#else
- pthread_t handle;
-#endif
-
- Private(): handle(0) { }
-
-#ifdef WIN32
- static DWORD WINAPI
-#else
- static void *
-#endif
- main_wrapper(void *a)
- {
- Thread *t = reinterpret_cast<Thread *>(a);
- t->main();
- t->state_ = FINISHED;
- return 0;
- }
-};
-
-
Thread::Thread():
priv_(new Private),
state_(PENDING)
if(state_>=JOINED)
return;
-#ifdef WIN32
- WaitForSingleObject(priv_->handle, INFINITE);
-#else
- pthread_join(priv_->handle, 0);
-#endif
+ platform_join();
state_ = JOINED;
}
if(state_!=RUNNING)
return;
-#ifdef WIN32
- TerminateThread(priv_->handle, 0);
-#else
- pthread_kill(priv_->handle, SIGKILL);
-#endif
+ platform_kill();
state_ = KILLED;
}
if(state_>=RUNNING)
throw logic_error("already launched");
-#ifdef WIN32
- DWORD dummy; // Win9x needs the lpTthreadId parameter
- priv_->handle = CreateThread(0, 0, &Private::main_wrapper, this, 0, &dummy);
-#else
- pthread_create(&priv_->handle, 0, &Private::main_wrapper, this);
-#endif
+ platform_launch();
state_ = RUNNING;
}
+ThreadReturn THREAD_CALL Thread::Private::main_wrapper(void *arg)
+{
+ Thread *thread = reinterpret_cast<Thread *>(arg);
+ thread->main();
+ thread->state_ = FINISHED;
+ return 0;
+}
+
} // namespace Msp
/** 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;
};
--- /dev/null
+#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
--- /dev/null
+#include <typeinfo>
+#include <msp/debug/demangle.h>
+#include <msp/io/print.h>
+#include "application.h"
+
+using namespace std;
+
+namespace Msp {
+
+void Application::display_exception(const exception &e)
+{
+ IO::print(IO::cerr, "An uncaught exception occurred.\n");
+ IO::print(IO::cerr, " type: %s\n", Debug::demangle(typeid(e).name()));
+ IO::print(IO::cerr, " what(): %s\n", e.what());
+}
+
+} // namespace Msp
--- /dev/null
+#include "application.h"
+
+int main(int argc, char **argv)
+{
+ return Msp::Application::run(argc, argv);
+}
--- /dev/null
+#include <cerrno>
+#include <pthread.h>
+#include "mutex.h"
+#include "mutex_private.h"
+#include "systemerror.h"
+
+namespace Msp {
+
+Mutex::Mutex():
+ priv(new Private)
+{
+ pthread_mutex_init(&priv->mutex, 0);
+}
+
+Mutex::~Mutex()
+{
+ pthread_mutex_destroy(&priv->mutex);
+ delete priv;
+}
+
+void Mutex::lock()
+{
+ if(int err = pthread_mutex_lock(&priv->mutex))
+ throw system_error("pthread_mutex_lock", err);
+}
+
+bool Mutex::trylock()
+{
+ int err = pthread_mutex_trylock(&priv->mutex);
+ if(err && err!=EBUSY)
+ throw system_error("pthread_mutex_trylock", err);
+ return !err;
+}
+
+void Mutex::unlock()
+{
+ if(int err = pthread_mutex_unlock(&priv->mutex))
+ throw system_error("pthread_mutex_unlock", err);
+}
+
+} // namespace Msp
--- /dev/null
+#ifndef MSP_CORE_MUTEX_PLATFORM_H_
+#define MSP_CORE_MUTEX_PLATFORM_H_
+
+#include <pthread.h>
+
+namespace Msp {
+
+typedef pthread_mutex_t PlatformMutex;
+
+} // namespace Msp
+
+#endif
--- /dev/null
+#include <sys/time.h>
+#include <cerrno>
+#include <msp/core/systemerror.h>
+#include <msp/time/rawtime_private.h>
+#include <msp/time/timestamp.h>
+#include <msp/time/utils.h>
+#include "mutex.h"
+#include "mutex_private.h"
+#include "semaphore.h"
+
+namespace Msp {
+
+struct Semaphore::Private
+{
+ Mutex mutex;
+ pthread_cond_t cond;
+ unsigned limit;
+ unsigned count;
+};
+
+
+Semaphore::Semaphore(unsigned limit):
+ priv(new Private)
+{
+ pthread_cond_init(&priv->cond, 0);
+ priv->limit = limit;
+ priv->count = 0;
+}
+
+Semaphore::~Semaphore()
+{
+ pthread_cond_destroy(&priv->cond);
+ delete priv;
+}
+
+void Semaphore::signal()
+{
+ MutexLock mlock(priv->mutex);
+ if(priv->count<priv->limit)
+ ++priv->count;
+ if(int err = pthread_cond_signal(&priv->cond))
+ throw system_error("pthread_cond_signal", err);
+}
+
+void Semaphore::wait()
+{
+ MutexLock mlock(priv->mutex);
+ while(!priv->count)
+ if(int err = pthread_cond_wait(&priv->cond, &priv->mutex.priv->mutex))
+ throw system_error("pthread_cond_wait", err);
+ --priv->count;
+}
+
+bool Semaphore::wait(const Time::TimeDelta &d)
+{
+ timespec timeout = Time::rawtime_to_timespec((Time::now()+d).raw());
+
+ int err = pthread_cond_timedwait(&priv->cond, &priv->mutex.priv->mutex, &timeout);
+ if(err && err!=ETIMEDOUT)
+ throw system_error("pthread_cond_timedwait", err);
+ return err==0;
+}
+
+} // namespace Msp
--- /dev/null
+#include <cerrno>
+#include <cstring>
+#include "systemerror.h"
+
+using namespace std;
+
+namespace Msp {
+
+string system_error::get_message(int c)
+{
+ if(c==-1)
+ c = errno;
+
+ return strerror(c);
+}
+
+} // namespace Msp
--- /dev/null
+#include <pthread.h>
+#include <signal.h>
+#include "thread.h"
+#include "thread_private.h"
+
+using namespace std;
+
+namespace Msp {
+
+void Thread::platform_join()
+{
+ pthread_join(priv_->handle, 0);
+}
+
+void Thread::platform_kill()
+{
+ pthread_kill(priv_->handle, SIGKILL);
+}
+
+void Thread::platform_launch()
+{
+ pthread_create(&priv_->handle, 0, &Private::main_wrapper, this);
+}
+
+} // namespace Msp
--- /dev/null
+#ifndef MSP_CORE_THREAD_PLATFORM_H_
+#define MSP_CORE_THREAD_PLATFORM_H_
+
+#include <pthread.h>
+
+namespace Msp {
+
+typedef pthread_t ThreadHandle;
+typedef void *ThreadReturn;
+
+#define THREAD_CALL
+
+} // namespace Msp
+
+#endif
--- /dev/null
+#include <windows.h>
+#include <typeinfo>
+#include <msp/debug/demangle.h>
+#include "application.h"
+
+using namespace std;
+
+namespace Msp {
+
+void Application::display_exception(const exception &e)
+{
+ string msg = Debug::demangle(typeid(e).name())+":\n"+e.what();
+ MessageBoxA(0, msg.c_str(), "Uncaught exception", MB_OK|MB_ICONERROR);
+}
+
+} // namespace Msp
--- /dev/null
+#include <windows.h>
+#include <msp/stringcodec/utf16.h>
+#include <msp/stringcodec/utf8.h>
+#include "application.h"
+
+using namespace std;
+using namespace Msp;
+
+int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE /*hPrevInstance*/, LPSTR /*lpCmdLine*/, int /*nCmdShow*/)
+{
+ int argc = 0;
+ LPWSTR *argv_w = CommandLineToArgvW(GetCommandLineW(), &argc);
+
+ unsigned max_size = 0;
+ for(int i=0; i<argc; ++i)
+ max_size += wcslen(argv_w[i])*4+1;
+
+ char *argv_buf = new char[max_size+(argc+1)*sizeof(char *)];
+ char **argv = reinterpret_cast<char **>(argv_buf);
+ char *argv_ptr = argv_buf+(argc+1)*sizeof(char *);
+ for(int i=0; i<argc; ++i)
+ {
+ argv[i] = argv_ptr;
+ string arg(reinterpret_cast<char *>(argv_w[i]), wcslen(argv_w[i])*2);
+ arg = StringCodec::transcode<StringCodec::Utf16Le, StringCodec::Utf8>(arg);
+ copy(arg.begin(), arg.end(), argv_ptr);
+ argv_ptr += arg.size();
+ *argv_ptr++ = 0;
+ }
+
+ LocalFree(argv_w);
+ int exit_code = Msp::Application::run(argc, argv, hInstance);
+ delete[] argv_buf;
+ return exit_code;
+}
--- /dev/null
+#include <windows.h>
+#include "mutex.h"
+#include "mutex_private.h"
+
+namespace Msp {
+
+Mutex::Mutex():
+ priv(new Private)
+{
+ InitializeCriticalSection(&priv->mutex);
+}
+
+Mutex::~Mutex()
+{
+ DeleteCriticalSection(&priv->mutex);
+ delete priv;
+}
+
+void Mutex::lock()
+{
+ EnterCriticalSection(&priv->mutex);
+}
+
+bool Mutex::trylock()
+{
+ return TryEnterCriticalSection(&priv->mutex);
+}
+
+void Mutex::unlock()
+{
+ LeaveCriticalSection(&priv->mutex);
+}
+
+} // namespace Msp
--- /dev/null
+#ifndef MSP_CORE_MUTEX_PLATFORM_H_
+#define MSP_CORE_MUTEX_PLATFORM_H_
+
+#include <windows.h>
+
+namespace Msp {
+
+typedef CRITICAL_SECTION PlatformMutex;
+
+} // namespace Msp
+
+#endif
--- /dev/null
+#include <windows.h>
+#include <msp/core/systemerror.h>
+#include <msp/time/units.h>
+#include "semaphore.h"
+
+namespace Msp {
+
+struct Semaphore::Private
+{
+ HANDLE handle;
+};
+
+
+Semaphore::Semaphore(unsigned limit):
+ priv(new Private)
+{
+ priv->handle = CreateSemaphore(0, 0, limit, 0);
+}
+
+Semaphore::~Semaphore()
+{
+ CloseHandle(priv->handle);
+ delete priv;
+}
+
+void Semaphore::signal()
+{
+ if(!ReleaseSemaphore(priv->handle, 1, 0))
+ throw system_error("ReleaseSemaphore");
+}
+
+void Semaphore::wait()
+{
+ DWORD ret = WaitForSingleObject(priv->handle, INFINITE);
+ if(ret==WAIT_FAILED)
+ throw system_error("WaitForSingleObject");
+}
+
+bool Semaphore::wait(const Time::TimeDelta &d)
+{
+ DWORD ret = WaitForSingleObject(priv->handle, (DWORD)(d/Time::usec));
+ if(ret==WAIT_FAILED)
+ throw system_error("WaitForSingleObject");
+ return ret==WAIT_OBJECT_0;
+}
+
+} // namespace Msp
--- /dev/null
+#include <windows.h>
+#include <msp/strings/lexicalcast.h>
+#include "systemerror.h"
+
+using namespace std;
+
+namespace Msp {
+string system_error::get_message(int c)
+{
+ if(c==-1)
+ c = GetLastError();
+
+ char msg[1024];
+ if(FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM, 0, c, 0, msg, sizeof(msg), 0))
+ return msg;
+ else
+ return lexical_cast<string>(c, Fmt().hex());
+}
+
+} // namespace Msp
--- /dev/null
+#include <windows.h>
+#include "thread.h"
+#include "thread_private.h"
+
+using namespace std;
+
+namespace Msp {
+
+void Thread::platform_join()
+{
+ WaitForSingleObject(priv_->handle, INFINITE);
+}
+
+void Thread::platform_kill()
+{
+ TerminateThread(priv_->handle, 0);
+}
+
+void Thread::platform_launch()
+{
+ DWORD dummy; // Win9x needs the lpTthreadId parameter
+ priv_->handle = CreateThread(0, 0, &Private::main_wrapper, this, 0, &dummy);
+}
+
+} // namespace Msp
--- /dev/null
+#ifndef MSP_CORE_THREAD_PLATFORM_H_
+#define MSP_CORE_THREAD_PLATFORM_H_
+
+#include <windows.h>
+
+namespace Msp {
+
+typedef HANDLE ThreadHandle;
+typedef DWORD ThreadReturn;
+
+#define THREAD_CALL WINAPI
+
+} // namespace Msp
+
+#endif
#include <cstdlib>
-#include <cerrno>
-#include <dirent.h>
-#ifdef WIN32
-#include <shlobj.h>
-#else
#include <unistd.h>
-#include <sys/stat.h>
-#endif
+#include <dirent.h>
#include <msp/core/systemerror.h>
#include <msp/strings/regex.h>
#include <msp/strings/utils.h>
{ }
-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;
}
}
-void rmdir(const Path &path)
-{
-#ifdef WIN32
- if(!RemoveDirectory(path.str().c_str()))
- throw system_error("RemoveDirectory");
-#else
- if(::rmdir(path.str().c_str())==-1)
- throw system_error("rmdir");
-#endif
-}
-
void rmpath(const Path &path)
{
list<string> files = list_files(path);
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);
-#ifdef WIN32
-#include <windows.h>
-#include <aclapi.h>
-#else
-#define _FILE_OFFSET_BITS 64
-#include <cerrno>
-#include <unistd.h>
-#include <sys/stat.h>
-#include <grp.h>
-#include <pwd.h>
-#endif
-#include <msp/core/systemerror.h>
-#include <msp/strings/format.h>
-#include <msp/time/rawtime_private.h>
#include "path.h"
#include "stat.h"
+#include "stat_private.h"
using namespace std;
-namespace {
-
-#ifdef WIN32
-PSID copy_sid(PSID sid)
-{
- if(!sid || !IsValidSid(sid))
- return 0;
- DWORD len = GetLengthSid(sid);
- PSID copy = reinterpret_cast<PSID>(HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, len));
- if(!CopySid(len, copy, sid))
- {
- DWORD err = GetLastError();
- HeapFree(GetProcessHeap(), 0, copy);
- throw Msp::system_error("CopySid", err);
- }
- return copy;
-}
-
-string get_account_name(PSID sid)
-{
- char name[1024];
- DWORD nlen = sizeof(name);
- char domain[1024];
- DWORD dlen = sizeof(domain);
- SID_NAME_USE use;
- if(!LookupAccountSid(0, sid, name, &nlen, domain, &dlen, &use))
- throw Msp::system_error("LookupAccountSid");
- return Msp::format("%s/%s", name, domain);
-}
-#endif
-
-}
-
-
namespace Msp {
namespace FS {
-struct Stat::Private
-{
-#ifdef WIN32
- PSID owner_id;
- PSID group_id;
-#else
- uid_t owner_id;
- gid_t group_id;
-#endif
-
- Private();
- Private(const Private &);
- ~Private();
-
-#ifndef WIN32
- /* This is here because it needs access to private members of Stat, but we
- can't expose the system stat struct in the public header */
- static Stat from_struct_stat(const struct stat &);
-#endif
-
- void fill_owner_info(Stat::OwnerInfo &);
-};
-
Stat::Private::Private():
owner_id(0),
group_id(0)
{ }
-Stat::Private::Private(const Private &other):
-#ifdef WIN32
- owner_id(copy_sid(other.owner_id)),
- group_id(copy_sid(other.group_id))
-#else
- owner_id(other.owner_id),
- group_id(other.group_id)
-#endif
-{ }
-
-Stat::Private::~Private()
-{
-#ifdef WIN32
- if(owner_id)
- HeapFree(GetProcessHeap(), 0, owner_id);
- if(group_id)
- HeapFree(GetProcessHeap(), 0, group_id);
-#endif
-}
-
-#ifndef WIN32
-Stat Stat::Private::from_struct_stat(const struct stat &st)
-{
- Stat result;
- result.exists = true;
- if(S_ISREG(st.st_mode))
- result.type = REGULAR;
- else if(S_ISDIR(st.st_mode))
- result.type = DIRECTORY;
- else if(S_ISLNK(st.st_mode))
- result.type = SYMLINK;
- else
- result.type = UNKNOWN;
- result.size = st.st_size;
- result.alloc_size = st.st_blocks*512;
- result.mtime = Time::TimeStamp::from_unixtime(st.st_mtime);
-
- result.priv = new Private;
- result.priv->owner_id = st.st_uid;
- result.priv->group_id = st.st_gid;
-
- return result;
-}
-#endif
-
-void Stat::Private::fill_owner_info(Stat::OwnerInfo &result)
-{
-#ifdef WIN32
- if(owner_id)
- result.owner = get_account_name(owner_id);
- else
- result.owner = "None";
-
- if(group_id)
- result.group = get_account_name(group_id);
- else
- result.group = "None";
-#else
- char buf[1024];
-
- struct passwd pw;
- struct passwd *owner;
- if(!getpwuid_r(owner_id, &pw, buf, sizeof(buf), &owner) && owner)
- result.owner = owner->pw_name;
- else
- result.owner = format("%d", owner_id);
-
- struct group gr;
- struct group *group;
- if(!getgrgid_r(group_id, &gr, buf, sizeof(buf), &group) && group)
- result.group = group->gr_name;
- else
- result.group = format("%d", group_id);
-#endif
-}
-
Stat::Stat():
exists(false),
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())
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
--- /dev/null
+#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
--- /dev/null
+#include <cstdlib>
+#include <unistd.h>
+#include <sys/stat.h>
+#include <msp/core/systemerror.h>
+#include "dir.h"
+
+using namespace std;
+
+namespace Msp {
+namespace FS {
+
+void mkdir(const Path &path, int mode)
+{
+ if(::mkdir(path.str().c_str(), mode)==-1)
+ throw system_error("mkdir");
+}
+
+void rmdir(const Path &path)
+{
+ if(::rmdir(path.str().c_str())==-1)
+ throw system_error("rmdir");
+}
+
+Path get_home_dir()
+{
+ const char *home = getenv("HOME");
+ if(home)
+ return home;
+ return ".";
+}
+
+Path get_user_data_dir(const string &appname)
+{
+ return get_home_dir()/("."+appname);
+}
+
+} // namespace FS
+} // namespace Msp
--- /dev/null
+#define _FILE_OFFSET_BITS 64
+#include <cerrno>
+#include <unistd.h>
+#include <sys/stat.h>
+#include <grp.h>
+#include <pwd.h>
+#include <msp/core/systemerror.h>
+#include <msp/strings/format.h>
+#include "stat.h"
+#include "stat_private.h"
+
+namespace Msp {
+namespace FS {
+
+Stat::Private::Private(const Private &other):
+ owner_id(other.owner_id),
+ group_id(other.group_id)
+{ }
+
+Stat::Private::~Private()
+{ }
+
+Stat Stat::Private::from_struct_stat(const struct stat &st)
+{
+ Stat result;
+ result.exists = true;
+ if(S_ISREG(st.st_mode))
+ result.type = REGULAR;
+ else if(S_ISDIR(st.st_mode))
+ result.type = DIRECTORY;
+ else if(S_ISLNK(st.st_mode))
+ result.type = SYMLINK;
+ else
+ result.type = UNKNOWN;
+ result.size = st.st_size;
+ result.alloc_size = st.st_blocks*512;
+ result.mtime = Time::TimeStamp::from_unixtime(st.st_mtime);
+
+ result.priv = new Private;
+ result.priv->owner_id = st.st_uid;
+ result.priv->group_id = st.st_gid;
+
+ return result;
+}
+
+void Stat::Private::fill_owner_info(Stat::OwnerInfo &result)
+{
+ char buf[1024];
+
+ struct passwd pw;
+ struct passwd *owner;
+ if(!getpwuid_r(owner_id, &pw, buf, sizeof(buf), &owner) && owner)
+ result.owner = owner->pw_name;
+ else
+ result.owner = format("%d", owner_id);
+
+ struct group gr;
+ struct group *group;
+ if(!getgrgid_r(group_id, &gr, buf, sizeof(buf), &group) && group)
+ result.group = group->gr_name;
+ else
+ result.group = format("%d", group_id);
+}
+
+
+Stat Stat::stat(const Path &path)
+{
+ struct stat st;
+ int ret = ::stat(path.str().c_str(), &st);
+ if(ret==-1)
+ {
+ if(errno==ENOENT)
+ return Stat();
+ else
+ throw system_error("stat");
+ }
+
+ return Private::from_struct_stat(st);
+}
+
+Stat Stat::lstat(const Path &path)
+{
+ struct stat st;
+ int ret = ::lstat(path.str().c_str(), &st);
+ if(ret==-1)
+ {
+ if(errno==ENOENT)
+ return Stat();
+ else
+ throw system_error("lstat");
+ }
+
+ return Private::from_struct_stat(st);
+}
+
+bool exists(const Path &path)
+{
+ return access(path.str().c_str(), F_OK)==0;
+}
+
+} // namespace FS
+} // namespace Msp
--- /dev/null
+#ifndef MSP_FS_STAT_PLATFORM_H_
+#define MSP_FS_STAT_PLATFORM_H_
+
+#include <unistd.h>
+
+namespace Msp {
+namespace FS {
+
+typedef uid_t UserID;
+typedef gid_t GroupID;
+
+} // namespace FS
+} // namespace Msp
+
+#endif
--- /dev/null
+#include <cstdio>
+#include <unistd.h>
+#include <msp/core/systemerror.h>
+#include "dir.h"
+#include "stat.h"
+#include "utils.h"
+
+using namespace std;
+
+namespace Msp {
+namespace FS {
+
+Path readlink(const Path &link)
+{
+ char buf[4096];
+ int len = ::readlink(link.c_str(), buf, sizeof(buf));
+ if(len==-1)
+ throw system_error("readlink");
+ return string(buf, len);
+}
+
+Path realpath(const Path &path)
+{
+ list<string> queue(path.begin(), path.end());
+ if(!path.is_absolute())
+ {
+ Path cwd = getcwd();
+ queue.insert(queue.begin(), cwd.begin(), cwd.end());
+ }
+
+ Path real;
+ unsigned n_links = 0;
+ while(!queue.empty())
+ {
+ Path next = real/queue.front();
+ queue.pop_front();
+
+ if(is_link(next))
+ {
+ if(++n_links>64)
+ throw runtime_error("too many symbolic links");
+ Path link = readlink(next);
+ queue.insert(queue.begin(), link.begin(), link.end());
+ }
+ else
+ real = next;
+ }
+
+ return real;
+}
+
+void rename(const Path &from, const Path &to)
+{
+ if(::rename(from.c_str(), to.c_str())==-1)
+ throw system_error("rename");
+}
+
+void unlink(const Path &path)
+{
+ if(::unlink(path.c_str())==-1)
+ throw system_error("unlink");
+}
+
+} // namespace FS
+} // namespace Msp
-#include <cstdio>
-#ifdef WIN32
-#include <windows.h>
-#else
-#include <unistd.h>
-#endif
-#include <msp/core/systemerror.h>
#include <msp/strings/utils.h>
#include "dir.h"
-#include "path.h"
-#include "stat.h"
#include "utils.h"
using namespace std;
return result;
}
-Path readlink(const Path &link)
-{
-#ifdef WIN32
- (void)link;
- throw logic_error("no symbolic links on win32");
-#else
- char buf[4096];
- int len = ::readlink(link.str().c_str(), buf, sizeof(buf));
- if(len==-1)
- throw system_error("readlink");
- return string(buf, len);
-#endif
-}
-
-Path realpath(const Path &path)
-{
-#ifdef WIN32
- if(path.is_absolute())
- return path;
- else
- return getcwd()/path;
-#else
- list<string> queue(path.begin(), path.end());
- if(!path.is_absolute())
- {
- Path cwd = getcwd();
- queue.insert(queue.begin(), cwd.begin(), cwd.end());
- }
-
- Path real;
- unsigned n_links = 0;
- while(!queue.empty())
- {
- Path next = real/queue.front();
- queue.pop_front();
-
- if(is_link(next))
- {
- if(++n_links>64)
- throw runtime_error("too many symbolic links");
- Path link = readlink(next);
- queue.insert(queue.begin(), link.begin(), link.end());
- }
- else
- real = next;
- }
-
- return real;
-#endif
-}
-
-void rename(const Path &from, const Path &to)
-{
-#ifdef WIN32
- if(!MoveFileEx(from.c_str(), to.c_str(), MOVEFILE_REPLACE_EXISTING))
- throw system_error("MoveFileEx");
-#else
- if(::rename(from.str().c_str(), to.str().c_str())==-1)
- throw system_error("rename");
-#endif
-}
-
-void unlink(const Path &path)
-{
-#ifdef WIN32
- if(!DeleteFile(path.c_str()))
- throw system_error("DeleteFile");
-#else
- if(::unlink(path.str().c_str())==-1)
- throw system_error("unlink");
-#endif
-}
-
Path relative(const Path &path, const Path &base)
{
Path::Iterator i = path.begin();
--- /dev/null
+#include <shlobj.h>
+#include <msp/core/systemerror.h>
+#include "dir.h"
+
+using namespace std;
+
+namespace Msp {
+namespace FS {
+
+void mkdir(const Path &path, int)
+{
+ if(!CreateDirectory(path.str().c_str(), NULL))
+ throw system_error("CreateDirectory");
+}
+
+void rmdir(const Path &path)
+{
+ if(!RemoveDirectory(path.str().c_str()))
+ throw system_error("RemoveDirectory");
+}
+
+Path get_home_dir()
+{
+ char home[MAX_PATH];
+ if(SHGetFolderPath(0, CSIDL_PERSONAL, 0, 0, home)==S_OK)
+ return home;
+ return ".";
+}
+
+Path get_user_data_dir(const string &appname)
+{
+ char datadir[MAX_PATH];
+ if(SHGetFolderPath(0, CSIDL_LOCAL_APPDATA, 0, 0, datadir)==S_OK)
+ return Path(datadir)/appname;
+ return ".";
+}
+
+} // namespace FS
+} // namespace Msp
--- /dev/null
+#include <windows.h>
+#include <aclapi.h>
+#include <msp/core/systemerror.h>
+#include <msp/strings/format.h>
+#include <msp/time/rawtime_private.h>
+#include "stat.h"
+#include "stat_private.h"
+
+using namespace std;
+
+namespace {
+
+PSID copy_sid(PSID sid)
+{
+ if(!sid || !IsValidSid(sid))
+ return 0;
+ DWORD len = GetLengthSid(sid);
+ PSID copy = reinterpret_cast<PSID>(HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, len));
+ if(!CopySid(len, copy, sid))
+ {
+ DWORD err = GetLastError();
+ HeapFree(GetProcessHeap(), 0, copy);
+ throw Msp::system_error("CopySid", err);
+ }
+ return copy;
+}
+
+string get_account_name(PSID sid)
+{
+ char name[1024];
+ DWORD nlen = sizeof(name);
+ char domain[1024];
+ DWORD dlen = sizeof(domain);
+ SID_NAME_USE use;
+ if(!LookupAccountSid(0, sid, name, &nlen, domain, &dlen, &use))
+ throw Msp::system_error("LookupAccountSid");
+ return Msp::format("%s/%s", name, domain);
+}
+
+}
+
+
+namespace Msp {
+namespace FS {
+
+Stat::Private::Private(const Private &other):
+ owner_id(copy_sid(other.owner_id)),
+ group_id(copy_sid(other.group_id))
+{ }
+
+Stat::Private::~Private()
+{
+ if(owner_id)
+ HeapFree(GetProcessHeap(), 0, owner_id);
+ if(group_id)
+ HeapFree(GetProcessHeap(), 0, group_id);
+}
+
+void Stat::Private::fill_owner_info(Stat::OwnerInfo &result)
+{
+ if(owner_id)
+ result.owner = get_account_name(owner_id);
+ else
+ result.owner = "None";
+
+ if(group_id)
+ result.group = get_account_name(group_id);
+ else
+ result.group = "None";
+}
+
+
+Stat Stat::stat(const Path &path)
+{
+ HANDLE handle;
+ handle = CreateFile(path.str().c_str(), READ_CONTROL, FILE_SHARE_READ, 0, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL|FILE_FLAG_BACKUP_SEMANTICS, 0);
+ if(handle==INVALID_HANDLE_VALUE)
+ {
+ DWORD err = GetLastError();
+ if(err==ERROR_FILE_NOT_FOUND)
+ return Stat();
+ else
+ throw system_error("CreateFile", err);
+ }
+
+ BY_HANDLE_FILE_INFORMATION info;
+ if(!GetFileInformationByHandle(handle, &info))
+ {
+ CloseHandle(handle);
+ throw system_error("GetFileInformationByHandle");
+ }
+
+ Stat result;
+ if(info.dwFileAttributes&FILE_ATTRIBUTE_DIRECTORY)
+ result.type = DIRECTORY;
+ else
+ result.type = REGULAR;
+
+ result.size = FileSize(info.nFileSizeHigh)<<32 | info.nFileSizeLow;
+ result.alloc_size = (result.size+511)&~511;
+ result.mtime = Time::TimeStamp(Time::filetime_to_rawtime(info.ftLastWriteTime));
+
+ PSECURITY_DESCRIPTOR sec_desc;
+ PSID owner = 0;
+ PSID group = 0;
+ const SECURITY_INFORMATION sec_info = OWNER_SECURITY_INFORMATION|GROUP_SECURITY_INFORMATION;
+ DWORD err = GetSecurityInfo(handle, SE_FILE_OBJECT, sec_info, &owner, &group, 0, 0, &sec_desc);
+ if(err)
+ {
+ CloseHandle(handle);
+ throw system_error("GetSecurityInfo", err);
+ }
+
+ result.priv = new Private;
+ result.priv->owner_id = copy_sid(owner);
+ result.priv->group_id = copy_sid(group);
+
+ LocalFree(sec_desc);
+
+ CloseHandle(handle);
+
+ return result;
+}
+
+Stat Stat::lstat(const Path &path)
+{
+ return stat(path);
+}
+
+bool exists(const Path &path)
+{
+ return GetFileAttributes(path.str().c_str())!=INVALID_FILE_ATTRIBUTES;
+}
+
+} // namespace FS
+} // namespace Msp
--- /dev/null
+#ifndef MSP_FS_STAT_PLATFORM_H_
+#define MSP_FS_STAT_PLATFORM_H_
+
+#include <windows.h>
+
+namespace Msp {
+namespace FS {
+
+typedef PSID UserID;
+typedef PSID GroupID;
+
+} // namespace FS
+} // namespace Msp
+
+#endif
--- /dev/null
+#include <windows.h>
+#include <msp/core/systemerror.h>
+#include "dir.h"
+#include "utils.h"
+
+using namespace std;
+
+namespace Msp {
+namespace FS {
+
+Path readlink(const Path &link)
+{
+ (void)link;
+ throw logic_error("no symbolic links on win32");
+}
+
+Path realpath(const Path &path)
+{
+ if(path.is_absolute())
+ return path;
+ else
+ return getcwd()/path;
+}
+
+void rename(const Path &from, const Path &to)
+{
+ if(!MoveFileEx(from.c_str(), to.c_str(), MOVEFILE_REPLACE_EXISTING))
+ throw system_error("MoveFileEx");
+}
+
+void unlink(const Path &path)
+{
+ if(!DeleteFile(path.c_str()))
+ throw system_error("DeleteFile");
+}
+
+} // namespace FS
+} // namespace Msp
-#ifndef WIN32
-#include <errno.h>
-#include <unistd.h>
-#include <fcntl.h>
-#include <termios.h>
-#include <sys/ioctl.h>
-#endif
-#include <msp/core/systemerror.h>
#include "console.h"
-#include "handle_private.h"
using namespace std;
-namespace {
-
-#ifdef WIN32
-DWORD stream_to_sys(Msp::IO::Console::Stream stream)
-{
- switch(stream)
- {
- case Msp::IO::Console::CIN: return STD_INPUT_HANDLE;
- case Msp::IO::Console::COUT: return STD_OUTPUT_HANDLE;
- case Msp::IO::Console::CERR: return STD_ERROR_HANDLE;
- default: throw invalid_argument("stream_to_sys");
- }
-}
-
-#else
-termios orig_attr;
-#endif
-
-} // namespace
-
namespace Msp {
namespace IO {
{
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)
Handle handle;
Console(Stream);
+ void platform_init();
public:
~Console();
+++ /dev/null
-#ifdef WIN32
-#include <windows.h>
-#endif
-#include <algorithm>
-#include <msp/core/systemerror.h>
-#include "eventreader.h"
-#include "handle_private.h"
-
-using namespace std;
-
-namespace Msp {
-namespace IO {
-
-struct EventReader::Private
-{
-#ifdef WIN32
- OVERLAPPED *overlapped;
- Handle event;
- unsigned buf_size;
- char *buffer;
- unsigned buf_avail;
- char *buf_next;
-#endif
-};
-
-
-EventReader::EventReader(Handle &h, unsigned size):
- handle(h),
- priv(0)
-{
-#ifdef WIN32
- priv = new Private;
-
- priv->overlapped = 0;
- *priv->event = CreateEvent(0, true, false, 0);
- priv->buf_size = size;
- priv->buffer = new char[priv->buf_size];
- priv->buf_avail = 0;
- priv->buf_next = priv->buffer;
-#else
- (void)size;
-#endif
-}
-
-EventReader::~EventReader()
-{
-#ifdef WIN32
- CloseHandle(*priv->event);
- delete priv->overlapped;
- delete[] priv->buffer;
-#endif
- delete priv;
-}
-
-const Handle &EventReader::get_event()
-{
-#ifdef WIN32
- start();
- return priv->event;
-#else
- return handle;
-#endif
-}
-
-void EventReader::start()
-{
-#ifdef WIN32
- if(priv->buf_avail || priv->overlapped)
- return;
-
- priv->overlapped = new OVERLAPPED;
- memset(priv->overlapped, 0, sizeof(OVERLAPPED));
- priv->overlapped->hEvent = *priv->event;
-
- DWORD ret;
- priv->buf_next = priv->buffer;
- if(!ReadFile(*handle, priv->buffer, priv->buf_size, &ret, priv->overlapped))
- {
- unsigned err = GetLastError();
- if(err!=ERROR_IO_PENDING)
- throw system_error("ReadFile");
- }
- else
- {
- priv->buf_avail = ret;
- delete priv->overlapped;
- priv->overlapped = 0;
- SetEvent(*priv->event);
- }
-#endif
-}
-
-void EventReader::wait()
-{
-#ifdef WIN32
- if(!priv->overlapped)
- return;
-
- DWORD ret;
- if(!GetOverlappedResult(*handle, priv->overlapped, &ret, true))
- throw system_error("GetOverlappedResult");
- else
- {
- priv->buf_avail = ret;
- delete priv->overlapped;
- priv->overlapped = 0;
- }
-#endif
-}
-
-unsigned EventReader::read(char *buf, unsigned len)
-{
-#ifdef WIN32
- if(!priv->buf_avail)
- {
- // No data in buffer, try to get some
- start();
- wait();
- }
-
- len = min(len, priv->buf_avail);
- memcpy(buf, priv->buf_next, len);
- priv->buf_next += len;
- priv->buf_avail -= len;
-
- if(!priv->buf_avail)
- {
- ResetEvent(*priv->event);
- start();
- }
-
- return len;
-#else
- return sys_read(handle, buf, len);
-#endif
-}
-
-} // namespace IO
-} // namespace Msp
-#ifndef WIN32
-#include <errno.h>
-#include <fcntl.h>
-#include <unistd.h>
-#endif
-#include <msp/strings/format.h>
-#include <msp/core/systemerror.h>
#include "file.h"
#include "handle_private.h"
mode = m;
-#ifdef WIN32
- int flags = 0;
- int share_flags = 0;
- int create_flags = OPEN_EXISTING;
-
- if(mode&M_READ)
- flags |= GENERIC_READ;
-
- if(mode&M_WRITE)
- {
- flags |= GENERIC_WRITE;
-
- switch(static_cast<int>(cm))
- {
- case C_NONE: create_flags = OPEN_EXISTING; break;
- case C_CREATE: create_flags = OPEN_ALWAYS; break;
- case C_TRUNCATE: create_flags = TRUNCATE_EXISTING; break;
- case C_OVERWRITE: create_flags = CREATE_ALWAYS; break;
- case C_NEW: create_flags = CREATE_NEW; break;
- }
- }
- else
- share_flags = FILE_SHARE_READ;
-
- *handle = CreateFile(fn.c_str(), flags, share_flags, 0, create_flags, FILE_ATTRIBUTE_NORMAL, 0);
- if(!handle)
- {
- int err = GetLastError();
- if(err==ERROR_FILE_NOT_FOUND)
- throw file_not_found(fn);
- else if(err==ERROR_FILE_EXISTS)
- throw file_already_exists(fn);
- else
- throw system_error(format("CreateFile(%s)", fn), err);
- }
-#else
- int flags = 0;
- switch(mode&M_RDWR)
- {
- case M_READ: flags |= O_RDONLY; break;
- case M_WRITE: flags |= O_WRONLY; break;
- case M_RDWR: flags |= O_RDWR; break;
- default:;
- }
-
- if(mode&M_WRITE)
- {
- if(cm&C_CREATE)
- flags |= O_CREAT;
- if(cm&C_TRUNCATE)
- flags |= O_TRUNC;
- if(cm&C_EXCLUSIVE)
- flags |= O_EXCL;
- }
- if(mode&M_APPEND)
- flags |= O_APPEND;
- if(mode&M_NONBLOCK)
- flags |= O_NONBLOCK;
-
- *handle = ::open(fn.c_str(), flags, 0666);
- if(!handle)
- {
- int err = errno;
- if(err==ENOENT)
- throw file_not_found(fn);
- else if(err==EEXIST)
- throw file_already_exists(fn);
- else
- throw system_error(format("open(%s)", fn), err);
- }
-#endif
+ platform_init(fn, cm);
}
File::~File()
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)
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();
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);
-#include <cerrno>
-#include <unistd.h>
-#include <msp/core/systemerror.h>
#include "handle.h"
#include "handle_private.h"
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
};
+void sys_set_blocking(Handle &, bool);
unsigned sys_read(Handle &, char *, unsigned);
unsigned sys_write(Handle &, const char *, unsigned);
void sys_close(Handle &);
#ifndef MSP_IO_HANDLE_PRIVATE_H_
#define MSP_IO_HANDLE_PRIVATE_H_
-#ifdef WIN32
-#include <windows.h>
-#endif
#include "handle.h"
+#include "handle_platform.h"
namespace Msp {
namespace IO {
struct Handle::Private
{
-#ifdef WIN32
- typedef HANDLE H;
-#else
- typedef int H;
-#endif
-
- H handle;
+ PlatformHandle handle;
Private();
- Private &operator=(H);
- operator H() const { return handle; }
+ Private &operator=(PlatformHandle);
+ operator PlatformHandle() const { return handle; }
};
} // namespace IO
-#ifndef WIN32
-#include <fcntl.h>
-#include <errno.h>
-#include <unistd.h>
-#endif
-#include <msp/core/systemerror.h>
-#include <msp/strings/format.h>
-#include "handle_private.h"
#include "pipe.h"
using namespace std;
{
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);
}
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)
public:
Pipe();
+private:
+ void platform_init();
+public:
~Pipe();
void set_block(bool);
-#include <cerrno>
#include <stdexcept>
-#ifndef WIN32
-#include <poll.h>
-#endif
-#include <msp/core/systemerror.h>
-#include <msp/strings/format.h>
#include "eventobject.h"
-#include "handle.h"
-#include "handle_private.h"
#include "poll.h"
+#include "poll_platform.h"
using namespace std;
-namespace {
-
-using namespace Msp;
-using namespace Msp::IO;
-
-inline short int sys_poll_event(PollEvent event)
-{
- int result = 0;
-
- if(event&~(P_INPUT|P_PRIO|P_OUTPUT))
- throw invalid_argument("sys_poll_event");
-
-#ifndef WIN32
- if(event&P_INPUT)
- result |= POLLIN;
- if(event&P_PRIO)
- result |= POLLPRI;
- if(event&P_OUTPUT)
- result |= POLLOUT;
-#endif
-
- return result;
-}
-
-inline PollEvent poll_event_from_sys(int event)
-{
- PollEvent result = P_NONE;
-
-#ifdef WIN32
- (void)event;
-#else
- if(event&POLLIN)
- result = result|P_INPUT;
- if(event&POLLPRI)
- result = result|P_PRIO;
- if(event&POLLOUT)
- result = result|P_OUTPUT;
- if(event&POLLERR)
- result = result|P_ERROR;
-#endif
-
- return result;
-}
-
-inline PollEvent do_poll(EventObject &obj, PollEvent pe, int timeout)
-{
-#ifdef WIN32
- if(timeout<0)
- timeout = INFINITE;
-
- DWORD ret = WaitForSingleObject(*obj.get_event_handle(), timeout);
- if(ret==WAIT_OBJECT_0)
- return pe;
- else if(ret==WAIT_FAILED)
- throw system_error("WaitForSingleObject");
-
- return P_NONE;
-#else
- pollfd pfd = { *obj.get_event_handle(), sys_poll_event(pe), 0 };
-
- int ret = ::poll(&pfd, 1, timeout);
- if(ret==-1)
- {
- if(errno==EINTR)
- return P_NONE;
- else
- throw system_error("poll");
- }
-
- return poll_event_from_sys(pfd.revents);
-#endif
-}
-
-}
-
-
namespace Msp {
namespace IO {
-struct Poller::Private
-{
-#ifdef WIN32
- vector<HANDLE> handles;
-#else
- vector<pollfd> pfd;
-#endif
-};
-
-
Poller::Poller():
priv(new Private),
objs_changed(false)
return do_poll(static_cast<int>(timeout/Time::msec));
}
-void Poller::rebuild_array()
-{
-#ifdef WIN32
- priv->handles.clear();
-
- for(EventMap::iterator i=objects.begin(); i!=objects.end(); ++i)
- priv->handles.push_back(*i->first->get_event_handle());
-#else
- priv->pfd.clear();
-
- for(EventMap::iterator i=objects.begin(); i!=objects.end(); ++i)
- {
- pollfd p;
- p.fd = *i->first->get_event_handle();
- p.events = sys_poll_event(i->second);
- priv->pfd.push_back(p);
- }
-#endif
-
- objs_changed = false;
-}
-
int Poller::do_poll(int timeout)
{
if(objs_changed)
poll_result.clear();
-#ifdef WIN32
- if(timeout<0)
- timeout = INFINITE;
-
- DWORD ret = WaitForMultipleObjects(priv->handles.size(), &priv->handles.front(), false, timeout);
- if(/*ret>=WAIT_OBJECT_0 &&*/ ret<WAIT_OBJECT_0+priv->handles.size())
- {
- EventMap::iterator i = objects.begin();
- advance(i, ret-WAIT_OBJECT_0);
- poll_result.push_back(Slot(i->first, i->second));
-
- return 1;
- }
- else if(ret==WAIT_FAILED)
- throw system_error("WaitForMultipleObjects");
+ platform_poll(timeout);
- return 0;
-#else
- int ret = ::poll(&priv->pfd.front(), priv->pfd.size(), timeout);
- if(ret==-1)
- {
- if(errno==EINTR)
- return 0;
- else
- throw system_error("poll");
- }
+ return poll_result.size();
+}
- int n = ret;
- EventMap::iterator j = objects.begin();
- for(vector<pollfd>::iterator i=priv->pfd.begin(); (i!=priv->pfd.end() && n>0); ++i, ++j)
- if(i->revents)
- {
- poll_result.push_back(Slot(j->first, poll_event_from_sys(i->revents)));
- --n;
- }
- return ret;
-#endif
-}
+PollEvent platform_poll(EventObject &, PollEvent, int);
PollEvent poll(EventObject &obj, PollEvent pe)
{
- return do_poll(obj, pe, -1);
+ return platform_poll(obj, pe, -1);
}
PollEvent poll(EventObject &obj, PollEvent pe, const Time::TimeDelta &timeout)
if(timeout<Time::zero)
throw invalid_argument("poll");
- return do_poll(obj, pe, static_cast<int>(timeout/Time::msec));
+ return platform_poll(obj, pe, static_cast<int>(timeout/Time::msec));
}
} // namespace IO
private:
void rebuild_array();
int do_poll(int);
+ void platform_poll(int);
public:
const SlotList &get_result() const { return poll_result; }
};
-#ifndef WIN32
-#define _LARGEFILE64_SOURCE
-#include <cerrno>
-#include <unistd.h>
-#else
-#include <windows.h>
-#endif
-#include <msp/core/systemerror.h>
#include <msp/strings/format.h>
-#include "handle.h"
-#include "handle_private.h"
#include "seekable.h"
using namespace std;
-namespace {
-
-using namespace Msp::IO;
-
-int sys_seek_type(SeekType st)
-{
-#ifdef WIN32
- if(st==S_BEG)
- return FILE_BEGIN;
- else if(st==S_CUR)
- return FILE_CURRENT;
- else if(st==S_END)
- return FILE_END;
-#else
- if(st==S_BEG)
- return SEEK_SET;
- else if(st==S_CUR)
- return SEEK_CUR;
- else if(st==S_END)
- return SEEK_END;
-#endif
-
- throw invalid_argument("sys_seek_type");
-}
-
-} // namespace
-
-
namespace Msp {
namespace IO {
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
-#ifdef WIN32
-#include <windows.h>
-#else
-#include <termios.h>
-#include <fcntl.h>
-#include <errno.h>
-#endif
-#include <msp/strings/format.h>
-#include <msp/core/systemerror.h>
-#include "handle_private.h"
#include "serial.h"
+#include "serial_private.h"
using namespace std;
namespace Msp {
namespace IO {
-struct Serial::DeviceState
-{
-#ifdef WIN32
- DCB state;
-#else
- termios state;
-#endif
-
- void get_from(const Handle &);
- void apply_to(const Handle &);
- void set_baud_rate(unsigned);
- void set_data_bits(unsigned);
- void set_parity(Parity);
- void set_stop_bits(unsigned);
-};
-
-void Serial::DeviceState::get_from(const Handle &handle)
-{
-#ifdef WIN32
- GetCommState(*handle, &state);
-#else
- tcgetattr(*handle, &state);
-#endif
-}
-
-void Serial::DeviceState::apply_to(const Handle &handle)
-{
-#ifdef WIN32
- if(SetCommState(*handle, &state)==0)
- throw system_error("SetCommState");
-#else
- if(tcsetattr(*handle, TCSADRAIN, &state)==-1)
- throw system_error("tcsetattr");
-#endif
-}
-
-void Serial::DeviceState::set_baud_rate(unsigned baud)
-{
-#ifdef WIN32
- state.BaudRate = baud;
-#else
- speed_t speed;
- switch(baud)
- {
- case 0: speed = B0; break;
- case 50: speed = B50; break;
- case 75: speed = B75; break;
- case 110: speed = B110; break;
- case 134: speed = B134; break;
- case 150: speed = B150; break;
- case 200: speed = B200; break;
- case 300: speed = B300; break;
- case 600: speed = B600; break;
- case 1200: speed = B1200; break;
- case 1800: speed = B1800; break;
- case 2400: speed = B2400; break;
- case 4800: speed = B4800; break;
- case 9600: speed = B9600; break;
- case 19200: speed = B19200; break;
- case 38400: speed = B38400; break;
- case 57600: speed = B57600; break;
- case 115200: speed = B115200; break;
- case 230400: speed = B230400; break;
- default: throw invalid_argument("set_baud_rate");
- }
-
- cfsetospeed(&state, speed);
- cfsetispeed(&state, speed);
-#endif
-}
-
-void Serial::DeviceState::set_data_bits(unsigned bits)
-{
-#ifdef WIN32
- state.ByteSize = bits;
-#else
- tcflag_t flag;
- switch(bits)
- {
- case 5: flag = CS5; break;
- case 6: flag = CS6; break;
- case 7: flag = CS7; break;
- case 8: flag = CS8; break;
- default: throw invalid_argument("set_data_bits");
- }
-
- state.c_cflag = (state.c_cflag&~CSIZE)|flag;
-#endif
-}
-
-void Serial::DeviceState::set_parity(Serial::Parity par)
-{
-#ifdef WIN32
- switch(par)
- {
- case Serial::NONE: state.Parity = NOPARITY; break;
- case Serial::EVEN: state.Parity = EVENPARITY; break;
- case Serial::ODD: state.Parity = ODDPARITY; break;
- default: throw invalid_argument("set_parity");
- }
-#else
- tcflag_t flag;
- switch(par)
- {
- case Serial::NONE: flag = 0; break;
- case Serial::EVEN: flag = PARENB; break;
- case Serial::ODD: flag = PARENB|PARODD; break;
- default: throw invalid_argument("set_parity");
- }
-
- state.c_cflag = (state.c_cflag&~(PARENB|PARODD))|flag;
-#endif
-}
-
-void Serial::DeviceState::set_stop_bits(unsigned bits)
-{
-#ifdef WIN32
- switch(bits)
- {
- case 1: state.StopBits = ONESTOPBIT; break;
- case 2: state.StopBits = TWOSTOPBITS; break;
- default: throw invalid_argument("set_stop_bits");
- }
-#else
- tcflag_t flag;
- switch(bits)
- {
- case 1: flag = 0; break;
- case 2: flag = CSTOPB; break;
- default: throw invalid_argument("set_stop_bits");
- }
-
- state.c_cflag = (state.c_cflag&~CSTOPB)|flag;
-#endif
-}
-
-
Serial::Serial(const string &descr):
reader(handle, 1024)
{
string::size_type comma = descr.find(',');
string port = descr.substr(0, comma);
-#ifdef WIN32
- port = "\\\\.\\"+port;
-
- *handle = CreateFile(port.c_str(), GENERIC_READ|GENERIC_WRITE, 0, 0, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL|FILE_FLAG_OVERLAPPED, 0);
- if(!handle)
- throw system_error(format("CreateFile(%s)", port));
- mode = M_READ|M_WRITE;
-
- COMMTIMEOUTS timeouts;
- timeouts.ReadIntervalTimeout = MAXDWORD;
- timeouts.ReadTotalTimeoutMultiplier = MAXDWORD;
- timeouts.ReadTotalTimeoutConstant = MAXDWORD-1;
- timeouts.WriteTotalTimeoutMultiplier = 0;
- timeouts.WriteTotalTimeoutConstant = 0;
- SetCommTimeouts(*handle, &timeouts);
-#else
- if(port.compare(0, 5, "/dev/"))
- port = "/dev/"+port;
-
- *handle = open(port.c_str(), O_RDWR);
- if(!handle)
- throw system_error(format("open(%s)", port));
- mode = M_READ|M_WRITE;
-
- termios t;
- tcgetattr(*handle, &t);
- t.c_iflag &= ~(ISTRIP|INLCR|IGNCR|ICRNL|IXON);
- t.c_lflag &= ~(ECHO|ICANON|ISIG|IEXTEN);
- t.c_oflag &= ~(OPOST|OCRNL|ONOCR|ONLRET);
- t.c_cc[VMIN] = 1;
- t.c_cc[VTIME] = 0;
- tcsetattr(*handle, TCSADRAIN, &t);
-#endif
+ platform_init(port);
if(comma!=string::npos)
{
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)
public:
Serial(const std::string &);
+private:
+ void platform_init(const std::string &);
+public:
virtual ~Serial();
private:
--- /dev/null
+#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
--- /dev/null
+#include <unistd.h>
+#include <fcntl.h>
+#include <termios.h>
+#include <sys/ioctl.h>
+#include <msp/core/systemerror.h>
+#include "console.h"
+#include "handle_private.h"
+
+namespace {
+
+termios orig_attr;
+
+}
+
+
+namespace Msp {
+namespace IO {
+
+void Console::platform_init()
+{
+ *handle = stream;
+
+ if(stream==CIN)
+ tcgetattr(*handle, &orig_attr);
+}
+
+Console::~Console()
+{
+ if(stream==CIN)
+ tcsetattr(*handle, TCSADRAIN, &orig_attr);
+}
+
+void Console::set_local_echo(bool e)
+{
+ check_access(M_READ);
+
+ termios t;
+ tcgetattr(*handle, &t);
+ t.c_lflag = (t.c_lflag&~ECHO) | (e?ECHO:0);
+ tcsetattr(*handle, TCSADRAIN, &t);
+}
+
+void Console::set_line_buffer(bool l)
+{
+ check_access(M_READ);
+
+ termios t;
+ if(tcgetattr(*handle, &t)==-1)
+ throw system_error("tcgetattr");
+ t.c_lflag = (t.c_lflag&~ICANON) | (l?ICANON:0);
+ // man termios warns that VMIN and VTIME may share indices with VEOF and VEOL
+ if(l)
+ {
+ t.c_cc[VEOF] = orig_attr.c_cc[VEOF];
+ t.c_cc[VEOL] = orig_attr.c_cc[VEOL];
+ }
+ else
+ {
+ t.c_cc[VMIN] = 1;
+ t.c_cc[VTIME] = 0;
+ }
+ if(tcsetattr(*handle, TCSADRAIN, &t)==-1)
+ throw system_error("tcsetattr");
+}
+
+void Console::get_size(unsigned &rows, unsigned &cols)
+{
+ check_access(M_WRITE);
+
+ struct winsize wsz;
+ if(ioctl(*handle, TIOCGWINSZ, &wsz)==-1)
+ throw system_error("ioctl TIOCGWINSZ");
+ rows = wsz.ws_row;
+ cols = wsz.ws_col;
+}
+
+void Console::redirect(Base &other)
+{
+ dup2(*other.get_handle(mode), *handle);
+}
+
+} // namespace IO
+} // namespace Msp
--- /dev/null
+#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
--- /dev/null
+#include <errno.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <msp/core/systemerror.h>
+#include <msp/strings/format.h>
+#include "file.h"
+#include "handle_private.h"
+
+using namespace std;
+
+namespace Msp {
+namespace IO {
+
+void File::platform_init(const string &fn, CreateMode cm)
+{
+ int flags = 0;
+ switch(mode&M_RDWR)
+ {
+ case M_READ: flags |= O_RDONLY; break;
+ case M_WRITE: flags |= O_WRONLY; break;
+ case M_RDWR: flags |= O_RDWR; break;
+ default:;
+ }
+
+ if(mode&M_WRITE)
+ {
+ if(cm&C_CREATE)
+ flags |= O_CREAT;
+ if(cm&C_TRUNCATE)
+ flags |= O_TRUNC;
+ if(cm&C_EXCLUSIVE)
+ flags |= O_EXCL;
+ }
+ if(mode&M_APPEND)
+ flags |= O_APPEND;
+ if(mode&M_NONBLOCK)
+ flags |= O_NONBLOCK;
+
+ *handle = ::open(fn.c_str(), flags, 0666);
+ if(!handle)
+ {
+ int err = errno;
+ if(err==ENOENT)
+ throw file_not_found(fn);
+ else if(err==EEXIST)
+ throw file_already_exists(fn);
+ else
+ throw system_error(format("open(%s)", fn), err);
+ }
+}
+
+void File::sync()
+{
+ signal_flush_required.emit();
+
+ fsync(*handle);
+}
+
+} // namespace IO
+} // namespace Msp
--- /dev/null
+#include <cerrno>
+#include <unistd.h>
+#include <fcntl.h>
+#include <msp/core/systemerror.h>
+#include "handle.h"
+#include "handle_private.h"
+
+namespace Msp {
+namespace IO {
+
+Handle::operator const void *() const
+{
+ return priv->handle!=-1 ? this : 0;
+}
+
+
+void sys_set_blocking(Handle &handle, bool b)
+{
+ int flags = fcntl(*handle, F_GETFD);
+ fcntl(*handle, F_SETFL, (flags&~O_NONBLOCK)|(b?0:O_NONBLOCK));
+}
+
+unsigned sys_read(Handle &handle, char *buf, unsigned size)
+{
+ int ret = read(*handle, buf, size);
+ if(ret==-1)
+ {
+ if(errno==EAGAIN)
+ return 0;
+ else
+ throw system_error("read");
+ }
+
+ return ret;
+}
+
+unsigned sys_write(Handle &handle, const char *buf, unsigned size)
+{
+ int ret = write(*handle, buf, size);
+ if(ret==-1)
+ {
+ if(errno==EAGAIN)
+ return 0;
+ else
+ throw system_error("write");
+ }
+
+ return ret;
+}
+
+void sys_close(Handle &handle)
+{
+ close(*handle);
+}
+
+} // namespace IO
+} // namespace Msp
--- /dev/null
+#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
--- /dev/null
+#include <unistd.h>
+#include <msp/core/systemerror.h>
+#include "handle_private.h"
+#include "pipe.h"
+
+namespace Msp {
+namespace IO {
+
+void Pipe::platform_init()
+{
+ int pipe_fd[2];
+ if(pipe(pipe_fd)==-1)
+ throw system_error("pipe");
+
+ *read_handle = pipe_fd[0];
+ *write_handle = pipe_fd[1];
+}
+
+} // namespace IO
+} // namespace Msp
--- /dev/null
+#include <cerrno>
+#include <msp/core/systemerror.h>
+#include <poll.h>
+#include "eventobject.h"
+#include "handle.h"
+#include "handle_private.h"
+#include "poll.h"
+#include "poll_platform.h"
+
+using namespace std;
+
+namespace {
+
+using namespace Msp;
+using namespace Msp::IO;
+
+inline short int sys_poll_event(PollEvent event)
+{
+ int result = 0;
+
+ if(event&~(P_INPUT|P_PRIO|P_OUTPUT))
+ throw invalid_argument("sys_poll_event");
+
+ if(event&P_INPUT)
+ result |= POLLIN;
+ if(event&P_PRIO)
+ result |= POLLPRI;
+ if(event&P_OUTPUT)
+ result |= POLLOUT;
+
+ return result;
+}
+
+inline PollEvent poll_event_from_sys(int event)
+{
+ PollEvent result = P_NONE;
+
+ if(event&POLLIN)
+ result = result|P_INPUT;
+ if(event&POLLPRI)
+ result = result|P_PRIO;
+ if(event&POLLOUT)
+ result = result|P_OUTPUT;
+ if(event&POLLERR)
+ result = result|P_ERROR;
+
+ return result;
+}
+
+}
+
+
+namespace Msp {
+namespace IO {
+
+void Poller::rebuild_array()
+{
+ priv->pfd.clear();
+
+ for(EventMap::iterator i=objects.begin(); i!=objects.end(); ++i)
+ {
+ pollfd p;
+ p.fd = *i->first->get_event_handle();
+ p.events = sys_poll_event(i->second);
+ priv->pfd.push_back(p);
+ }
+
+ objs_changed = false;
+}
+
+void Poller::platform_poll(int timeout)
+{
+ int ret = ::poll(&priv->pfd.front(), priv->pfd.size(), timeout);
+ if(ret==-1)
+ {
+ if(errno==EINTR)
+ return;
+ else
+ throw system_error("poll");
+ }
+
+ EventMap::iterator j = objects.begin();
+ for(vector<pollfd>::iterator i=priv->pfd.begin(); (i!=priv->pfd.end() && ret>0); ++i, ++j)
+ if(i->revents)
+ {
+ poll_result.push_back(Slot(j->first, poll_event_from_sys(i->revents)));
+ --ret;
+ }
+}
+
+
+PollEvent platform_poll(EventObject &obj, PollEvent pe, int timeout)
+{
+ pollfd pfd = { *obj.get_event_handle(), sys_poll_event(pe), 0 };
+
+ int ret = ::poll(&pfd, 1, timeout);
+ if(ret==-1)
+ {
+ if(errno==EINTR)
+ return P_NONE;
+ else
+ throw system_error("poll");
+ }
+
+ return poll_event_from_sys(pfd.revents);
+}
+
+} // namespace IO
+} // namespace Msp
--- /dev/null
+#ifndef MSP_IO_POLL_PLATFORM_H_
+#define MSP_IO_POLL_PLATFORM_H_
+
+#include <poll.h>
+#include <vector>
+
+namespace Msp {
+namespace IO {
+
+struct Poller::Private
+{
+ std::vector<pollfd> pfd;
+};
+
+} // namespace IO
+} // namespace Msp
+
+#endif
--- /dev/null
+#define _LARGEFILE64_SOURCE
+#include <cerrno>
+#include <unistd.h>
+#include <msp/core/systemerror.h>
+#include "handle.h"
+#include "handle_private.h"
+#include "seekable.h"
+
+using namespace std;
+
+namespace {
+
+using namespace Msp::IO;
+
+int sys_seek_type(SeekType st)
+{
+ if(st==S_BEG)
+ return SEEK_SET;
+ else if(st==S_CUR)
+ return SEEK_CUR;
+ else if(st==S_END)
+ return SEEK_END;
+
+ throw invalid_argument("sys_seek_type");
+}
+
+}
+
+namespace Msp {
+namespace IO {
+
+SeekOffset sys_seek(Handle &handle, SeekOffset offset, SeekType type)
+{
+ off64_t ret = lseek64(*handle, offset, sys_seek_type(type));
+ if(ret==(off64_t)-1)
+ {
+ if(errno==EINVAL)
+ throw bad_seek(offset, type);
+ else
+ throw system_error("lseek64");
+ }
+
+ return ret;
+}
+
+} // namespace IO
+} // namespace Msp
--- /dev/null
+#include <fcntl.h>
+#include <termios.h>
+#include <msp/core/systemerror.h>
+#include <msp/strings/format.h>
+#include "handle_private.h"
+#include "serial.h"
+#include "serial_private.h"
+
+using namespace std;
+
+namespace Msp {
+namespace IO {
+
+void Serial::platform_init(const string &port)
+{
+ string fn = port;
+ if(fn.compare(0, 5, "/dev/"))
+ fn = "/dev/"+fn;
+
+ *handle = open(fn.c_str(), O_RDWR);
+ if(!handle)
+ throw system_error(format("open(%s)", port));
+ mode = M_READ|M_WRITE;
+
+ termios t;
+ tcgetattr(*handle, &t);
+ t.c_iflag &= ~(ISTRIP|INLCR|IGNCR|ICRNL|IXON);
+ t.c_lflag &= ~(ECHO|ICANON|ISIG|IEXTEN);
+ t.c_oflag &= ~(OPOST|OCRNL|ONOCR|ONLRET);
+ t.c_cc[VMIN] = 1;
+ t.c_cc[VTIME] = 0;
+ tcsetattr(*handle, TCSADRAIN, &t);
+}
+
+
+void Serial::DeviceState::get_from(const Handle &handle)
+{
+ tcgetattr(*handle, &state);
+}
+
+void Serial::DeviceState::apply_to(const Handle &handle)
+{
+ if(tcsetattr(*handle, TCSADRAIN, &state)==-1)
+ throw system_error("tcsetattr");
+}
+
+void Serial::DeviceState::set_baud_rate(unsigned baud)
+{
+ speed_t speed;
+ switch(baud)
+ {
+ case 0: speed = B0; break;
+ case 50: speed = B50; break;
+ case 75: speed = B75; break;
+ case 110: speed = B110; break;
+ case 134: speed = B134; break;
+ case 150: speed = B150; break;
+ case 200: speed = B200; break;
+ case 300: speed = B300; break;
+ case 600: speed = B600; break;
+ case 1200: speed = B1200; break;
+ case 1800: speed = B1800; break;
+ case 2400: speed = B2400; break;
+ case 4800: speed = B4800; break;
+ case 9600: speed = B9600; break;
+ case 19200: speed = B19200; break;
+ case 38400: speed = B38400; break;
+ case 57600: speed = B57600; break;
+ case 115200: speed = B115200; break;
+ case 230400: speed = B230400; break;
+ default: throw invalid_argument("set_baud_rate");
+ }
+
+ cfsetospeed(&state, speed);
+ cfsetispeed(&state, speed);
+}
+
+void Serial::DeviceState::set_data_bits(unsigned bits)
+{
+ tcflag_t flag;
+ switch(bits)
+ {
+ case 5: flag = CS5; break;
+ case 6: flag = CS6; break;
+ case 7: flag = CS7; break;
+ case 8: flag = CS8; break;
+ default: throw invalid_argument("set_data_bits");
+ }
+
+ state.c_cflag = (state.c_cflag&~CSIZE)|flag;
+}
+
+void Serial::DeviceState::set_parity(Serial::Parity par)
+{
+ tcflag_t flag;
+ switch(par)
+ {
+ case Serial::NONE: flag = 0; break;
+ case Serial::EVEN: flag = PARENB; break;
+ case Serial::ODD: flag = PARENB|PARODD; break;
+ default: throw invalid_argument("set_parity");
+ }
+
+ state.c_cflag = (state.c_cflag&~(PARENB|PARODD))|flag;
+}
+
+void Serial::DeviceState::set_stop_bits(unsigned bits)
+{
+ tcflag_t flag;
+ switch(bits)
+ {
+ case 1: flag = 0; break;
+ case 2: flag = CSTOPB; break;
+ default: throw invalid_argument("set_stop_bits");
+ }
+
+ state.c_cflag = (state.c_cflag&~CSTOPB)|flag;
+}
+
+} // namespace IO
+} // namespace MSp
--- /dev/null
+#ifndef MSP_IO_SERIAL_PLATFORM_H_
+#define MSP_IO_SERIAL_PLATFORM_H_
+
+#include <termios.h>
+
+namespace Msp {
+namespace IO {
+
+typedef termios PlatformSerialDeviceState;
+
+} // namespace IO
+} // namespace Msp
+
+#endif
--- /dev/null
+#include <msp/core/systemerror.h>
+#include "console.h"
+#include "handle_private.h"
+
+using namespace std;
+
+namespace {
+
+DWORD stream_to_sys(Msp::IO::Console::Stream stream)
+{
+ switch(stream)
+ {
+ case Msp::IO::Console::CIN: return STD_INPUT_HANDLE;
+ case Msp::IO::Console::COUT: return STD_OUTPUT_HANDLE;
+ case Msp::IO::Console::CERR: return STD_ERROR_HANDLE;
+ default: throw invalid_argument("stream_to_sys");
+ }
+}
+
+} // namespace
+
+
+namespace Msp {
+namespace IO {
+
+void Console::platform_init()
+{
+ *handle = GetStdHandle(stream_to_sys(stream));
+}
+
+Console::~Console()
+{ }
+
+void Console::set_local_echo(bool e)
+{
+ check_access(M_READ);
+
+ DWORD m;
+ GetConsoleMode(*handle, &m);
+ SetConsoleMode(*handle, (m&~ENABLE_ECHO_INPUT) | (e?ENABLE_ECHO_INPUT:0));
+}
+
+void Console::set_line_buffer(bool l)
+{
+ check_access(M_READ);
+
+ DWORD m;
+ if(!GetConsoleMode(*handle, &m))
+ throw system_error("GetConsoleMode");
+ if(!SetConsoleMode(*handle, (m&~ENABLE_LINE_INPUT) | (l?ENABLE_LINE_INPUT:0)))
+ throw system_error("SetConsoleMode");
+}
+
+void Console::get_size(unsigned &rows, unsigned &cols)
+{
+ check_access(M_WRITE);
+
+ CONSOLE_SCREEN_BUFFER_INFO sbi;
+ if(!GetConsoleScreenBufferInfo(*handle, &sbi))
+ throw system_error("GetConsoleScreenBufferInfo");
+ // Right/bottom coords are inclusive
+ rows = sbi.srWindow.Bottom+1-sbi.srWindow.Top;
+ cols = sbi.srWindow.Right+1-sbi.srWindow.Left;
+}
+
+void Console::redirect(Base &other)
+{
+ SetStdHandle(stream_to_sys(stream), *other.get_handle(mode));
+}
+
+} // namespace IO
+} // namespace Msp
--- /dev/null
+#include <windows.h>
+#include <algorithm>
+#include <msp/core/systemerror.h>
+#include "eventreader.h"
+#include "handle_private.h"
+
+using namespace std;
+
+namespace Msp {
+namespace IO {
+
+struct EventReader::Private
+{
+ OVERLAPPED *overlapped;
+ Handle event;
+ unsigned buf_size;
+ char *buffer;
+ unsigned buf_avail;
+ char *buf_next;
+};
+
+
+EventReader::EventReader(Handle &h, unsigned size):
+ handle(h),
+ priv(new Private)
+{
+ priv->overlapped = 0;
+ *priv->event = CreateEvent(0, true, false, 0);
+ priv->buf_size = size;
+ priv->buffer = new char[priv->buf_size];
+ priv->buf_avail = 0;
+ priv->buf_next = priv->buffer;
+}
+
+EventReader::~EventReader()
+{
+ CloseHandle(*priv->event);
+ delete priv->overlapped;
+ delete[] priv->buffer;
+ delete priv;
+}
+
+const Handle &EventReader::get_event()
+{
+ start();
+ return priv->event;
+}
+
+void EventReader::start()
+{
+ if(priv->buf_avail || priv->overlapped)
+ return;
+
+ priv->overlapped = new OVERLAPPED;
+ memset(priv->overlapped, 0, sizeof(OVERLAPPED));
+ priv->overlapped->hEvent = *priv->event;
+
+ DWORD ret;
+ priv->buf_next = priv->buffer;
+ if(!ReadFile(*handle, priv->buffer, priv->buf_size, &ret, priv->overlapped))
+ {
+ unsigned err = GetLastError();
+ if(err!=ERROR_IO_PENDING)
+ throw system_error("ReadFile");
+ }
+ else
+ {
+ priv->buf_avail = ret;
+ delete priv->overlapped;
+ priv->overlapped = 0;
+ SetEvent(*priv->event);
+ }
+}
+
+void EventReader::wait()
+{
+ if(!priv->overlapped)
+ return;
+
+ DWORD ret;
+ if(!GetOverlappedResult(*handle, priv->overlapped, &ret, true))
+ throw system_error("GetOverlappedResult");
+ else
+ {
+ priv->buf_avail = ret;
+ delete priv->overlapped;
+ priv->overlapped = 0;
+ }
+}
+
+unsigned EventReader::read(char *buf, unsigned len)
+{
+ if(!priv->buf_avail)
+ {
+ // No data in buffer, try to get some
+ start();
+ wait();
+ }
+
+ len = min(len, priv->buf_avail);
+ memcpy(buf, priv->buf_next, len);
+ priv->buf_next += len;
+ priv->buf_avail -= len;
+
+ if(!priv->buf_avail)
+ {
+ ResetEvent(*priv->event);
+ start();
+ }
+
+ return len;
+}
+
+} // namespace IO
+} // namespace Msp
--- /dev/null
+#include <msp/core/systemerror.h>
+#include <msp/strings/format.h>
+#include "file.h"
+#include "handle_private.h"
+
+using namespace std;
+
+namespace Msp {
+namespace IO {
+
+void File::platform_init(const string &fn, CreateMode cm)
+{
+ int flags = 0;
+ int share_flags = 0;
+ int create_flags = OPEN_EXISTING;
+
+ if(mode&M_READ)
+ flags |= GENERIC_READ;
+
+ if(mode&M_WRITE)
+ {
+ flags |= GENERIC_WRITE;
+
+ switch(static_cast<int>(cm))
+ {
+ case C_NONE: create_flags = OPEN_EXISTING; break;
+ case C_CREATE: create_flags = OPEN_ALWAYS; break;
+ case C_TRUNCATE: create_flags = TRUNCATE_EXISTING; break;
+ case C_OVERWRITE: create_flags = CREATE_ALWAYS; break;
+ case C_NEW: create_flags = CREATE_NEW; break;
+ }
+ }
+ else
+ share_flags = FILE_SHARE_READ;
+
+ *handle = CreateFile(fn.c_str(), flags, share_flags, 0, create_flags, FILE_ATTRIBUTE_NORMAL, 0);
+ if(!handle)
+ {
+ int err = GetLastError();
+ if(err==ERROR_FILE_NOT_FOUND)
+ throw file_not_found(fn);
+ else if(err==ERROR_FILE_EXISTS)
+ throw file_already_exists(fn);
+ else
+ throw system_error(format("CreateFile(%s)", fn), err);
+ }
+}
+
+void File::sync()
+{
+}
+
+} // namespace IO
+} // namespace Msp
--- /dev/null
+#include <msp/core/systemerror.h>
+#include "handle.h"
+#include "handle_private.h"
+
+namespace Msp {
+namespace IO {
+
+Handle::operator const void *() const
+{
+ return priv->handle!=INVALID_HANDLE_VALUE ? this : 0;
+}
+
+
+void sys_set_blocking(Handle &, bool)
+{
+}
+
+unsigned sys_read(Handle &handle, char *buf, unsigned size)
+{
+ DWORD ret;
+ if(ReadFile(*handle, buf, size, &ret, 0)==0)
+ throw system_error("ReadFile");
+
+ return ret;
+}
+
+unsigned sys_write(Handle &handle, const char *buf, unsigned size)
+{
+ DWORD ret;
+ if(WriteFile(*handle, buf, size, &ret, 0)==0)
+ throw system_error("WriteFile");
+
+ return ret;
+}
+
+void sys_close(Handle &handle)
+{
+ CloseHandle(*handle);
+}
+
+} // namespace IO
+} // namespace Msp
--- /dev/null
+#ifndef MSP_IO_HANDLE_PLATFORM_H_
+#define MSP_IO_HANDLE_PLATFORM_H_
+
+#include <windows.h>
+
+namespace Msp {
+namespace IO {
+
+typedef HANDLE PlatformHandle;
+
+} // namespace IO
+} // namespace Msp
+
+#endif
--- /dev/null
+#include <msp/core/systemerror.h>
+#include <msp/strings/format.h>
+#include "handle_private.h"
+#include "pipe.h"
+
+using namespace std;
+
+namespace Msp {
+namespace IO {
+
+void Pipe::platform_init()
+{
+ string name = format("\\\\.\\pipe\\%u.%p", GetCurrentProcessId(), this);
+ *read_handle = CreateNamedPipe(name.c_str(), PIPE_ACCESS_INBOUND|FILE_FLAG_OVERLAPPED, PIPE_TYPE_BYTE, 1, 1024, 1024, 0, 0);
+ if(!read_handle)
+ throw system_error("CreateNamedPipe");
+
+ *write_handle = CreateFile(name.c_str(), GENERIC_WRITE, 0, 0, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, 0);
+ if(!write_handle)
+ {
+ unsigned err = GetLastError();
+ CloseHandle(*read_handle);
+ throw system_error(format("CreateFile(%s)", name), err);
+ }
+}
+
+} // namespace IO
+} // namespace Msp
--- /dev/null
+#include <msp/core/systemerror.h>
+#include "eventobject.h"
+#include "handle.h"
+#include "handle_private.h"
+#include "poll.h"
+#include "poll_platform.h"
+
+namespace Msp {
+namespace IO {
+
+void Poller::rebuild_array()
+{
+ priv->handles.clear();
+
+ for(EventMap::iterator i=objects.begin(); i!=objects.end(); ++i)
+ priv->handles.push_back(*i->first->get_event_handle());
+
+ objs_changed = false;
+}
+
+void Poller::platform_poll(int timeout)
+{
+ if(timeout<0)
+ timeout = INFINITE;
+
+ DWORD ret = WaitForMultipleObjects(priv->handles.size(), &priv->handles.front(), false, timeout);
+ if(/*ret>=WAIT_OBJECT_0 &&*/ ret<WAIT_OBJECT_0+priv->handles.size())
+ {
+ EventMap::iterator i = objects.begin();
+ advance(i, ret-WAIT_OBJECT_0);
+ poll_result.push_back(Slot(i->first, i->second));
+ }
+ else if(ret==WAIT_FAILED)
+ throw system_error("WaitForMultipleObjects");
+}
+
+
+PollEvent platform_poll(EventObject &obj, PollEvent pe, int timeout)
+{
+ if(timeout<0)
+ timeout = INFINITE;
+
+ DWORD ret = WaitForSingleObject(*obj.get_event_handle(), timeout);
+ if(ret==WAIT_OBJECT_0)
+ return pe;
+ else if(ret==WAIT_FAILED)
+ throw system_error("WaitForSingleObject");
+
+ return P_NONE;
+}
+
+} // namespace IO
+} // namespace Msp
--- /dev/null
+#ifndef MSP_IO_POLL_PLATFORM_H_
+#define MSP_IO_POLL_PLATFORM_H_
+
+#include <windows.h>
+#include <vector>
+
+namespace Msp {
+namespace IO {
+
+struct Poller::Private
+{
+ std::vector<HANDLE> handles;
+};
+
+} // namespace IO
+} // namespace Msp
+
+#endif
--- /dev/null
+#include <windows.h>
+#include <msp/core/systemerror.h>
+#include "handle.h"
+#include "handle_private.h"
+#include "seekable.h"
+
+using namespace std;
+
+namespace {
+
+using namespace Msp::IO;
+
+int sys_seek_type(SeekType st)
+{
+ if(st==S_BEG)
+ return FILE_BEGIN;
+ else if(st==S_CUR)
+ return FILE_CURRENT;
+ else if(st==S_END)
+ return FILE_END;
+
+ throw invalid_argument("sys_seek_type");
+}
+
+}
+
+namespace Msp {
+namespace IO {
+
+SeekOffset sys_seek(Handle &handle, SeekOffset offset, SeekType type)
+{
+ LONG high = offset>>32;
+ DWORD ret = SetFilePointer(*handle, offset, &high, sys_seek_type(type));
+ if(ret==INVALID_SET_FILE_POINTER)
+ {
+ DWORD err = GetLastError();
+ if(err!=NO_ERROR)
+ throw system_error("SetFilePointer");
+ }
+
+ return (SeekOffset(high)<<32) | ret;
+}
+
+} // namespace IO
+} // namespace Msp
--- /dev/null
+#include <msp/core/systemerror.h>
+#include <msp/strings/format.h>
+#include "handle_private.h"
+#include "serial.h"
+#include "serial_private.h"
+
+using namespace std;
+
+namespace Msp {
+namespace IO {
+
+void Serial::platform_init(const string &port)
+{
+ string name = "\\\\.\\"+port;
+
+ *handle = CreateFile(name.c_str(), GENERIC_READ|GENERIC_WRITE, 0, 0, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL|FILE_FLAG_OVERLAPPED, 0);
+ if(!handle)
+ throw system_error(format("CreateFile(%s)", port));
+ mode = M_READ|M_WRITE;
+
+ COMMTIMEOUTS timeouts;
+ timeouts.ReadIntervalTimeout = MAXDWORD;
+ timeouts.ReadTotalTimeoutMultiplier = MAXDWORD;
+ timeouts.ReadTotalTimeoutConstant = MAXDWORD-1;
+ timeouts.WriteTotalTimeoutMultiplier = 0;
+ timeouts.WriteTotalTimeoutConstant = 0;
+ SetCommTimeouts(*handle, &timeouts);
+}
+
+
+void Serial::DeviceState::get_from(const Handle &handle)
+{
+ GetCommState(*handle, &state);
+}
+
+void Serial::DeviceState::apply_to(const Handle &handle)
+{
+ if(SetCommState(*handle, &state)==0)
+ throw system_error("SetCommState");
+}
+
+void Serial::DeviceState::set_baud_rate(unsigned baud)
+{
+ state.BaudRate = baud;
+}
+
+void Serial::DeviceState::set_data_bits(unsigned bits)
+{
+ state.ByteSize = bits;
+}
+
+void Serial::DeviceState::set_parity(Serial::Parity par)
+{
+ switch(par)
+ {
+ case Serial::NONE: state.Parity = NOPARITY; break;
+ case Serial::EVEN: state.Parity = EVENPARITY; break;
+ case Serial::ODD: state.Parity = ODDPARITY; break;
+ default: throw invalid_argument("set_parity");
+ }
+}
+
+void Serial::DeviceState::set_stop_bits(unsigned bits)
+{
+ switch(bits)
+ {
+ case 1: state.StopBits = ONESTOPBIT; break;
+ case 2: state.StopBits = TWOSTOPBITS; break;
+ default: throw invalid_argument("set_stop_bits");
+ }
+}
+
+} // namespace IO
+} // namespace MSp
--- /dev/null
+#ifndef MSP_IO_SERIAL_PLATFORM_H_
+#define MSP_IO_SERIAL_PLATFORM_H_
+
+#include <windows.h>
+
+namespace Msp {
+namespace IO {
+
+typedef DCB PlatformSerialDeviceState;
+
+} // namespace IO
+} // namespace Msp
+
+#endif
+++ /dev/null
-#include "rawtime.h"
-#include "rawtime_private.h"
-
-namespace {
-
-#ifdef WIN32
-/// Returns the unixtime epoch as filetime
-Msp::Time::RawTime get_epoch()
-{
- SYSTEMTIME st;
- st.wYear = 1970;
- st.wMonth = 1;
- st.wDay = 1;
- st.wHour = 0;
- st.wMinute = 0;
- st.wSecond = 0;
- st.wMilliseconds = 0;
-
- FILETIME ft;
- SystemTimeToFileTime(&st, &ft);
- return (ft.dwLowDateTime+(static_cast<Msp::Time::RawTime>(ft.dwHighDateTime)<<32))/10;
-}
-#endif
-
-}
-
-
-namespace Msp {
-namespace Time {
-
-#ifdef WIN32
-RawTime filetime_to_rawtime(const FILETIME &ft)
-{
- static RawTime epoch = get_epoch();
-
- return (ft.dwLowDateTime+(static_cast<RawTime>(ft.dwHighDateTime)<<32))/10-epoch;
-}
-#else
-timeval rawtime_to_timeval(RawTime raw)
-{
- timeval tv;
- tv.tv_sec = raw/1000000;
- tv.tv_usec = raw%1000000;
- return tv;
-}
-
-timespec rawtime_to_timespec(RawTime raw)
-{
- timespec ts;
- ts.tv_sec = raw/1000000;
- ts.tv_nsec = (raw%1000000)*1000;
- return ts;
-}
-
-RawTime timeval_to_rawtime(const timeval &tv)
-{
- return tv.tv_sec*1000000LL+tv.tv_usec;
-}
-#endif
-
-} // namespace Time
-} // namespace Msp
#ifndef MSP_TIME_RAWTIME_PRIVATE_H_
#define MSP_TIME_RAWTIME_PRIVATE_H_
-#ifdef WIN32
-#include <windows.h>
-#else
-#include <sys/time.h>
-#endif
-#include "rawtime.h"
-
-namespace Msp {
-namespace Time {
-
-#ifdef WIN32
-RawTime filetime_to_rawtime(const FILETIME &);
-#else
-timeval rawtime_to_timeval(RawTime);
-timespec rawtime_to_timespec(RawTime);
-RawTime timeval_to_rawtime(const timeval &);
-#endif
-
-} // namespace Time
-} // namespace Msp
+#include "rawtime_platform.h"
#endif
#include <cstdlib>
-#ifdef WIN32
-#include <windows.h>
-#else
-#include <unistd.h>
-#include <fcntl.h>
-#endif
#include <msp/strings/format.h>
-#include <msp/core/systemerror.h>
-#include "timestamp.h"
#include "timezone.h"
-#include "utils.h"
using namespace std;
-namespace {
-
-using Msp::Time::TimeZone;
-
-#ifndef WIN32
-long get_long(char *&ptr)
-{
- long result = 0;
- for(unsigned i=0; i<4; ++i)
- result = (result<<8)+static_cast<unsigned char >(*ptr++);
- return result;
-}
-#endif
-
-TimeZone get_local_timezone()
-{
-#ifdef WIN32
- TIME_ZONE_INFORMATION tzinfo;
- DWORD dst = GetTimeZoneInformation(&tzinfo);
- if(dst==TIME_ZONE_ID_INVALID)
- throw Msp::system_error("GetTimeZoneInformation");
-
- int offset = tzinfo.Bias;
- if(dst==TIME_ZONE_ID_STANDARD)
- offset += tzinfo.StandardBias;
- else if(dst==TIME_ZONE_ID_DAYLIGHT)
- offset += tzinfo.DaylightBias;
-
- return TimeZone(offset);
-#else
- int fd = open("/etc/localtime", O_RDONLY);
- if(fd!=-1)
- {
- char hdr[44];
- int len = read(fd, hdr, sizeof(hdr));
- long gmtoff = -1;
- string name;
- if(len==44 && hdr[0]=='T' && hdr[1]=='Z' && hdr[2]=='i' && hdr[3]=='f')
- {
- char *ptr = hdr+20;
- long isgmtcnt = get_long(ptr);
- long isstdcnt = get_long(ptr);
- long leapcnt = get_long(ptr);
- long timecnt = get_long(ptr);
- long typecnt = get_long(ptr);
- long charcnt = get_long(ptr);
- int size = timecnt*5+typecnt*6+isgmtcnt+isstdcnt+leapcnt*8+charcnt;
- char *buf = new char[size];
- len = read(fd, buf, size);
- if(len==size)
- {
- ptr = buf;
- int index = -1;
- time_t cur_time = Msp::Time::now().to_unixtime();
- for(int i=0; i<timecnt; ++i)
- if(get_long(ptr)<=cur_time)
- index = i;
-
- if(index>0)
- index = ptr[index];
- ptr += timecnt;
-
- int abbrind = 0;
- for(int i=0; i<typecnt; ++i)
- {
- if((index>=0 && i==index) || (index<0 && !ptr[4] && gmtoff==-1))
- {
- gmtoff = get_long(ptr);
- ++ptr;
- abbrind = *ptr++;
- }
- else
- ptr += 6;
- }
-
- name = ptr+abbrind;
- }
- delete[] buf;
- }
- close(fd);
-
- if(gmtoff!=-1)
- return TimeZone(gmtoff/60, name);
- }
- return TimeZone();
-#endif
-}
-
-}
-
namespace Msp {
namespace Time {
const TimeZone &TimeZone::local()
{
- static TimeZone tz = get_local_timezone();
+ static TimeZone tz = platform_get_local_timezone();
return tz;
}
static const TimeZone &utc();
static const TimeZone &local();
+private:
+ static TimeZone platform_get_local_timezone();
};
} // namespace Time
--- /dev/null
+#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
--- /dev/null
+#ifndef MSP_TIME_RAWTIME_PLATFORM_H_
+#define MSP_TIME_RAWTIME_PLATFORM_H_
+
+#include <sys/time.h>
+#include "rawtime.h"
+
+namespace Msp {
+namespace Time {
+
+timeval rawtime_to_timeval(RawTime);
+timespec rawtime_to_timespec(RawTime);
+RawTime timeval_to_rawtime(const timeval &);
+
+} // namespace Time
+} // namespace Msp
+
+#endif
--- /dev/null
+#include <unistd.h>
+#include <fcntl.h>
+#include "timestamp.h"
+#include "timezone.h"
+#include "utils.h"
+
+using namespace std;
+
+namespace {
+
+long get_long(char *&ptr)
+{
+ long result = 0;
+ for(unsigned i=0; i<4; ++i)
+ result = (result<<8)+static_cast<unsigned char >(*ptr++);
+ return result;
+}
+
+}
+
+
+namespace Msp {
+namespace Time {
+
+TimeZone TimeZone::platform_get_local_timezone()
+{
+ int fd = open("/etc/localtime", O_RDONLY);
+ if(fd!=-1)
+ {
+ char hdr[44];
+ int len = read(fd, hdr, sizeof(hdr));
+ long gmtoff = -1;
+ string name;
+ if(len==44 && hdr[0]=='T' && hdr[1]=='Z' && hdr[2]=='i' && hdr[3]=='f')
+ {
+ char *ptr = hdr+20;
+ long isgmtcnt = get_long(ptr);
+ long isstdcnt = get_long(ptr);
+ long leapcnt = get_long(ptr);
+ long timecnt = get_long(ptr);
+ long typecnt = get_long(ptr);
+ long charcnt = get_long(ptr);
+ int size = timecnt*5+typecnt*6+isgmtcnt+isstdcnt+leapcnt*8+charcnt;
+ char *buf = new char[size];
+ len = read(fd, buf, size);
+ if(len==size)
+ {
+ ptr = buf;
+ int index = -1;
+ time_t cur_time = Msp::Time::now().to_unixtime();
+ for(int i=0; i<timecnt; ++i)
+ if(get_long(ptr)<=cur_time)
+ index = i;
+
+ if(index>0)
+ index = ptr[index];
+ ptr += timecnt;
+
+ int abbrind = 0;
+ for(int i=0; i<typecnt; ++i)
+ {
+ if((index>=0 && i==index) || (index<0 && !ptr[4] && gmtoff==-1))
+ {
+ gmtoff = get_long(ptr);
+ ++ptr;
+ abbrind = *ptr++;
+ }
+ else
+ ptr += 6;
+ }
+
+ name = ptr+abbrind;
+ }
+ delete[] buf;
+ }
+ close(fd);
+
+ if(gmtoff!=-1)
+ return TimeZone(gmtoff/60, name);
+ }
+ return TimeZone();
+}
+
+} // namespace Time
+} // namespace Msp
--- /dev/null
+#include <sys/resource.h>
+#include <sys/time.h>
+#include <cerrno>
+#include <msp/core/systemerror.h>
+#include "rawtime_private.h"
+#include "timedelta.h"
+#include "timestamp.h"
+#include "utils.h"
+
+namespace Msp {
+namespace Time {
+
+TimeStamp now()
+{
+ timeval tv;
+ gettimeofday(&tv, 0);
+ return TimeStamp(timeval_to_rawtime(tv));
+}
+
+TimeDelta get_cpu_time()
+{
+ rusage ru;
+ getrusage(RUSAGE_SELF, &ru);
+ return (ru.ru_utime.tv_sec+ru.ru_stime.tv_sec)*sec + (ru.ru_utime.tv_usec+ru.ru_stime.tv_usec)*usec;
+}
+
+void sleep(const TimeDelta &d)
+{
+ timespec ts = rawtime_to_timespec(d.raw());
+ while(nanosleep(&ts, 0)==-1)
+ if(errno!=EINTR)
+ throw system_error("nanosleep");
+}
+
+} // namespace Time
+} // namespace Msp
-#ifdef WIN32
-#include <windows.h>
-#else
-#include <sys/resource.h>
-#include <sys/time.h>
-#include <cerrno>
-#endif
-#include <msp/core/systemerror.h>
#include "datetime.h"
-#include "rawtime_private.h"
-#include "timedelta.h"
#include "timestamp.h"
#include "utils.h"
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
--- /dev/null
+#include "rawtime.h"
+#include "rawtime_private.h"
+
+namespace {
+
+/// Returns the unixtime epoch as filetime
+Msp::Time::RawTime get_epoch()
+{
+ SYSTEMTIME st;
+ st.wYear = 1970;
+ st.wMonth = 1;
+ st.wDay = 1;
+ st.wHour = 0;
+ st.wMinute = 0;
+ st.wSecond = 0;
+ st.wMilliseconds = 0;
+
+ FILETIME ft;
+ SystemTimeToFileTime(&st, &ft);
+ return (ft.dwLowDateTime+(static_cast<Msp::Time::RawTime>(ft.dwHighDateTime)<<32))/10;
+}
+
+}
+
+namespace Msp {
+namespace Time {
+
+RawTime filetime_to_rawtime(const FILETIME &ft)
+{
+ static RawTime epoch = get_epoch();
+
+ return (ft.dwLowDateTime+(static_cast<RawTime>(ft.dwHighDateTime)<<32))/10-epoch;
+}
+
+} // namespace Time
+} // namespace Msp
--- /dev/null
+#ifndef MSP_TIME_RAWTIME_PLATFORM_H_
+#define MSP_TIME_RAWTIME_PLATFORM_H_
+
+#include <windows.h>
+#include "rawtime.h"
+
+namespace Msp {
+namespace Time {
+
+RawTime filetime_to_rawtime(const FILETIME &);
+
+} // namespace Time
+} // namespace Msp
+
+#endif
--- /dev/null
+#include <windows.h>
+#include <msp/core/systemerror.h>
+#include "timezone.h"
+
+namespace Msp {
+namespace Time {
+
+TimeZone TimeZone::platform_get_local_timezone()
+{
+ TIME_ZONE_INFORMATION tzinfo;
+ DWORD dst = GetTimeZoneInformation(&tzinfo);
+ if(dst==TIME_ZONE_ID_INVALID)
+ throw Msp::system_error("GetTimeZoneInformation");
+
+ int offset = tzinfo.Bias;
+ if(dst==TIME_ZONE_ID_STANDARD)
+ offset += tzinfo.StandardBias;
+ else if(dst==TIME_ZONE_ID_DAYLIGHT)
+ offset += tzinfo.DaylightBias;
+
+ return TimeZone(offset);
+}
+
+} // namespace Time
+} // namespace Msp
--- /dev/null
+#include <windows.h>
+#include "rawtime_private.h"
+#include "timedelta.h"
+#include "timestamp.h"
+#include "utils.h"
+
+namespace Msp {
+namespace Time {
+
+TimeStamp now()
+{
+ FILETIME ft;
+ GetSystemTimeAsFileTime(&ft);
+ return TimeStamp(filetime_to_rawtime(ft));
+}
+
+TimeDelta get_cpu_time()
+{
+ //XXX Figure out the function to use on Win32
+ return TimeDelta();
+}
+
+void sleep(const TimeDelta &d)
+{
+ Sleep((DWORD)(d/msec));
+}
+
+} // namespace Time
+} // namespace Msp