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