]> git.tdb.fi Git - libs/core.git/blob - source/io/console.cpp
Unify end-of-file handling
[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/systemerror.h>
8 #include "console.h"
9 #include "handle_private.h"
10
11 using namespace std;
12
13 namespace {
14
15 #ifndef WIN32
16 termios orig_attr;
17 #endif
18
19 } // namespace
20
21 namespace Msp {
22 namespace IO {
23
24 Console::Console(unsigned n)
25 {
26         if(n>2)
27                 throw invalid_argument("Console::Console");
28
29         mode = (n==0 ? M_READ : M_WRITE);
30
31 #ifdef WIN32
32         switch(n)
33         {
34         case 0: *handle = GetStdHandle(STD_INPUT_HANDLE); break;
35         case 1: *handle = GetStdHandle(STD_OUTPUT_HANDLE); break;
36         case 2: *handle = GetStdHandle(STD_ERROR_HANDLE); break;
37         }
38 #else
39         *handle = n;
40
41         if(n==0)
42                 tcgetattr(*handle, &orig_attr);
43 #endif
44
45         if(n==0)
46                 set_events(P_INPUT);
47 }
48
49 Console::~Console()
50 {
51 #ifndef WIN32
52         if(handle==0)
53                 tcsetattr(*handle, TCSADRAIN, &orig_attr);
54 #endif
55 }
56
57 void Console::set_block(bool b)
58 {
59 #ifdef WIN32
60         // XXX Dunno how to do this in win32
61         (void)b;
62 #else
63         int flags = fcntl(*handle, F_GETFL);
64         flags = (flags&~O_NONBLOCK) | (b?0:O_NONBLOCK);
65         fcntl(*handle, F_SETFL, flags);
66 #endif
67 }
68
69 void Console::set_local_echo(bool e)
70 {
71         check_access(M_READ);
72
73 #ifdef WIN32
74         DWORD m;
75         GetConsoleMode(*handle, &m);
76         SetConsoleMode(*handle, (m&~ENABLE_ECHO_INPUT) | (e?ENABLE_ECHO_INPUT:0));
77 #else
78         termios t;
79         tcgetattr(*handle, &t);
80         t.c_lflag = (t.c_lflag&~ECHO) | (e?ECHO:0);
81         tcsetattr(*handle, TCSADRAIN, &t);
82 #endif
83 }
84
85 void Console::set_line_buffer(bool l)
86 {
87         check_access(M_READ);
88
89 #ifdef WIN32
90         DWORD m;
91         GetConsoleMode(*handle, &m);
92         SetConsoleMode(*handle, (m&~ENABLE_LINE_INPUT) | (l?ENABLE_LINE_INPUT:0));
93 #else
94         // XXX ICANON does more than just set line buffering, may need a bit more thought
95         termios t;
96         tcgetattr(*handle, &t);
97         t.c_lflag = (t.c_lflag&~ICANON) | (l?ICANON:0);
98         tcsetattr(*handle, TCSADRAIN, &t);
99 #endif
100 }
101
102 void Console::get_size(unsigned &rows, unsigned &cols)
103 {
104         check_access(M_WRITE);
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         check_access(M_WRITE);
121
122         return sys_write(handle, buf, len);
123 }
124
125 unsigned Console::do_read(char *buf, unsigned len)
126 {
127         check_access(M_READ);
128
129         unsigned ret = sys_read(handle, buf, len);
130         if(ret==0)
131                 set_eof();
132
133         return ret;
134 }
135
136 Console &Console::instance(unsigned n)
137 {
138         static Console in(0);
139         static Console out(1);
140         static Console err(2);
141
142         switch(n)
143         {
144         case 0: return in;
145         case 1: return out;
146         case 2: return err;
147         }
148
149         throw invalid_argument("Console::instance");
150 }
151
152 Console &cin = Console::instance(0);
153 Console &cout = Console::instance(1);
154 Console &cerr = Console::instance(2);
155
156 } // namespace IO
157 } // namespace Msp