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