]> git.tdb.fi Git - libs/core.git/blob - source/io/console.cpp
Use a self-assignment to copy all members
[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(Console::Stream stream)
18 {
19         switch(stream)
20         {
21         case INPUT: return STD_INPUT_HANDLE;
22         case OUTPUT: return STD_OUTPUT_HANDLE;
23         case ERROR: 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==INPUT ? M_READ : M_WRITE);
41
42 #ifdef WIN32
43         *handle = GetStdHandle(stream_to_sys(stream));
44 #else
45         *handle = stream;
46
47         if(stream==INPUT)
48                 tcgetattr(*handle, &orig_attr);
49 #endif
50
51         if(stream==INPUT)
52                 set_events(P_INPUT);
53 }
54
55 Console::~Console()
56 {
57 #ifndef WIN32
58         if(stream==INPUT)
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         // XXX ICANON does more than just set line buffering, may need a bit more thought
103         termios t;
104         if(tcgetattr(*handle, &t)==-1)
105                 throw system_error("tcgetattr");
106         t.c_lflag = (t.c_lflag&~ICANON) | (l?ICANON:0);
107         if(tcsetattr(*handle, TCSADRAIN, &t)==-1)
108                 throw system_error("tcsetattr");
109 #endif
110 }
111
112 void Console::get_size(unsigned &rows, unsigned &cols)
113 {
114         check_access(M_WRITE);
115
116 #ifdef WIN32
117         // XXX Figure out how to do this
118         rows = 24;
119         cols = 80;
120 #else
121         struct winsize wsz;
122         if(ioctl(*handle, TIOCGWINSZ, &wsz)==-1)
123                 throw system_error("ioctl TIOCGWINSZ");
124         rows = wsz.ws_row;
125         cols = wsz.ws_col;
126 #endif
127 }
128
129 void Console::redirect(Base &other)
130 {
131         Handle other_handle = other.get_handle(mode&M_RDWR);
132 #ifdef WIN32
133         SetStdHandle(stream_to_sys(stream), *other_handle);
134 #else
135         dup2(*other_handle, *handle);
136 #endif
137 }
138
139 unsigned Console::do_write(const char *buf, unsigned len)
140 {
141         check_access(M_WRITE);
142
143         return sys_write(handle, buf, len);
144 }
145
146 unsigned Console::do_read(char *buf, unsigned len)
147 {
148         check_access(M_READ);
149
150         unsigned ret = sys_read(handle, buf, len);
151         if(ret==0)
152                 set_eof();
153
154         return ret;
155 }
156
157 Console &Console::instance(Stream s)
158 {
159         static Console in(INPUT);
160         static Console out(OUTPUT);
161         static Console err(ERROR);
162
163         switch(s)
164         {
165         case INPUT: return in;
166         case OUTPUT: return out;
167         case ERROR: return err;
168         }
169
170         throw invalid_argument("Console::instance");
171 }
172
173 Console &cin = Console::instance(Console::INPUT);
174 Console &cout = Console::instance(Console::OUTPUT);
175 Console &cerr = Console::instance(Console::ERROR);
176
177 } // namespace IO
178 } // namespace Msp