]> git.tdb.fi Git - libs/core.git/blob - source/io/console.cpp
a03ad20747bf251c40c57f682e027f760756cb7e
[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         CONSOLE_SCREEN_BUFFER_INFO sbi;
128         if(!GetConsoleScreenBufferInfo(*handle, &sbi))
129                 throw system_error("GetConsoleScreenBufferInfo");
130         // Right/bottom coords are inclusive
131         rows = sbi.srWindow.Bottom+1-sbi.srWindow.Top;
132         cols = sbi.srWindow.Right+1-sbi.srWindow.Left;
133 #else
134         struct winsize wsz;
135         if(ioctl(*handle, TIOCGWINSZ, &wsz)==-1)
136                 throw system_error("ioctl TIOCGWINSZ");
137         rows = wsz.ws_row;
138         cols = wsz.ws_col;
139 #endif
140 }
141
142 void Console::redirect(Base &other)
143 {
144         Handle other_handle = other.get_handle(mode&M_RDWR);
145 #ifdef WIN32
146         SetStdHandle(stream_to_sys(stream), *other_handle);
147 #else
148         dup2(*other_handle, *handle);
149 #endif
150 }
151
152 unsigned Console::do_write(const char *buf, unsigned len)
153 {
154         check_access(M_WRITE);
155
156         return sys_write(handle, buf, len);
157 }
158
159 unsigned Console::do_read(char *buf, unsigned len)
160 {
161         check_access(M_READ);
162
163         unsigned ret = sys_read(handle, buf, len);
164         if(ret==0)
165                 set_eof();
166
167         return ret;
168 }
169
170 Console &Console::instance(Stream s)
171 {
172         static Console in(CIN);
173         static Console out(COUT);
174         static Console err(CERR);
175
176         switch(s)
177         {
178         case CIN: return in;
179         case COUT: return out;
180         case CERR: return err;
181         }
182
183         throw invalid_argument("Console::instance");
184 }
185
186 Console &cin = Console::instance(Console::CIN);
187 Console &cout = Console::instance(Console::COUT);
188 Console &cerr = Console::instance(Console::CERR);
189
190 } // namespace IO
191 } // namespace Msp