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