io-console 0.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/console.c +628 -0
- data/extconf.rb +20 -0
- data/lib/console/size.rb +20 -0
- metadata +48 -0
data/console.c
ADDED
@@ -0,0 +1,628 @@
|
|
1
|
+
/* -*- c-file-style: "ruby" -*- */
|
2
|
+
/*
|
3
|
+
* console IO module
|
4
|
+
*/
|
5
|
+
#include "ruby.h"
|
6
|
+
#ifdef HAVE_RUBY_IO_H
|
7
|
+
#include "ruby/io.h"
|
8
|
+
#else
|
9
|
+
#include "rubyio.h"
|
10
|
+
#endif
|
11
|
+
|
12
|
+
#ifndef HAVE_RB_IO_T
|
13
|
+
typedef OpenFile rb_io_t;
|
14
|
+
#endif
|
15
|
+
|
16
|
+
#ifdef HAVE_UNISTD_H
|
17
|
+
#include <unistd.h>
|
18
|
+
#endif
|
19
|
+
#ifdef HAVE_FCNTL_H
|
20
|
+
#include <fcntl.h>
|
21
|
+
#endif
|
22
|
+
#ifdef HAVE_SYS_IOCTL_H
|
23
|
+
#include <sys/ioctl.h>
|
24
|
+
#endif
|
25
|
+
|
26
|
+
#if defined HAVE_TERMIOS_H
|
27
|
+
# include <termios.h>
|
28
|
+
typedef struct termios conmode;
|
29
|
+
|
30
|
+
static int
|
31
|
+
setattr(int fd, conmode *t)
|
32
|
+
{
|
33
|
+
while (tcsetattr(fd, TCSAFLUSH, t)) {
|
34
|
+
if (errno != EINTR) return 0;
|
35
|
+
}
|
36
|
+
return 1;
|
37
|
+
}
|
38
|
+
# define getattr(fd, t) (tcgetattr(fd, t) == 0)
|
39
|
+
#elif defined HAVE_TERMIO_H
|
40
|
+
# include <termio.h>
|
41
|
+
typedef struct termio conmode;
|
42
|
+
# define setattr(fd, t) (ioctl(fd, TCSETAF, t) == 0)
|
43
|
+
# define getattr(fd, t) (ioctl(fd, TCGETA, t) == 0)
|
44
|
+
#elif defined HAVE_SGTTY_H
|
45
|
+
# include <sgtty.h>
|
46
|
+
typedef struct sgttyb conmode;
|
47
|
+
# ifdef HAVE_STTY
|
48
|
+
# define setattr(fd, t) (stty(fd, t) == 0)
|
49
|
+
# else
|
50
|
+
# define setattr(fd, t) (ioctl((fd), TIOCSETP, (t)) == 0)
|
51
|
+
# endif
|
52
|
+
# ifdef HAVE_GTTY
|
53
|
+
# define getattr(fd, t) (gtty(fd, t) == 0)
|
54
|
+
# else
|
55
|
+
# define getattr(fd, t) (ioctl((fd), TIOCGETP, (t)) == 0)
|
56
|
+
# endif
|
57
|
+
#elif defined _WIN32
|
58
|
+
#include <winioctl.h>
|
59
|
+
typedef DWORD conmode;
|
60
|
+
|
61
|
+
#ifdef HAVE_RB_W32_MAP_ERRNO
|
62
|
+
#define LAST_ERROR rb_w32_map_errno(GetLastError())
|
63
|
+
#else
|
64
|
+
#define LAST_ERROR EBADF
|
65
|
+
#endif
|
66
|
+
#define SET_LAST_ERROR (errno = LAST_ERROR, 0)
|
67
|
+
|
68
|
+
static int
|
69
|
+
setattr(int fd, conmode *t)
|
70
|
+
{
|
71
|
+
int x = SetConsoleMode((HANDLE)rb_w32_get_osfhandle(fd), *t);
|
72
|
+
if (!x) errno = LAST_ERROR;
|
73
|
+
return x;
|
74
|
+
}
|
75
|
+
|
76
|
+
static int
|
77
|
+
getattr(int fd, conmode *t)
|
78
|
+
{
|
79
|
+
int x = GetConsoleMode((HANDLE)rb_w32_get_osfhandle(fd), t);
|
80
|
+
if (!x) errno = LAST_ERROR;
|
81
|
+
return x;
|
82
|
+
}
|
83
|
+
#endif
|
84
|
+
#ifndef SET_LAST_ERROR
|
85
|
+
#define SET_LAST_ERROR (0)
|
86
|
+
#endif
|
87
|
+
|
88
|
+
#ifndef InitVM
|
89
|
+
#define InitVM(ext) {void InitVM_##ext(void);InitVM_##ext();}
|
90
|
+
#endif
|
91
|
+
|
92
|
+
static ID id_getc, id_console;
|
93
|
+
|
94
|
+
static void
|
95
|
+
set_rawmode(conmode *t)
|
96
|
+
{
|
97
|
+
#ifdef HAVE_CFMAKERAW
|
98
|
+
cfmakeraw(t);
|
99
|
+
#else
|
100
|
+
#if defined HAVE_TERMIOS_H || defined HAVE_TERMIO_H
|
101
|
+
t->c_iflag &= ~(IGNBRK|BRKINT|PARMRK|ISTRIP|INLCR|IGNCR|ICRNL|IXON);
|
102
|
+
t->c_oflag &= ~OPOST;
|
103
|
+
t->c_lflag &= ~(ECHO|ECHONL|ICANON|ISIG|IEXTEN);
|
104
|
+
t->c_cflag &= ~(CSIZE|PARENB);
|
105
|
+
t->c_cflag |= CS8;
|
106
|
+
#elif defined HAVE_SGTTY_H
|
107
|
+
t->sg_flags &= ~ECHO;
|
108
|
+
t->sg_flags |= RAW;
|
109
|
+
#elif defined _WIN32
|
110
|
+
*t = 0;
|
111
|
+
#endif
|
112
|
+
#endif
|
113
|
+
}
|
114
|
+
|
115
|
+
static void
|
116
|
+
set_noecho(conmode *t)
|
117
|
+
{
|
118
|
+
#if defined HAVE_TERMIOS_H || defined HAVE_TERMIO_H
|
119
|
+
t->c_lflag &= ~(ECHO | ECHOE | ECHOK | ECHONL);
|
120
|
+
#elif defined HAVE_SGTTY_H
|
121
|
+
t->sg_flags &= ~ECHO;
|
122
|
+
#elif defined _WIN32
|
123
|
+
*t &= ~ENABLE_ECHO_INPUT;
|
124
|
+
#endif
|
125
|
+
}
|
126
|
+
|
127
|
+
static void
|
128
|
+
set_echo(conmode *t)
|
129
|
+
{
|
130
|
+
#if defined HAVE_TERMIOS_H || defined HAVE_TERMIO_H
|
131
|
+
t->c_lflag |= (ECHO | ECHOE | ECHOK | ECHONL);
|
132
|
+
#elif defined HAVE_SGTTY_H
|
133
|
+
t->sg_flags |= ECHO;
|
134
|
+
#elif defined _WIN32
|
135
|
+
*t |= ENABLE_ECHO_INPUT;
|
136
|
+
#endif
|
137
|
+
}
|
138
|
+
|
139
|
+
static int
|
140
|
+
echo_p(conmode *t)
|
141
|
+
{
|
142
|
+
#if defined HAVE_TERMIOS_H || defined HAVE_TERMIO_H
|
143
|
+
return (t->c_lflag & (ECHO | ECHOE | ECHOK | ECHONL)) != 0;
|
144
|
+
#elif defined HAVE_SGTTY_H
|
145
|
+
return (t->sg_flags & ECHO) != 0;
|
146
|
+
#elif defined _WIN32
|
147
|
+
return (*t & ENABLE_ECHO_INPUT) != 0;
|
148
|
+
#endif
|
149
|
+
}
|
150
|
+
|
151
|
+
static int
|
152
|
+
set_ttymode(int fd, conmode *t, void (*setter)(conmode *))
|
153
|
+
{
|
154
|
+
conmode r;
|
155
|
+
if (!getattr(fd, t)) return 0;
|
156
|
+
r = *t;
|
157
|
+
setter(&r);
|
158
|
+
return setattr(fd, &r);
|
159
|
+
}
|
160
|
+
|
161
|
+
#ifdef GetReadFile
|
162
|
+
#define GetReadFD(fptr) fileno(GetReadFile(fptr))
|
163
|
+
#else
|
164
|
+
#define GetReadFD(fptr) ((fptr)->fd)
|
165
|
+
#endif
|
166
|
+
|
167
|
+
#ifdef GetWriteFile
|
168
|
+
#define GetWriteFD(fptr) fileno(GetWriteFile(fptr))
|
169
|
+
#else
|
170
|
+
static inline int
|
171
|
+
get_write_fd(const rb_io_t *fptr)
|
172
|
+
{
|
173
|
+
VALUE wio = fptr->tied_io_for_writing;
|
174
|
+
rb_io_t *ofptr;
|
175
|
+
if (!wio) return fptr->fd;
|
176
|
+
GetOpenFile(wio, ofptr);
|
177
|
+
return ofptr->fd;
|
178
|
+
}
|
179
|
+
#define GetWriteFD(fptr) get_write_fd(fptr)
|
180
|
+
#endif
|
181
|
+
|
182
|
+
#define FD_PER_IO 2
|
183
|
+
|
184
|
+
static VALUE
|
185
|
+
ttymode(VALUE io, VALUE (*func)(VALUE), void (*setter)(conmode *))
|
186
|
+
{
|
187
|
+
rb_io_t *fptr;
|
188
|
+
int status = -1;
|
189
|
+
int error = 0;
|
190
|
+
int fd[FD_PER_IO];
|
191
|
+
conmode t[FD_PER_IO];
|
192
|
+
VALUE result = Qnil;
|
193
|
+
|
194
|
+
GetOpenFile(io, fptr);
|
195
|
+
fd[0] = GetReadFD(fptr);
|
196
|
+
if (fd[0] != -1) {
|
197
|
+
if (set_ttymode(fd[0], t+0, setter)) {
|
198
|
+
status = 0;
|
199
|
+
}
|
200
|
+
else {
|
201
|
+
error = errno;
|
202
|
+
fd[0] = -1;
|
203
|
+
}
|
204
|
+
}
|
205
|
+
fd[1] = GetWriteFD(fptr);
|
206
|
+
if (fd[1] != -1 && fd[1] != fd[0]) {
|
207
|
+
if (set_ttymode(fd[1], t+1, setter)) {
|
208
|
+
status = 0;
|
209
|
+
}
|
210
|
+
else {
|
211
|
+
error = errno;
|
212
|
+
fd[1] = -1;
|
213
|
+
}
|
214
|
+
}
|
215
|
+
if (status == 0) {
|
216
|
+
result = rb_protect(func, io, &status);
|
217
|
+
}
|
218
|
+
GetOpenFile(io, fptr);
|
219
|
+
if (fd[0] != -1 && fd[0] == GetReadFD(fptr)) {
|
220
|
+
if (!setattr(fd[0], t+0)) {
|
221
|
+
error = errno;
|
222
|
+
status = -1;
|
223
|
+
}
|
224
|
+
}
|
225
|
+
if (fd[1] != -1 && fd[1] != fd[0] && fd[1] == GetWriteFD(fptr)) {
|
226
|
+
if (!setattr(fd[1], t+1)) {
|
227
|
+
error = errno;
|
228
|
+
status = -1;
|
229
|
+
}
|
230
|
+
}
|
231
|
+
if (status) {
|
232
|
+
if (status == -1) {
|
233
|
+
errno = error;
|
234
|
+
rb_sys_fail(0);
|
235
|
+
}
|
236
|
+
rb_jump_tag(status);
|
237
|
+
}
|
238
|
+
return result;
|
239
|
+
}
|
240
|
+
|
241
|
+
/*
|
242
|
+
* call-seq:
|
243
|
+
* io.raw {|io| }
|
244
|
+
*
|
245
|
+
* Yields +self+ within raw mode.
|
246
|
+
*
|
247
|
+
* STDIN.raw(&:gets)
|
248
|
+
*
|
249
|
+
* will read and return a line with echo back and line editing.
|
250
|
+
*/
|
251
|
+
static VALUE
|
252
|
+
console_raw(VALUE io)
|
253
|
+
{
|
254
|
+
return ttymode(io, rb_yield, set_rawmode);
|
255
|
+
}
|
256
|
+
|
257
|
+
/*
|
258
|
+
* call-seq:
|
259
|
+
* io.raw!
|
260
|
+
*
|
261
|
+
* Enables raw mode.
|
262
|
+
*
|
263
|
+
* If the terminal mode needs to be back, use io.raw { ... }.
|
264
|
+
*/
|
265
|
+
static VALUE
|
266
|
+
console_set_raw(VALUE io)
|
267
|
+
{
|
268
|
+
conmode t;
|
269
|
+
rb_io_t *fptr;
|
270
|
+
int fd;
|
271
|
+
|
272
|
+
GetOpenFile(io, fptr);
|
273
|
+
fd = GetReadFD(fptr);
|
274
|
+
if (!getattr(fd, &t)) rb_sys_fail(0);
|
275
|
+
set_rawmode(&t);
|
276
|
+
if (!setattr(fd, &t)) rb_sys_fail(0);
|
277
|
+
return io;
|
278
|
+
}
|
279
|
+
|
280
|
+
static VALUE
|
281
|
+
getc_call(VALUE io)
|
282
|
+
{
|
283
|
+
return rb_funcall2(io, id_getc, 0, 0);
|
284
|
+
}
|
285
|
+
|
286
|
+
/*
|
287
|
+
* call-seq:
|
288
|
+
* io.getch -> char
|
289
|
+
*
|
290
|
+
* Reads and returns a character in raw mode.
|
291
|
+
*/
|
292
|
+
static VALUE
|
293
|
+
console_getch(VALUE io)
|
294
|
+
{
|
295
|
+
return ttymode(io, getc_call, set_rawmode);
|
296
|
+
}
|
297
|
+
|
298
|
+
/*
|
299
|
+
* call-seq:
|
300
|
+
* io.noecho {|io| }
|
301
|
+
*
|
302
|
+
* Yields +self+ with disabling echo back.
|
303
|
+
*
|
304
|
+
* STDIN.noecho(&:gets)
|
305
|
+
*
|
306
|
+
* will read and return a line without echo back.
|
307
|
+
*/
|
308
|
+
static VALUE
|
309
|
+
console_noecho(VALUE io)
|
310
|
+
{
|
311
|
+
return ttymode(io, rb_yield, set_noecho);
|
312
|
+
}
|
313
|
+
|
314
|
+
/*
|
315
|
+
* call-seq:
|
316
|
+
* io.echo = flag
|
317
|
+
*
|
318
|
+
* Enables/disables echo back.
|
319
|
+
*/
|
320
|
+
static VALUE
|
321
|
+
console_set_echo(VALUE io, VALUE f)
|
322
|
+
{
|
323
|
+
conmode t;
|
324
|
+
rb_io_t *fptr;
|
325
|
+
int fd;
|
326
|
+
|
327
|
+
GetOpenFile(io, fptr);
|
328
|
+
fd = GetReadFD(fptr);
|
329
|
+
if (!getattr(fd, &t)) rb_sys_fail(0);
|
330
|
+
if (RTEST(f))
|
331
|
+
set_echo(&t);
|
332
|
+
else
|
333
|
+
set_noecho(&t);
|
334
|
+
if (!setattr(fd, &t)) rb_sys_fail(0);
|
335
|
+
return io;
|
336
|
+
}
|
337
|
+
|
338
|
+
/*
|
339
|
+
* call-seq:
|
340
|
+
* io.echo? -> true or false
|
341
|
+
*
|
342
|
+
* Returns +true+ if echo back is enabled.
|
343
|
+
*/
|
344
|
+
static VALUE
|
345
|
+
console_echo_p(VALUE io)
|
346
|
+
{
|
347
|
+
conmode t;
|
348
|
+
rb_io_t *fptr;
|
349
|
+
int fd;
|
350
|
+
|
351
|
+
GetOpenFile(io, fptr);
|
352
|
+
fd = GetReadFD(fptr);
|
353
|
+
if (!getattr(fd, &t)) rb_sys_fail(0);
|
354
|
+
return echo_p(&t) ? Qtrue : Qfalse;
|
355
|
+
}
|
356
|
+
|
357
|
+
#if defined TIOCGWINSZ
|
358
|
+
typedef struct winsize rb_console_size_t;
|
359
|
+
#define getwinsize(fd, buf) (ioctl((fd), TIOCGWINSZ, (buf)) == 0)
|
360
|
+
#define setwinsize(fd, buf) (ioctl((fd), TIOCSWINSZ, (buf)) == 0)
|
361
|
+
#define winsize_row(buf) (buf)->ws_row
|
362
|
+
#define winsize_col(buf) (buf)->ws_col
|
363
|
+
#elif defined _WIN32
|
364
|
+
typedef CONSOLE_SCREEN_BUFFER_INFO rb_console_size_t;
|
365
|
+
#define getwinsize(fd, buf) ( \
|
366
|
+
GetConsoleScreenBufferInfo((HANDLE)rb_w32_get_osfhandle(fd), (buf)) || \
|
367
|
+
SET_LAST_ERROR)
|
368
|
+
#define winsize_row(buf) ((buf)->srWindow.Bottom - (buf)->srWindow.Top + 1)
|
369
|
+
#define winsize_col(buf) (buf)->dwSize.X
|
370
|
+
#endif
|
371
|
+
|
372
|
+
#if defined TIOCGWINSZ || defined _WIN32
|
373
|
+
#define USE_CONSOLE_GETSIZE 1
|
374
|
+
#endif
|
375
|
+
|
376
|
+
#ifdef USE_CONSOLE_GETSIZE
|
377
|
+
/*
|
378
|
+
* call-seq:
|
379
|
+
* io.winsize -> [rows, columns]
|
380
|
+
*
|
381
|
+
* Returns console size.
|
382
|
+
*/
|
383
|
+
static VALUE
|
384
|
+
console_winsize(VALUE io)
|
385
|
+
{
|
386
|
+
rb_io_t *fptr;
|
387
|
+
int fd;
|
388
|
+
rb_console_size_t ws;
|
389
|
+
|
390
|
+
GetOpenFile(io, fptr);
|
391
|
+
fd = GetWriteFD(fptr);
|
392
|
+
if (!getwinsize(fd, &ws)) rb_sys_fail(0);
|
393
|
+
return rb_assoc_new(INT2NUM(winsize_row(&ws)), INT2NUM(winsize_col(&ws)));
|
394
|
+
}
|
395
|
+
|
396
|
+
/*
|
397
|
+
* call-seq:
|
398
|
+
* io.winsize = [rows, columns]
|
399
|
+
*
|
400
|
+
* Tries to set console size. The effect depends on the platform and
|
401
|
+
* the running environment.
|
402
|
+
*/
|
403
|
+
static VALUE
|
404
|
+
console_set_winsize(VALUE io, VALUE size)
|
405
|
+
{
|
406
|
+
rb_io_t *fptr;
|
407
|
+
rb_console_size_t ws;
|
408
|
+
#if defined _WIN32
|
409
|
+
HANDLE wh;
|
410
|
+
int newrow, newcol;
|
411
|
+
#endif
|
412
|
+
VALUE row, col, xpixel, ypixel;
|
413
|
+
#if defined TIOCSWINSZ
|
414
|
+
int fd;
|
415
|
+
#endif
|
416
|
+
|
417
|
+
GetOpenFile(io, fptr);
|
418
|
+
size = rb_Array(size);
|
419
|
+
rb_scan_args((int)RARRAY_LEN(size), RARRAY_PTR(size), "22",
|
420
|
+
&row, &col, &xpixel, &ypixel);
|
421
|
+
#if defined TIOCSWINSZ
|
422
|
+
fd = GetWriteFD(fptr);
|
423
|
+
ws.ws_row = ws.ws_col = ws.ws_xpixel = ws.ws_ypixel = 0;
|
424
|
+
#define SET(m) ws.ws_##m = NIL_P(m) ? 0 : (unsigned short)NUM2UINT(m)
|
425
|
+
SET(row);
|
426
|
+
SET(col);
|
427
|
+
SET(xpixel);
|
428
|
+
SET(ypixel);
|
429
|
+
#undef SET
|
430
|
+
if (!setwinsize(fd, &ws)) rb_sys_fail(0);
|
431
|
+
#elif defined _WIN32
|
432
|
+
wh = (HANDLE)rb_w32_get_osfhandle(GetReadFD(fptr));
|
433
|
+
newrow = (SHORT)NUM2UINT(row);
|
434
|
+
newcol = (SHORT)NUM2UINT(col);
|
435
|
+
if (!getwinsize(GetReadFD(fptr), &ws)) {
|
436
|
+
rb_sys_fail("GetConsoleScreenBufferInfo");
|
437
|
+
}
|
438
|
+
if ((ws.dwSize.X < newcol && (ws.dwSize.X = newcol, 1)) ||
|
439
|
+
(ws.dwSize.Y < newrow && (ws.dwSize.Y = newrow, 1))) {
|
440
|
+
if (!(SetConsoleScreenBufferSize(wh, ws.dwSize) || SET_LAST_ERROR)) {
|
441
|
+
rb_sys_fail("SetConsoleScreenBufferInfo");
|
442
|
+
}
|
443
|
+
}
|
444
|
+
ws.srWindow.Left = 0;
|
445
|
+
ws.srWindow.Top = 0;
|
446
|
+
ws.srWindow.Right = newcol;
|
447
|
+
ws.srWindow.Bottom = newrow;
|
448
|
+
if (!(SetConsoleWindowInfo(wh, FALSE, &ws.srWindow) || SET_LAST_ERROR)) {
|
449
|
+
rb_sys_fail("SetConsoleWindowInfo");
|
450
|
+
}
|
451
|
+
#endif
|
452
|
+
return io;
|
453
|
+
}
|
454
|
+
#endif
|
455
|
+
|
456
|
+
/*
|
457
|
+
* call-seq:
|
458
|
+
* io.iflush
|
459
|
+
*
|
460
|
+
* Flushes input buffer in kernel.
|
461
|
+
*/
|
462
|
+
static VALUE
|
463
|
+
console_iflush(VALUE io)
|
464
|
+
{
|
465
|
+
rb_io_t *fptr;
|
466
|
+
int fd;
|
467
|
+
|
468
|
+
GetOpenFile(io, fptr);
|
469
|
+
fd = GetReadFD(fptr);
|
470
|
+
#if defined HAVE_TERMIOS_H || defined HAVE_TERMIO_H
|
471
|
+
if (tcflush(fd, TCIFLUSH)) rb_sys_fail(0);
|
472
|
+
#endif
|
473
|
+
return io;
|
474
|
+
}
|
475
|
+
|
476
|
+
/*
|
477
|
+
* call-seq:
|
478
|
+
* io.oflush
|
479
|
+
*
|
480
|
+
* Flushes output buffer in kernel.
|
481
|
+
*/
|
482
|
+
static VALUE
|
483
|
+
console_oflush(VALUE io)
|
484
|
+
{
|
485
|
+
rb_io_t *fptr;
|
486
|
+
int fd;
|
487
|
+
|
488
|
+
GetOpenFile(io, fptr);
|
489
|
+
fd = GetWriteFD(fptr);
|
490
|
+
#if defined HAVE_TERMIOS_H || defined HAVE_TERMIO_H
|
491
|
+
if (tcflush(fd, TCOFLUSH)) rb_sys_fail(0);
|
492
|
+
#endif
|
493
|
+
return io;
|
494
|
+
}
|
495
|
+
|
496
|
+
/*
|
497
|
+
* call-seq:
|
498
|
+
* io.ioflush
|
499
|
+
*
|
500
|
+
* Flushes input and output buffers in kernel.
|
501
|
+
*/
|
502
|
+
static VALUE
|
503
|
+
console_ioflush(VALUE io)
|
504
|
+
{
|
505
|
+
rb_io_t *fptr;
|
506
|
+
#if defined HAVE_TERMIOS_H || defined HAVE_TERMIO_H
|
507
|
+
int fd1, fd2;
|
508
|
+
#endif
|
509
|
+
|
510
|
+
GetOpenFile(io, fptr);
|
511
|
+
#if defined HAVE_TERMIOS_H || defined HAVE_TERMIO_H
|
512
|
+
fd1 = GetReadFD(fptr);
|
513
|
+
fd2 = GetWriteFD(fptr);
|
514
|
+
if (fd2 != -1 && fd1 != fd2) {
|
515
|
+
if (tcflush(fd1, TCIFLUSH)) rb_sys_fail(0);
|
516
|
+
if (tcflush(fd2, TCOFLUSH)) rb_sys_fail(0);
|
517
|
+
}
|
518
|
+
else {
|
519
|
+
if (tcflush(fd1, TCIOFLUSH)) rb_sys_fail(0);
|
520
|
+
}
|
521
|
+
#endif
|
522
|
+
return io;
|
523
|
+
}
|
524
|
+
|
525
|
+
/*
|
526
|
+
* call-seq:
|
527
|
+
* IO.console -> #<File:/dev/tty>
|
528
|
+
*
|
529
|
+
* Returns an File instance opened console.
|
530
|
+
*/
|
531
|
+
static VALUE
|
532
|
+
console_dev(VALUE klass)
|
533
|
+
{
|
534
|
+
VALUE con = 0;
|
535
|
+
rb_io_t *fptr;
|
536
|
+
|
537
|
+
if (klass == rb_cIO) klass = rb_cFile;
|
538
|
+
if (rb_const_defined(klass, id_console)) {
|
539
|
+
con = rb_const_get(klass, id_console);
|
540
|
+
if (TYPE(con) == T_FILE) {
|
541
|
+
if ((fptr = RFILE(con)->fptr) && GetReadFD(fptr) != -1)
|
542
|
+
return con;
|
543
|
+
}
|
544
|
+
rb_mod_remove_const(klass, ID2SYM(id_console));
|
545
|
+
}
|
546
|
+
{
|
547
|
+
VALUE args[2];
|
548
|
+
#if defined HAVE_TERMIOS_H || defined HAVE_TERMIO_H || defined HAVE_SGTTY_H
|
549
|
+
# define CONSOLE_DEVICE "/dev/tty"
|
550
|
+
#elif defined _WIN32
|
551
|
+
# define CONSOLE_DEVICE "con$"
|
552
|
+
# define CONSOLE_DEVICE_FOR_READING "conin$"
|
553
|
+
# define CONSOLE_DEVICE_FOR_WRITING "conout$"
|
554
|
+
#endif
|
555
|
+
#ifndef CONSOLE_DEVICE_FOR_READING
|
556
|
+
# define CONSOLE_DEVICE_FOR_READING CONSOLE_DEVICE
|
557
|
+
#endif
|
558
|
+
#ifdef CONSOLE_DEVICE_FOR_WRITING
|
559
|
+
VALUE out;
|
560
|
+
rb_io_t *ofptr;
|
561
|
+
#endif
|
562
|
+
int fd;
|
563
|
+
|
564
|
+
#ifdef CONSOLE_DEVICE_FOR_WRITING
|
565
|
+
fd = open(CONSOLE_DEVICE_FOR_WRITING, O_WRONLY);
|
566
|
+
if (fd < 0) return Qnil;
|
567
|
+
rb_update_max_fd(fd);
|
568
|
+
args[1] = INT2FIX(O_WRONLY);
|
569
|
+
args[0] = INT2NUM(fd);
|
570
|
+
out = rb_class_new_instance(2, args, klass);
|
571
|
+
#endif
|
572
|
+
fd = open(CONSOLE_DEVICE_FOR_READING, O_RDWR);
|
573
|
+
if (fd < 0) {
|
574
|
+
#ifdef CONSOLE_DEVICE_FOR_WRITING
|
575
|
+
rb_io_close(out);
|
576
|
+
#endif
|
577
|
+
return Qnil;
|
578
|
+
}
|
579
|
+
rb_update_max_fd(fd);
|
580
|
+
args[1] = INT2FIX(O_RDWR);
|
581
|
+
args[0] = INT2NUM(fd);
|
582
|
+
con = rb_class_new_instance(2, args, klass);
|
583
|
+
GetOpenFile(con, fptr);
|
584
|
+
fptr->pathv = rb_obj_freeze(rb_str_new2(CONSOLE_DEVICE));
|
585
|
+
#ifdef CONSOLE_DEVICE_FOR_WRITING
|
586
|
+
GetOpenFile(out, ofptr);
|
587
|
+
# ifdef HAVE_RB_IO_GET_WRITE_IO
|
588
|
+
ofptr->pathv = fptr->pathv;
|
589
|
+
fptr->tied_io_for_writing = out;
|
590
|
+
# else
|
591
|
+
fptr->f2 = ofptr->f;
|
592
|
+
ofptr->f = 0;
|
593
|
+
# endif
|
594
|
+
ofptr->mode |= FMODE_SYNC;
|
595
|
+
#endif
|
596
|
+
fptr->mode |= FMODE_SYNC;
|
597
|
+
rb_const_set(klass, id_console, con);
|
598
|
+
}
|
599
|
+
return con;
|
600
|
+
}
|
601
|
+
|
602
|
+
/*
|
603
|
+
* IO console methods
|
604
|
+
*/
|
605
|
+
void
|
606
|
+
Init_console(void)
|
607
|
+
{
|
608
|
+
id_getc = rb_intern("getc");
|
609
|
+
id_console = rb_intern("console");
|
610
|
+
InitVM(console);
|
611
|
+
}
|
612
|
+
|
613
|
+
void
|
614
|
+
InitVM_console(void)
|
615
|
+
{
|
616
|
+
rb_define_method(rb_cIO, "raw", console_raw, 0);
|
617
|
+
rb_define_method(rb_cIO, "raw!", console_set_raw, 0);
|
618
|
+
rb_define_method(rb_cIO, "getch", console_getch, 0);
|
619
|
+
rb_define_method(rb_cIO, "echo=", console_set_echo, 1);
|
620
|
+
rb_define_method(rb_cIO, "echo?", console_echo_p, 0);
|
621
|
+
rb_define_method(rb_cIO, "noecho", console_noecho, 0);
|
622
|
+
rb_define_method(rb_cIO, "winsize", console_winsize, 0);
|
623
|
+
rb_define_method(rb_cIO, "winsize=", console_set_winsize, 1);
|
624
|
+
rb_define_method(rb_cIO, "iflush", console_iflush, 0);
|
625
|
+
rb_define_method(rb_cIO, "oflush", console_oflush, 0);
|
626
|
+
rb_define_method(rb_cIO, "ioflush", console_ioflush, 0);
|
627
|
+
rb_define_singleton_method(rb_cIO, "console", console_dev, 0);
|
628
|
+
}
|
data/extconf.rb
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
require 'mkmf'
|
2
|
+
|
3
|
+
ok = true
|
4
|
+
hdr = nil
|
5
|
+
case
|
6
|
+
when macro_defined?("_WIN32", "")
|
7
|
+
have_func("rb_w32_map_errno", "ruby.h")
|
8
|
+
when hdr = %w"termios.h termio.h".find {|h| have_header(h)}
|
9
|
+
have_func("cfmakeraw", hdr)
|
10
|
+
when have_header(hdr = "sgtty.h")
|
11
|
+
%w"stty gtty".each {|f| have_func(f, hdr)}
|
12
|
+
else
|
13
|
+
ok = false
|
14
|
+
end
|
15
|
+
have_header("sys/ioctl.h")
|
16
|
+
have_func("rb_io_get_write_io", "ruby/io.h")
|
17
|
+
have_func("dup3", "unistd.h")
|
18
|
+
if ok
|
19
|
+
create_makefile("io/console")
|
20
|
+
end
|
data/lib/console/size.rb
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
def IO.default_console_size
|
2
|
+
[
|
3
|
+
ENV["LINES"].to_i.nonzero? || 25,
|
4
|
+
ENV["COLUMNS"].to_i.nonzero? || 80,
|
5
|
+
]
|
6
|
+
end
|
7
|
+
|
8
|
+
begin
|
9
|
+
require 'io/console'
|
10
|
+
rescue LoadError
|
11
|
+
class IO
|
12
|
+
alias console_size default_console_size
|
13
|
+
end
|
14
|
+
else
|
15
|
+
def IO.console_size
|
16
|
+
console.winsize
|
17
|
+
rescue NoMethodError
|
18
|
+
default_console_size
|
19
|
+
end
|
20
|
+
end
|
metadata
ADDED
@@ -0,0 +1,48 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: io-console
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: '0.3'
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Nobu Nakada
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2011-06-24 00:00:00.000000000 Z
|
13
|
+
dependencies: []
|
14
|
+
description: add console capabilities to IO instances.
|
15
|
+
email: nobu@ruby-lang.org
|
16
|
+
executables: []
|
17
|
+
extensions:
|
18
|
+
- extconf.rb
|
19
|
+
extra_rdoc_files: []
|
20
|
+
files:
|
21
|
+
- console.c
|
22
|
+
- extconf.rb
|
23
|
+
- lib/console/size.rb
|
24
|
+
homepage: http://www.ruby-lang.org
|
25
|
+
licenses: []
|
26
|
+
post_install_message:
|
27
|
+
rdoc_options: []
|
28
|
+
require_paths:
|
29
|
+
- .
|
30
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
31
|
+
none: false
|
32
|
+
requirements:
|
33
|
+
- - ! '>='
|
34
|
+
- !ruby/object:Gem::Version
|
35
|
+
version: '0'
|
36
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
37
|
+
none: false
|
38
|
+
requirements:
|
39
|
+
- - ! '>='
|
40
|
+
- !ruby/object:Gem::Version
|
41
|
+
version: '0'
|
42
|
+
requirements: []
|
43
|
+
rubyforge_project:
|
44
|
+
rubygems_version: 1.8.10
|
45
|
+
signing_key:
|
46
|
+
specification_version: 3
|
47
|
+
summary: Console interface
|
48
|
+
test_files: []
|