Ruby
2.0.0p247(2013-06-27revision41674)
|
00001 /* -*- c-file-style: "ruby" -*- */ 00002 /* 00003 * console IO module 00004 */ 00005 #include "ruby.h" 00006 #ifdef HAVE_RUBY_IO_H 00007 #include "ruby/io.h" 00008 #else 00009 #include "rubyio.h" 00010 #endif 00011 00012 #ifndef HAVE_RB_IO_T 00013 typedef OpenFile rb_io_t; 00014 #endif 00015 00016 #ifdef HAVE_UNISTD_H 00017 #include <unistd.h> 00018 #endif 00019 #ifdef HAVE_FCNTL_H 00020 #include <fcntl.h> 00021 #endif 00022 #ifdef HAVE_SYS_IOCTL_H 00023 #include <sys/ioctl.h> 00024 #endif 00025 00026 #if defined HAVE_TERMIOS_H 00027 # include <termios.h> 00028 typedef struct termios conmode; 00029 00030 static int 00031 setattr(int fd, conmode *t) 00032 { 00033 while (tcsetattr(fd, TCSAFLUSH, t)) { 00034 if (errno != EINTR) return 0; 00035 } 00036 return 1; 00037 } 00038 # define getattr(fd, t) (tcgetattr(fd, t) == 0) 00039 #elif defined HAVE_TERMIO_H 00040 # include <termio.h> 00041 typedef struct termio conmode; 00042 # define setattr(fd, t) (ioctl(fd, TCSETAF, t) == 0) 00043 # define getattr(fd, t) (ioctl(fd, TCGETA, t) == 0) 00044 #elif defined HAVE_SGTTY_H 00045 # include <sgtty.h> 00046 typedef struct sgttyb conmode; 00047 # ifdef HAVE_STTY 00048 # define setattr(fd, t) (stty(fd, t) == 0) 00049 # else 00050 # define setattr(fd, t) (ioctl((fd), TIOCSETP, (t)) == 0) 00051 # endif 00052 # ifdef HAVE_GTTY 00053 # define getattr(fd, t) (gtty(fd, t) == 0) 00054 # else 00055 # define getattr(fd, t) (ioctl((fd), TIOCGETP, (t)) == 0) 00056 # endif 00057 #elif defined _WIN32 00058 #include <winioctl.h> 00059 typedef DWORD conmode; 00060 00061 #ifdef HAVE_RB_W32_MAP_ERRNO 00062 #define LAST_ERROR rb_w32_map_errno(GetLastError()) 00063 #else 00064 #define LAST_ERROR EBADF 00065 #endif 00066 #define SET_LAST_ERROR (errno = LAST_ERROR, 0) 00067 00068 static int 00069 setattr(int fd, conmode *t) 00070 { 00071 int x = SetConsoleMode((HANDLE)rb_w32_get_osfhandle(fd), *t); 00072 if (!x) errno = LAST_ERROR; 00073 return x; 00074 } 00075 00076 static int 00077 getattr(int fd, conmode *t) 00078 { 00079 int x = GetConsoleMode((HANDLE)rb_w32_get_osfhandle(fd), t); 00080 if (!x) errno = LAST_ERROR; 00081 return x; 00082 } 00083 #endif 00084 #ifndef SET_LAST_ERROR 00085 #define SET_LAST_ERROR (0) 00086 #endif 00087 00088 #ifndef InitVM 00089 #define InitVM(ext) {void InitVM_##ext(void);InitVM_##ext();} 00090 #endif 00091 00092 static ID id_getc, id_console; 00093 00094 typedef struct { 00095 int vmin; 00096 int vtime; 00097 } rawmode_arg_t; 00098 00099 static rawmode_arg_t * 00100 rawmode_opt(int argc, VALUE *argv, rawmode_arg_t *opts) 00101 { 00102 rawmode_arg_t *optp = NULL; 00103 VALUE vopts; 00104 rb_scan_args(argc, argv, "0:", &vopts); 00105 if (!NIL_P(vopts)) { 00106 VALUE vmin = rb_hash_aref(vopts, ID2SYM(rb_intern("min"))); 00107 VALUE vtime = rb_hash_aref(vopts, ID2SYM(rb_intern("time"))); 00108 /* default values by `stty raw` */ 00109 opts->vmin = 1; 00110 opts->vtime = 0; 00111 if (!NIL_P(vmin)) { 00112 opts->vmin = NUM2INT(vmin); 00113 optp = opts; 00114 } 00115 if (!NIL_P(vtime)) { 00116 VALUE v10 = INT2FIX(10); 00117 vtime = rb_funcall3(vtime, '*', 1, &v10); 00118 opts->vtime = NUM2INT(vtime); 00119 optp = opts; 00120 } 00121 } 00122 return optp; 00123 } 00124 00125 static void 00126 set_rawmode(conmode *t, void *arg) 00127 { 00128 #ifdef HAVE_CFMAKERAW 00129 cfmakeraw(t); 00130 t->c_lflag &= ~(ECHOE|ECHOK); 00131 #elif defined HAVE_TERMIOS_H || defined HAVE_TERMIO_H 00132 t->c_iflag &= ~(IGNBRK|BRKINT|PARMRK|ISTRIP|INLCR|IGNCR|ICRNL|IXON); 00133 t->c_oflag &= ~OPOST; 00134 t->c_lflag &= ~(ECHO|ECHOE|ECHOK|ECHONL|ICANON|ISIG|IEXTEN); 00135 t->c_cflag &= ~(CSIZE|PARENB); 00136 t->c_cflag |= CS8; 00137 #elif defined HAVE_SGTTY_H 00138 t->sg_flags &= ~ECHO; 00139 t->sg_flags |= RAW; 00140 #elif defined _WIN32 00141 *t = 0; 00142 #endif 00143 #if defined HAVE_TERMIOS_H || defined HAVE_TERMIO_H 00144 if (arg) { 00145 const rawmode_arg_t *r = arg; 00146 if (r->vmin >= 0) t->c_cc[VMIN] = r->vmin; 00147 if (r->vtime >= 0) t->c_cc[VTIME] = r->vtime; 00148 } 00149 #endif 00150 } 00151 00152 static void 00153 set_cookedmode(conmode *t, void *arg) 00154 { 00155 #if defined HAVE_TERMIOS_H || defined HAVE_TERMIO_H 00156 t->c_iflag |= (BRKINT|ISTRIP|ICRNL|IXON); 00157 t->c_oflag |= OPOST; 00158 t->c_lflag |= (ECHO|ECHOE|ECHOK|ECHONL|ICANON|ISIG|IEXTEN); 00159 #elif defined HAVE_SGTTY_H 00160 t->sg_flags |= ECHO; 00161 t->sg_flags &= ~RAW; 00162 #elif defined _WIN32 00163 *t |= ENABLE_ECHO_INPUT|ENABLE_LINE_INPUT|ENABLE_PROCESSED_INPUT; 00164 #endif 00165 } 00166 00167 static void 00168 set_noecho(conmode *t, void *arg) 00169 { 00170 #if defined HAVE_TERMIOS_H || defined HAVE_TERMIO_H 00171 t->c_lflag &= ~(ECHO | ECHOE | ECHOK | ECHONL); 00172 #elif defined HAVE_SGTTY_H 00173 t->sg_flags &= ~ECHO; 00174 #elif defined _WIN32 00175 *t &= ~ENABLE_ECHO_INPUT; 00176 #endif 00177 } 00178 00179 static void 00180 set_echo(conmode *t, void *arg) 00181 { 00182 #if defined HAVE_TERMIOS_H || defined HAVE_TERMIO_H 00183 t->c_lflag |= (ECHO | ECHOE | ECHOK | ECHONL); 00184 #elif defined HAVE_SGTTY_H 00185 t->sg_flags |= ECHO; 00186 #elif defined _WIN32 00187 *t |= ENABLE_ECHO_INPUT; 00188 #endif 00189 } 00190 00191 static int 00192 echo_p(conmode *t) 00193 { 00194 #if defined HAVE_TERMIOS_H || defined HAVE_TERMIO_H 00195 return (t->c_lflag & (ECHO | ECHONL)) != 0; 00196 #elif defined HAVE_SGTTY_H 00197 return (t->sg_flags & ECHO) != 0; 00198 #elif defined _WIN32 00199 return (*t & ENABLE_ECHO_INPUT) != 0; 00200 #endif 00201 } 00202 00203 static int 00204 set_ttymode(int fd, conmode *t, void (*setter)(conmode *, void *), void *arg) 00205 { 00206 conmode r; 00207 if (!getattr(fd, t)) return 0; 00208 r = *t; 00209 setter(&r, arg); 00210 return setattr(fd, &r); 00211 } 00212 00213 #ifdef GetReadFile 00214 #define GetReadFD(fptr) fileno(GetReadFile(fptr)) 00215 #else 00216 #define GetReadFD(fptr) ((fptr)->fd) 00217 #endif 00218 00219 #ifdef GetWriteFile 00220 #define GetWriteFD(fptr) fileno(GetWriteFile(fptr)) 00221 #else 00222 static inline int 00223 get_write_fd(const rb_io_t *fptr) 00224 { 00225 VALUE wio = fptr->tied_io_for_writing; 00226 rb_io_t *ofptr; 00227 if (!wio) return fptr->fd; 00228 GetOpenFile(wio, ofptr); 00229 return ofptr->fd; 00230 } 00231 #define GetWriteFD(fptr) get_write_fd(fptr) 00232 #endif 00233 00234 #define FD_PER_IO 2 00235 00236 static VALUE 00237 ttymode(VALUE io, VALUE (*func)(VALUE), void (*setter)(conmode *, void *), void *arg) 00238 { 00239 rb_io_t *fptr; 00240 int status = -1; 00241 int error = 0; 00242 int fd[FD_PER_IO]; 00243 conmode t[FD_PER_IO]; 00244 VALUE result = Qnil; 00245 00246 GetOpenFile(io, fptr); 00247 fd[0] = GetReadFD(fptr); 00248 if (fd[0] != -1) { 00249 if (set_ttymode(fd[0], t+0, setter, arg)) { 00250 status = 0; 00251 } 00252 else { 00253 error = errno; 00254 fd[0] = -1; 00255 } 00256 } 00257 fd[1] = GetWriteFD(fptr); 00258 if (fd[1] != -1 && fd[1] != fd[0]) { 00259 if (set_ttymode(fd[1], t+1, setter, arg)) { 00260 status = 0; 00261 } 00262 else { 00263 error = errno; 00264 fd[1] = -1; 00265 } 00266 } 00267 if (status == 0) { 00268 result = rb_protect(func, io, &status); 00269 } 00270 GetOpenFile(io, fptr); 00271 if (fd[0] != -1 && fd[0] == GetReadFD(fptr)) { 00272 if (!setattr(fd[0], t+0)) { 00273 error = errno; 00274 status = -1; 00275 } 00276 } 00277 if (fd[1] != -1 && fd[1] != fd[0] && fd[1] == GetWriteFD(fptr)) { 00278 if (!setattr(fd[1], t+1)) { 00279 error = errno; 00280 status = -1; 00281 } 00282 } 00283 if (status) { 00284 if (status == -1) { 00285 errno = error; 00286 rb_sys_fail(0); 00287 } 00288 rb_jump_tag(status); 00289 } 00290 return result; 00291 } 00292 00293 /* 00294 * call-seq: 00295 * io.raw(min: nil, time: nil) {|io| } 00296 * 00297 * Yields +self+ within raw mode. 00298 * 00299 * STDIN.raw(&:gets) 00300 * 00301 * will read and return a line without echo back and line editing. 00302 * 00303 * You must require 'io/console' to use this method. 00304 */ 00305 static VALUE 00306 console_raw(int argc, VALUE *argv, VALUE io) 00307 { 00308 rawmode_arg_t opts, *optp = rawmode_opt(argc, argv, &opts); 00309 return ttymode(io, rb_yield, set_rawmode, optp); 00310 } 00311 00312 /* 00313 * call-seq: 00314 * io.raw!(min: nil, time: nil) 00315 * 00316 * Enables raw mode. 00317 * 00318 * If the terminal mode needs to be back, use io.raw { ... }. 00319 * 00320 * You must require 'io/console' to use this method. 00321 */ 00322 static VALUE 00323 console_set_raw(int argc, VALUE *argv, VALUE io) 00324 { 00325 conmode t; 00326 rb_io_t *fptr; 00327 int fd; 00328 rawmode_arg_t opts, *optp = rawmode_opt(argc, argv, &opts); 00329 00330 GetOpenFile(io, fptr); 00331 fd = GetReadFD(fptr); 00332 if (!getattr(fd, &t)) rb_sys_fail(0); 00333 set_rawmode(&t, optp); 00334 if (!setattr(fd, &t)) rb_sys_fail(0); 00335 return io; 00336 } 00337 00338 /* 00339 * call-seq: 00340 * io.cooked {|io| } 00341 * 00342 * Yields +self+ within cooked mode. 00343 * 00344 * STDIN.cooked(&:gets) 00345 * 00346 * will read and return a line with echo back and line editing. 00347 * 00348 * You must require 'io/console' to use this method. 00349 */ 00350 static VALUE 00351 console_cooked(VALUE io) 00352 { 00353 return ttymode(io, rb_yield, set_cookedmode, NULL); 00354 } 00355 00356 /* 00357 * call-seq: 00358 * io.cooked! 00359 * 00360 * Enables cooked mode. 00361 * 00362 * If the terminal mode needs to be back, use io.cooked { ... }. 00363 * 00364 * You must require 'io/console' to use this method. 00365 */ 00366 static VALUE 00367 console_set_cooked(VALUE io) 00368 { 00369 conmode t; 00370 rb_io_t *fptr; 00371 int fd; 00372 00373 GetOpenFile(io, fptr); 00374 fd = GetReadFD(fptr); 00375 if (!getattr(fd, &t)) rb_sys_fail(0); 00376 set_cookedmode(&t, NULL); 00377 if (!setattr(fd, &t)) rb_sys_fail(0); 00378 return io; 00379 } 00380 00381 static VALUE 00382 getc_call(VALUE io) 00383 { 00384 return rb_funcall2(io, id_getc, 0, 0); 00385 } 00386 00387 /* 00388 * call-seq: 00389 * io.getch(min: nil, time: nil) -> char 00390 * 00391 * Reads and returns a character in raw mode. 00392 * 00393 * You must require 'io/console' to use this method. 00394 */ 00395 static VALUE 00396 console_getch(int argc, VALUE *argv, VALUE io) 00397 { 00398 rawmode_arg_t opts, *optp = rawmode_opt(argc, argv, &opts); 00399 return ttymode(io, getc_call, set_rawmode, optp); 00400 } 00401 00402 /* 00403 * call-seq: 00404 * io.noecho {|io| } 00405 * 00406 * Yields +self+ with disabling echo back. 00407 * 00408 * STDIN.noecho(&:gets) 00409 * 00410 * will read and return a line without echo back. 00411 * 00412 * You must require 'io/console' to use this method. 00413 */ 00414 static VALUE 00415 console_noecho(VALUE io) 00416 { 00417 return ttymode(io, rb_yield, set_noecho, NULL); 00418 } 00419 00420 /* 00421 * call-seq: 00422 * io.echo = flag 00423 * 00424 * Enables/disables echo back. 00425 * On some platforms, all combinations of this flags and raw/cooked 00426 * mode may not be valid. 00427 * 00428 * You must require 'io/console' to use this method. 00429 */ 00430 static VALUE 00431 console_set_echo(VALUE io, VALUE f) 00432 { 00433 conmode t; 00434 rb_io_t *fptr; 00435 int fd; 00436 00437 GetOpenFile(io, fptr); 00438 fd = GetReadFD(fptr); 00439 if (!getattr(fd, &t)) rb_sys_fail(0); 00440 if (RTEST(f)) 00441 set_echo(&t, NULL); 00442 else 00443 set_noecho(&t, NULL); 00444 if (!setattr(fd, &t)) rb_sys_fail(0); 00445 return io; 00446 } 00447 00448 /* 00449 * call-seq: 00450 * io.echo? -> true or false 00451 * 00452 * Returns +true+ if echo back is enabled. 00453 * 00454 * You must require 'io/console' to use this method. 00455 */ 00456 static VALUE 00457 console_echo_p(VALUE io) 00458 { 00459 conmode t; 00460 rb_io_t *fptr; 00461 int fd; 00462 00463 GetOpenFile(io, fptr); 00464 fd = GetReadFD(fptr); 00465 if (!getattr(fd, &t)) rb_sys_fail(0); 00466 return echo_p(&t) ? Qtrue : Qfalse; 00467 } 00468 00469 #if defined TIOCGWINSZ 00470 typedef struct winsize rb_console_size_t; 00471 #define getwinsize(fd, buf) (ioctl((fd), TIOCGWINSZ, (buf)) == 0) 00472 #define setwinsize(fd, buf) (ioctl((fd), TIOCSWINSZ, (buf)) == 0) 00473 #define winsize_row(buf) (buf)->ws_row 00474 #define winsize_col(buf) (buf)->ws_col 00475 #elif defined _WIN32 00476 typedef CONSOLE_SCREEN_BUFFER_INFO rb_console_size_t; 00477 #define getwinsize(fd, buf) ( \ 00478 GetConsoleScreenBufferInfo((HANDLE)rb_w32_get_osfhandle(fd), (buf)) || \ 00479 SET_LAST_ERROR) 00480 #define winsize_row(buf) ((buf)->srWindow.Bottom - (buf)->srWindow.Top + 1) 00481 #define winsize_col(buf) (buf)->dwSize.X 00482 #endif 00483 00484 #if defined TIOCGWINSZ || defined _WIN32 00485 #define USE_CONSOLE_GETSIZE 1 00486 #endif 00487 00488 #ifdef USE_CONSOLE_GETSIZE 00489 /* 00490 * call-seq: 00491 * io.winsize -> [rows, columns] 00492 * 00493 * Returns console size. 00494 * 00495 * You must require 'io/console' to use this method. 00496 */ 00497 static VALUE 00498 console_winsize(VALUE io) 00499 { 00500 rb_io_t *fptr; 00501 int fd; 00502 rb_console_size_t ws; 00503 00504 GetOpenFile(io, fptr); 00505 fd = GetWriteFD(fptr); 00506 if (!getwinsize(fd, &ws)) rb_sys_fail(0); 00507 return rb_assoc_new(INT2NUM(winsize_row(&ws)), INT2NUM(winsize_col(&ws))); 00508 } 00509 00510 /* 00511 * call-seq: 00512 * io.winsize = [rows, columns] 00513 * 00514 * Tries to set console size. The effect depends on the platform and 00515 * the running environment. 00516 * 00517 * You must require 'io/console' to use this method. 00518 */ 00519 static VALUE 00520 console_set_winsize(VALUE io, VALUE size) 00521 { 00522 rb_io_t *fptr; 00523 rb_console_size_t ws; 00524 #if defined _WIN32 00525 HANDLE wh; 00526 int newrow, newcol; 00527 #endif 00528 VALUE row, col, xpixel, ypixel; 00529 #if defined TIOCSWINSZ 00530 int fd; 00531 #endif 00532 00533 GetOpenFile(io, fptr); 00534 size = rb_Array(size); 00535 rb_scan_args((int)RARRAY_LEN(size), RARRAY_PTR(size), "22", 00536 &row, &col, &xpixel, &ypixel); 00537 #if defined TIOCSWINSZ 00538 fd = GetWriteFD(fptr); 00539 ws.ws_row = ws.ws_col = ws.ws_xpixel = ws.ws_ypixel = 0; 00540 #define SET(m) ws.ws_##m = NIL_P(m) ? 0 : (unsigned short)NUM2UINT(m) 00541 SET(row); 00542 SET(col); 00543 SET(xpixel); 00544 SET(ypixel); 00545 #undef SET 00546 if (!setwinsize(fd, &ws)) rb_sys_fail(0); 00547 #elif defined _WIN32 00548 wh = (HANDLE)rb_w32_get_osfhandle(GetReadFD(fptr)); 00549 newrow = (SHORT)NUM2UINT(row); 00550 newcol = (SHORT)NUM2UINT(col); 00551 if (!getwinsize(GetReadFD(fptr), &ws)) { 00552 rb_sys_fail("GetConsoleScreenBufferInfo"); 00553 } 00554 if ((ws.dwSize.X < newcol && (ws.dwSize.X = newcol, 1)) || 00555 (ws.dwSize.Y < newrow && (ws.dwSize.Y = newrow, 1))) { 00556 if (!(SetConsoleScreenBufferSize(wh, ws.dwSize) || SET_LAST_ERROR)) { 00557 rb_sys_fail("SetConsoleScreenBufferInfo"); 00558 } 00559 } 00560 ws.srWindow.Left = 0; 00561 ws.srWindow.Top = 0; 00562 ws.srWindow.Right = newcol; 00563 ws.srWindow.Bottom = newrow; 00564 if (!(SetConsoleWindowInfo(wh, FALSE, &ws.srWindow) || SET_LAST_ERROR)) { 00565 rb_sys_fail("SetConsoleWindowInfo"); 00566 } 00567 #endif 00568 return io; 00569 } 00570 #endif 00571 00572 /* 00573 * call-seq: 00574 * io.iflush 00575 * 00576 * Flushes input buffer in kernel. 00577 * 00578 * You must require 'io/console' to use this method. 00579 */ 00580 static VALUE 00581 console_iflush(VALUE io) 00582 { 00583 rb_io_t *fptr; 00584 int fd; 00585 00586 GetOpenFile(io, fptr); 00587 fd = GetReadFD(fptr); 00588 #if defined HAVE_TERMIOS_H || defined HAVE_TERMIO_H 00589 if (tcflush(fd, TCIFLUSH)) rb_sys_fail(0); 00590 #endif 00591 return io; 00592 } 00593 00594 /* 00595 * call-seq: 00596 * io.oflush 00597 * 00598 * Flushes output buffer in kernel. 00599 * 00600 * You must require 'io/console' to use this method. 00601 */ 00602 static VALUE 00603 console_oflush(VALUE io) 00604 { 00605 rb_io_t *fptr; 00606 int fd; 00607 00608 GetOpenFile(io, fptr); 00609 fd = GetWriteFD(fptr); 00610 #if defined HAVE_TERMIOS_H || defined HAVE_TERMIO_H 00611 if (tcflush(fd, TCOFLUSH)) rb_sys_fail(0); 00612 #endif 00613 return io; 00614 } 00615 00616 /* 00617 * call-seq: 00618 * io.ioflush 00619 * 00620 * Flushes input and output buffers in kernel. 00621 * 00622 * You must require 'io/console' to use this method. 00623 */ 00624 static VALUE 00625 console_ioflush(VALUE io) 00626 { 00627 rb_io_t *fptr; 00628 #if defined HAVE_TERMIOS_H || defined HAVE_TERMIO_H 00629 int fd1, fd2; 00630 #endif 00631 00632 GetOpenFile(io, fptr); 00633 #if defined HAVE_TERMIOS_H || defined HAVE_TERMIO_H 00634 fd1 = GetReadFD(fptr); 00635 fd2 = GetWriteFD(fptr); 00636 if (fd2 != -1 && fd1 != fd2) { 00637 if (tcflush(fd1, TCIFLUSH)) rb_sys_fail(0); 00638 if (tcflush(fd2, TCOFLUSH)) rb_sys_fail(0); 00639 } 00640 else { 00641 if (tcflush(fd1, TCIOFLUSH)) rb_sys_fail(0); 00642 } 00643 #endif 00644 return io; 00645 } 00646 00647 /* 00648 * call-seq: 00649 * IO.console -> #<File:/dev/tty> 00650 * 00651 * Returns an File instance opened console. 00652 * 00653 * You must require 'io/console' to use this method. 00654 */ 00655 static VALUE 00656 console_dev(VALUE klass) 00657 { 00658 VALUE con = 0; 00659 rb_io_t *fptr; 00660 00661 if (klass == rb_cIO) klass = rb_cFile; 00662 if (rb_const_defined(klass, id_console)) { 00663 con = rb_const_get(klass, id_console); 00664 if (RB_TYPE_P(con, T_FILE)) { 00665 if ((fptr = RFILE(con)->fptr) && GetReadFD(fptr) != -1) 00666 return con; 00667 } 00668 rb_mod_remove_const(klass, ID2SYM(id_console)); 00669 } 00670 { 00671 VALUE args[2]; 00672 #if defined HAVE_TERMIOS_H || defined HAVE_TERMIO_H || defined HAVE_SGTTY_H 00673 # define CONSOLE_DEVICE "/dev/tty" 00674 #elif defined _WIN32 00675 # define CONSOLE_DEVICE "con$" 00676 # define CONSOLE_DEVICE_FOR_READING "conin$" 00677 # define CONSOLE_DEVICE_FOR_WRITING "conout$" 00678 #endif 00679 #ifndef CONSOLE_DEVICE_FOR_READING 00680 # define CONSOLE_DEVICE_FOR_READING CONSOLE_DEVICE 00681 #endif 00682 #ifdef CONSOLE_DEVICE_FOR_WRITING 00683 VALUE out; 00684 rb_io_t *ofptr; 00685 #endif 00686 int fd; 00687 00688 #ifdef CONSOLE_DEVICE_FOR_WRITING 00689 fd = rb_cloexec_open(CONSOLE_DEVICE_FOR_WRITING, O_WRONLY, 0); 00690 if (fd < 0) return Qnil; 00691 rb_update_max_fd(fd); 00692 args[1] = INT2FIX(O_WRONLY); 00693 args[0] = INT2NUM(fd); 00694 out = rb_class_new_instance(2, args, klass); 00695 #endif 00696 fd = rb_cloexec_open(CONSOLE_DEVICE_FOR_READING, O_RDWR, 0); 00697 if (fd < 0) { 00698 #ifdef CONSOLE_DEVICE_FOR_WRITING 00699 rb_io_close(out); 00700 #endif 00701 return Qnil; 00702 } 00703 rb_update_max_fd(fd); 00704 args[1] = INT2FIX(O_RDWR); 00705 args[0] = INT2NUM(fd); 00706 con = rb_class_new_instance(2, args, klass); 00707 GetOpenFile(con, fptr); 00708 fptr->pathv = rb_obj_freeze(rb_str_new2(CONSOLE_DEVICE)); 00709 #ifdef CONSOLE_DEVICE_FOR_WRITING 00710 GetOpenFile(out, ofptr); 00711 # ifdef HAVE_RB_IO_GET_WRITE_IO 00712 ofptr->pathv = fptr->pathv; 00713 fptr->tied_io_for_writing = out; 00714 # else 00715 fptr->f2 = ofptr->f; 00716 ofptr->f = 0; 00717 # endif 00718 ofptr->mode |= FMODE_SYNC; 00719 #endif 00720 fptr->mode |= FMODE_SYNC; 00721 rb_const_set(klass, id_console, con); 00722 } 00723 return con; 00724 } 00725 00726 static VALUE 00727 io_getch(int argc, VALUE *argv, VALUE io) 00728 { 00729 return rb_funcall2(io, rb_intern("getc"), argc, argv); 00730 } 00731 00732 /* 00733 * IO console methods 00734 */ 00735 void 00736 Init_console(void) 00737 { 00738 id_getc = rb_intern("getc"); 00739 id_console = rb_intern("console"); 00740 InitVM(console); 00741 } 00742 00743 void 00744 InitVM_console(void) 00745 { 00746 rb_define_method(rb_cIO, "raw", console_raw, -1); 00747 rb_define_method(rb_cIO, "raw!", console_set_raw, -1); 00748 rb_define_method(rb_cIO, "cooked", console_cooked, 0); 00749 rb_define_method(rb_cIO, "cooked!", console_set_cooked, 0); 00750 rb_define_method(rb_cIO, "getch", console_getch, -1); 00751 rb_define_method(rb_cIO, "echo=", console_set_echo, 1); 00752 rb_define_method(rb_cIO, "echo?", console_echo_p, 0); 00753 rb_define_method(rb_cIO, "noecho", console_noecho, 0); 00754 rb_define_method(rb_cIO, "winsize", console_winsize, 0); 00755 rb_define_method(rb_cIO, "winsize=", console_set_winsize, 1); 00756 rb_define_method(rb_cIO, "iflush", console_iflush, 0); 00757 rb_define_method(rb_cIO, "oflush", console_oflush, 0); 00758 rb_define_method(rb_cIO, "ioflush", console_ioflush, 0); 00759 rb_define_singleton_method(rb_cIO, "console", console_dev, 0); 00760 { 00761 VALUE mReadable = rb_define_module_under(rb_cIO, "readable"); 00762 rb_define_method(mReadable, "getch", io_getch, -1); 00763 } 00764 } 00765