From: Mikko Rasa Date: Fri, 10 Jun 2011 18:01:55 +0000 (+0300) Subject: Move files to prepare for assimilation into core X-Git-Url: http://git.tdb.fi/?p=libs%2Fcore.git;a=commitdiff_plain;h=6e0fd758970bcb5bad5e3f2454b694cc4d7b4b66;ds=sidebyside Move files to prepare for assimilation into core --- diff --git a/source/base.cpp b/source/base.cpp deleted file mode 100644 index 48de3ee..0000000 --- a/source/base.cpp +++ /dev/null @@ -1,61 +0,0 @@ -#include "base.h" -#include "poll.h" - -using namespace std; - -namespace Msp { -namespace IO { - -Base::Base(): - mode(M_READ), - events(P_NONE), - eof_flag(false) -{ } - -Base::~Base() -{ - signal_deleted.emit(); -} - -bool Base::getline(string &line) -{ - line.clear(); - - if(eof_flag) - return false; - - while(1) - { - int c = get(); - if(c==-1 || c=='\n') - break; - line += c; - } - - return !eof_flag || !line.empty(); -} - -int Base::get() -{ - char c; - if(do_read(&c, 1)==0) - return -1; - return static_cast(c); -} - -void Base::set_events(PollEvent e) -{ - events = e; - signal_events_changed.emit(events); -} - -void Base::event(PollEvent ev) -{ - if(ev&P_INPUT) - signal_data_available.emit(); - - on_event(ev); -} - -} // namespace IO -} // namespace Msp diff --git a/source/base.h b/source/base.h deleted file mode 100644 index 774d034..0000000 --- a/source/base.h +++ /dev/null @@ -1,121 +0,0 @@ -#ifndef MSP_IO_BASE_H_ -#define MSP_IO_BASE_H_ - -#include -#include "mode.h" -#include "poll.h" -#include "types.h" - -namespace Msp { -namespace IO { - -/** -Common interface for all I/O objects. - -A derived class must call set_events(P_NONE) before it is destroyed to avoid -leaving stale pointers in an EventDispatcher. -*/ -class Base -{ -public: - /** Emitted when there is data available for reading. If all data is not - read, the signal is emitted again immediately. */ - sigc::signal signal_data_available; - - /** Emitted when there is no more data to be read. */ - sigc::signal signal_end_of_file; - - /** Emitted when there is a nonlinearity in I/O (such as a file being - seeked) and any data buffered by upper layers needs to be flushed. */ - sigc::signal signal_flush_required; - - /** Emitted when the I/O object has closed. */ - sigc::signal signal_closed; - - /** Emitted when the mask of interesting events changes. Mainly for use by - EventDispatcher. */ - sigc::signal signal_events_changed; - - /** Emitted when the object is deleted. Mainly for use by - EventDispatcher. */ - sigc::signal signal_deleted; - -protected: - Mode mode; - PollEvent events; - bool eof_flag; - - Base(); -private: - Base(const Base &); - Base &operator=(const Base &); -public: - virtual ~Base(); - - /** Sets blocking mode. When blocking is enabled, most operations won't - return until they can make progress. When blocking is disabled, these - operations may return immediately with a return code indicating that nothing - was done. - - Blocking is enabled by default. */ - virtual void set_block(bool) { } - - /** Returns the current mode flags. */ - Mode get_mode() const { return mode; } - -protected: - virtual unsigned do_write(const char *, unsigned) =0; - virtual unsigned do_read(char *, unsigned) =0; - -public: - /** Writes data from a buffer. Subject to blocking. Returns the number of - bytes written, which may be zero for a non-blockin operation. */ - unsigned write(const char *b, unsigned c) { return do_write(b, c); } - - /** Writes a string. This is identical to calling - write(s.data(), s.size()). */ - unsigned write(const std::string &s) { return do_write(s.data(), s.size()); } - - /** Writes a single character. This is identical to calling - write(&c, 1). */ - virtual unsigned put(char c) { return do_write(&c, 1); } - - /** Reads data into a buffer. Subject to blocking. Returns the number of - bytes read, which may be zero for a non-blocking operation. */ - unsigned read(char *b, unsigned c) { return do_read(b, c); } - - /** Reads characters up to the next linefeed or end-of-file. The linefeed - is not included in the line. Returns true if a line was successfully read, - false otherwise. */ - virtual bool getline(std::string &); - - /** Reads a single character. Returns -1 if no character was available due - to end-of-file or non-blocking operation. */ - virtual int get(); - - /** Returns the end-of-file flag. */ - bool eof() const { return eof_flag; } - -protected: - void set_events(PollEvent); - -public: - /** Returns a mask of the currently interesting events. Used by - EventDispatcher. */ - PollEvent get_events() const { return events; } - - /** Returns a handle for polling. Should throw if the object does not have - an event handle. */ - virtual Handle get_event_handle() =0; - - /** Notifies the object of an event. Used by EventDispatcher. */ - void event(PollEvent); - -protected: - virtual void on_event(PollEvent) { } -}; - -} // namespace IO -} // namespace Msp - -#endif diff --git a/source/buffered.cpp b/source/buffered.cpp deleted file mode 100644 index f53d2fc..0000000 --- a/source/buffered.cpp +++ /dev/null @@ -1,188 +0,0 @@ -#include -#include "buffered.h" -#include "except.h" - -using namespace std; - -namespace Msp { -namespace IO { - -Buffered::Buffered(Base &b, unsigned s): - below(b), - buf_size(s), - buf(new char[buf_size]), - begin(buf), - end(buf), - cur_op(M_NONE) -{ - mode = below.get_mode(); - below.signal_flush_required.connect(sigc::mem_fun(this, &Buffered::flush)); -} - -Buffered::~Buffered() -{ - try - { - flush(); - } - catch(...) - { } - - delete[] buf; -} - -void Buffered::flush() -{ - if(cur_op==M_WRITE) - { - unsigned used = end-begin; - if(used) - { - unsigned len = below.write(begin, used); - - begin=end = buf; - - if(len(end-begin), size); - memcpy(data, begin, len); - begin += len; - ret += len; - } - else - // Read the rest directly from the underlying object - ret += below.read(data, size); - - eof_flag = (below.eof() && begin==end); - - return ret; - } -} - -unsigned Buffered::put(char c) -{ - set_op(M_WRITE); - - if(end(*begin++); - - char c; - if(do_read(&c, 1)==0) - return -1; - return static_cast(c); -} - -void Buffered::set_op(Mode op) -{ - if(op!=cur_op) - flush(); - cur_op = op; -} - -unsigned Buffered::get_current_size() const -{ - return end-begin; -} - -Handle Buffered::get_event_handle() -{ - throw Exception("Buffered doesn't support events"); -} - -} // namespace IO -} // namespace Msp diff --git a/source/buffered.h b/source/buffered.h deleted file mode 100644 index 36d2a11..0000000 --- a/source/buffered.h +++ /dev/null @@ -1,46 +0,0 @@ -#ifndef MSP_IO_BUFFERED_H_ -#define MSP_IO_BUFFERED_H_ - -#include "base.h" - -namespace Msp { -namespace IO { - -class Buffered: public Base -{ -private: - Base &below; - unsigned buf_size; - char *buf; - char *begin; - char *end; - Mode cur_op; - -public: - Buffered(Base &, unsigned =8192); - ~Buffered(); - - void flush(); - -protected: - unsigned do_write(const char *, unsigned); - unsigned do_read(char *, unsigned); -public: - unsigned put(char); - - bool getline(std::string &); - int get(); - -private: - void set_op(Mode); -public: - Mode get_current_op() const { return cur_op; } - unsigned get_current_size() const; - - virtual Handle get_event_handle(); -}; - -} // namespace IO -} // namespace Msp - -#endif diff --git a/source/console.cpp b/source/console.cpp deleted file mode 100644 index 9db7737..0000000 --- a/source/console.cpp +++ /dev/null @@ -1,187 +0,0 @@ -#ifndef WIN32 -#include -#include -#include -#include -#endif -#include -#include "console.h" - -namespace { - -#ifndef WIN32 -termios orig_attr; -#endif - -} // namespace - -namespace Msp { -namespace IO { - -Console::Console(unsigned n) -{ - if(n>2) - throw InvalidParameterValue("Invalid parameter for Console::Console"); - - mode = (n==0 ? M_READ : M_WRITE); - -#ifdef WIN32 - switch(n) - { - case 0: handle = GetStdHandle(STD_INPUT_HANDLE); break; - case 1: handle = GetStdHandle(STD_OUTPUT_HANDLE); break; - case 2: handle = GetStdHandle(STD_ERROR_HANDLE); break; - } -#else - handle = n; - - if(handle==0) - tcgetattr(handle, &orig_attr); -#endif - - if(n==0) - set_events(P_INPUT); -} - -Console::~Console() -{ -#ifndef WIN32 - if(handle==0) - 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(0, F_GETFL); - flags = (flags&~O_NONBLOCK) | (b?0:O_NONBLOCK); - fcntl(0, F_SETFL, flags); -#endif -} - -void Console::set_local_echo(bool e) -{ - if(!(mode&M_READ)) - throw InvalidState("Local echo can only be set on input console"); - -#ifdef WIN32 - DWORD m; - GetConsoleMode(handle, &m); - SetConsoleMode(handle, (m&~ENABLE_ECHO_INPUT) | (e?ENABLE_ECHO_INPUT:0)); -#else - termios t; - tcgetattr(0, &t); - t.c_lflag = (t.c_lflag&~ECHO) | (e?ECHO:0); - tcsetattr(0, TCSADRAIN, &t); -#endif -} - -void Console::set_line_buffer(bool l) -{ - if(!(mode&M_READ)) - throw InvalidState("Line buffering can only be set on input console"); - -#ifdef WIN32 - DWORD m; - GetConsoleMode(handle, &m); - SetConsoleMode(handle, (m&~ENABLE_LINE_INPUT) | (l?ENABLE_LINE_INPUT:0)); -#else - // XXX ICANON does more than just set line buffering, may need a bit more thought - termios t; - tcgetattr(0, &t); - t.c_lflag = (t.c_lflag&~ICANON) | (l?ICANON:0); - tcsetattr(0, TCSADRAIN, &t); -#endif -} - -void Console::get_size(unsigned &rows, unsigned &cols) -{ - if(!(mode&M_WRITE)) - throw InvalidState("Size can only be queried from an output console"); - -#ifdef WIN32 - // XXX Figure out how to do this - rows = 24; - cols = 80; -#else - struct winsize wsz; - ioctl(handle, TIOCGWINSZ, &wsz); - rows = wsz.ws_row; - cols = wsz.ws_col; -#endif -} - -unsigned Console::do_write(const char *buf, unsigned len) -{ - if(!(mode&M_WRITE)) - throw InvalidState("Console is not writable"); - -#ifdef WIN32 - DWORD ret; - if(!WriteFile(handle, buf, len, &ret, 0)) - throw SystemError("Writing to console failed", GetLastError()); -#else - int ret = ::write(handle, buf, len); - if(ret==-1) - throw SystemError("Writing to console failed", errno); -#endif - - return ret; -} - -unsigned Console::do_read(char *buf, unsigned len) -{ - if(!(mode&M_READ)) - throw InvalidState("Console is not readable"); - -#ifdef WIN32 - DWORD ret; - if(!ReadFile(handle, buf, len, &ret, 0)) - throw SystemError("Reading from console failed", GetLastError()); -#else - int ret = ::read(handle, buf, len); - if(ret==-1) - { - if(errno==EAGAIN) - return 0; - else - throw SystemError("Reading from console failed", errno); - } - else if(ret==0) - eof_flag = true; -#endif - - return ret; -} - -Handle Console::get_event_handle() -{ - return 0; -} - -Console &Console::instance(unsigned n) -{ - static Console in(0); - static Console out(1); - static Console err(2); - - switch(n) - { - case 0: return in; - case 1: return out; - case 2: return err; - } - - throw InvalidParameterValue("Unknown Console instance requested"); -} - -Console &cin = Console::instance(0); -Console &cout = Console::instance(1); -Console &cerr = Console::instance(2); - -} // namespace IO -} // namespace Msp diff --git a/source/console.h b/source/console.h deleted file mode 100644 index 3c0bb71..0000000 --- a/source/console.h +++ /dev/null @@ -1,56 +0,0 @@ -#ifndef MSP_IO_CONSOLE_H_ -#define MSP_IO_CONSOLE_H_ - -#include "base.h" - -namespace Msp { -namespace IO { - -/** -Provides access to standard input, output and error streams. This class can't -be instantiated directly - use one of the cin, cout and cerr references -instead. -*/ -class Console: public Base -{ -private: - Handle handle; - - Console(unsigned); -public: - ~Console(); - - virtual void set_block(bool); - - /** If local echo is enabled, characters will appear on the console as they - are typed. Can only be used on an input Console. */ - void set_local_echo(bool); - - /** If line buffering is enabled, input will only be available when a - newline is encountered. On some systems, this may also enable line editing. - Can only be used on an input Console. - */ - void set_line_buffer(bool); - - /** Retrieves the size of the Console. Can only be used on an output - Console. */ - void get_size(unsigned &rows, unsigned &cols); - -protected: - virtual unsigned do_write(const char *, unsigned); - virtual unsigned do_read(char *, unsigned); - -public: - virtual Handle get_event_handle(); - - static Console &instance(unsigned); -}; - -extern Console &cin; -extern Console &cout; -extern Console &cerr; - -} // namespace IO -} // namespace Msp - -#endif diff --git a/source/eventdispatcher.cpp b/source/eventdispatcher.cpp deleted file mode 100644 index 06a594f..0000000 --- a/source/eventdispatcher.cpp +++ /dev/null @@ -1,75 +0,0 @@ -#include -#include "base.h" -#include "eventdispatcher.h" -#include "poll.h" - -namespace Msp { -namespace IO { - -EventDispatcher::EventDispatcher() -{ } - -void EventDispatcher::add(Base &obj) -{ - SlotMap::iterator i = objects.find(&obj); - if(i==objects.end()) - { - i = objects.insert(SlotMap::value_type(&obj, Slot(&obj))).first; - i->second.evch_conn = obj.signal_events_changed.connect(sigc::bind(sigc::mem_fun(this, &EventDispatcher::object_events_changed), &obj)); - i->second.del_conn = obj.signal_deleted.connect(sigc::bind(sigc::mem_fun(this, &EventDispatcher::object_deleted), &obj)); - - if(obj.get_events()) - poller.set_object(obj, obj.get_events()); - } -} - -void EventDispatcher::remove(Base &obj) -{ - SlotMap::iterator i = objects.find(&obj); - if(i!=objects.end()) - { - i->second.evch_conn.disconnect(); - i->second.del_conn.disconnect(); - objects.erase(i); - - poller.set_object(obj, P_NONE); - } -} - -void EventDispatcher::tick() -{ - if(objects.empty()) - return; - - if(poller.poll()>0) - dispatch(); -} - -void EventDispatcher::tick(const Time::TimeDelta &dt) -{ - if(objects.empty()) - return; - - if(poller.poll(dt)>0) - dispatch(); -} - -void EventDispatcher::object_events_changed(PollEvent ev, Base *obj) -{ - poller.set_object(*obj, ev); -} - -void EventDispatcher::object_deleted(Base *obj) -{ - remove(*obj); -} - -void EventDispatcher::dispatch() -{ - const Poller::SlotSeq &result = poller.get_result(); - for(Poller::SlotSeq::const_iterator i=result.begin(); i!=result.end(); ++i) - i->object->event(i->events); -} - -} // namespace IO -} // namespace Msp diff --git a/source/eventdispatcher.h b/source/eventdispatcher.h deleted file mode 100644 index 7e89d47..0000000 --- a/source/eventdispatcher.h +++ /dev/null @@ -1,55 +0,0 @@ -#ifndef EVENTDISPATCHER_H_ -#define EVENTDISPATCHER_H_ - -#include -#include -#include "poll.h" - -namespace Msp { -namespace IO { - -/** -Put your I/O objects inside one of these to get signaled when something happens -on some of them. -*/ -class EventDispatcher: public sigc::trackable -{ -private: - struct Slot - { - Base *obj; - sigc::connection evch_conn; - sigc::connection del_conn; - - Slot(Base *o): obj(o) { } - }; - - typedef std::map SlotMap; - - Poller poller; - SlotMap objects; - -public: - EventDispatcher(); - - void add(Base &); - void remove(Base &); - - /** Checks for and dispatches events. If there are no events available, - blocks until there are. */ - void tick(); - - /** Checks for and dispatches events. If there are no events available, - waits at most the specified time before returning. */ - void tick(const Time::TimeDelta &); - -private: - void object_events_changed(PollEvent, Base *); - void object_deleted(Base *); - void dispatch(); -}; - -} // namespace IO -} // namespace Msp - -#endif diff --git a/source/except.h b/source/except.h deleted file mode 100644 index 5770f64..0000000 --- a/source/except.h +++ /dev/null @@ -1,22 +0,0 @@ -#ifndef MSP_IO_EXCEPT_H_ -#define MSP_IO_EXCEPT_H_ - -#include - -namespace Msp { -namespace IO { - -class FileNotFound: public Exception -{ -public: - FileNotFound(const std::string &w_, const std::string &f): Exception(w_), filename(f) { } - const std::string &get_filename() { return filename; } - ~FileNotFound() throw() { } -private: - std::string filename; -}; - -} // namespace IO -} // namespace Msp - -#endif diff --git a/source/file.cpp b/source/file.cpp deleted file mode 100644 index 2990d5c..0000000 --- a/source/file.cpp +++ /dev/null @@ -1,242 +0,0 @@ -#ifndef WIN32 -#include -#include -#include -#endif -#include -#include "except.h" -#include "file.h" - -using namespace std; - -namespace Msp { -namespace IO { - -File::File(const string &fn, Mode m, CreateMode cm) -{ - if(!(m&M_RDWR)) - throw InvalidParameterValue("Invalid read/write mode"); - if(cm&~(C_CREATE|C_TRUNCATE)) - throw InvalidParameterValue("Invalid create mode"); - - mode = m; - -#ifdef WIN32 - int flags = 0; - int create_flags = OPEN_EXISTING; - - if(mode&M_READ) - flags |= GENERIC_READ; - else 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_CREATE+C_TRUNCATE: create_flags = CREATE_ALWAYS; break; - } - } - - handle = CreateFile(fn.c_str(), flags, 0, 0, create_flags, FILE_ATTRIBUTE_NORMAL, 0); - if(handle==INVALID_HANDLE_VALUE) - { - int err = GetLastError(); - if(err==ERROR_FILE_NOT_FOUND) - throw FileNotFound("Can't find file "+fn, fn); - else - throw SystemError(format("Can't open file '%s'", fn), GetLastError()); - } -#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(mode&M_APPEND) - flags |= O_APPEND; - if(mode&M_NONBLOCK) - flags |= O_NONBLOCK; - - handle = ::open(fn.c_str(), flags, 0666); - if(handle==-1) - { - int err = errno; - if(err==ENOENT) - throw FileNotFound("Can't find file "+fn, fn); - else - throw SystemError(format("Can't open file '%s'", fn), err); - } -#endif - - set_events(P_INPUT); -} - -File::~File() -{ - close(); -} - -void File::close() -{ - if(handle==MSP_IO_INVALID_HANDLE) - return; - - set_events(P_NONE); - - signal_flush_required.emit(); - -#ifdef WIN32 - CloseHandle(handle); -#else - ::close(handle); -#endif - - handle = MSP_IO_INVALID_HANDLE; - signal_closed.emit(); -} - -void File::set_block(bool b) -{ - check_access(M_NONE); - - 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 -} - -unsigned File::do_write(const char *buf, unsigned size) -{ - check_access(M_WRITE); - - if(size==0) - return 0; - -#ifdef WIN32 - if(mode&M_APPEND) - seek(0, S_END); - DWORD ret; - if(WriteFile(handle, buf, size, &ret, 0)==0) - throw SystemError("Writing to file failed", GetLastError()); -#else - int ret = ::write(handle, buf, size); - if(ret==-1) - { - if(errno==EAGAIN) - return 0; - else - throw SystemError("Writing to file failed", errno); - } -#endif - - return ret; -} - -unsigned File::do_read(char *buf, unsigned size) -{ - check_access(M_READ); - - if(size==0) - return 0; - -#ifdef WIN32 - DWORD ret; - if(ReadFile(handle, buf, size, &ret, 0)==0) - throw SystemError("Reading from file failed", GetLastError()); -#else - int ret = ::read(handle, buf, size); - if(ret==-1) - { - if(errno==EAGAIN) - return 0; - else - throw SystemError("Reading from file failed", errno); - } -#endif - - if(ret==0) - { - eof_flag = true; - signal_end_of_file.emit(); - } - - return ret; -} - -void File::sync() -{ -#ifndef WIN32 - signal_flush_required.emit(); - - fsync(handle); -#endif -} - -int File::seek(int off, SeekType st) -{ - check_access(M_NONE); - - signal_flush_required.emit(); - - int type = sys_seek_type(st); -#ifdef WIN32 - DWORD ret = SetFilePointer(handle, off, 0, type); - if(ret==INVALID_SET_FILE_POINTER) - throw SystemError("Seek failed", GetLastError()); -#else - int ret = lseek(handle, off, type); - if(ret==-1) - throw SystemError("Seek failed", errno); -#endif - - eof_flag = false; - - return ret; -} - -int File::tell() const -{ - check_access(M_NONE); - -#ifdef WIN32 - DWORD ret = SetFilePointer(handle, 0, 0, FILE_CURRENT); - if(ret==INVALID_SET_FILE_POINTER) - throw SystemError("Tell failed", GetLastError()); -#else - int ret = lseek(handle, 0, SEEK_CUR); - if(ret==-1) - throw SystemError("Tell failed", errno); -#endif - - return ret; -} - -void File::check_access(Mode m) const -{ - if(handle==MSP_IO_INVALID_HANDLE) - throw InvalidState("File is not open"); - if(m==M_READ && !(mode&M_READ)) - throw InvalidState("File is not readable"); - if(m==M_WRITE && !(mode&M_WRITE)) - throw InvalidState("File is not writable"); -} - -} // namespace IO -} // namespace Msp diff --git a/source/file.h b/source/file.h deleted file mode 100644 index 05aaf95..0000000 --- a/source/file.h +++ /dev/null @@ -1,77 +0,0 @@ -#ifndef MSP_IO_FILE_H_ -#define MSP_IO_FILE_H_ - -#include -#include "base.h" -#include "buffered.h" -#include "filtered.h" -#include "seek.h" - -namespace Msp { -namespace IO { - -/** -A class for reading and writing files. - -Non-blocking mode is not supported on Win32. -*/ -class File: public Base -{ -public: - enum CreateMode - { - C_NONE = 0, - C_CREATE = 1, - C_TRUNCATE = 2 - }; - -private: - Handle handle; - -public: - /** Creates a new file object and opens it. If the create flag is set and - 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 = CreateMode(C_CREATE+C_TRUNCATE)); - virtual ~File(); - - /** Closes the file. Any attempt to access the file after this will cause - an exception to be thrown. */ - void close(); - - void set_block(bool); - -protected: - virtual unsigned do_write(const char *, unsigned); - virtual unsigned do_read(char *, unsigned); - -public: - virtual void sync(); - - /** Changes the read/write offset of the file. Returns the new offset. */ - virtual int seek(int, SeekType); - - /** Returns the current read/write offset of the file. */ - virtual int tell() const; - - virtual Handle get_event_handle() { return handle; } - -private: - void check_access(Mode) const; -}; - -inline File::CreateMode operator|(File::CreateMode m, File::CreateMode n) -{ return File::CreateMode(static_cast(m)|static_cast(n)); } - -inline File::CreateMode operator&(File::CreateMode m, File::CreateMode n) -{ return File::CreateMode(static_cast(m)&static_cast(n)); } - -inline File::CreateMode operator~(File::CreateMode m) -{ return File::CreateMode(~static_cast(m)); } - -typedef Filtered BufferedFile; - -} // namespace IO -} // namespace Msp - -#endif diff --git a/source/filtered.h b/source/filtered.h deleted file mode 100644 index 0d323ec..0000000 --- a/source/filtered.h +++ /dev/null @@ -1,66 +0,0 @@ -#ifndef MSP_IO_FILTERED_H_ -#define MSP_IO_FILTERED_H_ - -namespace Msp { -namespace IO { - -template -class Filtered: public B -{ -private: - struct Activator - { - Filtered &f; - - Activator(Filtered &f_): f(f_) { f.active = true; } - ~Activator() { f.active = false; } - }; - - F filter; - bool active; - -public: - Filtered(): filter(*this), active(false) { } - ~Filtered() { active = true; } - - template - Filtered(A0 a0): B(a0), filter(*this), active(false) { } - - template - Filtered(A0 a0, A1 a1): B(a0, a1), filter(*this), active(false) { } - -protected: - virtual unsigned do_write(const char *b, unsigned s) - { - if(!active) - { - Activator a(*this); - return filter.write(b, s); - } - else - return B::do_write(b, s); - } - - virtual unsigned do_read(char *b, unsigned s) - { - if(!active) - { - Activator a(*this); - return filter.read(b, s); - } - else - return B::do_read(b, s); - } - -public: - virtual unsigned put(char c) { return filter.put(c); } - virtual bool getline(std::string &l) { return filter.getline(l); } - virtual int get() { return filter.get(); } - - F &get_filter() { return filter; } -}; - -} // namespace IO -} // namespace Msp - -#endif diff --git a/source/io/base.cpp b/source/io/base.cpp new file mode 100644 index 0000000..48de3ee --- /dev/null +++ b/source/io/base.cpp @@ -0,0 +1,61 @@ +#include "base.h" +#include "poll.h" + +using namespace std; + +namespace Msp { +namespace IO { + +Base::Base(): + mode(M_READ), + events(P_NONE), + eof_flag(false) +{ } + +Base::~Base() +{ + signal_deleted.emit(); +} + +bool Base::getline(string &line) +{ + line.clear(); + + if(eof_flag) + return false; + + while(1) + { + int c = get(); + if(c==-1 || c=='\n') + break; + line += c; + } + + return !eof_flag || !line.empty(); +} + +int Base::get() +{ + char c; + if(do_read(&c, 1)==0) + return -1; + return static_cast(c); +} + +void Base::set_events(PollEvent e) +{ + events = e; + signal_events_changed.emit(events); +} + +void Base::event(PollEvent ev) +{ + if(ev&P_INPUT) + signal_data_available.emit(); + + on_event(ev); +} + +} // namespace IO +} // namespace Msp diff --git a/source/io/base.h b/source/io/base.h new file mode 100644 index 0000000..774d034 --- /dev/null +++ b/source/io/base.h @@ -0,0 +1,121 @@ +#ifndef MSP_IO_BASE_H_ +#define MSP_IO_BASE_H_ + +#include +#include "mode.h" +#include "poll.h" +#include "types.h" + +namespace Msp { +namespace IO { + +/** +Common interface for all I/O objects. + +A derived class must call set_events(P_NONE) before it is destroyed to avoid +leaving stale pointers in an EventDispatcher. +*/ +class Base +{ +public: + /** Emitted when there is data available for reading. If all data is not + read, the signal is emitted again immediately. */ + sigc::signal signal_data_available; + + /** Emitted when there is no more data to be read. */ + sigc::signal signal_end_of_file; + + /** Emitted when there is a nonlinearity in I/O (such as a file being + seeked) and any data buffered by upper layers needs to be flushed. */ + sigc::signal signal_flush_required; + + /** Emitted when the I/O object has closed. */ + sigc::signal signal_closed; + + /** Emitted when the mask of interesting events changes. Mainly for use by + EventDispatcher. */ + sigc::signal signal_events_changed; + + /** Emitted when the object is deleted. Mainly for use by + EventDispatcher. */ + sigc::signal signal_deleted; + +protected: + Mode mode; + PollEvent events; + bool eof_flag; + + Base(); +private: + Base(const Base &); + Base &operator=(const Base &); +public: + virtual ~Base(); + + /** Sets blocking mode. When blocking is enabled, most operations won't + return until they can make progress. When blocking is disabled, these + operations may return immediately with a return code indicating that nothing + was done. + + Blocking is enabled by default. */ + virtual void set_block(bool) { } + + /** Returns the current mode flags. */ + Mode get_mode() const { return mode; } + +protected: + virtual unsigned do_write(const char *, unsigned) =0; + virtual unsigned do_read(char *, unsigned) =0; + +public: + /** Writes data from a buffer. Subject to blocking. Returns the number of + bytes written, which may be zero for a non-blockin operation. */ + unsigned write(const char *b, unsigned c) { return do_write(b, c); } + + /** Writes a string. This is identical to calling + write(s.data(), s.size()). */ + unsigned write(const std::string &s) { return do_write(s.data(), s.size()); } + + /** Writes a single character. This is identical to calling + write(&c, 1). */ + virtual unsigned put(char c) { return do_write(&c, 1); } + + /** Reads data into a buffer. Subject to blocking. Returns the number of + bytes read, which may be zero for a non-blocking operation. */ + unsigned read(char *b, unsigned c) { return do_read(b, c); } + + /** Reads characters up to the next linefeed or end-of-file. The linefeed + is not included in the line. Returns true if a line was successfully read, + false otherwise. */ + virtual bool getline(std::string &); + + /** Reads a single character. Returns -1 if no character was available due + to end-of-file or non-blocking operation. */ + virtual int get(); + + /** Returns the end-of-file flag. */ + bool eof() const { return eof_flag; } + +protected: + void set_events(PollEvent); + +public: + /** Returns a mask of the currently interesting events. Used by + EventDispatcher. */ + PollEvent get_events() const { return events; } + + /** Returns a handle for polling. Should throw if the object does not have + an event handle. */ + virtual Handle get_event_handle() =0; + + /** Notifies the object of an event. Used by EventDispatcher. */ + void event(PollEvent); + +protected: + virtual void on_event(PollEvent) { } +}; + +} // namespace IO +} // namespace Msp + +#endif diff --git a/source/io/buffered.cpp b/source/io/buffered.cpp new file mode 100644 index 0000000..f53d2fc --- /dev/null +++ b/source/io/buffered.cpp @@ -0,0 +1,188 @@ +#include +#include "buffered.h" +#include "except.h" + +using namespace std; + +namespace Msp { +namespace IO { + +Buffered::Buffered(Base &b, unsigned s): + below(b), + buf_size(s), + buf(new char[buf_size]), + begin(buf), + end(buf), + cur_op(M_NONE) +{ + mode = below.get_mode(); + below.signal_flush_required.connect(sigc::mem_fun(this, &Buffered::flush)); +} + +Buffered::~Buffered() +{ + try + { + flush(); + } + catch(...) + { } + + delete[] buf; +} + +void Buffered::flush() +{ + if(cur_op==M_WRITE) + { + unsigned used = end-begin; + if(used) + { + unsigned len = below.write(begin, used); + + begin=end = buf; + + if(len(end-begin), size); + memcpy(data, begin, len); + begin += len; + ret += len; + } + else + // Read the rest directly from the underlying object + ret += below.read(data, size); + + eof_flag = (below.eof() && begin==end); + + return ret; + } +} + +unsigned Buffered::put(char c) +{ + set_op(M_WRITE); + + if(end(*begin++); + + char c; + if(do_read(&c, 1)==0) + return -1; + return static_cast(c); +} + +void Buffered::set_op(Mode op) +{ + if(op!=cur_op) + flush(); + cur_op = op; +} + +unsigned Buffered::get_current_size() const +{ + return end-begin; +} + +Handle Buffered::get_event_handle() +{ + throw Exception("Buffered doesn't support events"); +} + +} // namespace IO +} // namespace Msp diff --git a/source/io/buffered.h b/source/io/buffered.h new file mode 100644 index 0000000..36d2a11 --- /dev/null +++ b/source/io/buffered.h @@ -0,0 +1,46 @@ +#ifndef MSP_IO_BUFFERED_H_ +#define MSP_IO_BUFFERED_H_ + +#include "base.h" + +namespace Msp { +namespace IO { + +class Buffered: public Base +{ +private: + Base &below; + unsigned buf_size; + char *buf; + char *begin; + char *end; + Mode cur_op; + +public: + Buffered(Base &, unsigned =8192); + ~Buffered(); + + void flush(); + +protected: + unsigned do_write(const char *, unsigned); + unsigned do_read(char *, unsigned); +public: + unsigned put(char); + + bool getline(std::string &); + int get(); + +private: + void set_op(Mode); +public: + Mode get_current_op() const { return cur_op; } + unsigned get_current_size() const; + + virtual Handle get_event_handle(); +}; + +} // namespace IO +} // namespace Msp + +#endif diff --git a/source/io/console.cpp b/source/io/console.cpp new file mode 100644 index 0000000..9db7737 --- /dev/null +++ b/source/io/console.cpp @@ -0,0 +1,187 @@ +#ifndef WIN32 +#include +#include +#include +#include +#endif +#include +#include "console.h" + +namespace { + +#ifndef WIN32 +termios orig_attr; +#endif + +} // namespace + +namespace Msp { +namespace IO { + +Console::Console(unsigned n) +{ + if(n>2) + throw InvalidParameterValue("Invalid parameter for Console::Console"); + + mode = (n==0 ? M_READ : M_WRITE); + +#ifdef WIN32 + switch(n) + { + case 0: handle = GetStdHandle(STD_INPUT_HANDLE); break; + case 1: handle = GetStdHandle(STD_OUTPUT_HANDLE); break; + case 2: handle = GetStdHandle(STD_ERROR_HANDLE); break; + } +#else + handle = n; + + if(handle==0) + tcgetattr(handle, &orig_attr); +#endif + + if(n==0) + set_events(P_INPUT); +} + +Console::~Console() +{ +#ifndef WIN32 + if(handle==0) + 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(0, F_GETFL); + flags = (flags&~O_NONBLOCK) | (b?0:O_NONBLOCK); + fcntl(0, F_SETFL, flags); +#endif +} + +void Console::set_local_echo(bool e) +{ + if(!(mode&M_READ)) + throw InvalidState("Local echo can only be set on input console"); + +#ifdef WIN32 + DWORD m; + GetConsoleMode(handle, &m); + SetConsoleMode(handle, (m&~ENABLE_ECHO_INPUT) | (e?ENABLE_ECHO_INPUT:0)); +#else + termios t; + tcgetattr(0, &t); + t.c_lflag = (t.c_lflag&~ECHO) | (e?ECHO:0); + tcsetattr(0, TCSADRAIN, &t); +#endif +} + +void Console::set_line_buffer(bool l) +{ + if(!(mode&M_READ)) + throw InvalidState("Line buffering can only be set on input console"); + +#ifdef WIN32 + DWORD m; + GetConsoleMode(handle, &m); + SetConsoleMode(handle, (m&~ENABLE_LINE_INPUT) | (l?ENABLE_LINE_INPUT:0)); +#else + // XXX ICANON does more than just set line buffering, may need a bit more thought + termios t; + tcgetattr(0, &t); + t.c_lflag = (t.c_lflag&~ICANON) | (l?ICANON:0); + tcsetattr(0, TCSADRAIN, &t); +#endif +} + +void Console::get_size(unsigned &rows, unsigned &cols) +{ + if(!(mode&M_WRITE)) + throw InvalidState("Size can only be queried from an output console"); + +#ifdef WIN32 + // XXX Figure out how to do this + rows = 24; + cols = 80; +#else + struct winsize wsz; + ioctl(handle, TIOCGWINSZ, &wsz); + rows = wsz.ws_row; + cols = wsz.ws_col; +#endif +} + +unsigned Console::do_write(const char *buf, unsigned len) +{ + if(!(mode&M_WRITE)) + throw InvalidState("Console is not writable"); + +#ifdef WIN32 + DWORD ret; + if(!WriteFile(handle, buf, len, &ret, 0)) + throw SystemError("Writing to console failed", GetLastError()); +#else + int ret = ::write(handle, buf, len); + if(ret==-1) + throw SystemError("Writing to console failed", errno); +#endif + + return ret; +} + +unsigned Console::do_read(char *buf, unsigned len) +{ + if(!(mode&M_READ)) + throw InvalidState("Console is not readable"); + +#ifdef WIN32 + DWORD ret; + if(!ReadFile(handle, buf, len, &ret, 0)) + throw SystemError("Reading from console failed", GetLastError()); +#else + int ret = ::read(handle, buf, len); + if(ret==-1) + { + if(errno==EAGAIN) + return 0; + else + throw SystemError("Reading from console failed", errno); + } + else if(ret==0) + eof_flag = true; +#endif + + return ret; +} + +Handle Console::get_event_handle() +{ + return 0; +} + +Console &Console::instance(unsigned n) +{ + static Console in(0); + static Console out(1); + static Console err(2); + + switch(n) + { + case 0: return in; + case 1: return out; + case 2: return err; + } + + throw InvalidParameterValue("Unknown Console instance requested"); +} + +Console &cin = Console::instance(0); +Console &cout = Console::instance(1); +Console &cerr = Console::instance(2); + +} // namespace IO +} // namespace Msp diff --git a/source/io/console.h b/source/io/console.h new file mode 100644 index 0000000..3c0bb71 --- /dev/null +++ b/source/io/console.h @@ -0,0 +1,56 @@ +#ifndef MSP_IO_CONSOLE_H_ +#define MSP_IO_CONSOLE_H_ + +#include "base.h" + +namespace Msp { +namespace IO { + +/** +Provides access to standard input, output and error streams. This class can't +be instantiated directly - use one of the cin, cout and cerr references +instead. +*/ +class Console: public Base +{ +private: + Handle handle; + + Console(unsigned); +public: + ~Console(); + + virtual void set_block(bool); + + /** If local echo is enabled, characters will appear on the console as they + are typed. Can only be used on an input Console. */ + void set_local_echo(bool); + + /** If line buffering is enabled, input will only be available when a + newline is encountered. On some systems, this may also enable line editing. + Can only be used on an input Console. + */ + void set_line_buffer(bool); + + /** Retrieves the size of the Console. Can only be used on an output + Console. */ + void get_size(unsigned &rows, unsigned &cols); + +protected: + virtual unsigned do_write(const char *, unsigned); + virtual unsigned do_read(char *, unsigned); + +public: + virtual Handle get_event_handle(); + + static Console &instance(unsigned); +}; + +extern Console &cin; +extern Console &cout; +extern Console &cerr; + +} // namespace IO +} // namespace Msp + +#endif diff --git a/source/io/eventdispatcher.cpp b/source/io/eventdispatcher.cpp new file mode 100644 index 0000000..06a594f --- /dev/null +++ b/source/io/eventdispatcher.cpp @@ -0,0 +1,75 @@ +#include +#include "base.h" +#include "eventdispatcher.h" +#include "poll.h" + +namespace Msp { +namespace IO { + +EventDispatcher::EventDispatcher() +{ } + +void EventDispatcher::add(Base &obj) +{ + SlotMap::iterator i = objects.find(&obj); + if(i==objects.end()) + { + i = objects.insert(SlotMap::value_type(&obj, Slot(&obj))).first; + i->second.evch_conn = obj.signal_events_changed.connect(sigc::bind(sigc::mem_fun(this, &EventDispatcher::object_events_changed), &obj)); + i->second.del_conn = obj.signal_deleted.connect(sigc::bind(sigc::mem_fun(this, &EventDispatcher::object_deleted), &obj)); + + if(obj.get_events()) + poller.set_object(obj, obj.get_events()); + } +} + +void EventDispatcher::remove(Base &obj) +{ + SlotMap::iterator i = objects.find(&obj); + if(i!=objects.end()) + { + i->second.evch_conn.disconnect(); + i->second.del_conn.disconnect(); + objects.erase(i); + + poller.set_object(obj, P_NONE); + } +} + +void EventDispatcher::tick() +{ + if(objects.empty()) + return; + + if(poller.poll()>0) + dispatch(); +} + +void EventDispatcher::tick(const Time::TimeDelta &dt) +{ + if(objects.empty()) + return; + + if(poller.poll(dt)>0) + dispatch(); +} + +void EventDispatcher::object_events_changed(PollEvent ev, Base *obj) +{ + poller.set_object(*obj, ev); +} + +void EventDispatcher::object_deleted(Base *obj) +{ + remove(*obj); +} + +void EventDispatcher::dispatch() +{ + const Poller::SlotSeq &result = poller.get_result(); + for(Poller::SlotSeq::const_iterator i=result.begin(); i!=result.end(); ++i) + i->object->event(i->events); +} + +} // namespace IO +} // namespace Msp diff --git a/source/io/eventdispatcher.h b/source/io/eventdispatcher.h new file mode 100644 index 0000000..7e89d47 --- /dev/null +++ b/source/io/eventdispatcher.h @@ -0,0 +1,55 @@ +#ifndef EVENTDISPATCHER_H_ +#define EVENTDISPATCHER_H_ + +#include +#include +#include "poll.h" + +namespace Msp { +namespace IO { + +/** +Put your I/O objects inside one of these to get signaled when something happens +on some of them. +*/ +class EventDispatcher: public sigc::trackable +{ +private: + struct Slot + { + Base *obj; + sigc::connection evch_conn; + sigc::connection del_conn; + + Slot(Base *o): obj(o) { } + }; + + typedef std::map SlotMap; + + Poller poller; + SlotMap objects; + +public: + EventDispatcher(); + + void add(Base &); + void remove(Base &); + + /** Checks for and dispatches events. If there are no events available, + blocks until there are. */ + void tick(); + + /** Checks for and dispatches events. If there are no events available, + waits at most the specified time before returning. */ + void tick(const Time::TimeDelta &); + +private: + void object_events_changed(PollEvent, Base *); + void object_deleted(Base *); + void dispatch(); +}; + +} // namespace IO +} // namespace Msp + +#endif diff --git a/source/io/except.h b/source/io/except.h new file mode 100644 index 0000000..5770f64 --- /dev/null +++ b/source/io/except.h @@ -0,0 +1,22 @@ +#ifndef MSP_IO_EXCEPT_H_ +#define MSP_IO_EXCEPT_H_ + +#include + +namespace Msp { +namespace IO { + +class FileNotFound: public Exception +{ +public: + FileNotFound(const std::string &w_, const std::string &f): Exception(w_), filename(f) { } + const std::string &get_filename() { return filename; } + ~FileNotFound() throw() { } +private: + std::string filename; +}; + +} // namespace IO +} // namespace Msp + +#endif diff --git a/source/io/file.cpp b/source/io/file.cpp new file mode 100644 index 0000000..2990d5c --- /dev/null +++ b/source/io/file.cpp @@ -0,0 +1,242 @@ +#ifndef WIN32 +#include +#include +#include +#endif +#include +#include "except.h" +#include "file.h" + +using namespace std; + +namespace Msp { +namespace IO { + +File::File(const string &fn, Mode m, CreateMode cm) +{ + if(!(m&M_RDWR)) + throw InvalidParameterValue("Invalid read/write mode"); + if(cm&~(C_CREATE|C_TRUNCATE)) + throw InvalidParameterValue("Invalid create mode"); + + mode = m; + +#ifdef WIN32 + int flags = 0; + int create_flags = OPEN_EXISTING; + + if(mode&M_READ) + flags |= GENERIC_READ; + else 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_CREATE+C_TRUNCATE: create_flags = CREATE_ALWAYS; break; + } + } + + handle = CreateFile(fn.c_str(), flags, 0, 0, create_flags, FILE_ATTRIBUTE_NORMAL, 0); + if(handle==INVALID_HANDLE_VALUE) + { + int err = GetLastError(); + if(err==ERROR_FILE_NOT_FOUND) + throw FileNotFound("Can't find file "+fn, fn); + else + throw SystemError(format("Can't open file '%s'", fn), GetLastError()); + } +#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(mode&M_APPEND) + flags |= O_APPEND; + if(mode&M_NONBLOCK) + flags |= O_NONBLOCK; + + handle = ::open(fn.c_str(), flags, 0666); + if(handle==-1) + { + int err = errno; + if(err==ENOENT) + throw FileNotFound("Can't find file "+fn, fn); + else + throw SystemError(format("Can't open file '%s'", fn), err); + } +#endif + + set_events(P_INPUT); +} + +File::~File() +{ + close(); +} + +void File::close() +{ + if(handle==MSP_IO_INVALID_HANDLE) + return; + + set_events(P_NONE); + + signal_flush_required.emit(); + +#ifdef WIN32 + CloseHandle(handle); +#else + ::close(handle); +#endif + + handle = MSP_IO_INVALID_HANDLE; + signal_closed.emit(); +} + +void File::set_block(bool b) +{ + check_access(M_NONE); + + 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 +} + +unsigned File::do_write(const char *buf, unsigned size) +{ + check_access(M_WRITE); + + if(size==0) + return 0; + +#ifdef WIN32 + if(mode&M_APPEND) + seek(0, S_END); + DWORD ret; + if(WriteFile(handle, buf, size, &ret, 0)==0) + throw SystemError("Writing to file failed", GetLastError()); +#else + int ret = ::write(handle, buf, size); + if(ret==-1) + { + if(errno==EAGAIN) + return 0; + else + throw SystemError("Writing to file failed", errno); + } +#endif + + return ret; +} + +unsigned File::do_read(char *buf, unsigned size) +{ + check_access(M_READ); + + if(size==0) + return 0; + +#ifdef WIN32 + DWORD ret; + if(ReadFile(handle, buf, size, &ret, 0)==0) + throw SystemError("Reading from file failed", GetLastError()); +#else + int ret = ::read(handle, buf, size); + if(ret==-1) + { + if(errno==EAGAIN) + return 0; + else + throw SystemError("Reading from file failed", errno); + } +#endif + + if(ret==0) + { + eof_flag = true; + signal_end_of_file.emit(); + } + + return ret; +} + +void File::sync() +{ +#ifndef WIN32 + signal_flush_required.emit(); + + fsync(handle); +#endif +} + +int File::seek(int off, SeekType st) +{ + check_access(M_NONE); + + signal_flush_required.emit(); + + int type = sys_seek_type(st); +#ifdef WIN32 + DWORD ret = SetFilePointer(handle, off, 0, type); + if(ret==INVALID_SET_FILE_POINTER) + throw SystemError("Seek failed", GetLastError()); +#else + int ret = lseek(handle, off, type); + if(ret==-1) + throw SystemError("Seek failed", errno); +#endif + + eof_flag = false; + + return ret; +} + +int File::tell() const +{ + check_access(M_NONE); + +#ifdef WIN32 + DWORD ret = SetFilePointer(handle, 0, 0, FILE_CURRENT); + if(ret==INVALID_SET_FILE_POINTER) + throw SystemError("Tell failed", GetLastError()); +#else + int ret = lseek(handle, 0, SEEK_CUR); + if(ret==-1) + throw SystemError("Tell failed", errno); +#endif + + return ret; +} + +void File::check_access(Mode m) const +{ + if(handle==MSP_IO_INVALID_HANDLE) + throw InvalidState("File is not open"); + if(m==M_READ && !(mode&M_READ)) + throw InvalidState("File is not readable"); + if(m==M_WRITE && !(mode&M_WRITE)) + throw InvalidState("File is not writable"); +} + +} // namespace IO +} // namespace Msp diff --git a/source/io/file.h b/source/io/file.h new file mode 100644 index 0000000..05aaf95 --- /dev/null +++ b/source/io/file.h @@ -0,0 +1,77 @@ +#ifndef MSP_IO_FILE_H_ +#define MSP_IO_FILE_H_ + +#include +#include "base.h" +#include "buffered.h" +#include "filtered.h" +#include "seek.h" + +namespace Msp { +namespace IO { + +/** +A class for reading and writing files. + +Non-blocking mode is not supported on Win32. +*/ +class File: public Base +{ +public: + enum CreateMode + { + C_NONE = 0, + C_CREATE = 1, + C_TRUNCATE = 2 + }; + +private: + Handle handle; + +public: + /** Creates a new file object and opens it. If the create flag is set and + 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 = CreateMode(C_CREATE+C_TRUNCATE)); + virtual ~File(); + + /** Closes the file. Any attempt to access the file after this will cause + an exception to be thrown. */ + void close(); + + void set_block(bool); + +protected: + virtual unsigned do_write(const char *, unsigned); + virtual unsigned do_read(char *, unsigned); + +public: + virtual void sync(); + + /** Changes the read/write offset of the file. Returns the new offset. */ + virtual int seek(int, SeekType); + + /** Returns the current read/write offset of the file. */ + virtual int tell() const; + + virtual Handle get_event_handle() { return handle; } + +private: + void check_access(Mode) const; +}; + +inline File::CreateMode operator|(File::CreateMode m, File::CreateMode n) +{ return File::CreateMode(static_cast(m)|static_cast(n)); } + +inline File::CreateMode operator&(File::CreateMode m, File::CreateMode n) +{ return File::CreateMode(static_cast(m)&static_cast(n)); } + +inline File::CreateMode operator~(File::CreateMode m) +{ return File::CreateMode(~static_cast(m)); } + +typedef Filtered BufferedFile; + +} // namespace IO +} // namespace Msp + +#endif diff --git a/source/io/filtered.h b/source/io/filtered.h new file mode 100644 index 0000000..0d323ec --- /dev/null +++ b/source/io/filtered.h @@ -0,0 +1,66 @@ +#ifndef MSP_IO_FILTERED_H_ +#define MSP_IO_FILTERED_H_ + +namespace Msp { +namespace IO { + +template +class Filtered: public B +{ +private: + struct Activator + { + Filtered &f; + + Activator(Filtered &f_): f(f_) { f.active = true; } + ~Activator() { f.active = false; } + }; + + F filter; + bool active; + +public: + Filtered(): filter(*this), active(false) { } + ~Filtered() { active = true; } + + template + Filtered(A0 a0): B(a0), filter(*this), active(false) { } + + template + Filtered(A0 a0, A1 a1): B(a0, a1), filter(*this), active(false) { } + +protected: + virtual unsigned do_write(const char *b, unsigned s) + { + if(!active) + { + Activator a(*this); + return filter.write(b, s); + } + else + return B::do_write(b, s); + } + + virtual unsigned do_read(char *b, unsigned s) + { + if(!active) + { + Activator a(*this); + return filter.read(b, s); + } + else + return B::do_read(b, s); + } + +public: + virtual unsigned put(char c) { return filter.put(c); } + virtual bool getline(std::string &l) { return filter.getline(l); } + virtual int get() { return filter.get(); } + + F &get_filter() { return filter; } +}; + +} // namespace IO +} // namespace Msp + +#endif diff --git a/source/io/memory.cpp b/source/io/memory.cpp new file mode 100644 index 0000000..6ea130b --- /dev/null +++ b/source/io/memory.cpp @@ -0,0 +1,127 @@ +#include +#include +#include "except.h" +#include "memory.h" + +using namespace std; + +namespace Msp { +namespace IO { + +Memory::Memory(char *d, unsigned s) +{ + init(d, d+s, M_RDWR); +} + +Memory::Memory(char *b, char *e) +{ + init(b, e, M_RDWR); +} + +Memory::Memory(const char *cd, unsigned s) +{ + char *d = const_cast(cd); + init(d, d+s, M_READ); +} + +Memory::Memory(const char *b, const char *e) +{ + init(const_cast(b), const_cast(e), M_READ); +} + +void Memory::init(char *b, char *e, Mode m) +{ + begin = b; + end = e; + pos = begin; + mode = m; +} + +unsigned Memory::do_write(const char *buf, unsigned size) +{ + check_mode(M_WRITE); + + size = min(size, end-pos); + memcpy(pos, buf, size); + pos += size; + return size; +} + +unsigned Memory::do_read(char *buf, unsigned size) +{ + if(pos==end) + { + eof_flag = true; + return 0; + } + + size = min(size, end-pos); + memcpy(buf, pos, size); + pos += size; + return size; +} + +unsigned Memory::put(char c) +{ + check_mode(M_WRITE); + *pos++ = c; + return 1; +} + +bool Memory::getline(string &line) +{ + char *nl = find(pos, end, '\n'); + line.assign(pos, nl); + bool result = (nl!=pos); + pos = nl; + return result; +} + +int Memory::get() +{ + if(pos==end) + { + eof_flag = true; + return -1; + } + + return static_cast(*pos++); +} + +unsigned Memory::seek(int off, SeekType type) +{ + char *new_pos; + if(type==S_BEG) + new_pos = begin+off; + else if(type==S_CUR) + new_pos = pos+off; + else if(type==S_END) + new_pos = end+off; + else + throw InvalidParameterValue("Invalid seek type"); + + if(new_posend) + throw InvalidParameterValue("Invalid seek offset"); + + pos = new_pos; + return pos-begin; +} + +Handle Memory::get_event_handle() +{ + throw Exception("Memory doesn't support events"); +} + +void Memory::check_mode(Mode m) const +{ + if(m==M_WRITE) + { + if(!(mode&M_WRITE)) + throw InvalidState("Memory is not writable"); + if(pos==end) + throw InvalidState("Attempt to write past end of Memory"); + } +} + +} // namespace IO +} // namespace Msp diff --git a/source/io/memory.h b/source/io/memory.h new file mode 100644 index 0000000..ba6c4d8 --- /dev/null +++ b/source/io/memory.h @@ -0,0 +1,44 @@ +#ifndef MSP_IO_MEMORY_H_ +#define MSP_IO_MEMORY_H_ + +#include "base.h" +#include "seek.h" + +namespace Msp { +namespace IO { + +class Memory: public Base +{ +private: + char *begin; + char *end; + char *pos; + +public: + Memory(char *, unsigned); + Memory(char *, char *); + Memory(const char *, unsigned); + Memory(const char *, const char *); +private: + void init(char *, char *, Mode); + + virtual unsigned do_write(const char *, unsigned); + virtual unsigned do_read(char *, unsigned); +public: + virtual unsigned put(char); + virtual bool getline(std::string &); + virtual int get(); + + unsigned seek(int, SeekType); + unsigned tell() const { return pos-begin; } + + virtual Handle get_event_handle(); + +private: + void check_mode(Mode) const; +}; + +} // namespace IO +} // namespace Msp + +#endif diff --git a/source/io/mode.h b/source/io/mode.h new file mode 100644 index 0000000..5e103f2 --- /dev/null +++ b/source/io/mode.h @@ -0,0 +1,29 @@ +#ifndef MSP_IO_MODE_H_ +#define MSP_IO_MODE_H_ + +namespace Msp { +namespace IO { + +enum Mode +{ + M_NONE = 0, + M_READ = 1, + M_WRITE = 2, + M_RDWR = M_READ|M_WRITE, + M_APPEND = 4, + M_NONBLOCK = 8 +}; + +inline Mode operator|(Mode m, Mode n) +{ return Mode(static_cast(m)|static_cast(n)); } + +inline Mode operator&(Mode m, Mode n) +{ return Mode(static_cast(m)&static_cast(n)); } + +inline Mode operator~(Mode m) +{ return Mode(~static_cast(m)); } + +} // namespace IO +} // namespace Msp + +#endif diff --git a/source/io/pipe.cpp b/source/io/pipe.cpp new file mode 100644 index 0000000..b3735aa --- /dev/null +++ b/source/io/pipe.cpp @@ -0,0 +1,182 @@ +#ifndef WIN32 +#include +#include +#endif +#include +#include "pipe.h" + +using namespace std; + +namespace Msp { +namespace IO { + +Pipe::Pipe() +{ +#ifdef WIN32 + string name = format("\\\\.\\pipe\\%u.%p", GetCurrentProcessId(), this); + handle[0] = CreateNamedPipe(name.c_str(), PIPE_ACCESS_INBOUND|FILE_FLAG_OVERLAPPED, PIPE_TYPE_BYTE, 1, 1024, 1024, 0, 0); + if(handle[0]==INVALID_HANDLE_VALUE) + throw SystemError("Unable to create pipe", GetLastError()); + + handle[1] = CreateFile(name.c_str(), GENERIC_WRITE, 0, 0, OPEN_EXISTING, 0, 0); + if(handle[1]==INVALID_HANDLE_VALUE) + { + unsigned err = GetLastError(); + CloseHandle(handle[0]); + throw SystemError("Unable to create pipe", err); + } + + overlapped = 0; + event = CreateEvent(0, true, false, 0); + buf_size = 1024; + buffer = new char[buf_size]; + buf_avail = 0; + buf_next = buffer; +#else + if(pipe(handle)==-1) + throw SystemError("Unable to create pipe", errno); +#endif + + set_events(P_INPUT); +} + +Pipe::~Pipe() +{ + close(); +} + +void Pipe::close() +{ + set_events(P_NONE); + + signal_flush_required.emit(); +#ifdef WIN32 + CloseHandle(handle[0]); + CloseHandle(handle[1]); +#else + ::close(handle[0]); + ::close(handle[1]); + signal_closed.emit(); +#endif +} + +void Pipe::set_block(bool b) +{ + mode = (mode&~M_NONBLOCK); + if(b) + mode = (mode|M_NONBLOCK); + +#ifndef WIN32 + int flags = fcntl(handle[0], F_GETFD); + fcntl(handle[0], F_SETFL, (flags&O_NONBLOCK)|(b?0:O_NONBLOCK)); + flags = fcntl(handle[1], F_GETFD); + fcntl(handle[1], F_SETFL, (flags&O_NONBLOCK)|(b?0:O_NONBLOCK)); +#endif +} + +unsigned Pipe::do_write(const char *buf, unsigned size) +{ + if(size==0) + return 0; + +#ifdef WIN32 + DWORD ret; + if(!WriteFile(handle[1], buf, size, &ret, 0)) + throw SystemError("Writing to pipe failed", GetLastError()); +#else + int ret = ::write(handle[1], buf, size); + if(ret==-1) + { + if(errno==EAGAIN) + return 0; + else + throw SystemError("Writing to pipe failed", errno); + } +#endif + + return ret; +} + +unsigned Pipe::do_read(char *buf, unsigned size) +{ + if(size==0) + return 0; + +#ifdef WIN32 + // Initiate overlapped read if needed + get_event_handle(); + + if(overlapped) + { + DWORD ret; + if(!GetOverlappedResult(handle[0], overlapped, &ret, !buf_avail)) + throw SystemError("Reading from pipe failed", GetLastError()); + else + { + buf_avail += ret; + delete overlapped; + overlapped = 0; + } + } + + unsigned ret = min(buf_avail, size); + memcpy(buf, buf_next, ret); + buf_next += ret; + buf_avail -= ret; + + // Initiate another overlapped read in case someone is polling us + get_event_handle(); +#else + int ret = ::read(handle[0], buf, size); + if(ret==-1) + { + if(errno==EAGAIN) + return 0; + else + throw SystemError("Reading from pipe failed", errno); + } +#endif + + if(ret==0) + { + eof_flag = true; + signal_end_of_file.emit(); + } + + return ret; +} + +Handle Pipe::get_event_handle() +{ +#ifdef WIN32 + if(!overlapped && !buf_avail) + { + overlapped = new OVERLAPPED; + memset(overlapped, 0, sizeof(OVERLAPPED)); + overlapped->hEvent = event; + + DWORD ret; + buf_next = buffer; + if(!ReadFile(handle[0], buffer, buf_size, &ret, overlapped)) + { + unsigned err = GetLastError(); + if(err!=ERROR_IO_PENDING) + throw SystemError("Failed to start an overlapped read", err); + } + else + { + buf_avail = ret; + delete overlapped; + overlapped = 0; + SetEvent(event); + } + } + + return event; +#else + return handle[0]; +#endif +} + +} // namespace IO +} // namespace Msp diff --git a/source/io/pipe.h b/source/io/pipe.h new file mode 100644 index 0000000..71edf7e --- /dev/null +++ b/source/io/pipe.h @@ -0,0 +1,41 @@ +#ifndef MSP_IO_PIPE_H_ +#define MSP_IO_PIPE_H_ + +#include "base.h" + +namespace Msp { +namespace IO { + +class Pipe: public Base +{ +private: + Handle handle[2]; +#ifdef WIN32 + OVERLAPPED *overlapped; + Handle event; + unsigned buf_size; + char *buffer; + unsigned buf_avail; + char *buf_next; +#endif + +public: + Pipe(); + ~Pipe(); + + void close(); + + void set_block(bool); + +protected: + virtual unsigned do_write(const char *, unsigned); + virtual unsigned do_read(char *, unsigned); + +public: + virtual Handle get_event_handle(); +}; + +} // namespace IO +} // namespace Msp + +#endif diff --git a/source/io/poll.cpp b/source/io/poll.cpp new file mode 100644 index 0000000..dce1912 --- /dev/null +++ b/source/io/poll.cpp @@ -0,0 +1,212 @@ +#include +#include +#include +#include "except.h" +#include "base.h" +#include "poll.h" + +namespace { + +using namespace Msp; +using namespace Msp::IO; + +inline int sys_poll_event(PollEvent event) +{ + int result = 0; + + if(event&~(P_INPUT|P_PRIO|P_OUTPUT)) + throw InvalidParameterValue("Invalid poll events"); + +#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 + // Stop the compiler from complaining about unused parameter + event = 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(Base &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 SystemError("Poll failed", GetLastError()); + + 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 SystemError("Poll failed", errno); + } + + return poll_event_from_sys(pfd.revents); +#endif +} + +} + +namespace Msp { +namespace IO { + +Poller::Poller(): + pfd_dirty(false) +{ } + +void Poller::set_object(Base &obj, PollEvent ev) +{ + // Verify that the object has an event handle + if(ev) + obj.get_event_handle(); + + SlotMap::iterator i = objects.find(&obj); + if(i!=objects.end()) + { + if(ev) + i->second.events = ev; + else + objects.erase(i); + + pfd_dirty = true; + } + else if(ev) + { +#ifdef WIN32 + if(objects.size()>=MAXIMUM_WAIT_OBJECTS) + throw InvalidState("Maximum number of wait objects reached"); +#endif + objects.insert(SlotMap::value_type(&obj, Slot(&obj, ev))); + + pfd_dirty = true; + } +} + +int Poller::poll() +{ + return do_poll(-1); +} + +int Poller::poll(const Time::TimeDelta &timeout) +{ + if(timeout(timeout/Time::msec)); +} + +void Poller::rebuild_pfd() +{ + pfd.clear(); + + pollfd p; + + for(SlotMap::iterator i=objects.begin(); i!=objects.end(); ++i) + { + p.fd = i->second.object->get_event_handle(); +#ifndef WIN32 + p.events = sys_poll_event(i->second.events); +#endif + pfd.push_back(p); + } + + pfd_dirty = false; +} + +int Poller::do_poll(int timeout) +{ + if(pfd_dirty) + rebuild_pfd(); + + poll_result.clear(); + +#ifdef WIN32 + if(timeout<0) + timeout = INFINITE; + + DWORD ret = WaitForMultipleObjects(pfd.size(), &pfd.front().fd, false, timeout); + if(/*ret>=WAIT_OBJECT_0 &&*/ retsecond.object, i->second.events)); + + return 1; + } + else if(ret==WAIT_FAILED) + throw SystemError("Poll failed", GetLastError()); + + return 0; +#else + int ret = ::poll(&pfd.front(), pfd.size(), timeout); + if(ret==-1) + { + if(errno==EINTR) + return 0; + else + throw SystemError("Poll failed", errno); + } + + int n = ret; + SlotMap::iterator j = objects.begin(); + for(std::vector::iterator i=pfd.begin(); (i!=pfd.end() && n>0); ++i,++j) + if(i->revents) + { + poll_result.push_back(Slot(j->second.object, poll_event_from_sys(i->revents))); + --n; + } + + return ret; +#endif +} + + +PollEvent poll(Base &obj, PollEvent pe) +{ + return do_poll(obj, pe, -1); +} + +PollEvent poll(Base &obj, PollEvent pe, const Time::TimeDelta &timeout) +{ + if(timeout(timeout/Time::msec)); +} + +} // namespace IO +} // namespace Msp diff --git a/source/io/poll.h b/source/io/poll.h new file mode 100644 index 0000000..6367d8f --- /dev/null +++ b/source/io/poll.h @@ -0,0 +1,82 @@ +#ifndef MSP_IO_POLL_H_ +#define MSP_IO_POLL_H_ + +#ifndef WIN32 +#include +#endif +#include +#include +#include +#include +#include "types.h" + +namespace Msp { +namespace IO { + +class Base; + +enum PollEvent +{ + P_NONE = 0, + P_INPUT = 1, + P_PRIO = 2, + P_OUTPUT = 4, + P_ERROR = 8 +}; + +inline PollEvent operator|(PollEvent e, PollEvent f) +{ return PollEvent(static_cast(e)|static_cast(f)); } + +inline PollEvent operator&(PollEvent e, PollEvent f) +{ return PollEvent(static_cast(e)&static_cast(f)); } + +inline PollEvent operator~(PollEvent e) +{ return PollEvent(~static_cast(e)); } + + +class Poller +{ +public: + struct Slot + { + Base *object; + PollEvent events; + + Slot(Base *o, PollEvent e): object(o), events(e) { } + }; + + typedef std::list SlotSeq; +private: + typedef std::map SlotMap; + +#ifdef WIN32 + struct pollfd + { + Handle fd; + }; +#endif + + SlotMap objects; + std::vector pfd; + bool pfd_dirty; + SlotSeq poll_result; + + void rebuild_pfd(); + int do_poll(int); + +public: + Poller(); + + void set_object(Base &, PollEvent); + int poll(); + int poll(const Time::TimeDelta &); + const SlotSeq &get_result() const { return poll_result; } +}; + +PollEvent poll(Base &, PollEvent); +PollEvent poll(Base &, PollEvent, const Time::TimeDelta &); + +} // namespace IO +} // namespace Msp + +#endif diff --git a/source/io/print.h b/source/io/print.h new file mode 100644 index 0000000..65744cb --- /dev/null +++ b/source/io/print.h @@ -0,0 +1,66 @@ +#ifndef MSP_IO_PRINT_H_ +#define MSP_IO_PRINT_H_ + +#include +#include "base.h" +#include "console.h" + +namespace Msp { +namespace IO { + +/** +Writes a string to an I/O object. Same as o.write(f). Provided for +completeness with the other print functions. +*/ +inline unsigned print(Base &o, const std::string &f) +{ return o.write(f); } + +template +inline unsigned print(Base &o, const std::string &f, A1 a1) +{ return print(o, format(f, a1)); } + +template +inline unsigned print(Base &o, const std::string &f, A1 a1, A2 a2) +{ return print(o, format(f, a1, a2)); } + +template +inline unsigned print(Base &o, const std::string &f, A1 a1, A2 a2, A3 a3) +{ return print(o, format(f, a1, a2, a3)); } + +template +inline unsigned print(Base &o, const std::string &f, A1 a1, A2 a2, A3 a3, A4 a4) +{ return print(o, format(f, a1, a2, a3, a4)); } + +template +inline unsigned print(Base &o, const std::string &f, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5) +{ return print(o, format(f, a1, a2, a3, a4, a5)); } + +/* The following functions print to console */ + +inline unsigned print(const std::string &f) +{ return print(cout, f); } + +template +inline unsigned print(const std::string &f, A1 a1) +{ return print(cout, f, a1); } + +template +inline unsigned print(const std::string &f, A1 a1, A2 a2) +{ return print(cout, f, a1, a2); } + +template +inline unsigned print(const std::string &f, A1 a1, A2 a2, A3 a3) +{ return print(cout, f, a1, a2, a3); } + +template +inline unsigned print(const std::string &f, A1 a1, A2 a2, A3 a3, A4 a4) +{ return print(cout, f, a1, a2, a3, a4); } + +template +inline unsigned print(const std::string &f, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5) +{ return print(cout, f, a1, a2, a3, a4, a5); } + +} // namespace IO +} // namespace Msp + +#endif diff --git a/source/io/seek.cpp b/source/io/seek.cpp new file mode 100644 index 0000000..b10c5a0 --- /dev/null +++ b/source/io/seek.cpp @@ -0,0 +1,32 @@ +#ifdef WIN32 +#include +#endif +#include "except.h" +#include "seek.h" + +namespace Msp { +namespace 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 InvalidParameterValue("Invalid seek type"); +} + +} // namespace IO +} // namespace Msp diff --git a/source/io/seek.h b/source/io/seek.h new file mode 100644 index 0000000..3c6c331 --- /dev/null +++ b/source/io/seek.h @@ -0,0 +1,19 @@ +#ifndef MSP_IO_SEEK_H_ +#define MSP_IO_SEEK_H_ + +namespace Msp { +namespace IO { + +enum SeekType +{ + S_BEG, + S_CUR, + S_END +}; + +extern int sys_seek_type(SeekType); + +} // namespace IO +} // namespace Msp + +#endif diff --git a/source/io/serial.cpp b/source/io/serial.cpp new file mode 100644 index 0000000..ec6a198 --- /dev/null +++ b/source/io/serial.cpp @@ -0,0 +1,340 @@ +#ifdef WIN32 +#include +#else +#include +#include +#include +#endif +#include +#include "except.h" +#include "serial.h" + +using namespace std; + +namespace { + +using namespace Msp; +using namespace Msp::IO; + +#ifdef WIN32 +typedef DCB DeviceState; +#else +typedef termios DeviceState; +#endif + +void get_state(Handle handle, DeviceState &state) +{ +#ifdef WIN32 + GetCommState(handle, &state); +#else + tcgetattr(handle, &state); +#endif +} + +void set_state(Handle handle, DeviceState &state) +{ +#ifdef WIN32 + if(SetCommState(handle, &state)==0) + throw SystemError("Cannot set serial port parameters", GetLastError()); +#else + if(tcsetattr(handle, TCSADRAIN, &state)==-1) + throw SystemError("Cannot set serial port parameters", errno); +#endif +} + +void set_baud_rate(DeviceState &state, 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 InvalidParameterValue("Invalid baud rate"); + } + + cfsetospeed(&state, speed); + cfsetispeed(&state, speed); +#endif +} + +void set_data_bits(DeviceState &state, 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 InvalidParameterValue("Invalid data bit count"); + } + + state.c_cflag = (state.c_cflag&~CSIZE)|flag; +#endif +} + +void set_parity(DeviceState &state, 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 InvalidParameterValue("Invalid 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 InvalidParameterValue("Invalid parity"); + } + + state.c_cflag = (state.c_cflag&~(PARENB|PARODD))|flag; +#endif +} + +void set_stop_bits(DeviceState &state, unsigned bits) +{ +#ifdef WIN32 + switch(bits) + { + case 1: state.StopBits = ONESTOPBIT; break; + case 2: state.StopBits = TWOSTOPBITS; break; + default: throw InvalidParameterValue("Invalid stop bit count"); + } +#else + tcflag_t flag; + switch(bits) + { + case 1: flag = 0; break; + case 2: flag = CSTOPB; break; + default: throw InvalidParameterValue("Invalid stop bit count"); + } + + state.c_cflag = (state.c_cflag&~CSTOPB)|flag; +#endif +} + +} + + +namespace Msp { +namespace IO { + +Serial::Serial(const string &descr) +{ + 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, 0); + if(handle==INVALID_HANDLE_VALUE) + throw SystemError(format("Can't open serial port '%s'", port), GetLastError()); + 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==-1) + throw SystemError(format("Can't open serial port '%s'", port), errno); + mode = M_READ|M_WRITE; + + termios t; + tcgetattr(handle, &t); + t.c_lflag &= ~(ECHO|ICANON); + t.c_oflag &= ~OPOST; + tcsetattr(handle, TCSADRAIN, &t); +#endif + + if(comma!=string::npos) + { + try + { + set_parameters(descr.substr(comma+1)); + } + catch(...) + { + close(); + throw; + } + } + + set_events(P_INPUT); +} + +Serial::~Serial() +{ + close(); +} + +void Serial::close() +{ +#ifdef WIN32 + CloseHandle(handle); +#else + ::close(handle); +#endif +} + +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 +} + +void Serial::set_baud_rate(unsigned rate) +{ + DeviceState state; + get_state(handle, state); + ::set_baud_rate(state, rate); + set_state(handle, state); +} + +void Serial::set_data_bits(unsigned bits) +{ + DeviceState state; + get_state(handle, state); + ::set_data_bits(state, bits); + set_state(handle, state); +} + +void Serial::set_parity(Parity par) +{ + DeviceState state; + get_state(handle, state); + ::set_parity(state, par); + set_state(handle, state); +} + +void Serial::set_stop_bits(unsigned bits) +{ + DeviceState state; + get_state(handle, state); + ::set_stop_bits(state, bits); + set_state(handle, state); +} + +void Serial::set_parameters(const string ¶ms) +{ + unsigned i; + for(i=0; i'8') + throw InvalidParameterValue("Invalid data bit count"); + if(params[i+2]!='N' && params[i+2]!='E' && params[i+2]!='O') + throw InvalidParameterValue("Invalid parity"); + if(params[i+3]!='1' && params[i+3]!='2') + throw InvalidParameterValue("Invalid stop bit count"); + + DeviceState state; + get_state(handle, state); + ::set_baud_rate(state, lexical_cast(params.substr(0, i))); + ::set_data_bits(state, params[i+1]-'0'); + ::set_parity(state, (params[i+2]=='E' ? EVEN : params[i+2]=='O' ? ODD : NONE)); + ::set_stop_bits(state, params[i+3]-'0'); + set_state(handle, state); +} + +unsigned Serial::do_write(const char *buf, unsigned size) +{ + if(size==0) + return 0; + +#ifdef WIN32 + DWORD ret; + if(WriteFile(handle, buf, size, &ret, 0)==0) + throw SystemError("Writing to serial port failed", GetLastError()); +#else + int ret = ::write(handle, buf, size); + if(ret==-1) + { + if(errno==EAGAIN) + return 0; + else + throw SystemError("Writing to serial port failed", errno); + } +#endif + + return ret; +} + +unsigned Serial::do_read(char *buf, unsigned size) +{ + if(size==0) + return 0; + +#ifdef WIN32 + DWORD ret; + if(ReadFile(handle, buf, size, &ret, 0)==0) + throw SystemError("Reading from serial port failed", GetLastError()); +#else + int ret = ::read(handle, buf, size); + if(ret==-1) + { + if(errno==EAGAIN) + return 0; + else + throw SystemError("Reading from serial port failed", errno); + } +#endif + + return ret; +} + +Handle Serial::get_event_handle() +{ +#ifdef WIN32 + throw Exception("Serial port events not supported on win32 yet"); +#else + return handle; +#endif +} + +} // namespace IO +} // namespace Msp diff --git a/source/io/serial.h b/source/io/serial.h new file mode 100644 index 0000000..069789c --- /dev/null +++ b/source/io/serial.h @@ -0,0 +1,49 @@ +#ifndef MSP_IO_SERIAL_H_ +#define MSP_IO_SERIAL_H_ + +#include "base.h" + +namespace Msp { +namespace IO { + +class Serial: public Base +{ +public: + enum Parity + { + NONE, + EVEN, + ODD + }; + +private: + Handle handle; + +public: + Serial(const std::string &); + virtual ~Serial(); + +private: + void close(); + +public: + virtual void set_block(bool); + + void set_baud_rate(unsigned); + void set_data_bits(unsigned); + void set_parity(Parity); + void set_stop_bits(unsigned); + void set_parameters(const std::string &); + +private: + virtual unsigned do_write(const char *, unsigned); + virtual unsigned do_read(char *, unsigned); + +public: + virtual Handle get_event_handle(); +}; + +} // namespace IO +} // namespace Msp + +#endif diff --git a/source/io/types.h b/source/io/types.h new file mode 100644 index 0000000..f18b7cb --- /dev/null +++ b/source/io/types.h @@ -0,0 +1,22 @@ +#ifndef MSP_IO_TYPES_H_ +#define MSP_IO_TYPES_H_ + +#ifdef WIN32 +#include +#endif + +namespace Msp { +namespace IO { + +#ifdef WIN32 +typedef HANDLE Handle; +#define MSP_IO_INVALID_HANDLE INVALID_HANDLE_VALUE +#else +typedef int Handle; +#define MSP_IO_INVALID_HANDLE -1 +#endif + +} // namespace IO +} // namespace Msp + +#endif diff --git a/source/io/utils.cpp b/source/io/utils.cpp new file mode 100644 index 0000000..eee51cc --- /dev/null +++ b/source/io/utils.cpp @@ -0,0 +1,17 @@ +#include "base.h" +#include "utils.h" + +namespace Msp { +namespace IO { + +unsigned read_all(Base &obj, char *buf, unsigned size) +{ + unsigned pos = 0; + while(pos -#include -#include "except.h" -#include "memory.h" - -using namespace std; - -namespace Msp { -namespace IO { - -Memory::Memory(char *d, unsigned s) -{ - init(d, d+s, M_RDWR); -} - -Memory::Memory(char *b, char *e) -{ - init(b, e, M_RDWR); -} - -Memory::Memory(const char *cd, unsigned s) -{ - char *d = const_cast(cd); - init(d, d+s, M_READ); -} - -Memory::Memory(const char *b, const char *e) -{ - init(const_cast(b), const_cast(e), M_READ); -} - -void Memory::init(char *b, char *e, Mode m) -{ - begin = b; - end = e; - pos = begin; - mode = m; -} - -unsigned Memory::do_write(const char *buf, unsigned size) -{ - check_mode(M_WRITE); - - size = min(size, end-pos); - memcpy(pos, buf, size); - pos += size; - return size; -} - -unsigned Memory::do_read(char *buf, unsigned size) -{ - if(pos==end) - { - eof_flag = true; - return 0; - } - - size = min(size, end-pos); - memcpy(buf, pos, size); - pos += size; - return size; -} - -unsigned Memory::put(char c) -{ - check_mode(M_WRITE); - *pos++ = c; - return 1; -} - -bool Memory::getline(string &line) -{ - char *nl = find(pos, end, '\n'); - line.assign(pos, nl); - bool result = (nl!=pos); - pos = nl; - return result; -} - -int Memory::get() -{ - if(pos==end) - { - eof_flag = true; - return -1; - } - - return static_cast(*pos++); -} - -unsigned Memory::seek(int off, SeekType type) -{ - char *new_pos; - if(type==S_BEG) - new_pos = begin+off; - else if(type==S_CUR) - new_pos = pos+off; - else if(type==S_END) - new_pos = end+off; - else - throw InvalidParameterValue("Invalid seek type"); - - if(new_posend) - throw InvalidParameterValue("Invalid seek offset"); - - pos = new_pos; - return pos-begin; -} - -Handle Memory::get_event_handle() -{ - throw Exception("Memory doesn't support events"); -} - -void Memory::check_mode(Mode m) const -{ - if(m==M_WRITE) - { - if(!(mode&M_WRITE)) - throw InvalidState("Memory is not writable"); - if(pos==end) - throw InvalidState("Attempt to write past end of Memory"); - } -} - -} // namespace IO -} // namespace Msp diff --git a/source/memory.h b/source/memory.h deleted file mode 100644 index ba6c4d8..0000000 --- a/source/memory.h +++ /dev/null @@ -1,44 +0,0 @@ -#ifndef MSP_IO_MEMORY_H_ -#define MSP_IO_MEMORY_H_ - -#include "base.h" -#include "seek.h" - -namespace Msp { -namespace IO { - -class Memory: public Base -{ -private: - char *begin; - char *end; - char *pos; - -public: - Memory(char *, unsigned); - Memory(char *, char *); - Memory(const char *, unsigned); - Memory(const char *, const char *); -private: - void init(char *, char *, Mode); - - virtual unsigned do_write(const char *, unsigned); - virtual unsigned do_read(char *, unsigned); -public: - virtual unsigned put(char); - virtual bool getline(std::string &); - virtual int get(); - - unsigned seek(int, SeekType); - unsigned tell() const { return pos-begin; } - - virtual Handle get_event_handle(); - -private: - void check_mode(Mode) const; -}; - -} // namespace IO -} // namespace Msp - -#endif diff --git a/source/mode.h b/source/mode.h deleted file mode 100644 index 5e103f2..0000000 --- a/source/mode.h +++ /dev/null @@ -1,29 +0,0 @@ -#ifndef MSP_IO_MODE_H_ -#define MSP_IO_MODE_H_ - -namespace Msp { -namespace IO { - -enum Mode -{ - M_NONE = 0, - M_READ = 1, - M_WRITE = 2, - M_RDWR = M_READ|M_WRITE, - M_APPEND = 4, - M_NONBLOCK = 8 -}; - -inline Mode operator|(Mode m, Mode n) -{ return Mode(static_cast(m)|static_cast(n)); } - -inline Mode operator&(Mode m, Mode n) -{ return Mode(static_cast(m)&static_cast(n)); } - -inline Mode operator~(Mode m) -{ return Mode(~static_cast(m)); } - -} // namespace IO -} // namespace Msp - -#endif diff --git a/source/pipe.cpp b/source/pipe.cpp deleted file mode 100644 index b3735aa..0000000 --- a/source/pipe.cpp +++ /dev/null @@ -1,182 +0,0 @@ -#ifndef WIN32 -#include -#include -#endif -#include -#include "pipe.h" - -using namespace std; - -namespace Msp { -namespace IO { - -Pipe::Pipe() -{ -#ifdef WIN32 - string name = format("\\\\.\\pipe\\%u.%p", GetCurrentProcessId(), this); - handle[0] = CreateNamedPipe(name.c_str(), PIPE_ACCESS_INBOUND|FILE_FLAG_OVERLAPPED, PIPE_TYPE_BYTE, 1, 1024, 1024, 0, 0); - if(handle[0]==INVALID_HANDLE_VALUE) - throw SystemError("Unable to create pipe", GetLastError()); - - handle[1] = CreateFile(name.c_str(), GENERIC_WRITE, 0, 0, OPEN_EXISTING, 0, 0); - if(handle[1]==INVALID_HANDLE_VALUE) - { - unsigned err = GetLastError(); - CloseHandle(handle[0]); - throw SystemError("Unable to create pipe", err); - } - - overlapped = 0; - event = CreateEvent(0, true, false, 0); - buf_size = 1024; - buffer = new char[buf_size]; - buf_avail = 0; - buf_next = buffer; -#else - if(pipe(handle)==-1) - throw SystemError("Unable to create pipe", errno); -#endif - - set_events(P_INPUT); -} - -Pipe::~Pipe() -{ - close(); -} - -void Pipe::close() -{ - set_events(P_NONE); - - signal_flush_required.emit(); -#ifdef WIN32 - CloseHandle(handle[0]); - CloseHandle(handle[1]); -#else - ::close(handle[0]); - ::close(handle[1]); - signal_closed.emit(); -#endif -} - -void Pipe::set_block(bool b) -{ - mode = (mode&~M_NONBLOCK); - if(b) - mode = (mode|M_NONBLOCK); - -#ifndef WIN32 - int flags = fcntl(handle[0], F_GETFD); - fcntl(handle[0], F_SETFL, (flags&O_NONBLOCK)|(b?0:O_NONBLOCK)); - flags = fcntl(handle[1], F_GETFD); - fcntl(handle[1], F_SETFL, (flags&O_NONBLOCK)|(b?0:O_NONBLOCK)); -#endif -} - -unsigned Pipe::do_write(const char *buf, unsigned size) -{ - if(size==0) - return 0; - -#ifdef WIN32 - DWORD ret; - if(!WriteFile(handle[1], buf, size, &ret, 0)) - throw SystemError("Writing to pipe failed", GetLastError()); -#else - int ret = ::write(handle[1], buf, size); - if(ret==-1) - { - if(errno==EAGAIN) - return 0; - else - throw SystemError("Writing to pipe failed", errno); - } -#endif - - return ret; -} - -unsigned Pipe::do_read(char *buf, unsigned size) -{ - if(size==0) - return 0; - -#ifdef WIN32 - // Initiate overlapped read if needed - get_event_handle(); - - if(overlapped) - { - DWORD ret; - if(!GetOverlappedResult(handle[0], overlapped, &ret, !buf_avail)) - throw SystemError("Reading from pipe failed", GetLastError()); - else - { - buf_avail += ret; - delete overlapped; - overlapped = 0; - } - } - - unsigned ret = min(buf_avail, size); - memcpy(buf, buf_next, ret); - buf_next += ret; - buf_avail -= ret; - - // Initiate another overlapped read in case someone is polling us - get_event_handle(); -#else - int ret = ::read(handle[0], buf, size); - if(ret==-1) - { - if(errno==EAGAIN) - return 0; - else - throw SystemError("Reading from pipe failed", errno); - } -#endif - - if(ret==0) - { - eof_flag = true; - signal_end_of_file.emit(); - } - - return ret; -} - -Handle Pipe::get_event_handle() -{ -#ifdef WIN32 - if(!overlapped && !buf_avail) - { - overlapped = new OVERLAPPED; - memset(overlapped, 0, sizeof(OVERLAPPED)); - overlapped->hEvent = event; - - DWORD ret; - buf_next = buffer; - if(!ReadFile(handle[0], buffer, buf_size, &ret, overlapped)) - { - unsigned err = GetLastError(); - if(err!=ERROR_IO_PENDING) - throw SystemError("Failed to start an overlapped read", err); - } - else - { - buf_avail = ret; - delete overlapped; - overlapped = 0; - SetEvent(event); - } - } - - return event; -#else - return handle[0]; -#endif -} - -} // namespace IO -} // namespace Msp diff --git a/source/pipe.h b/source/pipe.h deleted file mode 100644 index 71edf7e..0000000 --- a/source/pipe.h +++ /dev/null @@ -1,41 +0,0 @@ -#ifndef MSP_IO_PIPE_H_ -#define MSP_IO_PIPE_H_ - -#include "base.h" - -namespace Msp { -namespace IO { - -class Pipe: public Base -{ -private: - Handle handle[2]; -#ifdef WIN32 - OVERLAPPED *overlapped; - Handle event; - unsigned buf_size; - char *buffer; - unsigned buf_avail; - char *buf_next; -#endif - -public: - Pipe(); - ~Pipe(); - - void close(); - - void set_block(bool); - -protected: - virtual unsigned do_write(const char *, unsigned); - virtual unsigned do_read(char *, unsigned); - -public: - virtual Handle get_event_handle(); -}; - -} // namespace IO -} // namespace Msp - -#endif diff --git a/source/poll.cpp b/source/poll.cpp deleted file mode 100644 index dce1912..0000000 --- a/source/poll.cpp +++ /dev/null @@ -1,212 +0,0 @@ -#include -#include -#include -#include "except.h" -#include "base.h" -#include "poll.h" - -namespace { - -using namespace Msp; -using namespace Msp::IO; - -inline int sys_poll_event(PollEvent event) -{ - int result = 0; - - if(event&~(P_INPUT|P_PRIO|P_OUTPUT)) - throw InvalidParameterValue("Invalid poll events"); - -#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 - // Stop the compiler from complaining about unused parameter - event = 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(Base &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 SystemError("Poll failed", GetLastError()); - - 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 SystemError("Poll failed", errno); - } - - return poll_event_from_sys(pfd.revents); -#endif -} - -} - -namespace Msp { -namespace IO { - -Poller::Poller(): - pfd_dirty(false) -{ } - -void Poller::set_object(Base &obj, PollEvent ev) -{ - // Verify that the object has an event handle - if(ev) - obj.get_event_handle(); - - SlotMap::iterator i = objects.find(&obj); - if(i!=objects.end()) - { - if(ev) - i->second.events = ev; - else - objects.erase(i); - - pfd_dirty = true; - } - else if(ev) - { -#ifdef WIN32 - if(objects.size()>=MAXIMUM_WAIT_OBJECTS) - throw InvalidState("Maximum number of wait objects reached"); -#endif - objects.insert(SlotMap::value_type(&obj, Slot(&obj, ev))); - - pfd_dirty = true; - } -} - -int Poller::poll() -{ - return do_poll(-1); -} - -int Poller::poll(const Time::TimeDelta &timeout) -{ - if(timeout(timeout/Time::msec)); -} - -void Poller::rebuild_pfd() -{ - pfd.clear(); - - pollfd p; - - for(SlotMap::iterator i=objects.begin(); i!=objects.end(); ++i) - { - p.fd = i->second.object->get_event_handle(); -#ifndef WIN32 - p.events = sys_poll_event(i->second.events); -#endif - pfd.push_back(p); - } - - pfd_dirty = false; -} - -int Poller::do_poll(int timeout) -{ - if(pfd_dirty) - rebuild_pfd(); - - poll_result.clear(); - -#ifdef WIN32 - if(timeout<0) - timeout = INFINITE; - - DWORD ret = WaitForMultipleObjects(pfd.size(), &pfd.front().fd, false, timeout); - if(/*ret>=WAIT_OBJECT_0 &&*/ retsecond.object, i->second.events)); - - return 1; - } - else if(ret==WAIT_FAILED) - throw SystemError("Poll failed", GetLastError()); - - return 0; -#else - int ret = ::poll(&pfd.front(), pfd.size(), timeout); - if(ret==-1) - { - if(errno==EINTR) - return 0; - else - throw SystemError("Poll failed", errno); - } - - int n = ret; - SlotMap::iterator j = objects.begin(); - for(std::vector::iterator i=pfd.begin(); (i!=pfd.end() && n>0); ++i,++j) - if(i->revents) - { - poll_result.push_back(Slot(j->second.object, poll_event_from_sys(i->revents))); - --n; - } - - return ret; -#endif -} - - -PollEvent poll(Base &obj, PollEvent pe) -{ - return do_poll(obj, pe, -1); -} - -PollEvent poll(Base &obj, PollEvent pe, const Time::TimeDelta &timeout) -{ - if(timeout(timeout/Time::msec)); -} - -} // namespace IO -} // namespace Msp diff --git a/source/poll.h b/source/poll.h deleted file mode 100644 index 6367d8f..0000000 --- a/source/poll.h +++ /dev/null @@ -1,82 +0,0 @@ -#ifndef MSP_IO_POLL_H_ -#define MSP_IO_POLL_H_ - -#ifndef WIN32 -#include -#endif -#include -#include -#include -#include -#include "types.h" - -namespace Msp { -namespace IO { - -class Base; - -enum PollEvent -{ - P_NONE = 0, - P_INPUT = 1, - P_PRIO = 2, - P_OUTPUT = 4, - P_ERROR = 8 -}; - -inline PollEvent operator|(PollEvent e, PollEvent f) -{ return PollEvent(static_cast(e)|static_cast(f)); } - -inline PollEvent operator&(PollEvent e, PollEvent f) -{ return PollEvent(static_cast(e)&static_cast(f)); } - -inline PollEvent operator~(PollEvent e) -{ return PollEvent(~static_cast(e)); } - - -class Poller -{ -public: - struct Slot - { - Base *object; - PollEvent events; - - Slot(Base *o, PollEvent e): object(o), events(e) { } - }; - - typedef std::list SlotSeq; -private: - typedef std::map SlotMap; - -#ifdef WIN32 - struct pollfd - { - Handle fd; - }; -#endif - - SlotMap objects; - std::vector pfd; - bool pfd_dirty; - SlotSeq poll_result; - - void rebuild_pfd(); - int do_poll(int); - -public: - Poller(); - - void set_object(Base &, PollEvent); - int poll(); - int poll(const Time::TimeDelta &); - const SlotSeq &get_result() const { return poll_result; } -}; - -PollEvent poll(Base &, PollEvent); -PollEvent poll(Base &, PollEvent, const Time::TimeDelta &); - -} // namespace IO -} // namespace Msp - -#endif diff --git a/source/print.h b/source/print.h deleted file mode 100644 index 65744cb..0000000 --- a/source/print.h +++ /dev/null @@ -1,66 +0,0 @@ -#ifndef MSP_IO_PRINT_H_ -#define MSP_IO_PRINT_H_ - -#include -#include "base.h" -#include "console.h" - -namespace Msp { -namespace IO { - -/** -Writes a string to an I/O object. Same as o.write(f). Provided for -completeness with the other print functions. -*/ -inline unsigned print(Base &o, const std::string &f) -{ return o.write(f); } - -template -inline unsigned print(Base &o, const std::string &f, A1 a1) -{ return print(o, format(f, a1)); } - -template -inline unsigned print(Base &o, const std::string &f, A1 a1, A2 a2) -{ return print(o, format(f, a1, a2)); } - -template -inline unsigned print(Base &o, const std::string &f, A1 a1, A2 a2, A3 a3) -{ return print(o, format(f, a1, a2, a3)); } - -template -inline unsigned print(Base &o, const std::string &f, A1 a1, A2 a2, A3 a3, A4 a4) -{ return print(o, format(f, a1, a2, a3, a4)); } - -template -inline unsigned print(Base &o, const std::string &f, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5) -{ return print(o, format(f, a1, a2, a3, a4, a5)); } - -/* The following functions print to console */ - -inline unsigned print(const std::string &f) -{ return print(cout, f); } - -template -inline unsigned print(const std::string &f, A1 a1) -{ return print(cout, f, a1); } - -template -inline unsigned print(const std::string &f, A1 a1, A2 a2) -{ return print(cout, f, a1, a2); } - -template -inline unsigned print(const std::string &f, A1 a1, A2 a2, A3 a3) -{ return print(cout, f, a1, a2, a3); } - -template -inline unsigned print(const std::string &f, A1 a1, A2 a2, A3 a3, A4 a4) -{ return print(cout, f, a1, a2, a3, a4); } - -template -inline unsigned print(const std::string &f, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5) -{ return print(cout, f, a1, a2, a3, a4, a5); } - -} // namespace IO -} // namespace Msp - -#endif diff --git a/source/seek.cpp b/source/seek.cpp deleted file mode 100644 index b10c5a0..0000000 --- a/source/seek.cpp +++ /dev/null @@ -1,32 +0,0 @@ -#ifdef WIN32 -#include -#endif -#include "except.h" -#include "seek.h" - -namespace Msp { -namespace 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 InvalidParameterValue("Invalid seek type"); -} - -} // namespace IO -} // namespace Msp diff --git a/source/seek.h b/source/seek.h deleted file mode 100644 index 3c6c331..0000000 --- a/source/seek.h +++ /dev/null @@ -1,19 +0,0 @@ -#ifndef MSP_IO_SEEK_H_ -#define MSP_IO_SEEK_H_ - -namespace Msp { -namespace IO { - -enum SeekType -{ - S_BEG, - S_CUR, - S_END -}; - -extern int sys_seek_type(SeekType); - -} // namespace IO -} // namespace Msp - -#endif diff --git a/source/serial.cpp b/source/serial.cpp deleted file mode 100644 index ec6a198..0000000 --- a/source/serial.cpp +++ /dev/null @@ -1,340 +0,0 @@ -#ifdef WIN32 -#include -#else -#include -#include -#include -#endif -#include -#include "except.h" -#include "serial.h" - -using namespace std; - -namespace { - -using namespace Msp; -using namespace Msp::IO; - -#ifdef WIN32 -typedef DCB DeviceState; -#else -typedef termios DeviceState; -#endif - -void get_state(Handle handle, DeviceState &state) -{ -#ifdef WIN32 - GetCommState(handle, &state); -#else - tcgetattr(handle, &state); -#endif -} - -void set_state(Handle handle, DeviceState &state) -{ -#ifdef WIN32 - if(SetCommState(handle, &state)==0) - throw SystemError("Cannot set serial port parameters", GetLastError()); -#else - if(tcsetattr(handle, TCSADRAIN, &state)==-1) - throw SystemError("Cannot set serial port parameters", errno); -#endif -} - -void set_baud_rate(DeviceState &state, 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 InvalidParameterValue("Invalid baud rate"); - } - - cfsetospeed(&state, speed); - cfsetispeed(&state, speed); -#endif -} - -void set_data_bits(DeviceState &state, 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 InvalidParameterValue("Invalid data bit count"); - } - - state.c_cflag = (state.c_cflag&~CSIZE)|flag; -#endif -} - -void set_parity(DeviceState &state, 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 InvalidParameterValue("Invalid 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 InvalidParameterValue("Invalid parity"); - } - - state.c_cflag = (state.c_cflag&~(PARENB|PARODD))|flag; -#endif -} - -void set_stop_bits(DeviceState &state, unsigned bits) -{ -#ifdef WIN32 - switch(bits) - { - case 1: state.StopBits = ONESTOPBIT; break; - case 2: state.StopBits = TWOSTOPBITS; break; - default: throw InvalidParameterValue("Invalid stop bit count"); - } -#else - tcflag_t flag; - switch(bits) - { - case 1: flag = 0; break; - case 2: flag = CSTOPB; break; - default: throw InvalidParameterValue("Invalid stop bit count"); - } - - state.c_cflag = (state.c_cflag&~CSTOPB)|flag; -#endif -} - -} - - -namespace Msp { -namespace IO { - -Serial::Serial(const string &descr) -{ - 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, 0); - if(handle==INVALID_HANDLE_VALUE) - throw SystemError(format("Can't open serial port '%s'", port), GetLastError()); - 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==-1) - throw SystemError(format("Can't open serial port '%s'", port), errno); - mode = M_READ|M_WRITE; - - termios t; - tcgetattr(handle, &t); - t.c_lflag &= ~(ECHO|ICANON); - t.c_oflag &= ~OPOST; - tcsetattr(handle, TCSADRAIN, &t); -#endif - - if(comma!=string::npos) - { - try - { - set_parameters(descr.substr(comma+1)); - } - catch(...) - { - close(); - throw; - } - } - - set_events(P_INPUT); -} - -Serial::~Serial() -{ - close(); -} - -void Serial::close() -{ -#ifdef WIN32 - CloseHandle(handle); -#else - ::close(handle); -#endif -} - -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 -} - -void Serial::set_baud_rate(unsigned rate) -{ - DeviceState state; - get_state(handle, state); - ::set_baud_rate(state, rate); - set_state(handle, state); -} - -void Serial::set_data_bits(unsigned bits) -{ - DeviceState state; - get_state(handle, state); - ::set_data_bits(state, bits); - set_state(handle, state); -} - -void Serial::set_parity(Parity par) -{ - DeviceState state; - get_state(handle, state); - ::set_parity(state, par); - set_state(handle, state); -} - -void Serial::set_stop_bits(unsigned bits) -{ - DeviceState state; - get_state(handle, state); - ::set_stop_bits(state, bits); - set_state(handle, state); -} - -void Serial::set_parameters(const string ¶ms) -{ - unsigned i; - for(i=0; i'8') - throw InvalidParameterValue("Invalid data bit count"); - if(params[i+2]!='N' && params[i+2]!='E' && params[i+2]!='O') - throw InvalidParameterValue("Invalid parity"); - if(params[i+3]!='1' && params[i+3]!='2') - throw InvalidParameterValue("Invalid stop bit count"); - - DeviceState state; - get_state(handle, state); - ::set_baud_rate(state, lexical_cast(params.substr(0, i))); - ::set_data_bits(state, params[i+1]-'0'); - ::set_parity(state, (params[i+2]=='E' ? EVEN : params[i+2]=='O' ? ODD : NONE)); - ::set_stop_bits(state, params[i+3]-'0'); - set_state(handle, state); -} - -unsigned Serial::do_write(const char *buf, unsigned size) -{ - if(size==0) - return 0; - -#ifdef WIN32 - DWORD ret; - if(WriteFile(handle, buf, size, &ret, 0)==0) - throw SystemError("Writing to serial port failed", GetLastError()); -#else - int ret = ::write(handle, buf, size); - if(ret==-1) - { - if(errno==EAGAIN) - return 0; - else - throw SystemError("Writing to serial port failed", errno); - } -#endif - - return ret; -} - -unsigned Serial::do_read(char *buf, unsigned size) -{ - if(size==0) - return 0; - -#ifdef WIN32 - DWORD ret; - if(ReadFile(handle, buf, size, &ret, 0)==0) - throw SystemError("Reading from serial port failed", GetLastError()); -#else - int ret = ::read(handle, buf, size); - if(ret==-1) - { - if(errno==EAGAIN) - return 0; - else - throw SystemError("Reading from serial port failed", errno); - } -#endif - - return ret; -} - -Handle Serial::get_event_handle() -{ -#ifdef WIN32 - throw Exception("Serial port events not supported on win32 yet"); -#else - return handle; -#endif -} - -} // namespace IO -} // namespace Msp diff --git a/source/serial.h b/source/serial.h deleted file mode 100644 index 069789c..0000000 --- a/source/serial.h +++ /dev/null @@ -1,49 +0,0 @@ -#ifndef MSP_IO_SERIAL_H_ -#define MSP_IO_SERIAL_H_ - -#include "base.h" - -namespace Msp { -namespace IO { - -class Serial: public Base -{ -public: - enum Parity - { - NONE, - EVEN, - ODD - }; - -private: - Handle handle; - -public: - Serial(const std::string &); - virtual ~Serial(); - -private: - void close(); - -public: - virtual void set_block(bool); - - void set_baud_rate(unsigned); - void set_data_bits(unsigned); - void set_parity(Parity); - void set_stop_bits(unsigned); - void set_parameters(const std::string &); - -private: - virtual unsigned do_write(const char *, unsigned); - virtual unsigned do_read(char *, unsigned); - -public: - virtual Handle get_event_handle(); -}; - -} // namespace IO -} // namespace Msp - -#endif diff --git a/source/types.h b/source/types.h deleted file mode 100644 index f18b7cb..0000000 --- a/source/types.h +++ /dev/null @@ -1,22 +0,0 @@ -#ifndef MSP_IO_TYPES_H_ -#define MSP_IO_TYPES_H_ - -#ifdef WIN32 -#include -#endif - -namespace Msp { -namespace IO { - -#ifdef WIN32 -typedef HANDLE Handle; -#define MSP_IO_INVALID_HANDLE INVALID_HANDLE_VALUE -#else -typedef int Handle; -#define MSP_IO_INVALID_HANDLE -1 -#endif - -} // namespace IO -} // namespace Msp - -#endif diff --git a/source/utils.cpp b/source/utils.cpp deleted file mode 100644 index eee51cc..0000000 --- a/source/utils.cpp +++ /dev/null @@ -1,17 +0,0 @@ -#include "base.h" -#include "utils.h" - -namespace Msp { -namespace IO { - -unsigned read_all(Base &obj, char *buf, unsigned size) -{ - unsigned pos = 0; - while(pos