442bbb0f7dc0dbcd70b1cd0da62e74f247f8c162
[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         return sys_write(handle, buf, len);
127 }
128
129 unsigned Console::do_read(char *buf, unsigned len)
130 {
131         if(!(mode&M_READ))
132                 throw invalid_access(M_READ);
133
134         unsigned ret = sys_read(handle, buf, len);
135         if(ret==0)
136                 eof_flag = true;
137
138         return ret;
139 }
140
141 Console &Console::instance(unsigned n)
142 {
143         static Console in(0);
144         static Console out(1);
145         static Console err(2);
146
147         switch(n)
148         {
149         case 0: return in;
150         case 1: return out;
151         case 2: return err;
152         }
153
154         throw invalid_argument("Console::instance");
155 }
156
157 Console &cin = Console::instance(0);
158 Console &cout = Console::instance(1);
159 Console &cerr = Console::instance(2);
160
161 } // namespace IO
162 } // namespace Msp