From 33a5613489bbb9d4eab5c8761af88f4c1352aad4 Mon Sep 17 00:00:00 2001 From: Mikko Rasa Date: Tue, 24 Jun 2008 19:40:17 +0000 Subject: [PATCH] Add support for console I/O --- source/console.cpp | 173 +++++++++++++++++++++++++++++++++++++++++++++ source/console.h | 57 +++++++++++++++ source/print.h | 36 ++++++++-- 3 files changed, 261 insertions(+), 5 deletions(-) create mode 100644 source/console.cpp create mode 100644 source/console.h diff --git a/source/console.cpp b/source/console.cpp new file mode 100644 index 0000000..eb7ac4b --- /dev/null +++ b/source/console.cpp @@ -0,0 +1,173 @@ +/* $Id$ + +This file is part of libmspio +Copyright © 2008 Mikko Rasa, Mikkosoft Productions +Distributed under the LGPL +*/ + +#ifndef WIN32 +#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 +} + +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 +} + +Handle Console::get_event_handle() +{ + return 0; +} + +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(1, 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(0, 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; +} + +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 new file mode 100644 index 0000000..439ee7b --- /dev/null +++ b/source/console.h @@ -0,0 +1,57 @@ +/* $Id$ + +This file is part of libmspio +Copyright © 2008 Mikko Rasa, Mikkosoft Productions +Distributed under the LGPL +*/ + +#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); + + virtual Handle get_event_handle(); +private: + virtual unsigned do_write(const char *, unsigned); + virtual unsigned do_read(char *, unsigned); +public: + static Console &instance(unsigned); +}; + +extern Console &cin; +extern Console &cout; +extern Console &cerr; + +} // namespace IO +} // namespace Msp + +#endif diff --git a/source/print.h b/source/print.h index 16f9225..10fb02e 100644 --- a/source/print.h +++ b/source/print.h @@ -10,6 +10,7 @@ Distributed under the LGPL #include #include "base.h" +#include "console.h" namespace Msp { namespace IO { @@ -23,23 +24,48 @@ inline unsigned print(Base &o, const std::string &f) template inline unsigned print(Base &o, const std::string &f, A1 a1) -{ return o.write(format(f, a1)); } +{ return print(o, format(f, a1)); } template inline unsigned print(Base &o, const std::string &f, A1 a1, A2 a2) -{ return o.write(format(f, a1, 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 o.write(format(f, a1, a2, 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 o.write(format(f, a1, a2, a3, 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 o.write(format(f, a1, a2, a3, a4, 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 -- 2.43.0