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