ext/rubysl/curses/curses.c in rubysl-curses-1.0.0 vs ext/rubysl/curses/curses.c in rubysl-curses-2.0.0

- old
+ new

@@ -1,22 +1,26 @@ /* -*- C -*- - * $Id: curses.c 25899 2009-11-24 07:02:04Z shyouhei $ + * $Id: curses.c 42241 2013-07-29 13:25:46Z zzak $ * * ext/curses/curses.c - * + * * by MAEDA Shugo (ender@pic-internet.or.jp) * modified by Yukihiro Matsumoto (matz@netlab.co.jp), * Toki Yoshinori, * Hitoshi Takahashi, * and Takaaki Tateishi (ttate@kt.jaist.ac.jp) * * maintainers: * - Takaaki Tateishi (ttate@kt.jaist.ac.jp) + * + * documentation: + * - Vincent Batts (vbatts@hashbangbash.com) */ #include "ruby.h" -#include "rubyio.h" +#include "ruby/io.h" +#include "ruby/thread.h" #if defined(HAVE_NCURSES_H) # include <ncurses.h> #elif defined(HAVE_NCURSES_CURSES_H) # include <ncurses/curses.h> @@ -52,106 +56,151 @@ /* supports only ncurses mouse routines */ #ifdef NCURSES_MOUSE_VERSION # define USE_MOUSE 1 #endif -#define NUM2CH NUM2LONG -#define CH2FIX LONG2FIX +#define NUM2CH NUM2CHR +#define CH2FIX CHR2FIX static VALUE mCurses; static VALUE mKey; static VALUE cWindow; +static VALUE cPad; #ifdef USE_MOUSE static VALUE cMouseEvent; #endif static VALUE rb_stdscr; struct windata { WINDOW *window; }; -#define CHECK(c) c +static VALUE window_attroff(VALUE obj, VALUE attrs); +static VALUE window_attron(VALUE obj, VALUE attrs); +static VALUE window_attrset(VALUE obj, VALUE attrs); -static VALUE window_attroff(); -static VALUE window_attron(); -static VALUE window_attrset(); - static void -no_window() +no_window(void) { rb_raise(rb_eRuntimeError, "already closed window"); } #define GetWINDOW(obj, winp) do {\ if (!OBJ_TAINTED(obj) && rb_safe_level() >= 4)\ rb_raise(rb_eSecurityError, "Insecure: operation on untainted window");\ - Data_Get_Struct(obj, struct windata, winp);\ - if (winp->window == 0) no_window();\ + TypedData_Get_Struct((obj), struct windata, &windata_type, (winp));\ + if ((winp)->window == 0) no_window();\ } while (0) static void -free_window(winp) - struct windata *winp; +window_free(void *p) { + struct windata *winp = p; if (winp->window && winp->window != stdscr) delwin(winp->window); winp->window = 0; - free(winp); + xfree(winp); } +static size_t +window_memsize(const void *p) +{ + const struct windata *winp = p; + size_t size = sizeof(*winp); + if (!winp) return 0; + if (winp->window && winp->window != stdscr) size += sizeof(winp->window); + return size; +} + +static const rb_data_type_t windata_type = { + "windata", + {0, window_free, window_memsize,} +}; + static VALUE -prep_window(class, window) - VALUE class; - WINDOW *window; +prep_window(VALUE class, WINDOW *window) { VALUE obj; struct windata *winp; if (window == NULL) { rb_raise(rb_eRuntimeError, "failed to create window"); } obj = rb_obj_alloc(class); - Data_Get_Struct(obj, struct windata, winp); + TypedData_Get_Struct(obj, struct windata, &windata_type, winp); winp->window = window; - - return obj; + + return obj; } /*-------------------------- module Curses --------------------------*/ -/* def init_screen */ +/* + * Document-method: Curses.init_screen + * + * Initialize a standard screen + * + * see also Curses.stdscr + */ static VALUE -curses_init_screen() +curses_init_screen(void) { - rb_secure(4); if (rb_stdscr) return rb_stdscr; initscr(); if (stdscr == 0) { rb_raise(rb_eRuntimeError, "can't initialize curses"); } clear(); rb_stdscr = prep_window(cWindow, stdscr); return rb_stdscr; } -/* def stdscr */ +/* + * Document-method: Curses.stdscr + * + * The Standard Screen. + * + * Upon initializing curses, a default window called stdscr, + * which is the size of the terminal screen, is created. + * + * Many curses functions use this window. + */ #define curses_stdscr curses_init_screen -/* def close_screen */ +/* + * Document-method: Curses.close_screen + * + * A program should always call Curses.close_screen before exiting or + * escaping from curses mode temporarily. This routine + * restores tty modes, moves the cursor to the lower + * left-hand corner of the screen and resets the terminal + * into the proper non-visual mode. + * + * Calling Curses.refresh or Curses.doupdate after a temporary + * escape causes the program to resume visual mode. + * + */ static VALUE -curses_close_screen() +curses_close_screen(void) { curses_stdscr(); #ifdef HAVE_ISENDWIN if (!isendwin()) #endif endwin(); rb_stdscr = 0; return Qnil; } +/* + * This is no runtime method, + * but a function called before the proc ends + * + * Similar to Curses.close_screen, except that it also + * garbage collects/unregisters the Curses.stdscr + */ static void curses_finalize(VALUE dummy) { if (stdscr #ifdef HAVE_ISENDWIN @@ -161,677 +210,1308 @@ endwin(); rb_stdscr = 0; rb_gc_unregister_address(&rb_stdscr); } -/* def closed? */ +#ifdef HAVE_ISENDWIN +/* + * Document-method: Curses.closed? + * + * Returns +true+ if the window/screen has been closed, + * without any subsequent Curses.refresh calls, + * returns +false+ otherwise. + */ static VALUE -curses_closed() +curses_closed(void) { -#ifdef HAVE_ISENDWIN curses_stdscr(); if (isendwin()) { return Qtrue; } return Qfalse; +} #else - rb_notimplement(); +#define curses_closed rb_f_notimplement #endif -} -/* def clear */ +/* + * Document-method: Curses.clear + * + * Clears every position on the screen completely, + * so that a subsequent call by Curses.refresh for the screen/window + * will be repainted from scratch. + */ static VALUE -curses_clear(obj) - VALUE obj; +curses_clear(VALUE obj) { curses_stdscr(); wclear(stdscr); return Qnil; } -/* def clrtoeol */ +/* + * Document-method: Curses.clrtoeol + * + * Clears to the end of line, that the cursor is currently on. + */ static VALUE -curses_clrtoeol() +curses_clrtoeol(void) { curses_stdscr(); clrtoeol(); return Qnil; } -/* def refresh */ +/* + * Document-method: Curses.refresh + * + * Refreshes the windows and lines. + * + */ static VALUE -curses_refresh(obj) - VALUE obj; +curses_refresh(VALUE obj) { curses_stdscr(); refresh(); return Qnil; } -/* def doupdate */ +/* + * Document-method: Curses.doupdate + * + * Refreshes the windows and lines. + * + * Curses.doupdate allows multiple updates with + * more efficiency than Curses.refresh alone. + */ static VALUE -curses_doupdate(obj) - VALUE obj; +curses_doupdate(VALUE obj) { curses_stdscr(); #ifdef HAVE_DOUPDATE doupdate(); #else refresh(); #endif return Qnil; } -/* def echo */ +/* + * Document-method: Curses.echo + * + * Enables characters typed by the user + * to be echoed by Curses.getch as they are typed. + */ static VALUE -curses_echo(obj) - VALUE obj; +curses_echo(VALUE obj) { curses_stdscr(); echo(); return Qnil; } -/* def noecho */ +/* + * Document-method: Curses.noecho + * + * Disables characters typed by the user + * to be echoed by Curses.getch as they are typed. + */ static VALUE -curses_noecho(obj) - VALUE obj; +curses_noecho(VALUE obj) { curses_stdscr(); noecho(); return Qnil; } -/* def raw */ +/* + * Document-method: Curses.raw + * + * Put the terminal into raw mode. + * + * Raw mode is similar to Curses.cbreak mode, in that characters typed + * are immediately passed through to the user program. + * + * The differences are that in raw mode, the interrupt, quit, + * suspend, and flow control characters are all passed through + * uninterpreted, instead of generating a signal. The behavior + * of the BREAK key depends on other bits in the tty driver + * that are not set by curses. + */ static VALUE -curses_raw(obj) - VALUE obj; +curses_raw(VALUE obj) { curses_stdscr(); raw(); return Qnil; } -/* def noraw */ +/* + * Document-method: Curses.noraw + * + * Put the terminal out of raw mode. + * + * see Curses.raw for more detail + */ static VALUE -curses_noraw(obj) - VALUE obj; +curses_noraw(VALUE obj) { curses_stdscr(); noraw(); return Qnil; } -/* def cbreak */ +/* + * Document-method: Curses.cbreak + * + * Put the terminal into cbreak mode. + * + * Normally, the tty driver buffers typed characters until + * a newline or carriage return is typed. The Curses.cbreak + * routine disables line buffering and erase/kill + * character-processing (interrupt and flow control characters + * are unaffected), making characters typed by the user + * immediately available to the program. + * + * The Curses.nocbreak routine returns the terminal to normal (cooked) mode. + * + * Initially the terminal may or may not be in cbreak mode, + * as the mode is inherited; therefore, a program should + * call Curses.cbreak or Curses.nocbreak explicitly. + * Most interactive programs using curses set the cbreak mode. + * Note that Curses.cbreak overrides Curses.raw. + * + * see also Curses.raw + */ static VALUE -curses_cbreak(obj) - VALUE obj; +curses_cbreak(VALUE obj) { curses_stdscr(); cbreak(); return Qnil; } -/* def nocbreak */ +/* + * Document-method: Curses.nocbreak + * + * Put the terminal into normal mode (out of cbreak mode). + * + * See Curses.cbreak for more detail. + */ static VALUE -curses_nocbreak(obj) - VALUE obj; +curses_nocbreak(VALUE obj) { curses_stdscr(); nocbreak(); return Qnil; } -/* def nl */ +/* + * Document-method: Curses.nl + * + * Enable the underlying display device to translate + * the return key into newline on input, and whether it + * translates newline into return and line-feed on output + * (in either case, the call Curses.addch('\n') does the + * equivalent of return and line feed on the virtual screen). + * + * Initially, these translations do occur. If you disable + * them using Curses.nonl, curses will be able to make better use + * of the line-feed capability, resulting in faster cursor + * motion. Also, curses will then be able to detect the return key. + */ static VALUE -curses_nl(obj) - VALUE obj; +curses_nl(VALUE obj) { curses_stdscr(); nl(); return Qnil; } -/* def nonl */ +/* + * Document-method: Curses.nl + * + * Disable the underlying display device to translate + * the return key into newline on input + * + * See Curses.nl for more detail + */ static VALUE -curses_nonl(obj) - VALUE obj; +curses_nonl(VALUE obj) { curses_stdscr(); nonl(); return Qnil; } -/* def beep */ +/* + * Document-method: Curses.beep + * + * Sounds an audible alarm on the terminal, if possible; + * otherwise it flashes the screen (visual bell). + * + * see also Curses.flash + */ static VALUE -curses_beep(obj) - VALUE obj; +curses_beep(VALUE obj) { #ifdef HAVE_BEEP curses_stdscr(); beep(); #endif return Qnil; } -/* def flash */ +/* + * Document-method: Curses.flash + * + * Flashes the screen, for visual alarm on the terminal, if possible; + * otherwise it sounds the alert. + * + * see also Curses.beep + */ static VALUE -curses_flash(obj) - VALUE obj; +curses_flash(VALUE obj) { #ifdef HAVE_FLASH curses_stdscr(); flash(); #endif return Qnil; } -/* def ungetch */ -static VALUE -curses_ungetch(obj, ch) - VALUE obj; - VALUE ch; +static int +curses_char(VALUE c) { + if (FIXNUM_P(c)) { + return NUM2INT(c); + } + else { + int cc; + + StringValue(c); + if (RSTRING_LEN(c) == 0 || RSTRING_LEN(c) > 1) { + rb_raise(rb_eArgError, "string not corresponding a character"); + } + cc = RSTRING_PTR(c)[0]; + if (cc > 0x7f) { + rb_raise(rb_eArgError, "no multibyte string supported (yet)"); + } + return cc; + } +} + #ifdef HAVE_UNGETCH +/* + * Document-method: Curses.ungetch + * call-seq: ungetch(ch) + * + * Places +ch+ back onto the input queue to be returned by + * the next call to Curses.getch. + * + * There is just one input queue for all windows. + */ +static VALUE +curses_ungetch(VALUE obj, VALUE ch) +{ + int c = curses_char(ch); curses_stdscr(); - ungetch(NUM2INT(ch)); -#else - rb_notimplement(); -#endif + ungetch(c); return Qnil; } +#else +#define curses_ungetch rb_f_notimplement +#endif -/* def setpos(y, x) */ +/* + * Document-method: Curses.setpos + * call-seq: setpos(y, x) + * + * A setter for the position of the cursor, + * using coordinates +x+ and +y+ + * + */ static VALUE -curses_setpos(obj, y, x) - VALUE obj; - VALUE y; - VALUE x; +curses_setpos(VALUE obj, VALUE y, VALUE x) { curses_stdscr(); move(NUM2INT(y), NUM2INT(x)); return Qnil; } -/* def standout */ +/* + * Document-method: Curses.standout + * + * Enables the best highlighting mode of the terminal. + * + * This is equivalent to Curses:Window.attron(A_STANDOUT) + * + * see also Curses::Window.attrset additional information + */ static VALUE -curses_standout(obj) - VALUE obj; +curses_standout(VALUE obj) { curses_stdscr(); standout(); return Qnil; } -/* def standend */ +/* + * Document-method: Curses.standend + * + * Enables the Normal display (no highlight) + * + * This is equivalent to Curses.attron(A_NORMAL) + * + * see also Curses::Window.attrset for additional information. + */ static VALUE -curses_standend(obj) - VALUE obj; +curses_standend(VALUE obj) { curses_stdscr(); standend(); return Qnil; } -/* def inch */ +/* + * Document-method: Curses.inch + * + * Returns the character at the current position. + */ static VALUE -curses_inch(obj) - VALUE obj; +curses_inch(VALUE obj) { curses_stdscr(); return CH2FIX(inch()); } -/* def addch(ch) */ +/* + * Document-method: Curses.addch + * call-seq: addch(ch) + * + * Add a character +ch+, with attributes, then advance the cursor. + * + * see also the system manual for curs_addch(3) + */ static VALUE -curses_addch(obj, ch) - VALUE obj; - VALUE ch; +curses_addch(VALUE obj, VALUE ch) { curses_stdscr(); addch(NUM2CH(ch)); return Qnil; } -/* def insch(ch) */ +/* + * Document-method: Curses.insch + * call-seq: insch(ch) + * + * Insert a character +ch+, before the cursor. + * + */ static VALUE -curses_insch(obj, ch) - VALUE obj; - VALUE ch; +curses_insch(VALUE obj, VALUE ch) { curses_stdscr(); insch(NUM2CH(ch)); return Qnil; } -/* def addstr(str) */ +/* + * Document-method: Curses.addstr + * call-seq: addstr(str) + * + * add a string of characters +str+, to the window and advance cursor + * + */ static VALUE -curses_addstr(obj, str) - VALUE obj; - VALUE str; +curses_addstr(VALUE obj, VALUE str) { + StringValue(str); + str = rb_str_export_locale(str); curses_stdscr(); if (!NIL_P(str)) { - addstr(STR2CSTR(str)); + addstr(StringValueCStr(str)); } return Qnil; } -/* def getch */ -static VALUE -curses_getch(obj) - VALUE obj; +static void * +getch_func(void *arg) { - rb_read_check(stdin); - curses_stdscr(); - return UINT2NUM(getch()); + int *ip = (int *)arg; + *ip = getch(); + return 0; } -/* def getstr */ +/* + * Document-method: Curses.getch + * + * Read and returns a character from the window. + * + * See Curses::Key to all the function KEY_* available + * + */ static VALUE -curses_getstr(obj) - VALUE obj; +curses_getch(VALUE obj) { - char rtn[1024]; /* This should be big enough.. I hope */ + int c; curses_stdscr(); - rb_read_check(stdin); + rb_thread_call_without_gvl(getch_func, &c, RUBY_UBF_IO, 0); + if (c == EOF) return Qnil; + if (rb_isprint(c)) { + char ch = (char)c; + + return rb_locale_str_new(&ch, 1); + } + return UINT2NUM(c); +} + +/* This should be big enough.. I hope */ +#define GETSTR_BUF_SIZE 1024 + +static void * +getstr_func(void *arg) +{ + char *rtn = (char *)arg; #if defined(HAVE_GETNSTR) - getnstr(rtn,1023); + getnstr(rtn,GETSTR_BUF_SIZE-1); #else getstr(rtn); #endif - return rb_tainted_str_new2(rtn); + return 0; } -/* def delch */ +/* + * Document-method: Curses.getstr + * + * This is equivalent to a series f Curses::Window.getch calls + * + */ static VALUE -curses_delch(obj) - VALUE obj; +curses_getstr(VALUE obj) { + char rtn[GETSTR_BUF_SIZE]; + curses_stdscr(); + rb_thread_call_without_gvl(getstr_func, rtn, RUBY_UBF_IO, 0); + return rb_locale_str_new_cstr(rtn); +} + +/* + * Document-method: Curses.delch + * + * Delete the character under the cursor + * + */ +static VALUE +curses_delch(VALUE obj) +{ + curses_stdscr(); delch(); return Qnil; } -/* def delelteln */ +/* + * Document-method: Curses.deleteln + * + * Delete the line under the cursor. + * + */ static VALUE -curses_deleteln(obj) - VALUE obj; +curses_deleteln(VALUE obj) { curses_stdscr(); #if defined(HAVE_DELETELN) || defined(deleteln) deleteln(); #endif return Qnil; } -/* def insertln */ +/* + * Document-method: Curses.insertln + * + * Inserts a line above the cursor, and the bottom line is lost + * + */ static VALUE -curses_insertln(obj) - VALUE obj; +curses_insertln(VALUE obj) { curses_stdscr(); #if defined(HAVE_INSERTLN) || defined(insertln) insertln(); #endif return Qnil; } -/* def keyname */ +/* + * Document-method: Curses.keyname + * call-seq: keyname(c) + * + * Returns the character string corresponding to key +c+ + */ static VALUE -curses_keyname(obj, c) - VALUE obj; - VALUE c; +curses_keyname(VALUE obj, VALUE c) { #ifdef HAVE_KEYNAME - const char *name; + int cc = curses_char(c); + const char *name; - curses_stdscr(); - name = keyname(NUM2INT(c)); - if (name) { - return rb_str_new2(name); - } else { - return Qnil; - } + curses_stdscr(); + name = keyname(cc); + if (name) { + return rb_str_new_cstr(name); + } + else { + return Qnil; + } #else - return Qnil; + return Qnil; #endif } +/* + * Document-method: Curses.lines + * + * Returns the number of lines on the screen + */ static VALUE -curses_lines() +curses_lines(void) { return INT2FIX(LINES); } +/* + * Document-method: Curses.cols + * + * Returns the number of columns on the screen + */ static VALUE -curses_cols() +curses_cols(void) { return INT2FIX(COLS); } +/* + * Document-method: Curses.curs_set + * call-seq: curs_set(visibility) + * + * Sets Cursor Visibility. + * 0: invisible + * 1: visible + * 2: very visible + */ static VALUE curses_curs_set(VALUE obj, VALUE visibility) { #ifdef HAVE_CURS_SET - int n; - curses_stdscr(); - return (n = curs_set(NUM2INT(visibility)) != ERR) ? INT2FIX(n) : Qnil; + int n; + curses_stdscr(); + return (n = curs_set(NUM2INT(visibility)) != ERR) ? INT2FIX(n) : Qnil; #else - return Qnil; + return Qnil; #endif } +/* + * Document-method: Curses.scrl + * call-seq: scrl(num) + * + * Scrolls the current window Fixnum +num+ lines. + * The current cursor position is not changed. + * + * For positive +num+, it scrolls up. + * + * For negative +num+, it scrolls down. + * + */ static VALUE curses_scrl(VALUE obj, VALUE n) { - /* may have to raise exception on ERR */ + /* may have to raise exception on ERR */ #ifdef HAVE_SCRL - curses_stdscr(); - return (scrl(NUM2INT(n)) == OK) ? Qtrue : Qfalse; + curses_stdscr(); + return (scrl(NUM2INT(n)) == OK) ? Qtrue : Qfalse; #else - return Qfalse; + return Qfalse; #endif } +/* + * Document-method: Curses.setscrreg + * + * call-seq: + * setscrreg(top, bottom) + * + * Set a software scrolling region in a window. + * +top+ and +bottom+ are lines numbers of the margin. + * + * If this option and Curses.scrollok are enabled, an attempt to move off + * the bottom margin line causes all lines in the scrolling region + * to scroll one line in the direction of the first line. + * Only the text of the window is scrolled. + * + */ static VALUE curses_setscrreg(VALUE obj, VALUE top, VALUE bottom) { - /* may have to raise exception on ERR */ + /* may have to raise exception on ERR */ #ifdef HAVE_SETSCRREG - curses_stdscr(); - return (setscrreg(NUM2INT(top), NUM2INT(bottom)) == OK) ? Qtrue : Qfalse; + curses_stdscr(); + return (setscrreg(NUM2INT(top), NUM2INT(bottom)) == OK) ? Qtrue : Qfalse; #else - return Qfalse; + return Qfalse; #endif } +/* + * Document-method: Curses.attroff + * call-seq: attroff(attrs) + * + * Turns on the named attributes +attrs+ without affecting any others. + * + * See also Curses::Window.attrset for additional information. + */ static VALUE curses_attroff(VALUE obj, VALUE attrs) { - curses_stdscr(); - return window_attroff(rb_stdscr,attrs); - /* return INT2FIX(attroff(NUM2INT(attrs))); */ + curses_stdscr(); + return window_attroff(rb_stdscr,attrs); + /* return INT2FIX(attroff(NUM2INT(attrs))); */ } +/* + * Document-method: Curses.attron + * call-seq: attron(attrs) + * + * Turns off the named attributes +attrs+ + * without turning any other attributes on or off. + * + * See also Curses::Window.attrset for additional information. + */ static VALUE curses_attron(VALUE obj, VALUE attrs) { - curses_stdscr(); - return window_attron(rb_stdscr,attrs); - /* return INT2FIX(attroff(NUM2INT(attrs))); */ + curses_stdscr(); + return window_attron(rb_stdscr,attrs); + /* return INT2FIX(attroff(NUM2INT(attrs))); */ } +/* + * Document-method: Curses.attrset + * call-seq: attrset(attrs) + * + * Sets the current attributes of the given window to +attrs+. + * + * see also Curses::Window.attrset + * + */ static VALUE curses_attrset(VALUE obj, VALUE attrs) { - curses_stdscr(); - return window_attrset(rb_stdscr,attrs); - /* return INT2FIX(attroff(NUM2INT(attrs))); */ + curses_stdscr(); + return window_attrset(rb_stdscr,attrs); + /* return INT2FIX(attroff(NUM2INT(attrs))); */ } +/* + * Document-method: Curses.bkgdset + * call-seq: bkgdset(ch) + * + * Manipulate the background of the named window + * with character Integer +ch+ + * + * The background becomes a property of the character + * and moves with the character through any scrolling + * and insert/delete line/character operations. + * + * see also the system manual for curs_bkgd(3) + */ static VALUE curses_bkgdset(VALUE obj, VALUE ch) { #ifdef HAVE_BKGDSET - curses_stdscr(); - bkgdset(NUM2CH(ch)); + curses_stdscr(); + bkgdset(NUM2CH(ch)); #endif - return Qnil; + return Qnil; } +/* + * call-seq: bkgd(ch) + * + * Window background manipulation routines. + * + * Set the background property of the current + * and then apply the character Integer +ch+ setting + * to every character position in that window. + * + * see also the system manual for curs_bkgd(3) + */ static VALUE curses_bkgd(VALUE obj, VALUE ch) { #ifdef HAVE_BKGD - curses_stdscr(); - return (bkgd(NUM2CH(ch)) == OK) ? Qtrue : Qfalse; + curses_stdscr(); + return (bkgd(NUM2CH(ch)) == OK) ? Qtrue : Qfalse; #else - return Qfalse; + return Qfalse; #endif } +#if defined(HAVE_USE_DEFAULT_COLORS) +/* + * tells the curses library to use terminal's default colors. + * + * see also the system manual for default_colors(3) + */ static VALUE +curses_use_default_colors(VALUE obj) +{ + curses_stdscr(); + use_default_colors(); + return Qnil; +} +#else +#define curses_use_default_colors rb_f_notimplement +#endif + +#if defined(HAVE_TABSIZE) +/* + * Document-method: Curses.TABSIZE= + * call-seq: TABSIZE=(value) + * + * Sets the TABSIZE to Integer +value+ + */ +static VALUE +curses_tabsize_set(VALUE obj, VALUE val) +{ + TABSIZE = NUM2INT(val); + return INT2NUM(TABSIZE); +} +#else +#define curses_tabsize_set rb_f_notimplement +#endif + +#if defined(HAVE_TABSIZE) +/* + * Returns the number of positions in a tab. + */ +static VALUE +curses_tabsize_get(VALUE ojb) +{ + return INT2NUM(TABSIZE); +} +#else +#define curses_tabsize_get rb_f_notimplement +#endif + +#if defined(HAVE_ESCDELAY) +/* + * call-seq: Curses.ESCDELAY=(value) + * + * Sets the ESCDELAY to Integer +value+ + */ +static VALUE +curses_escdelay_set(VALUE obj, VALUE val) +{ + ESCDELAY = NUM2INT(val); + return INT2NUM(ESCDELAY); +} +#else +#define curses_escdelay_set rb_f_notimplement +#endif + +#if defined(HAVE_ESCDELAY) +/* + * Returns the total time, in milliseconds, for which + * curses will await a character sequence, e.g., a function key + */ +static VALUE +curses_escdelay_get(VALUE obj) +{ + return INT2NUM(ESCDELAY); +} +#else +#define curses_escdelay_get rb_f_notimplement +#endif + +/* + * Document-method: Curses.resize + * call-seq: resize(lines, cols) + * + * alias for Curses.resizeterm + * + */ + +/* + * Document-method: Curses.resizeterm + * call-seq: resizeterm(lines, cols) + * + * Resize the current term to Fixnum +lines+ and Fixnum +cols+ + * + */ +static VALUE curses_resizeterm(VALUE obj, VALUE lin, VALUE col) { #if defined(HAVE_RESIZETERM) - curses_stdscr(); - return (resizeterm(NUM2INT(lin),NUM2INT(col)) == OK) ? Qtrue : Qfalse; + curses_stdscr(); + return (resizeterm(NUM2INT(lin),NUM2INT(col)) == OK) ? Qtrue : Qfalse; #else - return Qnil; + return Qnil; #endif } #ifdef USE_COLOR +/* + * Document-method: Curses.start_color + * + * Initializes the color attributes, for terminals that support it. + * + * This must be called, in order to use color attributes. + * It is good practice to call it just after Curses.init_screen + */ static VALUE curses_start_color(VALUE obj) { - /* may have to raise exception on ERR */ - curses_stdscr(); - return (start_color() == OK) ? Qtrue : Qfalse; + /* may have to raise exception on ERR */ + curses_stdscr(); + return (start_color() == OK) ? Qtrue : Qfalse; } +/* + * Document-method: Curses.init_pair + * call-seq: init_pair(pair, f, b) + * + * Changes the definition of a color-pair. + * + * It takes three arguments: the number of the color-pair to be changed +pair+, + * the foreground color number +f+, and the background color number +b+. + * + * If the color-pair was previously initialized, the screen is + * refreshed and all occurrences of that color-pair are changed + * to the new definition. + * + */ static VALUE curses_init_pair(VALUE obj, VALUE pair, VALUE f, VALUE b) { - /* may have to raise exception on ERR */ - curses_stdscr(); - return (init_pair(NUM2INT(pair),NUM2INT(f),NUM2INT(b)) == OK) ? Qtrue : Qfalse; + /* may have to raise exception on ERR */ + curses_stdscr(); + return (init_pair(NUM2INT(pair),NUM2INT(f),NUM2INT(b)) == OK) ? Qtrue : Qfalse; } +/* + * Document-method: Curses.init_color + * call-seq: init_color(color, r, g, b) + * + * Changes the definition of a color. It takes four arguments: + * * the number of the color to be changed, +color+ + * * the amount of red, +r+ + * * the amount of green, +g+ + * * the amount of blue, +b+ + * + * The value of the first argument must be between 0 and COLORS. + * (See the section Colors for the default color index.) Each + * of the last three arguments must be a value between 0 and 1000. + * When Curses.init_color is used, all occurrences of that color + * on the screen immediately change to the new definition. + */ static VALUE curses_init_color(VALUE obj, VALUE color, VALUE r, VALUE g, VALUE b) { - /* may have to raise exception on ERR */ - curses_stdscr(); - return (init_color(NUM2INT(color),NUM2INT(r), - NUM2INT(g),NUM2INT(b)) == OK) ? Qtrue : Qfalse; + /* may have to raise exception on ERR */ + curses_stdscr(); + return (init_color(NUM2INT(color),NUM2INT(r), + NUM2INT(g),NUM2INT(b)) == OK) ? Qtrue : Qfalse; } +/* + * Document-method: Curses.has_colors? + * + * Returns +true+ or +false+ depending on whether the terminal has color capabilities. + */ static VALUE curses_has_colors(VALUE obj) { - curses_stdscr(); - return has_colors() ? Qtrue : Qfalse; + curses_stdscr(); + return has_colors() ? Qtrue : Qfalse; } +/* + * Document-method: Curses.can_change_color? + * + * Returns +true+ or +false+ depending on whether the terminal can change color attributes + */ static VALUE curses_can_change_color(VALUE obj) { - curses_stdscr(); - return can_change_color() ? Qtrue : Qfalse; + curses_stdscr(); + return can_change_color() ? Qtrue : Qfalse; } +#if defined(HAVE_COLORS) +/* + * Document-method: Curses.color + * + * returns COLORS + */ static VALUE +curses_colors(VALUE obj) +{ + return INT2FIX(COLORS); +} +#else +#define curses_colors rb_f_notimplement +#endif + +/* + * Document-method: Curses.color_content + * call-seq: color_content(color) + * + * Returns an 3 item Array of the RGB values in +color+ + */ +static VALUE curses_color_content(VALUE obj, VALUE color) { - short r,g,b; + short r,g,b; - curses_stdscr(); - color_content(NUM2INT(color),&r,&g,&b); - return rb_ary_new3(3,INT2FIX(r),INT2FIX(g),INT2FIX(b)); + curses_stdscr(); + color_content(NUM2INT(color),&r,&g,&b); + return rb_ary_new3(3,INT2FIX(r),INT2FIX(g),INT2FIX(b)); } + +#if defined(HAVE_COLOR_PAIRS) +/* + * Document-method: Curses.color_pairs + * + * Returns the COLOR_PAIRS available, if the curses library supports it. + */ static VALUE +curses_color_pairs(VALUE obj) +{ + return INT2FIX(COLOR_PAIRS); +} +#else +#define curses_color_pairs rb_f_notimplement +#endif + +/* + * Document-method: Curses.pair_content + * call-seq: pair_content(pair) + * + * Returns a 2 item Array, with the foreground and + * background color, in +pair+ + */ +static VALUE curses_pair_content(VALUE obj, VALUE pair) { - short f,b; + short f,b; - curses_stdscr(); - pair_content(NUM2INT(pair),&f,&b); - return rb_ary_new3(2,INT2FIX(f),INT2FIX(b)); + curses_stdscr(); + pair_content(NUM2INT(pair),&f,&b); + return rb_ary_new3(2,INT2FIX(f),INT2FIX(b)); } +/* + * Document-method: Curses.color_pair + * call-seq: color_pair(attrs) + * + * Sets the color pair attributes to +attrs+. + * + * This should be equivalent to Curses.attrset(COLOR_PAIR(+attrs+)) + * + * TODO: validate that equivalency + */ static VALUE curses_color_pair(VALUE obj, VALUE attrs) { - return INT2FIX(COLOR_PAIR(NUM2INT(attrs))); + return INT2FIX(COLOR_PAIR(NUM2INT(attrs))); } +/* + * Document-method: Curses.pair_number + * call-seq: pair_number(attrs) + * + * Returns the Fixnum color pair number of attributes +attrs+. + */ static VALUE curses_pair_number(VALUE obj, VALUE attrs) { - curses_stdscr(); - return INT2FIX(PAIR_NUMBER(NUM2INT(attrs))); + curses_stdscr(); + return INT2FIX(PAIR_NUMBER(NUM2LONG(attrs))); } #endif /* USE_COLOR */ #ifdef USE_MOUSE struct mousedata { - MEVENT *mevent; + MEVENT *mevent; }; static void -no_mevent() +no_mevent(void) { - rb_raise(rb_eRuntimeError, "no such mouse event"); + rb_raise(rb_eRuntimeError, "no such mouse event"); } #define GetMOUSE(obj, data) do {\ if (!OBJ_TAINTED(obj) && rb_safe_level() >= 4)\ rb_raise(rb_eSecurityError, "Insecure: operation on untainted mouse");\ - Data_Get_Struct(obj, struct mousedata, data);\ - if (data->mevent == 0) no_mevent();\ + TypedData_Get_Struct((obj), struct mousedata, &mousedata_type, (data));\ + if ((data)->mevent == 0) no_mevent();\ } while (0) static void -curses_mousedata_free(struct mousedata *mdata) +curses_mousedata_free(void *p) { - if (mdata->mevent) - free(mdata->mevent); + struct mousedata *mdata = p; + if (mdata->mevent) + xfree(mdata->mevent); } +static size_t +curses_mousedata_memsize(const void *p) +{ + const struct mousedata *mdata = p; + size_t size = sizeof(*mdata); + if (!mdata) return 0; + if (mdata->mevent) size += sizeof(mdata->mevent); + return size; +} + +static const rb_data_type_t mousedata_type = { + "mousedata", + {0, curses_mousedata_free, curses_mousedata_memsize,} +}; + +/* + * Document-method: Curses.getmouse + * + * Returns coordinates of the mouse. + * + * This will read and pop the mouse event data off the queue + * + * See the BUTTON*, ALL_MOUSE_EVENTS and REPORT_MOUSE_POSITION constants, to examine the mask of the event + */ static VALUE curses_getmouse(VALUE obj) { - struct mousedata *mdata; - VALUE val; + struct mousedata *mdata; + VALUE val; - curses_stdscr(); - val = Data_Make_Struct(cMouseEvent,struct mousedata, - 0,curses_mousedata_free,mdata); - mdata->mevent = (MEVENT*)xmalloc(sizeof(MEVENT)); - return (getmouse(mdata->mevent) == OK) ? val : Qnil; + curses_stdscr(); + val = TypedData_Make_Struct(cMouseEvent,struct mousedata, + &mousedata_type,mdata); + mdata->mevent = (MEVENT*)xmalloc(sizeof(MEVENT)); + return (getmouse(mdata->mevent) == OK) ? val : Qnil; } +/* + * Document-method: Curses.ungetmouse + * + * It pushes a KEY_MOUSE event onto the input queue, and associates with that + * event the given state data and screen-relative character-cell coordinates. + * + * The Curses.ungetmouse function behaves analogously to Curses.ungetch. + */ static VALUE curses_ungetmouse(VALUE obj, VALUE mevent) { - struct mousedata *mdata; + struct mousedata *mdata; - curses_stdscr(); - GetMOUSE(mevent,mdata); - return (ungetmouse(mdata->mevent) == OK) ? Qtrue : Qfalse; + curses_stdscr(); + GetMOUSE(mevent,mdata); + return (ungetmouse(mdata->mevent) == OK) ? Qtrue : Qfalse; } +/* + * Document-method: Curses.mouseinterval + * call-seq: mouseinterval(interval) + * + * The Curses.mouseinterval function sets the maximum time + * (in thousands of a second) that can elapse between press + * and release events for them to be recognized as a click. + * + * Use Curses.mouseinterval(0) to disable click resolution. + * This function returns the previous interval value. + * + * Use Curses.mouseinterval(-1) to obtain the interval without + * altering it. + * + * The default is one sixth of a second. + */ static VALUE curses_mouseinterval(VALUE obj, VALUE interval) { - curses_stdscr(); - return mouseinterval(NUM2INT(interval)) ? Qtrue : Qfalse; + curses_stdscr(); + return mouseinterval(NUM2INT(interval)) ? Qtrue : Qfalse; } +/* + * Document-method: Curses.mousemask + * call-seq: mousemask(mask) + * + * Returns the +mask+ of the reportable events + */ static VALUE curses_mousemask(VALUE obj, VALUE mask) { - curses_stdscr(); - return INT2NUM(mousemask(NUM2UINT(mask),NULL)); + curses_stdscr(); + return INT2NUM(mousemask(NUM2UINT(mask),NULL)); } #define DEFINE_MOUSE_GET_MEMBER(func_name,mem) \ static VALUE func_name (VALUE mouse) \ { \ - struct mousedata *mdata; \ - GetMOUSE(mouse, mdata); \ - return (UINT2NUM(mdata->mevent -> mem)); \ + struct mousedata *mdata; \ + GetMOUSE(mouse, mdata); \ + return (UINT2NUM(mdata->mevent -> mem)); \ } +/* + * Document-method: Curses::MouseEvent.eid + * + * Returns the current mouse id + */ DEFINE_MOUSE_GET_MEMBER(curs_mouse_id, id) +/* + * Document-method: Curses::MouseEvent.x + * + * Returns the current mouse's X coordinate + */ DEFINE_MOUSE_GET_MEMBER(curs_mouse_x, x) +/* + * Document-method: Curses::MouseEvent.y + * + * Returns the current mouse's Y coordinate + */ DEFINE_MOUSE_GET_MEMBER(curs_mouse_y, y) +/* + * Document-method: Curses::MouseEvent.z + * + * Returns the current mouse's Z coordinate + */ DEFINE_MOUSE_GET_MEMBER(curs_mouse_z, z) +/* + * Document-method: Curses::MouseEvent.bstate + * + * Returns the current mouse's button state. Use this with the button state + * constants to determine which buttons were pressed. + */ DEFINE_MOUSE_GET_MEMBER(curs_mouse_bstate, bstate) #undef define_curs_mouse_member #endif /* USE_MOUSE */ +#ifdef HAVE_TIMEOUT +/* + * Document-method: Curses.timeout= + * call-seq: timeout=(delay) + * + * Sets block and non-blocking reads for the window. + * - If delay is negative, blocking read is used (i.e., waits indefinitely for input). + * - If delay is zero, then non-blocking read is used (i.e., read returns ERR if no input is waiting). + * - If delay is positive, then read blocks for delay milliseconds, and returns ERR if there is still no input. + * + */ static VALUE curses_timeout(VALUE obj, VALUE delay) { -#ifdef HAVE_TIMEOUT - curses_stdscr(); - timeout(NUM2INT(delay)); - return Qnil; + curses_stdscr(); + timeout(NUM2INT(delay)); + return Qnil; +} #else - rb_notimplement(); +#define curses_timeout rb_f_notimplement #endif -} +#ifdef HAVE_DEF_PROG_MODE +/* + * Document-method: Curses.def_prog_mode + * + * Save the current terminal modes as the "program" + * state for use by the Curses.reset_prog_mode + * + * This is done automatically by Curses.init_screen + */ static VALUE curses_def_prog_mode(VALUE obj) { -#ifdef HAVE_DEF_PROG_MODE - curses_stdscr(); - return def_prog_mode() == OK ? Qtrue : Qfalse; + curses_stdscr(); + return def_prog_mode() == OK ? Qtrue : Qfalse; +} #else - rb_notimplement(); +#define curses_def_prog_mode rb_f_notimplement #endif -} +#ifdef HAVE_RESET_PROG_MODE +/* + * Document-method: Curses.reset_prog_mode + * + * Reset the current terminal modes to the saved state + * by the Curses.def_prog_mode + * + * This is done automatically by Curses.close_screen + */ static VALUE curses_reset_prog_mode(VALUE obj) { -#ifdef HAVE_RESET_PROG_MODE - curses_stdscr(); - return reset_prog_mode() == OK ? Qtrue : Qfalse; + curses_stdscr(); + return reset_prog_mode() == OK ? Qtrue : Qfalse; +} #else - rb_notimplement(); +#define curses_reset_prog_mode rb_f_notimplement #endif -} /*-------------------------- class Window --------------------------*/ -/* def self.allocate */ +/* returns a Curses::Window object */ static VALUE window_s_allocate(VALUE class) { struct windata *winp; - return Data_Make_Struct(class, struct windata, 0, free_window, winp); + return TypedData_Make_Struct(class, struct windata, &windata_type, winp); } -/* def initialize(h, w, top, left) */ +/* + * Document-method: Curses::Window.new + * call-seq: new(height, width, top, left) + * + * Construct a new Curses::Window with constraints of + * +height+ lines, +width+ columns, begin at +top+ line, and begin +left+ most column. + * + * A new window using full screen is called as + * Curses::Window.new(0,0,0,0) + * + */ static VALUE -window_initialize(obj, h, w, top, left) - VALUE obj; - VALUE h; - VALUE w; - VALUE top; - VALUE left; +window_initialize(VALUE obj, VALUE h, VALUE w, VALUE top, VALUE left) { struct windata *winp; WINDOW *window; - rb_secure(4); curses_init_screen(); - Data_Get_Struct(obj, struct windata, winp); + TypedData_Get_Struct(obj, struct windata, &windata_type, winp); if (winp->window) delwin(winp->window); window = newwin(NUM2INT(h), NUM2INT(w), NUM2INT(top), NUM2INT(left)); wclear(window); winp->window = window; return obj; } -/* def subwin(height, width, top, left) */ +/* + * Document-method: Curses::Window.subwin + * call-seq: subwin(height, width, top, left) + * + * Construct a new subwindow with constraints of + * +height+ lines, +width+ columns, begin at +top+ line, and begin +left+ most column. + * + */ static VALUE -window_subwin(obj, height, width, top, left) - VALUE obj; - VALUE height; - VALUE width; - VALUE top; - VALUE left; +window_subwin(VALUE obj, VALUE height, VALUE width, VALUE top, VALUE left) { struct windata *winp; WINDOW *window; VALUE win; int h, w, t, l; @@ -845,67 +1525,86 @@ win = prep_window(rb_obj_class(obj), window); return win; } -/* def close */ +/* + * Document-method: Curses::Window.close + * + * Deletes the window, and frees the memory + */ static VALUE -window_close(obj) - VALUE obj; +window_close(VALUE obj) { struct windata *winp; - + GetWINDOW(obj, winp); delwin(winp->window); winp->window = 0; return Qnil; } -/* def clear */ +/* + * Document-method: Curses::Window.clear + * + * Clear the window. + */ static VALUE -window_clear(obj) - VALUE obj; +window_clear(VALUE obj) { struct windata *winp; - + GetWINDOW(obj, winp); wclear(winp->window); - + return Qnil; } -/* def clrtoeol */ +/* + * Document-method: Curses::Window.clrtoeol + * + * Clear the window to the end of line, that the cursor is currently on. + */ static VALUE -window_clrtoeol(obj) - VALUE obj; +window_clrtoeol(VALUE obj) { struct windata *winp; - + GetWINDOW(obj, winp); wclrtoeol(winp->window); - + return Qnil; } -/* def refresh */ +/* + * Document-method: Curses::Window.refresh + * + * Refreshes the windows and lines. + * + */ static VALUE -window_refresh(obj) - VALUE obj; +window_refresh(VALUE obj) { struct windata *winp; - + GetWINDOW(obj, winp); wrefresh(winp->window); - + return Qnil; } -/* def noutrefresh */ +/* + * Document-method: Curses::Window.noutrefresh + * + * Refreshes the windows and lines. + * + * Curses::Window.noutrefresh allows multiple updates with + * more efficiency than Curses::Window.refresh alone. + */ static VALUE -window_noutrefresh(obj) - VALUE obj; +window_noutrefresh(VALUE obj) { struct windata *winp; GetWINDOW(obj, winp); #ifdef HAVE_DOUPDATE @@ -915,69 +1614,85 @@ #endif return Qnil; } -/* def move(y, x) */ +/* + * Document-method: Curses::Window.move + * call-seq: move(y,x) + * + * Moves the window so that the upper left-hand corner is at position (+y+, +x+) + */ static VALUE -window_move(obj, y, x) - VALUE obj; - VALUE y; - VALUE x; +window_move(VALUE obj, VALUE y, VALUE x) { struct windata *winp; - + GetWINDOW(obj, winp); mvwin(winp->window, NUM2INT(y), NUM2INT(x)); return Qnil; } -/* def setpos(y, x) */ +/* + * Document-method: Curses::Window.setpos + * call-seq: setpos(y, x) + * + * A setter for the position of the cursor + * in the current window, + * using coordinates +x+ and +y+ + * + */ static VALUE -window_setpos(obj, y, x) - VALUE obj; - VALUE y; - VALUE x; +window_setpos(VALUE obj, VALUE y, VALUE x) { struct windata *winp; - + GetWINDOW(obj, winp); wmove(winp->window, NUM2INT(y), NUM2INT(x)); return Qnil; } -/* def cury */ +/* + * Document-method: Curses::Window.cury + * + * A getter for the current line (Y coord) of the window + */ static VALUE -window_cury(obj) - VALUE obj; +window_cury(VALUE obj) { struct windata *winp; - int x, y; + int RB_UNUSED_VAR(x), y; GetWINDOW(obj, winp); getyx(winp->window, y, x); return INT2FIX(y); } -/* def curx */ +/* + * Document-method: Curses::Window.curx + * + * A getter for the current column (X coord) of the window + */ static VALUE -window_curx(obj) - VALUE obj; +window_curx(VALUE obj) { struct windata *winp; - int x, y; + int x, RB_UNUSED_VAR(y); GetWINDOW(obj, winp); getyx(winp->window, y, x); return INT2FIX(x); } -/* def maxy */ +/* + * Document-method: Curses::Window.maxy + * + * A getter for the maximum lines for the window + */ static VALUE -window_maxy(obj) - VALUE obj; +window_maxy(VALUE obj) { struct windata *winp; GetWINDOW(obj, winp); #if defined(getmaxy) @@ -991,14 +1706,17 @@ #else return INT2FIX(winp->window->_maxy+1); #endif } -/* def maxx */ +/* + * Document-method: Curses::Window.maxx + * + * A getter for the maximum columns for the window + */ static VALUE -window_maxx(obj) - VALUE obj; +window_maxx(VALUE obj) { struct windata *winp; GetWINDOW(obj, winp); #if defined(getmaxx) @@ -1012,485 +1730,976 @@ #else return INT2FIX(winp->window->_maxx+1); #endif } -/* def begy */ +/* + * Document-method: Curses::Window.begy + * + * A getter for the beginning line (Y coord) of the window + */ static VALUE -window_begy(obj) - VALUE obj; +window_begy(VALUE obj) { struct windata *winp; - int x, y; + int RB_UNUSED_VAR(x), y; GetWINDOW(obj, winp); #ifdef getbegyx getbegyx(winp->window, y, x); - return INT2FIX(y); #else - return INT2FIX(winp->window->_begy); + y = winp->window->_begy; #endif + return INT2FIX(y); } -/* def begx */ +/* + * Document-method: Curses::Window.begx + * + * A getter for the beginning column (X coord) of the window + */ static VALUE -window_begx(obj) - VALUE obj; +window_begx(VALUE obj) { struct windata *winp; - int x, y; + int x, RB_UNUSED_VAR(y); GetWINDOW(obj, winp); #ifdef getbegyx getbegyx(winp->window, y, x); - return INT2FIX(x); #else - return INT2FIX(winp->window->_begx); + x = winp->window->_begx; #endif + return INT2FIX(x); } -/* def box(vert, hor) */ +/* + * Document-method: Curses::Window.box + * call-seq: box(vert, hor) + * + * set the characters to frame the window in. + * The vertical +vert+ and horizontal +hor+ character. + * + * win = Curses::Window.new(5,5,5,5) + * win.box(?|, ?-) + * + */ static VALUE -window_box(argc, argv, self) - int argc; - VALUE argv[], self; +window_box(int argc, VALUE *argv, VALUE self) { - struct windata *winp; + struct windata *winp; VALUE vert, hor, corn; rb_scan_args(argc, argv, "21", &vert, &hor, &corn); GetWINDOW(self, winp); box(winp->window, NUM2CH(vert), NUM2CH(hor)); if (!NIL_P(corn)) { - int cur_x, cur_y, x, y; - chtype c; + int cur_x, cur_y, x, y; + chtype c; - c = NUM2CH(corn); - getyx(winp->window, cur_y, cur_x); - x = NUM2INT(window_maxx(self)) - 1; - y = NUM2INT(window_maxy(self)) - 1; - wmove(winp->window, 0, 0); - waddch(winp->window, c); - wmove(winp->window, y, 0); - waddch(winp->window, c); - wmove(winp->window, y, x); - waddch(winp->window, c); - wmove(winp->window, 0, x); - waddch(winp->window, c); - wmove(winp->window, cur_y, cur_x); + c = NUM2CH(corn); + getyx(winp->window, cur_y, cur_x); + x = NUM2INT(window_maxx(self)) - 1; + y = NUM2INT(window_maxy(self)) - 1; + wmove(winp->window, 0, 0); + waddch(winp->window, c); + wmove(winp->window, y, 0); + waddch(winp->window, c); + wmove(winp->window, y, x); + waddch(winp->window, c); + wmove(winp->window, 0, x); + waddch(winp->window, c); + wmove(winp->window, cur_y, cur_x); } - + return Qnil; } -/* def standout */ +/* + * Document-method: Curses::Window.standout + * + * Enables the best highlighting mode of the terminal. + * + * This is equivalent to Curses::Window.attron(A_STANDOUT) + * + * see also Curses::Window.attrset + */ static VALUE -window_standout(obj) - VALUE obj; +window_standout(VALUE obj) { struct windata *winp; - + GetWINDOW(obj, winp); wstandout(winp->window); return Qnil; } -/* def standend */ +/* + * Document-method: Curses::Window.standend + * + * Enables the Normal display (no highlight) + * + * This is equivalent to Curses::Window.attron(A_NORMAL) + * + * see also Curses::Window.attrset + */ static VALUE -window_standend(obj) - VALUE obj; +window_standend(VALUE obj) { struct windata *winp; - + GetWINDOW(obj, winp); wstandend(winp->window); return Qnil; } -/* def inch */ +/* + * Document-method: Curses::Window.inch + * + * Returns the character at the current position of the window. + */ static VALUE -window_inch(obj) - VALUE obj; +window_inch(VALUE obj) { struct windata *winp; - + GetWINDOW(obj, winp); return CH2FIX(winch(winp->window)); } -/* def addch(ch) */ +/* + * Document-method: Curses::Window.addch + * call-seq: addch(ch) + * + * Add a character +ch+, with attributes, to the window, then advance the cursor. + * + * see also the system manual for curs_addch(3) + */ static VALUE -window_addch(obj, ch) - VALUE obj; - VALUE ch; +window_addch(VALUE obj, VALUE ch) { struct windata *winp; - + GetWINDOW(obj, winp); waddch(winp->window, NUM2CH(ch)); - + return Qnil; } -/* def insch(ch) */ +/* + * Document-method: Curses::Window.insch + * call-seq: insch(ch) + * + * Insert a character +ch+, before the cursor, in the current window + * + */ static VALUE -window_insch(obj, ch) - VALUE obj; - VALUE ch; +window_insch(VALUE obj, VALUE ch) { struct windata *winp; - + GetWINDOW(obj, winp); winsch(winp->window, NUM2CH(ch)); - + return Qnil; } -/* def addstr(str) */ +/* + * Document-method: Curses::Window.addstr + * call-seq: addstr(str) + * + * add a string of characters +str+, to the window and advance cursor + * + */ static VALUE -window_addstr(obj, str) - VALUE obj; - VALUE str; +window_addstr(VALUE obj, VALUE str) { if (!NIL_P(str)) { struct windata *winp; + StringValue(str); + str = rb_str_export_locale(str); GetWINDOW(obj, winp); - waddstr(winp->window, STR2CSTR(str)); + waddstr(winp->window, StringValueCStr(str)); } return Qnil; } -/* def <<(str) */ +/* + * Document-method: Curses::Window.<< + * + * call-seq: + * <<(str) + * + * Add String +str+ to the current string. + * + * See also Curses::Window.addstr + */ static VALUE -window_addstr2(obj, str) - VALUE obj; - VALUE str; +window_addstr2(VALUE obj, VALUE str) { window_addstr(obj, str); return obj; } -/* def getch */ -static VALUE -window_getch(obj) - VALUE obj; +struct wgetch_arg { + WINDOW *win; + int c; +}; + +static void * +wgetch_func(void *_arg) { - struct windata *winp; - - rb_read_check(stdin); - GetWINDOW(obj, winp); - return UINT2NUM(wgetch(winp->window)); + struct wgetch_arg *arg = (struct wgetch_arg *)_arg; + arg->c = wgetch(arg->win); + return 0; } -/* def getstr */ +/* + * Document-method: Curses::Window.getch + * + * Read and returns a character from the window. + * + * See Curses::Key to all the function KEY_* available + * + */ static VALUE -window_getstr(obj) - VALUE obj; +window_getch(VALUE obj) { struct windata *winp; - char rtn[1024]; /* This should be big enough.. I hope */ - + struct wgetch_arg arg; + int c; + GetWINDOW(obj, winp); - rb_read_check(stdin); + arg.win = winp->window; + rb_thread_call_without_gvl(wgetch_func, (void *)&arg, RUBY_UBF_IO, 0); + c = arg.c; + if (c == EOF) return Qnil; + if (rb_isprint(c)) { + char ch = (char)c; + + return rb_locale_str_new(&ch, 1); + } + return UINT2NUM(c); +} + +struct wgetstr_arg { + WINDOW *win; + char rtn[GETSTR_BUF_SIZE]; +}; + +static void * +wgetstr_func(void *_arg) +{ + struct wgetstr_arg *arg = (struct wgetstr_arg *)_arg; #if defined(HAVE_WGETNSTR) - wgetnstr(winp->window, rtn, 1023); + wgetnstr(arg->win, arg->rtn, GETSTR_BUF_SIZE-1); #else - wgetstr(winp->window, rtn); + wgetstr(arg->win, arg->rtn); #endif - return rb_tainted_str_new2(rtn); + return 0; } -/* def delch */ +/* + * Document-method: Curses::Window.getstr + * + * This is equivalent to a series f Curses::Window.getch calls + * + */ static VALUE -window_delch(obj) - VALUE obj; +window_getstr(VALUE obj) { struct windata *winp; - + struct wgetstr_arg arg; + GetWINDOW(obj, winp); + arg.win = winp->window; + rb_thread_call_without_gvl(wgetstr_func, (void *)&arg, RUBY_UBF_IO, 0); + return rb_locale_str_new_cstr(arg.rtn); +} + +/* + * Document-method: Curses::Window.delch + * + * Delete the character under the cursor + * + */ +static VALUE +window_delch(VALUE obj) +{ + struct windata *winp; + + GetWINDOW(obj, winp); wdelch(winp->window); return Qnil; } -/* def delelteln */ +/* + * Document-method: Curses::Window.deleteln + * + * Delete the line under the cursor. + * + */ static VALUE -window_deleteln(obj) - VALUE obj; +window_deleteln(VALUE obj) { #if defined(HAVE_WDELETELN) || defined(wdeleteln) struct windata *winp; - + GetWINDOW(obj, winp); wdeleteln(winp->window); #endif return Qnil; } -/* def insertln */ +/* + * Document-method: Curses::Window.insertln + * + * Inserts a line above the cursor, and the bottom line is lost + * + */ static VALUE -window_insertln(obj) - VALUE obj; +window_insertln(VALUE obj) { #if defined(HAVE_WINSERTLN) || defined(winsertln) struct windata *winp; - + GetWINDOW(obj, winp); winsertln(winp->window); #endif return Qnil; } +/* + * Document-method: Curses::Window.scrollok + * call-seq: scrollok(bool) + * + * Controls what happens when the cursor of a window + * is moved off the edge of the window or scrolling region, + * either as a result of a newline action on the bottom line, + * or typing the last character of the last line. + * + * If disabled, (+bool+ is false), the cursor is left on the bottom line. + * + * If enabled, (+bool+ is true), the window is scrolled up one line + * (Note that to get the physical scrolling effect on the terminal, + * it is also necessary to call Curses::Window.idlok) + */ static VALUE window_scrollok(VALUE obj, VALUE bf) { - struct windata *winp; + struct windata *winp; - GetWINDOW(obj, winp); - scrollok(winp->window, RTEST(bf) ? TRUE : FALSE); - return Qnil; + GetWINDOW(obj, winp); + scrollok(winp->window, RTEST(bf) ? TRUE : FALSE); + return Qnil; } +/* + * Document-method: Curses::Window.idlok + * call-seq: idlok(bool) + * + * If +bool+ is +true+ curses considers using the hardware insert/delete + * line feature of terminals so equipped. + * + * If +bool+ is +false+, disables use of line insertion and deletion. + * This option should be enabled only if the application needs insert/delete + * line, for example, for a screen editor. + * + * It is disabled by default because insert/delete line tends to be visually + * annoying when used in applications where it is not really needed. + * If insert/delete line cannot be used, curses redraws the changed portions of all lines. + * + */ static VALUE window_idlok(VALUE obj, VALUE bf) { - struct windata *winp; + struct windata *winp; - GetWINDOW(obj, winp); - idlok(winp->window, RTEST(bf) ? TRUE : FALSE); - return Qnil; + GetWINDOW(obj, winp); + idlok(winp->window, RTEST(bf) ? TRUE : FALSE); + return Qnil; } +/* + * Document-method: Curses::Window.setscrreg + * call-seq: + * setscrreg(top, bottom) + * + * Set a software scrolling region in a window. + * +top+ and +bottom+ are lines numbers of the margin. + * + * If this option and Curses::Window.scrollok are enabled, an attempt to move + * off the bottom margin line causes all lines in the scrolling region to + * scroll one line in the direction of the first line. Only the text of the + * window is scrolled. + * + */ static VALUE window_setscrreg(VALUE obj, VALUE top, VALUE bottom) { #ifdef HAVE_WSETSCRREG - struct windata *winp; - int res; + struct windata *winp; + int res; - GetWINDOW(obj, winp); - res = wsetscrreg(winp->window, NUM2INT(top), NUM2INT(bottom)); - /* may have to raise exception on ERR */ - return (res == OK) ? Qtrue : Qfalse; + GetWINDOW(obj, winp); + res = wsetscrreg(winp->window, NUM2INT(top), NUM2INT(bottom)); + /* may have to raise exception on ERR */ + return (res == OK) ? Qtrue : Qfalse; #else - return Qfalse; + return Qfalse; #endif } #if defined(USE_COLOR) && defined(HAVE_WCOLOR_SET) +/* + * Document-method: Curses::Window.color_set + * call-seq: color_set(col) + * + * Sets the current color of the given window to the + * foreground/background combination described by the Fixnum +col+. + */ static VALUE -window_color_set(VALUE obj, VALUE col) +window_color_set(VALUE obj, VALUE col) { - struct windata *winp; - int res; + struct windata *winp; + int res; - GetWINDOW(obj, winp); - res = wcolor_set(winp->window, NUM2INT(col), NULL); - return (res == OK) ? Qtrue : Qfalse; + GetWINDOW(obj, winp); + res = wcolor_set(winp->window, NUM2INT(col), NULL); + return (res == OK) ? Qtrue : Qfalse; } -#endif /* USE_COLOR */ +#endif /* defined(USE_COLOR) && defined(HAVE_WCOLOR_SET) */ +/* + * Document-method: Curses::Window.scroll + * + * Scrolls the current window up one line. + */ static VALUE window_scroll(VALUE obj) { - struct windata *winp; + struct windata *winp; - GetWINDOW(obj, winp); - /* may have to raise exception on ERR */ - return (scroll(winp->window) == OK) ? Qtrue : Qfalse; + GetWINDOW(obj, winp); + /* may have to raise exception on ERR */ + return (scroll(winp->window) == OK) ? Qtrue : Qfalse; } +/* + * Document-method: Curses::Window.scrl + * call-seq: scrl(num) + * + * Scrolls the current window Fixnum +num+ lines. + * The current cursor position is not changed. + * + * For positive +num+, it scrolls up. + * + * For negative +num+, it scrolls down. + * + */ static VALUE window_scrl(VALUE obj, VALUE n) { #ifdef HAVE_WSCRL - struct windata *winp; + struct windata *winp; - GetWINDOW(obj, winp); - /* may have to raise exception on ERR */ - return (wscrl(winp->window,NUM2INT(n)) == OK) ? Qtrue : Qfalse; + GetWINDOW(obj, winp); + /* may have to raise exception on ERR */ + return (wscrl(winp->window,NUM2INT(n)) == OK) ? Qtrue : Qfalse; #else - return Qfalse; + return Qfalse; #endif } +/* + * Document-method: Curses::Window.attroff + * call-seq: attroff(attrs) + * + * Turns on the named attributes +attrs+ without affecting any others. + * + * See also Curses::Window.attrset + */ static VALUE window_attroff(VALUE obj, VALUE attrs) { #ifdef HAVE_WATTROFF - struct windata *winp; + struct windata *winp; - GetWINDOW(obj,winp); - return INT2FIX(wattroff(winp->window,NUM2INT(attrs))); + GetWINDOW(obj,winp); + return INT2FIX(wattroff(winp->window,NUM2INT(attrs))); #else - return Qtrue; + return Qtrue; #endif } +/* + * Document-method: Curses::Window.attron + * call-seq: attron(attrs) + * + * Turns off the named attributes +attrs+ + * without turning any other attributes on or off. + * + * See also Curses::Window.attrset + */ static VALUE window_attron(VALUE obj, VALUE attrs) { #ifdef HAVE_WATTRON - struct windata *winp; - VALUE val; + struct windata *winp; + VALUE val; - GetWINDOW(obj,winp); - val = INT2FIX(wattron(winp->window,NUM2INT(attrs))); - if( rb_block_given_p() ){ - rb_yield(val); - wattroff(winp->window,NUM2INT(attrs)); - return val; - } - else{ - return val; - } + GetWINDOW(obj,winp); + val = INT2FIX(wattron(winp->window,NUM2INT(attrs))); + if (rb_block_given_p()) { + rb_yield(val); + wattroff(winp->window,NUM2INT(attrs)); + return val; + } + else{ + return val; + } #else - return Qtrue; + return Qtrue; #endif } +/* + * Document-method: Curses::Window.attrset + * call-seq: attrset(attrs) + * + * Sets the current attributes of the given window to +attrs+. + * + * The following video attributes, defined in <curses.h>, can + * be passed to the routines Curses::Window.attron, Curses::Window.attroff, + * and Curses::Window.attrset, or OR'd with the characters passed to addch. + * A_NORMAL Normal display (no highlight) + * A_STANDOUT Best highlighting mode of the terminal. + * A_UNDERLINE Underlining + * A_REVERSE Reverse video + * A_BLINK Blinking + * A_DIM Half bright + * A_BOLD Extra bright or bold + * A_PROTECT Protected mode + * A_INVIS Invisible or blank mode + * A_ALTCHARSET Alternate character set + * A_CHARTEXT Bit-mask to extract a character + * COLOR_PAIR(n) Color-pair number n + * + * TODO: provide some examples here. + * + * see also system manual curs_attr(3) + */ static VALUE window_attrset(VALUE obj, VALUE attrs) { #ifdef HAVE_WATTRSET - struct windata *winp; + struct windata *winp; - GetWINDOW(obj,winp); - return INT2FIX(wattrset(winp->window,NUM2INT(attrs))); + GetWINDOW(obj,winp); + return INT2FIX(wattrset(winp->window,NUM2INT(attrs))); #else - return Qtrue; + return Qtrue; #endif } +/* + * Document-method: Curses::Window.bkgdset + * call-seq: bkgdset(ch) + * + * Manipulate the background of the current window + * with character Integer +ch+ + * + * see also Curses.bkgdset + */ static VALUE window_bkgdset(VALUE obj, VALUE ch) { #ifdef HAVE_WBKGDSET - struct windata *winp; + struct windata *winp; - GetWINDOW(obj,winp); - wbkgdset(winp->window, NUM2CH(ch)); + GetWINDOW(obj,winp); + wbkgdset(winp->window, NUM2CH(ch)); #endif - return Qnil; + return Qnil; } +/* + * Document-method: Curses::Window.bkgd + * call-seq: bkgd(ch) + * + * Set the background of the current window + * and apply character Integer +ch+ to every character. + * + * see also Curses.bkgd + */ static VALUE window_bkgd(VALUE obj, VALUE ch) { #ifdef HAVE_WBKGD - struct windata *winp; + struct windata *winp; - GetWINDOW(obj,winp); - return (wbkgd(winp->window, NUM2CH(ch)) == OK) ? Qtrue : Qfalse; + GetWINDOW(obj,winp); + return (wbkgd(winp->window, NUM2CH(ch)) == OK) ? Qtrue : Qfalse; #else - return Qfalse; + return Qfalse; #endif } +/* + * Document-method: Curses::Window.getbkgd + * + * Returns an Integer (+ch+) for the character property in the current window. + */ static VALUE window_getbkgd(VALUE obj) { #ifdef HAVE_WGETBKGD - chtype c; - struct windata *winp; + chtype c; + struct windata *winp; - GetWINDOW(obj,winp); - return (c = getbkgd(winp->window) != ERR) ? CH2FIX(c) : Qnil; + GetWINDOW(obj,winp); + return (c = getbkgd(winp->window) != ERR) ? CH2FIX(c) : Qnil; #else - return Qnil; + return Qnil; #endif } +/* + * Document-method: Curses::Window.resize + * call-seq: resize(lines, cols) + * + * Resize the current window to Fixnum +lines+ and Fixnum +cols+ + * + */ static VALUE window_resize(VALUE obj, VALUE lin, VALUE col) { #if defined(HAVE_WRESIZE) - struct windata *winp; + struct windata *winp; - GetWINDOW(obj,winp); - return wresize(winp->window, NUM2INT(lin), NUM2INT(col)) == OK ? Qtrue : Qfalse; + GetWINDOW(obj,winp); + return wresize(winp->window, NUM2INT(lin), NUM2INT(col)) == OK ? Qtrue : Qfalse; #else - return Qnil; + return Qnil; #endif } +#ifdef HAVE_KEYPAD +/* + * Document-method: Curses::Window.keypad= + * call-seq: + * keypad=(bool) + * + * See Curses::Window.keypad + */ + +/* + * Document-method: Curses::Window.keypad + * call-seq: + * keypad(bool) + * + * Enables the keypad of the user's terminal. + * + * If enabled (+bool+ is +true+), the user can press a function key + * (such as an arrow key) and wgetch returns a single value representing + * the function key, as in KEY_LEFT. If disabled (+bool+ is +false+), + * curses does not treat function keys specially and the program has to + * interpret the escape sequences itself. If the keypad in the terminal + * can be turned on (made to transmit) and off (made to work locally), + * turning on this option causes the terminal keypad to be turned on when + * Curses::Window.getch is called. + * + * The default value for keypad is false. + * + */ static VALUE window_keypad(VALUE obj, VALUE val) { -#ifdef HAVE_KEYPAD - struct windata *winp; + struct windata *winp; - GetWINDOW(obj,winp); - /* keypad() of NetBSD's libcurses returns no value */ + GetWINDOW(obj,winp); + /* keypad() of NetBSD's libcurses returns no value */ #if defined(__NetBSD__) && !defined(NCURSES_VERSION) - keypad(winp->window,(RTEST(val) ? TRUE : FALSE)); - return Qnil; + keypad(winp->window,(RTEST(val) ? TRUE : FALSE)); + return Qnil; #else - /* may have to raise exception on ERR */ - return (keypad(winp->window,RTEST(val) ? TRUE : FALSE)) == OK ? - Qtrue : Qfalse; + /* may have to raise exception on ERR */ + return (keypad(winp->window,RTEST(val) ? TRUE : FALSE)) == OK ? + Qtrue : Qfalse; #endif -#else - rb_notimplement(); -#endif /* HAVE_KEYPAD */ } +#else +#define window_keypad rb_f_notimplement +#endif +#ifdef HAVE_NODELAY +/* + * Document-method: Curses::Window.nodelay + * call-seq: + * window.nodelay = bool + * + * When in no-delay mode Curses::Window#getch is a non-blocking call. If no + * input is ready #getch returns ERR. + * + * When in delay mode (+bool+ is +false+ which is the default), + * Curses::Window#getch blocks until a key is pressed. + * + */ static VALUE window_nodelay(VALUE obj, VALUE val) { -#ifdef HAVE_NODELAY - struct windata *winp; - GetWINDOW(obj,winp); + struct windata *winp; + GetWINDOW(obj,winp); - /* nodelay() of NetBSD's libcurses returns no value */ + /* nodelay() of NetBSD's libcurses returns no value */ #if defined(__NetBSD__) && !defined(NCURSES_VERSION) - nodelay(winp->window, RTEST(val) ? TRUE : FALSE); - return Qnil; + nodelay(winp->window, RTEST(val) ? TRUE : FALSE); + return Qnil; #else - return nodelay(winp->window,RTEST(val) ? TRUE : FALSE) == OK ? Qtrue : Qfalse; + return nodelay(winp->window,RTEST(val) ? TRUE : FALSE) == OK ? Qtrue : Qfalse; #endif +} #else - rb_notimplement(); +#define window_nodelay rb_f_notimplement #endif -} +#ifdef HAVE_WTIMEOUT +/* + * Document-method: Curses::Window.timeout= + * call-seq: timeout=(delay) + * + * Sets block and non-blocking reads for the window. + * - If delay is negative, blocking read is used (i.e., waits indefinitely for input). + * - If delay is zero, then non-blocking read is used (i.e., read returns ERR if no input is waiting). + * - If delay is positive, then read blocks for delay milliseconds, and returns ERR if there is still no input. + * + */ static VALUE window_timeout(VALUE obj, VALUE delay) { -#ifdef HAVE_WTIMEOUT - struct windata *winp; - GetWINDOW(obj,winp); + struct windata *winp; + GetWINDOW(obj,winp); - wtimeout(winp->window,NUM2INT(delay)); - return Qnil; + wtimeout(winp->window,NUM2INT(delay)); + return Qnil; +} #else - rb_notimplement(); +#define window_timeout rb_f_notimplement #endif + +/*--------------------------- class Pad ----------------------------*/ + +#ifdef HAVE_NEWPAD +/* + * Document-method: Curses::Pad.new + * + * call-seq: + * new(height, width) + * + * Construct a new Curses::Pad with constraints of +height+ lines, +width+ + * columns + * + */ +static VALUE +pad_initialize(VALUE obj, VALUE h, VALUE w) +{ + struct windata *padp; + WINDOW *window; + + curses_init_screen(); + TypedData_Get_Struct(obj, struct windata, &windata_type, padp); + if (padp->window) delwin(padp->window); + window = newpad(NUM2INT(h), NUM2INT(w)); + wclear(window); + padp->window = window; + + return obj; } +#if 1 +#define pad_subpad window_subwin +#else +/* + * Document-method: Curses::Pad.subpad + * call-seq: + * subpad(height, width, begin_x, begin_y) + * + * Construct a new subpad with constraints of +height+ lines, +width+ columns, + * begin at +begin_x+ line, and +begin_y+ columns on the pad. + * + */ +static VALUE +pad_subpad(VALUE obj, VALUE height, VALUE width, VALUE begin_x, VALUE begin_y) +{ + struct windata *padp; + WINDOW *subpad; + VALUE pad; + int h, w, x, y; + + h = NUM2INT(height); + w = NUM2INT(width); + x = NUM2INT(begin_x); + y = NUM2INT(begin_y); + GetWINDOW(obj, padp); + subpad = subwin(padp->window, h, w, x, y); + pad = prep_window(rb_obj_class(obj), subpad); + + return pad; +} +#endif + +/* + * Document-method: Curses::Pad.refresh + * + * call-seq: + * pad.refresh(pad_minrow, pad_mincol, screen_minrow, screen_mincol, screen_maxrow, screen_maxcol) + * + * Refreshes the pad. +pad_minrow+ and pad_mincol+ define the upper-left + * corner of the rectangle to be displayed. +screen_minrow+, +screen_mincol+, + * +screen_maxrow+, +screen_maxcol+ define the edges of the rectangle to be + * displayed on the screen. + * + */ +static VALUE +pad_refresh(VALUE obj, VALUE pminrow, VALUE pmincol, VALUE sminrow, + VALUE smincol, VALUE smaxrow, VALUE smaxcol) +{ + struct windata *padp; + int pmr, pmc, smr, smc, sxr, sxc; + + pmr = NUM2INT(pminrow); + pmc = NUM2INT(pmincol); + smr = NUM2INT(sminrow); + smc = NUM2INT(smincol); + sxr = NUM2INT(smaxrow); + sxc = NUM2INT(smaxcol); + + GetWINDOW(obj, padp); + prefresh(padp->window, pmr, pmc, smr, smc, sxr, sxc); + + return Qnil; +} + +/* + * Document-method: Curses::Pad.noutrefresh + * + * call-seq: + * pad.noutrefresh(pad_minrow, pad_mincol, screen_minrow, screen_mincol, screen_maxrow, screen_maxcol) + * + * Refreshes the pad. +pad_minrow+ and pad_mincol+ define the upper-left + * corner of the rectangle to be displayed. +screen_minrow+, +screen_mincol+, + * +screen_maxrow+, +screen_maxcol+ define the edges of the rectangle to be + * displayed on the screen. + * + */ +static VALUE +pad_noutrefresh(VALUE obj, VALUE pminrow, VALUE pmincol, VALUE sminrow, + VALUE smincol, VALUE smaxrow, VALUE smaxcol) +{ + struct windata *padp; + int pmr, pmc, smr, smc, sxr, sxc; + + pmr = NUM2INT(pminrow); + pmc = NUM2INT(pmincol); + smr = NUM2INT(sminrow); + smc = NUM2INT(smincol); + sxr = NUM2INT(smaxrow); + sxc = NUM2INT(smaxcol); + + GetWINDOW(obj, padp); +#ifdef HAVE_DOUPDATE + pnoutrefresh(padp->window, pmr, pmc, smr, smc, sxr, sxc); +#else + prefresh(padp->window, pmr, pmc, smr, smc, sxr, sxc); +#endif + + return Qnil; +} +#endif /* HAVE_NEWPAD */ + /*------------------------- Initialization -------------------------*/ + +/* + * Document-module: Curses + * + * == Description + * An implementation of the CRT screen handling and optimization library. + * + * == Structures and such + * + * === Classes + * + * * Curses::Window - class with the means to draw a window or box + * * Curses::MouseEvent - class for collecting mouse events + * + * === Modules + * + * Curses:: The curses implementation + * Curses::Key:: Collection of constants for keypress events + * + * == Examples + * + * * hello.rb + * :include: sample/curses/hello.rb + * + * + * * rain.rb + * :include: sample/curses/rain.rb + * + * + */ void -Init_curses() +Init_curses(void) { mCurses = rb_define_module("Curses"); + + /* + * Document-module: Curses::Key + * + * + * a container for the KEY_* values. + * + * See also system manual for getch(3) + * + */ mKey = rb_define_module_under(mCurses, "Key"); rb_gc_register_address(&rb_stdscr); #ifdef USE_MOUSE + /* + * Document-class: Curses::MouseEvent + * + * == Description + * + * Curses::MouseEvent + * + * == Example + * + * * mouse.rb + * :include: sample/curses/mouse.rb + * + */ cMouseEvent = rb_define_class_under(mCurses,"MouseEvent",rb_cObject); rb_undef_method(CLASS_OF(cMouseEvent),"new"); rb_define_method(cMouseEvent, "eid", curs_mouse_id, 0); rb_define_method(cMouseEvent, "x", curs_mouse_x, 0); rb_define_method(cMouseEvent, "y", curs_mouse_y, 0); rb_define_method(cMouseEvent, "z", curs_mouse_z, 0); rb_define_method(cMouseEvent, "bstate", curs_mouse_bstate, 0); #endif /* USE_MOUSE */ + rb_define_module_function(mCurses, "ESCDELAY=", curses_escdelay_set, 1); + rb_define_module_function(mCurses, "ESCDELAY", curses_escdelay_get, 0); + rb_define_module_function(mCurses, "TABSIZE", curses_tabsize_get, 0); + rb_define_module_function(mCurses, "TABSIZE=", curses_tabsize_set, 1); + + rb_define_module_function(mCurses, "use_default_colors", curses_use_default_colors, 0); rb_define_module_function(mCurses, "init_screen", curses_init_screen, 0); rb_define_module_function(mCurses, "close_screen", curses_close_screen, 0); rb_define_module_function(mCurses, "closed?", curses_closed, 0); rb_define_module_function(mCurses, "stdscr", curses_stdscr, 0); rb_define_module_function(mCurses, "refresh", curses_refresh, 0); @@ -1501,12 +2710,12 @@ rb_define_module_function(mCurses, "noecho", curses_noecho, 0); rb_define_module_function(mCurses, "raw", curses_raw, 0); rb_define_module_function(mCurses, "noraw", curses_noraw, 0); rb_define_module_function(mCurses, "cbreak", curses_cbreak, 0); rb_define_module_function(mCurses, "nocbreak", curses_nocbreak, 0); - rb_define_alias(mCurses, "crmode", "cbreak"); - rb_define_alias(mCurses, "nocrmode", "nocbreak"); + rb_define_module_function(mCurses, "crmode", curses_cbreak, 0); + rb_define_module_function(mCurses, "nocrmode", curses_nocbreak, 0); rb_define_module_function(mCurses, "nl", curses_nl, 0); rb_define_module_function(mCurses, "nonl", curses_nonl, 0); rb_define_module_function(mCurses, "beep", curses_beep, 0); rb_define_module_function(mCurses, "flash", curses_flash, 0); rb_define_module_function(mCurses, "ungetch", curses_ungetch, 1); @@ -1540,11 +2749,13 @@ rb_define_module_function(mCurses, "init_pair", curses_init_pair, 3); rb_define_module_function(mCurses, "init_color", curses_init_color, 4); rb_define_module_function(mCurses, "has_colors?", curses_has_colors, 0); rb_define_module_function(mCurses, "can_change_color?", curses_can_change_color, 0); + rb_define_module_function(mCurses, "colors", curses_colors, 0); rb_define_module_function(mCurses, "color_content", curses_color_content, 1); + rb_define_module_function(mCurses, "color_pairs", curses_color_pairs, 0); rb_define_module_function(mCurses, "pair_content", curses_pair_content, 1); rb_define_module_function(mCurses, "color_pair", curses_color_pair, 1); rb_define_module_function(mCurses, "pair_number", curses_pair_number, 1); #endif /* USE_COLOR */ #ifdef USE_MOUSE @@ -1556,10 +2767,70 @@ rb_define_module_function(mCurses, "timeout=", curses_timeout, 1); rb_define_module_function(mCurses, "def_prog_mode", curses_def_prog_mode, 0); rb_define_module_function(mCurses, "reset_prog_mode", curses_reset_prog_mode, 0); + { + VALUE version; +#if defined(HAVE_FUNC_CURSES_VERSION) + /* ncurses and PDcurses */ + version = rb_str_new2(curses_version()); +#elif defined(HAVE_VAR_CURSES_VERSION) + /* SVR4 curses has an undocumented and undeclared variable, curses_version. + * It contains a string, "SVR4". */ + RUBY_EXTERN char *curses_version; + version = rb_sprintf("curses (%s)", curses_version); +#else + /* BSD curses, perhaps. NetBSD 5 still use it. */ + version = rb_str_new2("curses (unknown)"); +#endif + /* + * Identifies curses library version. + * + * - "ncurses 5.9.20110404" + * - "PDCurses 3.4 - Public Domain 2008" + * - "curses (SVR4)" (System V curses) + * - "curses (unknown)" (The original BSD curses? NetBSD maybe.) + * + */ + rb_define_const(mCurses, "VERSION", version); + } + + /* + * Document-class: Curses::Window + * + * == Description + * + * The means by which to create and manage frames or windows. + * While there may be more than one window at a time, only one window + * will receive input. + * + * == Usage + * + * require 'curses' + * + * Curses.init_screen() + * + * my_str = "LOOK! PONIES!" + * bwin = Curses::Window.new( 10, (my_str.length + 10), + * (Curses.lines - 10) / 2, + * (Curses.cols - (my_str.length + 10)) / 2 ) + * bwin.box("\\", "/") + * bwin.refresh + * win = bwin.subwin( 6, my_str.length + 6, + * (Curses.lines - 6) / 2, + * (Curses.cols - (my_str.length + 6)) / 2 ) + * win.setpos(2,3) + * win.addstr(my_str) + * # or even + * win << "\nORLY" + * win << "\nYES!! " + my_str + * win.refresh + * win.getch + * win.close + * + */ cWindow = rb_define_class_under(mCurses, "Window", rb_cData); rb_define_alloc_func(cWindow, window_s_allocate); rb_define_method(cWindow, "initialize", window_initialize, 4); rb_define_method(cWindow, "subwin", window_subwin, 4); rb_define_method(cWindow, "close", window_close, 0); @@ -1608,526 +2879,1451 @@ rb_define_method(cWindow, "getbkgd", window_getbkgd, 0); rb_define_method(cWindow, "nodelay=", window_nodelay, 1); rb_define_method(cWindow, "timeout=", window_timeout, 1); +#ifdef HAVE_NEWPAD + /* + * Document-class: Curses::Pad + * + * == Description + * + * A Pad is like a Window but allows for scrolling of contents that cannot + * fit on the screen. Pads do not refresh automatically, use Pad#refresh + * or Pad#noutrefresh instead. + * + */ + cPad = rb_define_class_under(mCurses, "Pad", cWindow); + /* inherits alloc_func from cWindow */ + rb_define_method(cPad, "initialize", pad_initialize, 2); + rb_define_method(cPad, "subpad", pad_subpad, 4); + rb_define_method(cPad, "refresh", pad_refresh, 6); + rb_define_method(cPad, "noutrefresh", pad_noutrefresh, 6); + rb_undef_method(cPad, "subwin"); +#endif + #define rb_curses_define_const(c) rb_define_const(mCurses,#c,UINT2NUM(c)) #ifdef USE_COLOR + /* Document-const: A_ATTRIBUTES + * + * Character attribute mask: + * Bit-mask to extract attributes + * + * See Curses.inch or Curses::Window.inch + */ rb_curses_define_const(A_ATTRIBUTES); #ifdef A_NORMAL + /* Document-const: A_NORMAL + * + * Attribute mask: + * Normal display (no highlight) + * + * See Curses.attrset + */ rb_curses_define_const(A_NORMAL); #endif + /* Document-const: A_STANDOUT + * + * Attribute mask: + * Best highlighting mode of the terminal. + * + * See Curses.attrset + */ rb_curses_define_const(A_STANDOUT); + /* Document-const: A_UNDERLINE + * + * Attribute mask: + * Underlining + * + * See Curses.attrset + */ rb_curses_define_const(A_UNDERLINE); + /* Document-const: A_REVERSE + * + * Attribute mask: + * Reverse video + * + * See Curses.attrset + */ rb_curses_define_const(A_REVERSE); + /* Document-const: A_BLINK + * + * Attribute mask: + * Blinking + * + * See Curses.attrset + */ rb_curses_define_const(A_BLINK); + /* Document-const: A_DIM + * + * Attribute mask: + * Half bright + * + * See Curses.attrset + */ rb_curses_define_const(A_DIM); + /* Document-const: A_BOLD + * + * Attribute mask: + * Extra bright or bold + * + * See Curses.attrset + */ rb_curses_define_const(A_BOLD); + /* Document-const: A_PROTECT + * + * Attribute mask: + * Protected mode + * + * See Curses.attrset + */ rb_curses_define_const(A_PROTECT); #ifdef A_INVIS /* for NetBSD */ + /* Document-const: A_INVIS + * + * Attribute mask: + * Invisible or blank mode + * + * See Curses.attrset + */ rb_curses_define_const(A_INVIS); #endif + /* Document-const: A_ALTCHARSET + * + * Attribute mask: + * Alternate character set + * + * See Curses.attrset + */ rb_curses_define_const(A_ALTCHARSET); + /* Document-const: A_CHARTEXT + * + * Attribute mask: + * Bit-mask to extract a character + * + * See Curses.attrset + */ rb_curses_define_const(A_CHARTEXT); #ifdef A_HORIZONTAL + /* Document-const: A_HORIZONTAL + * + * Attribute mask: + * horizontal highlight + * + * Check system curs_attr(3x) for support + */ rb_curses_define_const(A_HORIZONTAL); #endif #ifdef A_LEFT + /* Document-const: A_LEFT + * + * Attribute mask: + * left highlight + * + * Check system curs_attr(3x) for support + */ rb_curses_define_const(A_LEFT); #endif #ifdef A_LOW + /* Document-const: A_LOW + * + * Attribute mask: + * low highlight + * + * Check system curs_attr(3x) for support + */ rb_curses_define_const(A_LOW); #endif #ifdef A_RIGHT + /* Document-const: A_RIGHT + * + * Attribute mask: + * right highlight + * + * Check system curs_attr(3x) for support + */ rb_curses_define_const(A_RIGHT); #endif #ifdef A_TOP + /* Document-const: A_TOP + * + * Attribute mask: + * top highlight + * + * Check system curs_attr(3x) for support + */ rb_curses_define_const(A_TOP); #endif #ifdef A_VERTICAL + /* Document-const: A_VERTICAL + * + * Attribute mask: + * vertical highlight + * + * Check system curs_attr(3x) for support + */ rb_curses_define_const(A_VERTICAL); #endif + /* Document-const: A_COLOR + * + * Character attribute mask: + * Bit-mask to extract color-pair field information + * + * See Curses.inch or Curses::Window.inch + */ rb_curses_define_const(A_COLOR); #ifdef COLORS + /* + * Document-const: Curses::COLORS + * + * Number of the colors available + */ rb_curses_define_const(COLORS); #endif + /* + * Document-const: Curses::COLOR_BLACK + * + * Value of the color black + */ rb_curses_define_const(COLOR_BLACK); + /* + * Document-const: COLOR_RED + * + * Value of the color red + */ rb_curses_define_const(COLOR_RED); + /* + * Document-const: COLOR_GREEN + * + * Value of the color green + */ rb_curses_define_const(COLOR_GREEN); + /* + * Document-const: COLOR_YELLOW + * + * Value of the color yellow + */ rb_curses_define_const(COLOR_YELLOW); + /* + * Document-const: COLOR_BLUE + * + * Value of the color blue + */ rb_curses_define_const(COLOR_BLUE); + /* + * Document-const: COLOR_MAGENTA + * + * Value of the color magenta + */ rb_curses_define_const(COLOR_MAGENTA); + /* + * Document-const: COLOR_CYAN + * + * Value of the color cyan + */ rb_curses_define_const(COLOR_CYAN); + /* + * Document-const: COLOR_WHITE + * + * Value of the color white + */ rb_curses_define_const(COLOR_WHITE); #endif /* USE_COLOR */ #ifdef USE_MOUSE #ifdef BUTTON1_PRESSED + /* Document-const: BUTTON1_PRESSED + * + * Mouse event mask: + * mouse button 1 down + * + * See Curses.getmouse + */ rb_curses_define_const(BUTTON1_PRESSED); #endif #ifdef BUTTON1_RELEASED + /* Document-const: BUTTON1_RELEASED + * + * Mouse event mask: + * mouse button 1 up + * + * See Curses.getmouse + */ rb_curses_define_const(BUTTON1_RELEASED); #endif #ifdef BUTTON1_CLICKED + /* Document-const: BUTTON1_CLICKED + * + * Mouse event mask: + * mouse button 1 clicked + * + * See Curses.getmouse + */ rb_curses_define_const(BUTTON1_CLICKED); #endif #ifdef BUTTON1_DOUBLE_CLICKED + /* Document-const: BUTTON1_DOUBLE_CLICKED + * + * Mouse event mask: + * mouse button 1 double clicked + * + * See Curses.getmouse + */ rb_curses_define_const(BUTTON1_DOUBLE_CLICKED); #endif #ifdef BUTTON1_TRIPLE_CLICKED + /* Document-const: BUTTON1_TRIPLE_CLICKED + * + * Mouse event mask: + * mouse button 1 triple clicked + * + * See Curses.getmouse + */ rb_curses_define_const(BUTTON1_TRIPLE_CLICKED); #endif #ifdef BUTTON2_PRESSED + /* Document-const: BUTTON2_PRESSED + * + * Mouse event mask: + * mouse button 2 down + * + * See Curses.getmouse + */ rb_curses_define_const(BUTTON2_PRESSED); #endif #ifdef BUTTON2_RELEASED + /* Document-const: BUTTON2_RELEASED + * + * Mouse event mask: + * mouse button 2 up + * + * See Curses.getmouse + */ rb_curses_define_const(BUTTON2_RELEASED); #endif #ifdef BUTTON2_CLICKED + /* Document-const: BUTTON2_CLICKED + * + * Mouse event mask: + * mouse button 2 clicked + * + * See Curses.getmouse + */ rb_curses_define_const(BUTTON2_CLICKED); #endif #ifdef BUTTON2_DOUBLE_CLICKED + /* Document-const: BUTTON2_DOUBLE_CLICKED + * + * Mouse event mask: + * mouse button 2 double clicked + * + * See Curses.getmouse + */ rb_curses_define_const(BUTTON2_DOUBLE_CLICKED); #endif #ifdef BUTTON2_TRIPLE_CLICKED + /* Document-const: BUTTON2_TRIPLE_CLICKED + * + * Mouse event mask: + * mouse button 2 triple clicked + * + * See Curses.getmouse + */ rb_curses_define_const(BUTTON2_TRIPLE_CLICKED); #endif #ifdef BUTTON3_PRESSED + /* Document-const: BUTTON3_PRESSED + * + * Mouse event mask: + * mouse button 3 down + * + * See Curses.getmouse + */ rb_curses_define_const(BUTTON3_PRESSED); #endif #ifdef BUTTON3_RELEASED + /* Document-const: BUTTON3_RELEASED + * + * Mouse event mask: + * mouse button 3 up + * + * See Curses.getmouse + */ rb_curses_define_const(BUTTON3_RELEASED); #endif #ifdef BUTTON3_CLICKED + /* Document-const: BUTTON3_CLICKED + * + * Mouse event mask: + * mouse button 3 clicked + * + * See Curses.getmouse + */ rb_curses_define_const(BUTTON3_CLICKED); #endif #ifdef BUTTON3_DOUBLE_CLICKED + /* Document-const: BUTTON3_DOUBLE_CLICKED + * + * Mouse event mask: + * mouse button 3 double clicked + * + * See Curses.getmouse + */ rb_curses_define_const(BUTTON3_DOUBLE_CLICKED); #endif #ifdef BUTTON3_TRIPLE_CLICKED + /* Document-const: BUTTON3_TRIPLE_CLICKED + * + * Mouse event mask: + * mouse button 3 triple clicked + * + * See Curses.getmouse + */ rb_curses_define_const(BUTTON3_TRIPLE_CLICKED); #endif #ifdef BUTTON4_PRESSED + /* Document-const: BUTTON4_PRESSED + * + * Mouse event mask: + * mouse button 4 down + * + * See Curses.getmouse + */ rb_curses_define_const(BUTTON4_PRESSED); #endif #ifdef BUTTON4_RELEASED + /* Document-const: BUTTON4_RELEASED + * + * Mouse event mask: + * mouse button 4 up + * + * See Curses.getmouse + */ rb_curses_define_const(BUTTON4_RELEASED); #endif #ifdef BUTTON4_CLICKED + /* Document-const: BUTTON4_CLICKED + * + * Mouse event mask: + * mouse button 4 clicked + * + * See Curses.getmouse + */ rb_curses_define_const(BUTTON4_CLICKED); #endif #ifdef BUTTON4_DOUBLE_CLICKED + /* Document-const: BUTTON4_DOUBLE_CLICKED + * + * Mouse event mask: + * mouse button 4 double clicked + * + * See Curses.getmouse + */ rb_curses_define_const(BUTTON4_DOUBLE_CLICKED); #endif #ifdef BUTTON4_TRIPLE_CLICKED + /* Document-const: BUTTON4_TRIPLE_CLICKED + * + * Mouse event mask: + * mouse button 4 triple clicked + * + * See Curses.getmouse + */ rb_curses_define_const(BUTTON4_TRIPLE_CLICKED); #endif #ifdef BUTTON_SHIFT + /* Document-const: BUTTON_SHIFT + * + * Mouse event mask: + * shift was down during button state change + * + * See Curses.getmouse + */ rb_curses_define_const(BUTTON_SHIFT); #endif #ifdef BUTTON_CTRL + /* Document-const: BUTTON_CTRL + * + * Mouse event mask: + * control was down during button state change + * + * See Curses.getmouse + */ rb_curses_define_const(BUTTON_CTRL); #endif #ifdef BUTTON_ALT + /* Document-const: BUTTON_ALT + * + * Mouse event mask: + * alt was down during button state change + * + * See Curses.getmouse + */ rb_curses_define_const(BUTTON_ALT); #endif #ifdef ALL_MOUSE_EVENTS + /* Document-const: ALL_MOUSE_EVENTS + * + * Mouse event mask: + * report all button state changes + * + * See Curses.getmouse + */ rb_curses_define_const(ALL_MOUSE_EVENTS); #endif #ifdef REPORT_MOUSE_POSITION + /* Document-const: REPORT_MOUSE_POSITION + * + * Mouse event mask: + * report mouse movement + * + * See Curses.getmouse + */ rb_curses_define_const(REPORT_MOUSE_POSITION); #endif #endif /* USE_MOUSE */ #if defined(KEY_MOUSE) && defined(USE_MOUSE) + /* Document-const: KEY_MOUSE + * Mouse event read + */ + /* Document-const: MOUSE + * Mouse event read + */ rb_curses_define_const(KEY_MOUSE); rb_define_const(mKey, "MOUSE", INT2NUM(KEY_MOUSE)); #endif #ifdef KEY_MIN + /* Document-const: KEY_MIN + * The minimum allowed curses key value. + */ + /* Document-const: MIN + * The minimum allowed curses key value. + */ rb_curses_define_const(KEY_MIN); rb_define_const(mKey, "MIN", INT2NUM(KEY_MIN)); #endif #ifdef KEY_BREAK + /* Document-const: KEY_BREAK + * Break key + */ + /* Document-const: BREAK + * Break key + */ rb_curses_define_const(KEY_BREAK); rb_define_const(mKey, "BREAK", INT2NUM(KEY_BREAK)); #endif #ifdef KEY_DOWN + /* Document-const: KEY_DOWN + * the down arrow key + */ + /* Document-const: DOWN + * the down arrow key + */ rb_curses_define_const(KEY_DOWN); rb_define_const(mKey, "DOWN", INT2NUM(KEY_DOWN)); #endif #ifdef KEY_UP + /* Document-const: KEY_UP + * the up arrow key + */ + /* Document-const: UP + * the up arrow key + */ rb_curses_define_const(KEY_UP); rb_define_const(mKey, "UP", INT2NUM(KEY_UP)); #endif #ifdef KEY_LEFT + /* Document-const: KEY_LEFT + * the left arrow key + */ + /* Document-const: LEFT + * the left arrow key + */ rb_curses_define_const(KEY_LEFT); rb_define_const(mKey, "LEFT", INT2NUM(KEY_LEFT)); #endif #ifdef KEY_RIGHT + /* Document-const: KEY_RIGHT + * the right arrow key + */ + /* Document-const: RIGHT + * the right arrow key + */ rb_curses_define_const(KEY_RIGHT); rb_define_const(mKey, "RIGHT", INT2NUM(KEY_RIGHT)); #endif #ifdef KEY_HOME + /* Document-const: KEY_HOME + * Home key (upward+left arrow) + */ + /* Document-const: HOME + * Home key (upward+left arrow) + */ rb_curses_define_const(KEY_HOME); rb_define_const(mKey, "HOME", INT2NUM(KEY_HOME)); #endif #ifdef KEY_BACKSPACE + /* Document-const: KEY_BACKSPACE + * Backspace + */ + /* Document-const: BACKSPACE + * Backspace + */ rb_curses_define_const(KEY_BACKSPACE); rb_define_const(mKey, "BACKSPACE", INT2NUM(KEY_BACKSPACE)); #endif #ifdef KEY_F /* KEY_F(n) : 0 <= n <= 63 */ { - int i; - char c[8]; - for( i=0; i<64; i++ ){ - sprintf(c, "KEY_F%d", i); - rb_define_const(mCurses, c, INT2NUM(KEY_F(i))); - sprintf(c, "F%d", i); - rb_define_const(mKey, c, INT2NUM(KEY_F(i))); - } + int i; + char c[8]; + for (i=0; i<64; i++) { + sprintf(c, "KEY_F%d", i); + rb_define_const(mCurses, c, INT2NUM(KEY_F(i))); + sprintf(c, "F%d", i); + rb_define_const(mKey, c, INT2NUM(KEY_F(i))); + } } #endif #ifdef KEY_DL + /* Document-const: KEY_DL + * Delete line + */ + /* Document-const: DL + * Delete line + */ rb_curses_define_const(KEY_DL); rb_define_const(mKey, "DL", INT2NUM(KEY_DL)); #endif #ifdef KEY_IL + /* Document-const: KEY_IL + * Insert line + */ + /* Document-const: IL + * Insert line + */ rb_curses_define_const(KEY_IL); rb_define_const(mKey, "IL", INT2NUM(KEY_IL)); #endif #ifdef KEY_DC + /* Document-const: KEY_DC + * Delete character + */ + /* Document-const: DC + * Delete character + */ rb_curses_define_const(KEY_DC); rb_define_const(mKey, "DC", INT2NUM(KEY_DC)); #endif #ifdef KEY_IC + /* Document-const: KEY_IC + * Insert char or enter insert mode + */ + /* Document-const: IC + * Insert char or enter insert mode + */ rb_curses_define_const(KEY_IC); rb_define_const(mKey, "IC", INT2NUM(KEY_IC)); #endif #ifdef KEY_EIC + /* Document-const: KEY_EIC + * Enter insert char mode + */ + /* Document-const: EIC + * Enter insert char mode + */ rb_curses_define_const(KEY_EIC); rb_define_const(mKey, "EIC", INT2NUM(KEY_EIC)); #endif #ifdef KEY_CLEAR + /* Document-const: KEY_CLEAR + * Clear Screen + */ + /* Document-const: CLEAR + * Clear Screen + */ rb_curses_define_const(KEY_CLEAR); rb_define_const(mKey, "CLEAR", INT2NUM(KEY_CLEAR)); #endif #ifdef KEY_EOS + /* Document-const: KEY_EOS + * Clear to end of screen + */ + /* Document-const: EOS + * Clear to end of screen + */ rb_curses_define_const(KEY_EOS); rb_define_const(mKey, "EOS", INT2NUM(KEY_EOS)); #endif #ifdef KEY_EOL + /* Document-const: KEY_EOL + * Clear to end of line + */ + /* Document-const: EOL + * Clear to end of line + */ rb_curses_define_const(KEY_EOL); rb_define_const(mKey, "EOL", INT2NUM(KEY_EOL)); #endif #ifdef KEY_SF + /* Document-const: KEY_SF + * Scroll 1 line forward + */ + /* Document-const: SF + * Scroll 1 line forward + */ rb_curses_define_const(KEY_SF); rb_define_const(mKey, "SF", INT2NUM(KEY_SF)); #endif #ifdef KEY_SR + /* Document-const: KEY_SR + * Scroll 1 line backward (reverse) + */ + /* Document-const: SR + * Scroll 1 line backward (reverse) + */ rb_curses_define_const(KEY_SR); rb_define_const(mKey, "SR", INT2NUM(KEY_SR)); #endif #ifdef KEY_NPAGE + /* Document-const: KEY_NPAGE + * Next page + */ + /* Document-const: NPAGE + * Next page + */ rb_curses_define_const(KEY_NPAGE); rb_define_const(mKey, "NPAGE", INT2NUM(KEY_NPAGE)); #endif #ifdef KEY_PPAGE + /* Document-const: KEY_PPAGE + * Previous page + */ + /* Document-const: PPAGE + * Previous page + */ rb_curses_define_const(KEY_PPAGE); rb_define_const(mKey, "PPAGE", INT2NUM(KEY_PPAGE)); #endif #ifdef KEY_STAB + /* Document-const: KEY_STAB + * Set tab + */ + /* Document-const: STAB + * Set tab + */ rb_curses_define_const(KEY_STAB); rb_define_const(mKey, "STAB", INT2NUM(KEY_STAB)); #endif #ifdef KEY_CTAB + /* Document-const: KEY_CTAB + * Clear tab + */ + /* Document-const: CTAB + * Clear tab + */ rb_curses_define_const(KEY_CTAB); rb_define_const(mKey, "CTAB", INT2NUM(KEY_CTAB)); #endif #ifdef KEY_CATAB + /* Document-const: KEY_CATAB + * Clear all tabs + */ + /* Document-const: CATAB + * Clear all tabs + */ rb_curses_define_const(KEY_CATAB); rb_define_const(mKey, "CATAB", INT2NUM(KEY_CATAB)); #endif #ifdef KEY_ENTER + /* Document-const: KEY_ENTER + * Enter or send + */ + /* Document-const: ENTER + * Enter or send + */ rb_curses_define_const(KEY_ENTER); rb_define_const(mKey, "ENTER", INT2NUM(KEY_ENTER)); #endif #ifdef KEY_SRESET + /* Document-const: KEY_SRESET + * Soft (partial) reset + */ + /* Document-const: SRESET + * Soft (partial) reset + */ rb_curses_define_const(KEY_SRESET); rb_define_const(mKey, "SRESET", INT2NUM(KEY_SRESET)); #endif #ifdef KEY_RESET + /* Document-const: KEY_RESET + * Reset or hard reset + */ + /* Document-const: RESET + * Reset or hard reset + */ rb_curses_define_const(KEY_RESET); rb_define_const(mKey, "RESET", INT2NUM(KEY_RESET)); #endif #ifdef KEY_PRINT + /* Document-const: KEY_PRINT + * Print or copy + */ + /* Document-const: PRINT + * Print or copy + */ rb_curses_define_const(KEY_PRINT); rb_define_const(mKey, "PRINT", INT2NUM(KEY_PRINT)); #endif #ifdef KEY_LL + /* Document-const: KEY_LL + * Home down or bottom (lower left) + */ + /* Document-const: LL + * Home down or bottom (lower left) + */ rb_curses_define_const(KEY_LL); rb_define_const(mKey, "LL", INT2NUM(KEY_LL)); #endif #ifdef KEY_A1 + /* Document-const: KEY_A1 + * Upper left of keypad + */ + /* Document-const: A1 + * Upper left of keypad + */ rb_curses_define_const(KEY_A1); rb_define_const(mKey, "A1", INT2NUM(KEY_A1)); #endif #ifdef KEY_A3 + /* Document-const: KEY_A3 + * Upper right of keypad + */ + /* Document-const: A3 + * Upper right of keypad + */ rb_curses_define_const(KEY_A3); rb_define_const(mKey, "A3", INT2NUM(KEY_A3)); #endif #ifdef KEY_B2 + /* Document-const: KEY_B2 + * Center of keypad + */ + /* Document-const: B2 + * Center of keypad + */ rb_curses_define_const(KEY_B2); rb_define_const(mKey, "B2", INT2NUM(KEY_B2)); #endif #ifdef KEY_C1 + /* Document-const: KEY_C1 + * Lower left of keypad + */ + /* Document-const: C1 + * Lower left of keypad + */ rb_curses_define_const(KEY_C1); rb_define_const(mKey, "C1", INT2NUM(KEY_C1)); #endif #ifdef KEY_C3 + /* Document-const: KEY_C3 + * Lower right of keypad + */ + /* Document-const: C3 + * Lower right of keypad + */ rb_curses_define_const(KEY_C3); rb_define_const(mKey, "C3", INT2NUM(KEY_C3)); #endif #ifdef KEY_BTAB + /* Document-const: BTAB + * Back tab key + */ + /* Document-const: KEY_BTAB + * Back tab key + */ rb_curses_define_const(KEY_BTAB); rb_define_const(mKey, "BTAB", INT2NUM(KEY_BTAB)); #endif #ifdef KEY_BEG + /* Document-const: KEY_BEG + * Beginning key + */ + /* Document-const: BEG + * Beginning key + */ rb_curses_define_const(KEY_BEG); rb_define_const(mKey, "BEG", INT2NUM(KEY_BEG)); #endif #ifdef KEY_CANCEL + /* Document-const: KEY_CANCEL + * Cancel key + */ + /* Document-const: CANCEL + * Cancel key + */ rb_curses_define_const(KEY_CANCEL); rb_define_const(mKey, "CANCEL", INT2NUM(KEY_CANCEL)); #endif #ifdef KEY_CLOSE + /* Document-const: KEY_CLOSE + * Close key + */ + /* Document-const: CLOSE + * Close key + */ rb_curses_define_const(KEY_CLOSE); rb_define_const(mKey, "CLOSE", INT2NUM(KEY_CLOSE)); #endif #ifdef KEY_COMMAND + /* Document-const: KEY_COMMAND + * Cmd (command) key + */ + /* Document-const: COMMAND + * Cmd (command) key + */ rb_curses_define_const(KEY_COMMAND); rb_define_const(mKey, "COMMAND", INT2NUM(KEY_COMMAND)); #endif #ifdef KEY_COPY + /* Document-const: KEY_COPY + * Copy key + */ + /* Document-const: COPY + * Copy key + */ rb_curses_define_const(KEY_COPY); rb_define_const(mKey, "COPY", INT2NUM(KEY_COPY)); #endif #ifdef KEY_CREATE + /* Document-const: KEY_CREATE + * Create key + */ + /* Document-const: CREATE + * Create key + */ rb_curses_define_const(KEY_CREATE); rb_define_const(mKey, "CREATE", INT2NUM(KEY_CREATE)); #endif #ifdef KEY_END + /* Document-const: KEY_END + * End key + */ + /* Document-const: END + * End key + */ rb_curses_define_const(KEY_END); rb_define_const(mKey, "END", INT2NUM(KEY_END)); #endif #ifdef KEY_EXIT + /* Document-const: KEY_EXIT + * Exit key + */ + /* Document-const: EXIT + * Exit key + */ rb_curses_define_const(KEY_EXIT); rb_define_const(mKey, "EXIT", INT2NUM(KEY_EXIT)); #endif #ifdef KEY_FIND + /* Document-const: KEY_FIND + * Find key + */ + /* Document-const: FIND + * Find key + */ rb_curses_define_const(KEY_FIND); rb_define_const(mKey, "FIND", INT2NUM(KEY_FIND)); #endif #ifdef KEY_HELP + /* Document-const: KEY_HELP + * Help key + */ + /* Document-const: HELP + * Help key + */ rb_curses_define_const(KEY_HELP); rb_define_const(mKey, "HELP", INT2NUM(KEY_HELP)); #endif #ifdef KEY_MARK + /* Document-const: KEY_MARK + * Mark key + */ + /* Document-const: MARK + * Mark key + */ rb_curses_define_const(KEY_MARK); rb_define_const(mKey, "MARK", INT2NUM(KEY_MARK)); #endif #ifdef KEY_MESSAGE + /* Document-const: KEY_MESSAGE + * Message key + */ + /* Document-const: MESSAGE + * Message key + */ rb_curses_define_const(KEY_MESSAGE); rb_define_const(mKey, "MESSAGE", INT2NUM(KEY_MESSAGE)); #endif #ifdef KEY_MOVE + /* Document-const: KEY_MOVE + * Move key + */ + /* Document-const: MOVE + * Move key + */ rb_curses_define_const(KEY_MOVE); rb_define_const(mKey, "MOVE", INT2NUM(KEY_MOVE)); #endif #ifdef KEY_NEXT + /* Document-const: KEY_NEXT + * Next object key + */ + /* Document-const: NEXT + * Next object key + */ rb_curses_define_const(KEY_NEXT); rb_define_const(mKey, "NEXT", INT2NUM(KEY_NEXT)); #endif #ifdef KEY_OPEN + /* Document-const: KEY_OPEN + * Open key + */ + /* Document-const: OPEN + * Open key + */ rb_curses_define_const(KEY_OPEN); rb_define_const(mKey, "OPEN", INT2NUM(KEY_OPEN)); #endif #ifdef KEY_OPTIONS + /* Document-const: KEY_OPTIONS + * Options key + */ + /* Document-const: OPTIONS + * Options key + */ rb_curses_define_const(KEY_OPTIONS); rb_define_const(mKey, "OPTIONS", INT2NUM(KEY_OPTIONS)); #endif #ifdef KEY_PREVIOUS + /* Document-const: KEY_PREVIOUS + * Previous object key + */ + /* Document-const: PREVIOUS + * Previous object key + */ rb_curses_define_const(KEY_PREVIOUS); rb_define_const(mKey, "PREVIOUS", INT2NUM(KEY_PREVIOUS)); #endif #ifdef KEY_REDO + /* Document-const: KEY_REDO + * Redo key + */ + /* Document-const: REDO + * Redo key + */ rb_curses_define_const(KEY_REDO); rb_define_const(mKey, "REDO", INT2NUM(KEY_REDO)); #endif #ifdef KEY_REFERENCE + /* Document-const: KEY_REFERENCE + * Reference key + */ + /* Document-const: REFERENCE + * Reference key + */ rb_curses_define_const(KEY_REFERENCE); rb_define_const(mKey, "REFERENCE", INT2NUM(KEY_REFERENCE)); #endif #ifdef KEY_REFRESH + /* Document-const: KEY_REFRESH + * Refresh key + */ + /* Document-const: REFRESH + * Refresh key + */ rb_curses_define_const(KEY_REFRESH); rb_define_const(mKey, "REFRESH", INT2NUM(KEY_REFRESH)); #endif #ifdef KEY_REPLACE + /* Document-const: KEY_REPLACE + * Replace key + */ + /* Document-const: REPLACE + * Replace key + */ rb_curses_define_const(KEY_REPLACE); rb_define_const(mKey, "REPLACE", INT2NUM(KEY_REPLACE)); #endif #ifdef KEY_RESTART + /* Document-const: KEY_RESTART + * Restart key + */ + /* Document-const: RESTART + * Restart key + */ rb_curses_define_const(KEY_RESTART); rb_define_const(mKey, "RESTART", INT2NUM(KEY_RESTART)); #endif #ifdef KEY_RESUME + /* Document-const: KEY_RESUME + * Resume key + */ + /* Document-const: RESUME + * Resume key + */ rb_curses_define_const(KEY_RESUME); rb_define_const(mKey, "RESUME", INT2NUM(KEY_RESUME)); #endif #ifdef KEY_SAVE + /* Document-const: KEY_SAVE + * Save key + */ + /* Document-const: SAVE + * Save key + */ rb_curses_define_const(KEY_SAVE); rb_define_const(mKey, "SAVE", INT2NUM(KEY_SAVE)); #endif #ifdef KEY_SBEG + /* Document-const: KEY_SBEG + * Shifted beginning key + */ + /* Document-const: SBEG + * Shifted beginning key + */ rb_curses_define_const(KEY_SBEG); rb_define_const(mKey, "SBEG", INT2NUM(KEY_SBEG)); #endif #ifdef KEY_SCANCEL + /* Document-const: KEY_SCANCEL + * Shifted cancel key + */ + /* Document-const: SCANCEL + * Shifted cancel key + */ rb_curses_define_const(KEY_SCANCEL); rb_define_const(mKey, "SCANCEL", INT2NUM(KEY_SCANCEL)); #endif #ifdef KEY_SCOMMAND + /* Document-const: KEY_SCOMMAND + * Shifted command key + */ + /* Document-const: SCOMMAND + * Shifted command key + */ rb_curses_define_const(KEY_SCOMMAND); rb_define_const(mKey, "SCOMMAND", INT2NUM(KEY_SCOMMAND)); #endif #ifdef KEY_SCOPY + /* Document-const: KEY_SCOPY + * Shifted copy key + */ + /* Document-const: SCOPY + * Shifted copy key + */ rb_curses_define_const(KEY_SCOPY); rb_define_const(mKey, "SCOPY", INT2NUM(KEY_SCOPY)); #endif #ifdef KEY_SCREATE + /* Document-const: KEY_SCREATE + * Shifted create key + */ + /* Document-const: SCREATE + * Shifted create key + */ rb_curses_define_const(KEY_SCREATE); rb_define_const(mKey, "SCREATE", INT2NUM(KEY_SCREATE)); #endif #ifdef KEY_SDC + /* Document-const: KEY_SDC + * Shifted delete char key + */ + /* Document-const: SDC + * Shifted delete char key + */ rb_curses_define_const(KEY_SDC); rb_define_const(mKey, "SDC", INT2NUM(KEY_SDC)); #endif #ifdef KEY_SDL + /* Document-const: KEY_SDL + * Shifted delete line key + */ + /* Document-const: SDL + * Shifted delete line key + */ rb_curses_define_const(KEY_SDL); rb_define_const(mKey, "SDL", INT2NUM(KEY_SDL)); #endif #ifdef KEY_SELECT + /* Document-const: KEY_SELECT + * Select key + */ + /* Document-const: SELECT + * Select key + */ rb_curses_define_const(KEY_SELECT); rb_define_const(mKey, "SELECT", INT2NUM(KEY_SELECT)); #endif #ifdef KEY_SEND + /* Document-const: KEY_SEND + * Shifted end key + */ + /* Document-const: SEND + * Shifted end key + */ rb_curses_define_const(KEY_SEND); rb_define_const(mKey, "SEND", INT2NUM(KEY_SEND)); #endif #ifdef KEY_SEOL + /* Document-const: KEY_SEOL + * Shifted clear line key + */ + /* Document-const: SEOL + * Shifted clear line key + */ rb_curses_define_const(KEY_SEOL); rb_define_const(mKey, "SEOL", INT2NUM(KEY_SEOL)); #endif #ifdef KEY_SEXIT + /* Document-const: KEY_SEXIT + * Shifted exit key + */ + /* Document-const: SEXIT + * Shifted exit key + */ rb_curses_define_const(KEY_SEXIT); rb_define_const(mKey, "SEXIT", INT2NUM(KEY_SEXIT)); #endif #ifdef KEY_SFIND + /* Document-const: KEY_SFIND + * Shifted find key + */ + /* Document-const: SFIND + * Shifted find key + */ rb_curses_define_const(KEY_SFIND); rb_define_const(mKey, "SFIND", INT2NUM(KEY_SFIND)); #endif #ifdef KEY_SHELP + /* Document-const: KEY_SHELP + * Shifted help key + */ + /* Document-const: SHELP + * Shifted help key + */ rb_curses_define_const(KEY_SHELP); rb_define_const(mKey, "SHELP", INT2NUM(KEY_SHELP)); #endif #ifdef KEY_SHOME + /* Document-const: KEY_SHOME + * Shifted home key + */ + /* Document-const: SHOME + * Shifted home key + */ rb_curses_define_const(KEY_SHOME); rb_define_const(mKey, "SHOME", INT2NUM(KEY_SHOME)); #endif #ifdef KEY_SIC + /* Document-const: KEY_SIC + * Shifted input key + */ + /* Document-const: SIC + * Shifted input key + */ rb_curses_define_const(KEY_SIC); rb_define_const(mKey, "SIC", INT2NUM(KEY_SIC)); #endif #ifdef KEY_SLEFT + /* Document-const: KEY_SLEFT + * Shifted left arrow key + */ + /* Document-const: SLEFT + * Shifted left arrow key + */ rb_curses_define_const(KEY_SLEFT); rb_define_const(mKey, "SLEFT", INT2NUM(KEY_SLEFT)); #endif #ifdef KEY_SMESSAGE + /* Document-const: KEY_SMESSAGE + * Shifted message key + */ + /* Document-const: SMESSAGE + * Shifted message key + */ rb_curses_define_const(KEY_SMESSAGE); rb_define_const(mKey, "SMESSAGE", INT2NUM(KEY_SMESSAGE)); #endif #ifdef KEY_SMOVE + /* Document-const: KEY_SMOVE + * Shifted move key + */ + /* Document-const: SMOVE + * Shifted move key + */ rb_curses_define_const(KEY_SMOVE); rb_define_const(mKey, "SMOVE", INT2NUM(KEY_SMOVE)); #endif #ifdef KEY_SNEXT + /* Document-const: KEY_SNEXT + * Shifted next key + */ + /* Document-const: SNEXT + * Shifted next key + */ rb_curses_define_const(KEY_SNEXT); rb_define_const(mKey, "SNEXT", INT2NUM(KEY_SNEXT)); #endif #ifdef KEY_SOPTIONS + /* Document-const: KEY_SOPTIONS + * Shifted options key + */ + /* Document-const: SOPTIONS + * Shifted options key + */ rb_curses_define_const(KEY_SOPTIONS); rb_define_const(mKey, "SOPTIONS", INT2NUM(KEY_SOPTIONS)); #endif #ifdef KEY_SPREVIOUS + /* Document-const: KEY_SPREVIOUS + * Shifted previous key + */ + /* Document-const: SPREVIOUS + * Shifted previous key + */ rb_curses_define_const(KEY_SPREVIOUS); rb_define_const(mKey, "SPREVIOUS", INT2NUM(KEY_SPREVIOUS)); #endif #ifdef KEY_SPRINT + /* Document-const: KEY_SPRINT + * Shifted print key + */ + /* Document-const: SPRINT + * Shifted print key + */ rb_curses_define_const(KEY_SPRINT); rb_define_const(mKey, "SPRINT", INT2NUM(KEY_SPRINT)); #endif #ifdef KEY_SREDO + /* Document-const: KEY_SREDO + * Shifted redo key + */ + /* Document-const: SREDO + * Shifted redo key + */ rb_curses_define_const(KEY_SREDO); rb_define_const(mKey, "SREDO", INT2NUM(KEY_SREDO)); #endif #ifdef KEY_SREPLACE + /* Document-const: KEY_SREPLACE + * Shifted replace key + */ + /* Document-const: SREPLACE + * Shifted replace key + */ rb_curses_define_const(KEY_SREPLACE); rb_define_const(mKey, "SREPLACE", INT2NUM(KEY_SREPLACE)); #endif #ifdef KEY_SRIGHT + /* Document-const: KEY_SRIGHT + * Shifted right arrow key + */ + /* Document-const: SRIGHT + * Shifted right arrow key + */ rb_curses_define_const(KEY_SRIGHT); rb_define_const(mKey, "SRIGHT", INT2NUM(KEY_SRIGHT)); #endif #ifdef KEY_SRSUME + /* Document-const: KEY_SRSUME + * Shifted resume key + */ + /* Document-const: SRSUME + * Shifted resume key + */ rb_curses_define_const(KEY_SRSUME); rb_define_const(mKey, "SRSUME", INT2NUM(KEY_SRSUME)); #endif #ifdef KEY_SSAVE + /* Document-const: KEY_SSAVE + * Shifted save key + */ + /* Document-const: SSAVE + * Shifted save key + */ rb_curses_define_const(KEY_SSAVE); rb_define_const(mKey, "SSAVE", INT2NUM(KEY_SSAVE)); #endif #ifdef KEY_SSUSPEND + /* Document-const: KEY_SSUSPEND + * Shifted suspend key + */ + /* Document-const: SSUSPEND + * Shifted suspend key + */ rb_curses_define_const(KEY_SSUSPEND); rb_define_const(mKey, "SSUSPEND", INT2NUM(KEY_SSUSPEND)); #endif #ifdef KEY_SUNDO + /* Document-const: KEY_SUNDO + * Shifted undo key + */ + /* Document-const: SUNDO + * Shifted undo key + */ rb_curses_define_const(KEY_SUNDO); rb_define_const(mKey, "SUNDO", INT2NUM(KEY_SUNDO)); #endif #ifdef KEY_SUSPEND + /* Document-const: KEY_SUSPEND + * Suspend key + */ + /* Document-const: SUSPEND + * Suspend key + */ rb_curses_define_const(KEY_SUSPEND); rb_define_const(mKey, "SUSPEND", INT2NUM(KEY_SUSPEND)); #endif #ifdef KEY_UNDO + /* Document-const: KEY_UNDO + * Undo key + */ + /* Document-const: UNDO + * Undo key + */ rb_curses_define_const(KEY_UNDO); rb_define_const(mKey, "UNDO", INT2NUM(KEY_UNDO)); #endif #ifdef KEY_RESIZE + /* Document-const: KEY_RESIZE + * Screen Resized + */ + /* Document-const: RESIZE + * Screen Resized + */ rb_curses_define_const(KEY_RESIZE); rb_define_const(mKey, "RESIZE", INT2NUM(KEY_RESIZE)); #endif #ifdef KEY_MAX + /* Document-const: KEY_MAX + * The maximum allowed curses key value. + */ + /* Document-const: MAX + * The maximum allowed curses key value. + */ rb_curses_define_const(KEY_MAX); rb_define_const(mKey, "MAX", INT2NUM(KEY_MAX)); #endif { - int c; - char name[] = "KEY_CTRL_x"; - for( c = 'A'; c <= 'Z'; c++ ){ - sprintf(name, "KEY_CTRL_%c", c); - rb_define_const(mCurses, name, INT2FIX(c - 'A' + 1)); - } + int c; + char name[] = "KEY_CTRL_x"; + for (c = 'A'; c <= 'Z'; c++) { + name[sizeof(name) - 2] = c; + rb_define_const(mCurses, name, INT2FIX(c - 'A' + 1)); + } } #undef rb_curses_define_const rb_set_end_proc(curses_finalize, 0); }