]> git.tdb.fi Git - libs/core.git/blob - source/console.cpp
eb7ac4b588bf4b6724ad8b28f02142ab010531ca
[libs/core.git] / source / console.cpp
1 /* $Id$
2
3 This file is part of libmspio
4 Copyright © 2008  Mikko Rasa, Mikkosoft Productions
5 Distributed under the LGPL
6 */
7
8 #ifndef WIN32
9 #include <errno.h>
10 #include <fcntl.h>
11 #include <termios.h>
12 #endif
13 #include <msp/core/except.h>
14 #include "console.h"
15
16 namespace {
17
18 #ifndef WIN32
19 termios orig_attr;
20 #endif
21
22 } // namespace
23
24 namespace Msp {
25 namespace IO {
26
27 Console::Console(unsigned n)
28 {
29         if(n>2)
30                 throw InvalidParameterValue("Invalid parameter for Console::Console");
31
32         mode=(n==0 ? M_READ : M_WRITE);
33
34 #ifdef WIN32
35         switch(n)
36         {
37         case 0: handle=GetStdHandle(STD_INPUT_HANDLE); break;
38         case 1: handle=GetStdHandle(STD_OUTPUT_HANDLE); break;
39         case 2: handle=GetStdHandle(STD_ERROR_HANDLE); break;
40         }
41 #else
42         handle=n;
43
44         if(handle==0)
45                 tcgetattr(handle, &orig_attr);
46 #endif
47 }
48
49 Console::~Console()
50 {
51 #ifndef WIN32
52         if(handle==0)
53                 tcsetattr(handle, TCSADRAIN, &orig_attr);
54 #endif
55 }
56
57 void Console::set_block(bool b)
58 {
59 #ifdef WIN32
60         // XXX Dunno how to do this in win32
61         (void)b;
62 #else
63         int flags=fcntl(0, F_GETFL);
64         flags=(flags&~O_NONBLOCK) | (b?0:O_NONBLOCK);
65         fcntl(0, F_SETFL, flags);
66 #endif
67 }
68
69 void Console::set_local_echo(bool e)
70 {
71         if(!(mode&M_READ))
72                 throw InvalidState("Local echo can only be set on input console");
73
74 #ifdef WIN32
75         DWORD m;
76         GetConsoleMode(handle, &m);
77         SetConsoleMode(handle, (m&~ENABLE_ECHO_INPUT) | (e?ENABLE_ECHO_INPUT:0));
78 #else
79         termios t;
80         tcgetattr(0, &t);
81         t.c_lflag=(t.c_lflag&~ECHO) | (e?ECHO:0);
82         tcsetattr(0, TCSADRAIN, &t);
83 #endif
84 }
85
86 void Console::set_line_buffer(bool l)
87 {
88         if(!(mode&M_READ))
89                 throw InvalidState("Line buffering can only be set on input console");
90
91 #ifdef WIN32
92         DWORD m;
93         GetConsoleMode(handle, &m);
94         SetConsoleMode(handle, (m&~ENABLE_LINE_INPUT) | (l?ENABLE_LINE_INPUT:0));
95 #else
96         // XXX ICANON does more than just set line buffering, may need a bit more thought
97         termios t;
98         tcgetattr(0, &t);
99         t.c_lflag=(t.c_lflag&~ICANON) | (l?ICANON:0);
100         tcsetattr(0, TCSADRAIN, &t);
101 #endif
102 }
103
104 Handle Console::get_event_handle()
105 {
106         return 0;
107 }
108
109 unsigned Console::do_write(const char *buf, unsigned len)
110 {
111         if(!(mode&M_WRITE))
112                 throw InvalidState("Console is not writable");
113
114 #ifdef WIN32
115         DWORD ret;
116         if(!WriteFile(handle, buf, len, &ret, 0))
117                 throw SystemError("Writing to console failed", GetLastError());
118 #else
119         int ret=::write(1, buf, len);
120         if(ret==-1)
121                 throw SystemError("Writing to console failed", errno);
122 #endif
123
124         return ret;
125 }
126
127 unsigned Console::do_read(char *buf, unsigned len)
128 {
129         if(!(mode&M_READ))
130                 throw InvalidState("Console is not readable");
131
132 #ifdef WIN32
133         DWORD ret;
134         if(!ReadFile(handle, buf, len, &ret, 0))
135                 throw SystemError("Reading from console failed", GetLastError());
136 #else
137         int ret=::read(0, buf, len);
138         if(ret==-1)
139         {
140                 if(errno==EAGAIN)
141                         return 0;
142                 else
143                         throw SystemError("Reading from console failed", errno);
144         }
145         else if(ret==0)
146                 eof_flag=true;
147 #endif
148
149         return ret;
150 }
151
152 Console &Console::instance(unsigned n)
153 {
154         static Console in(0);
155         static Console out(1);
156         static Console err(2);
157
158         switch(n)
159         {
160         case 0: return in;
161         case 1: return out;
162         case 2: return err;
163         }
164
165         throw InvalidParameterValue("Unknown Console instance requested");
166 }
167
168 Console &cin=Console::instance(0);
169 Console &cout=Console::instance(1);
170 Console &cerr=Console::instance(2);
171
172 } // namespace IO
173 } // namespace Msp