]> git.tdb.fi Git - libs/core.git/blob - source/io/console.cpp
Merge branch 'io-master'
[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/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 unsigned Console::do_write(const char *buf, unsigned len)
119 {
120         if(!(mode&M_WRITE))
121                 throw InvalidState("Console is not writable");
122
123 #ifdef WIN32
124         DWORD ret;
125         if(!WriteFile(handle, buf, len, &ret, 0))
126                 throw SystemError("Writing to console failed", GetLastError());
127 #else
128         int ret = ::write(handle, buf, len);
129         if(ret==-1)
130                 throw SystemError("Writing to console failed", errno);
131 #endif
132
133         return ret;
134 }
135
136 unsigned Console::do_read(char *buf, unsigned len)
137 {
138         if(!(mode&M_READ))
139                 throw InvalidState("Console is not readable");
140
141 #ifdef WIN32
142         DWORD ret;
143         if(!ReadFile(handle, buf, len, &ret, 0))
144                 throw SystemError("Reading from console failed", GetLastError());
145 #else
146         int ret = ::read(handle, buf, len);
147         if(ret==-1)
148         {
149                 if(errno==EAGAIN)
150                         return 0;
151                 else
152                         throw SystemError("Reading from console failed", errno);
153         }
154         else if(ret==0)
155                 eof_flag = true;
156 #endif
157
158         return ret;
159 }
160
161 Handle Console::get_event_handle()
162 {
163         return 0;
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