]> git.tdb.fi Git - libs/core.git/blob - source/io/console.cpp
Use the new Handle class to hide platform details from public headers
[libs/core.git] / source / io / 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/systemerror.h>
8 #include "console.h"
9 #include "handle_private.h"
10
11 using namespace std;
12
13 namespace {
14
15 #ifndef WIN32
16 termios orig_attr;
17 #endif
18
19 } // namespace
20
21 namespace Msp {
22 namespace IO {
23
24 Console::Console(unsigned n)
25 {
26         if(n>2)
27                 throw invalid_argument("Console::Console");
28
29         mode = (n==0 ? M_READ : M_WRITE);
30
31 #ifdef WIN32
32         switch(n)
33         {
34         case 0: *handle = GetStdHandle(STD_INPUT_HANDLE); break;
35         case 1: *handle = GetStdHandle(STD_OUTPUT_HANDLE); break;
36         case 2: *handle = GetStdHandle(STD_ERROR_HANDLE); break;
37         }
38 #else
39         *handle = n;
40
41         if(n==0)
42                 tcgetattr(*handle, &orig_attr);
43 #endif
44
45         if(n==0)
46                 set_events(P_INPUT);
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(*handle, F_GETFL);
64         flags = (flags&~O_NONBLOCK) | (b?0:O_NONBLOCK);
65         fcntl(*handle, F_SETFL, flags);
66 #endif
67 }
68
69 void Console::set_local_echo(bool e)
70 {
71         if(!(mode&M_READ))
72                 throw invalid_access(M_READ);
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(*handle, &t);
81         t.c_lflag = (t.c_lflag&~ECHO) | (e?ECHO:0);
82         tcsetattr(*handle, TCSADRAIN, &t);
83 #endif
84 }
85
86 void Console::set_line_buffer(bool l)
87 {
88         if(!(mode&M_READ))
89                 throw invalid_access(M_READ);
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(*handle, &t);
99         t.c_lflag = (t.c_lflag&~ICANON) | (l?ICANON:0);
100         tcsetattr(*handle, TCSADRAIN, &t);
101 #endif
102 }
103
104 void Console::get_size(unsigned &rows, unsigned &cols)
105 {
106         if(!(mode&M_WRITE))
107                 throw invalid_access(M_WRITE);
108
109 #ifdef WIN32
110         // XXX Figure out how to do this
111         rows = 24;
112         cols = 80;
113 #else
114         struct winsize wsz;
115         ioctl(*handle, TIOCGWINSZ, &wsz);
116         rows = wsz.ws_row;
117         cols = wsz.ws_col;
118 #endif
119 }
120
121 unsigned Console::do_write(const char *buf, unsigned len)
122 {
123         if(!(mode&M_WRITE))
124                 throw invalid_access(M_WRITE);
125
126 #ifdef WIN32
127         DWORD ret;
128         if(!WriteFile(*handle, buf, len, &ret, 0))
129                 throw system_error("WriteFile");
130 #else
131         int ret = ::write(*handle, buf, len);
132         if(ret==-1)
133                 throw system_error("write");
134 #endif
135
136         return ret;
137 }
138
139 unsigned Console::do_read(char *buf, unsigned len)
140 {
141         if(!(mode&M_READ))
142                 throw invalid_access(M_READ);
143
144 #ifdef WIN32
145         DWORD ret;
146         if(!ReadFile(*handle, buf, len, &ret, 0))
147                 throw system_error("ReadFile");
148 #else
149         int ret = ::read(*handle, buf, len);
150         if(ret==-1)
151         {
152                 if(errno==EAGAIN)
153                         return 0;
154                 else
155                         throw system_error("read");
156         }
157         else if(ret==0)
158                 eof_flag = true;
159 #endif
160
161         return ret;
162 }
163
164 Console &Console::instance(unsigned n)
165 {
166         static Console in(0);
167         static Console out(1);
168         static Console err(2);
169
170         switch(n)
171         {
172         case 0: return in;
173         case 1: return out;
174         case 2: return err;
175         }
176
177         throw invalid_argument("Console::instance");
178 }
179
180 Console &cin = Console::instance(0);
181 Console &cout = Console::instance(1);
182 Console &cerr = Console::instance(2);
183
184 } // namespace IO
185 } // namespace Msp