forked from rlane/ncursesw-ruby
-
Notifications
You must be signed in to change notification settings - Fork 13
/
ncurses_wrap.c
2896 lines (2809 loc) · 101 KB
/
ncurses_wrap.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
/*
* ncurses-ruby is a ruby module for accessing the FSF's ncurses library
* (C) 2002, 2003, 2004 Tobias Peters <[email protected]>
* (C) 2004 Simon Kaczor <[email protected]>
* (C) 2005 2006 2009 2011 Tobias Herzke
* (C) 2013 Gaute Hope <[email protected]>
*
* This module is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This module is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this module; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
* $Id: ncurses_wrap.c,v 1.19 2011-05-30 23:05:50 t-peters Exp $
*
* This file was adapted from the original ncurses header file which
* has the following copyright statements:
*/
/****************************************************************************
* Copyright (c) 1998 Free Software Foundation, Inc. *
* *
* Permission is hereby granted, free of charge, to any person obtaining a *
* copy of this software and associated documentation files (the *
* "Software"), to deal in the Software without restriction, including *
* without limitation the rights to use, copy, modify, merge, publish, *
* distribute, distribute with modifications, sublicense, and/or sell *
* copies of the Software, and to permit persons to whom the Software is *
* furnished to do so, subject to the following conditions: *
* *
* The above copyright notice and this permission notice shall be included *
* in all copies or substantial portions of the Software. *
* *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS *
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF *
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. *
* IN NO EVENT SHALL THE ABOVE COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, *
* DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR *
* OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR *
* THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
* *
* Except as contained in this notice, the name(s) of the above copyright *
* holders shall not be used in advertising or otherwise to promote the *
* sale, use or other dealings in this Software without prior written *
* authorization. *
****************************************************************************/
/****************************************************************************
* Author: Zeyd M. Ben-Halim <[email protected]> 1992,1995 *
* and: Eric S. Raymond <[email protected]> *
****************************************************************************/
/*
NOT IMPLEMENTED:
- terminfo, termcap-functions
- rippoffline
- v*printw functions (but normal printw functions are supported!)
*/
#include "ncurses_wrap.h"
#include "compat.h"
#ifdef HAVE_LOCALE_H
#include <locale.h>
#endif
#ifdef HAVE_CLOCK_GETTIME
#include <time.h>
#endif
#ifdef HAVE_SYS_TIME_H
#include <sys/time.h>
#endif
VALUE mNcurses; /* module Ncurses */
VALUE cWINDOW; /* class Ncurses::WINDOW */
VALUE cSCREEN; /* class Ncurses::SCREEN */
VALUE eNcurses; /* Ncurses::Exception thrown by this extension */
static void Init_ncurses_full(void);
static
void
init_constants_1(void)
{
#ifdef CURSES
rb_define_const(mNcurses, "CURSES", INT2NUM((int)(CURSES)));
#endif
#ifdef CURSES_H
rb_define_const(mNcurses, "CURSES_H", INT2NUM((int)(CURSES_H)));
#endif
#ifdef NCURSES_VERSION_MAJOR
rb_define_const(mNcurses, "NCURSES_VERSION_MAJOR",
INT2NUM((int)(NCURSES_VERSION_MAJOR)));
#endif
#ifdef NCURSES_VERSION_MINOR
rb_define_const(mNcurses, "NCURSES_VERSION_MINOR",
INT2NUM((int)(NCURSES_VERSION_MINOR)));
#endif
#ifdef NCURSES_VERSION_PATCH
rb_define_const(mNcurses, "NCURSES_VERSION_PATCH",
INT2NUM((int)(NCURSES_VERSION_PATCH)));
#endif
#ifdef NCURSES_VERSION
rb_define_const(mNcurses, "NCURSES_VERSION",
rb_str_new2(NCURSES_VERSION));
#endif
/* attributes */
#ifdef WA_ATTRIBUTES
rb_define_const(mNcurses, "WA_ATTRIBUTES", INT2NUM(WA_ATTRIBUTES));
rb_define_const(mNcurses, "WA_NORMAL", INT2NUM(WA_NORMAL));
rb_define_const(mNcurses, "WA_STANDOUT", INT2NUM(WA_STANDOUT));
rb_define_const(mNcurses, "WA_UNDERLINE", INT2NUM(WA_UNDERLINE));
rb_define_const(mNcurses, "WA_REVERSE", INT2NUM(WA_REVERSE));
rb_define_const(mNcurses, "WA_BLINK", INT2NUM(WA_BLINK));
rb_define_const(mNcurses, "WA_DIM", INT2NUM(WA_DIM));
rb_define_const(mNcurses, "WA_BOLD", INT2NUM(WA_BOLD));
rb_define_const(mNcurses, "WA_ALTCHARSET", INT2NUM(WA_ALTCHARSET));
rb_define_const(mNcurses, "WA_INVIS", INT2NUM(WA_INVIS));
rb_define_const(mNcurses, "WA_PROTECT", INT2NUM(WA_PROTECT));
rb_define_const(mNcurses, "WA_HORIZONTAL", INT2NUM(WA_HORIZONTAL));
rb_define_const(mNcurses, "WA_LEFT", INT2NUM(WA_LEFT));
rb_define_const(mNcurses, "WA_LOW", INT2NUM(WA_LOW));
rb_define_const(mNcurses, "WA_RIGHT", INT2NUM(WA_RIGHT));
rb_define_const(mNcurses, "WA_TOP", INT2NUM(WA_TOP));
rb_define_const(mNcurses, "WA_VERTICAL", INT2NUM(WA_VERTICAL));
#endif
/* locale flags */
#ifdef HAVE_LOCALE_H
rb_define_const(mNcurses, "LC_ALL", INT2NUM(LC_ALL));
rb_define_const(mNcurses, "LC_COLLATE", INT2NUM(LC_COLLATE));
rb_define_const(mNcurses, "LC_CTYPE", INT2NUM(LC_CTYPE));
rb_define_const(mNcurses, "LC_MESSAGES", INT2NUM(LC_MESSAGES));
rb_define_const(mNcurses, "LC_MONETARY", INT2NUM(LC_MONETARY));
rb_define_const(mNcurses, "LC_NUMERIC", INT2NUM(LC_NUMERIC));
rb_define_const(mNcurses, "LC_TIME", INT2NUM(LC_TIME));
#endif
}
static VALUE rbncurs_COLORS()
{return INT2NUM(COLORS);}
static VALUE rbncurs_COLOR_PAIRS()
{return INT2NUM(COLOR_PAIRS);}
static
void
init_globals_1(void)
{
/* colors */
NCFUNC(COLORS, 0);
NCFUNC(COLOR_PAIRS, 0);
}
static
void
init_constants_2(void)
{
rb_define_const(mNcurses, "COLOR_BLACK", INT2NUM(COLOR_BLACK));
rb_define_const(mNcurses, "COLOR_RED", INT2NUM(COLOR_RED));
rb_define_const(mNcurses, "COLOR_GREEN", INT2NUM(COLOR_GREEN));
rb_define_const(mNcurses, "COLOR_YELLOW", INT2NUM(COLOR_YELLOW));
rb_define_const(mNcurses, "COLOR_BLUE", INT2NUM(COLOR_BLUE));
rb_define_const(mNcurses, "COLOR_MAGENTA", INT2NUM(COLOR_MAGENTA));
rb_define_const(mNcurses, "COLOR_CYAN", INT2NUM(COLOR_CYAN));
rb_define_const(mNcurses, "COLOR_WHITE", INT2NUM(COLOR_WHITE));
rb_define_const(mNcurses, "ERR", INT2NUM(ERR));
rb_define_const(mNcurses, "OK", INT2NUM(OK));
/* values for the _flags member */
#ifdef _SUBWIN
rb_define_const(mNcurses, "SUBWIN", INT2NUM(_SUBWIN));
#endif
#ifdef _ENDLINE
rb_define_const(mNcurses, "ENDLINE", INT2NUM(_ENDLINE));
#endif
#ifdef _FULLWIN
rb_define_const(mNcurses, "FULLWIN", INT2NUM(_FULLWIN));
#endif
#ifdef _SCROLLWIN
rb_define_const(mNcurses, "SCROLLWIN", INT2NUM(_SCROLLWIN));
#endif
#ifdef _ISPAD
rb_define_const(mNcurses, "ISPAD", INT2NUM(_ISPAD));
#endif
#ifdef _HASMOVED
rb_define_const(mNcurses, "HASMOVED", INT2NUM(_HASMOVED));
#endif
#ifdef _WRAPPED
rb_define_const(mNcurses, "WRAPPED", INT2NUM(_WRAPPED));
#endif
#ifdef _NOCHANGE
/*
* this value is used in the firstchar and lastchar fields to mark
* unchanged lines
*/
rb_define_const(mNcurses, "NOCHANGE", INT2NUM(_NOCHANGE));
#endif
#ifdef _NEWINDEX
/*
* this value is used in the oldindex field to mark lines created by
* insertions and scrolls.
*/
rb_define_const(mNcurses, "NEWINDEX", INT2NUM(_NEWINDEX));
#endif
#ifdef CCHARW_MAX
rb_define_const(mNcurses, "CCHARW_MAX", INT2NUM(CCHARW_MAX));
#endif
}
/// Portable (1.8,1.9) determination of array length (calling #length)
long rbncurs_array_length(VALUE array)
{
return NUM2LONG(rb_funcall(array, rb_intern("length"), 0));
}
VALUE wrap_window(WINDOW* window)
{
if (window == 0) return Qnil;
{
VALUE windows_hash = rb_iv_get(mNcurses, "@windows_hash");
VALUE window_adress = INT2NUM((long)(window));
VALUE rb_window = rb_hash_aref(windows_hash, window_adress);
if (rb_window == Qnil) {
rb_window = Data_Wrap_Struct(cWINDOW, 0, 0, window);
rb_iv_set(rb_window, "@destroyed", Qfalse);
rb_hash_aset(windows_hash, window_adress, rb_window);
}
return rb_window;
}
}
WINDOW* get_window(VALUE rb_window)
{
WINDOW* window;
if (rb_window == Qnil) return 0;
if (rb_iv_get(rb_window, "@destroyed") == Qtrue) {
rb_raise(eNcurses, "Attempt to access a destroyed window");
return 0;
}
Data_Get_Struct(rb_window, WINDOW, window);
return window;
}
static VALUE rbncurs_delwin(VALUE dummy, VALUE arg1) {
VALUE windows_hash = rb_iv_get(mNcurses, "@windows_hash");
WINDOW* window = get_window(arg1);
VALUE window_adress = INT2NUM((long)(window));
rb_funcall(windows_hash, rb_intern("delete"), 1, window_adress);
rb_iv_set(arg1, "@destroyed", Qtrue);
return INT2NUM(delwin(window));
}
static VALUE wrap_screen(SCREEN* screen)
{
if (screen == 0) return Qnil;
{
VALUE screens_hash = rb_iv_get(mNcurses, "@screens_hash");
VALUE screen_adress = INT2NUM((long)(screen));
VALUE rb_screen = rb_hash_aref(screens_hash, screen_adress);
if (rb_screen == Qnil) {
rb_screen = Data_Wrap_Struct(cSCREEN, 0, 0, screen);
rb_iv_set(rb_screen, "@destroyed", Qfalse);
rb_hash_aset(screens_hash, screen_adress, rb_screen);
}
return rb_screen;
}
}
static SCREEN* get_screen(VALUE rb_screen)
{
SCREEN* screen;
if (rb_screen == Qnil) return 0;
if (rb_iv_get(rb_screen, "@destroyed") == Qtrue) {
rb_raise(eNcurses, "Attempt to access a destroyed screen");
return 0;
}
Data_Get_Struct(rb_screen, SCREEN, screen);
return screen;
}
#ifdef HAVE_DELSCREEN
static VALUE rbncurs_delscreen(VALUE dummy, VALUE arg1) {
VALUE screens_hash = rb_iv_get(mNcurses, "@screens_hash");
SCREEN* screen = get_screen(arg1);
VALUE screen_adress = INT2NUM((long)(screen));
rb_funcall(screens_hash, rb_intern("delete"), 1, screen_adress);
rb_iv_set(arg1, "@destroyed", Qtrue);
delscreen(screen);
return Qnil;
}
#endif
static VALUE rbncurs_winchnstr(VALUE dummy, VALUE rb_win, VALUE rb_str, VALUE rb_n)
{
if (rb_obj_is_instance_of(rb_str, rb_cArray) != Qtrue) {
rb_raise(rb_eArgError, "2nd argument must be an empty Array");
return Qnil;
}
{
WINDOW * window = get_window(rb_win);
int n = NUM2INT(rb_n);
chtype * str = ALLOC_N(chtype, n + 1);
int return_value;
return_value = winchnstr(window, str, n);
if (return_value != ERR) {
int i;
for (i = 0; i < return_value; ++i) {
rb_ary_push(rb_str, INT2NUM(str[i]));
}
}
xfree(str);
return INT2NUM(return_value);
}
}
static VALUE rbncurs_wgetnstr(VALUE dummy, VALUE rb_win, VALUE rb_chstr, VALUE rb_n)
{
WINDOW * window = get_window(rb_win);
int n = NUM2INT(rb_n);
char * str = ALLOC_N(char, n + 1);
int return_value;
return_value = wgetnstr(window, str, n);
if (return_value != ERR) {
rb_str_cat2(rb_chstr, str);
}
xfree(str);
return INT2NUM(return_value);
}
static VALUE rbncurs_winnstr(VALUE dummy, VALUE rb_win, VALUE rb_chstr, VALUE rb_n)
{
WINDOW * window = get_window(rb_win);
int n = NUM2INT(rb_n);
char* str = ALLOC_N(char, n + 1);
int return_value;
return_value = winnstr(window, str, n);
if (return_value != ERR) {
rb_str_cat(rb_chstr, str, return_value);
}
xfree(str);
return INT2NUM(return_value);
}
#if defined(HAVE_PANEL_H) || defined(HAVE_NCURSESW_PANEL_H)
#include "panel_wrap.h" /* needs access to mNcurses, wrap_window, get_window */
#endif
#if defined(HAVE_FORM_H) || defined(HAVE_NCURSESW_FORM_H)
#include "form_wrap.h" /* needs init_form */
#endif
#if defined(HAVE_MENU_H) || defined(HAVE_NCURSESW_MENU_H)
#include "menu_wrap.h" /* needs init_menu */
#endif
static
void
init_functions_0(void)
{
#ifdef HAVE_DELSCREEN
NCFUNC(delscreen, 1);
#endif
NCFUNC(delwin, 1);
NCFUNC(winchnstr, 3);
NCFUNC(winnstr, 3);
NCFUNC(wgetnstr, 3);
}
static VALUE get_stdscr()
{
VALUE rb_stdscr = rb_iv_get(mNcurses, "@stdscr");
if (rb_stdscr == Qnil) {
rb_stdscr = wrap_window(stdscr);
rb_iv_set(mNcurses, "@stdscr", rb_stdscr);
}
return rb_stdscr;
}
static VALUE get_curscr()
{
VALUE rb_curscr = rb_iv_get(mNcurses, "@curscr");
if (rb_curscr == Qnil) {
rb_curscr = wrap_window(curscr);
rb_iv_set(mNcurses, "@curscr", rb_curscr);
}
return rb_curscr;
}
#ifdef HAVE_NEWSCR
static VALUE get_newscr()
{
VALUE rb_newscr = rb_iv_get(mNcurses, "@newscr");
if (rb_newscr == Qnil) {
rb_newscr = wrap_window(newscr);
rb_iv_set(mNcurses, "@newscr", rb_newscr);
}
return rb_newscr;
}
#endif
static VALUE get_LINES() {return INT2NUM(LINES);}
static VALUE get_COLS() {return INT2NUM(COLS);}
#ifdef HAVE_TABSIZE
static VALUE get_TABSIZE() {return INT2NUM(TABSIZE);}
#endif
#ifdef HAVE_ESCDELAY
/* This global was an undocumented feature under AIX curses. */
/* ESC expire time in milliseconds */
static VALUE get_ESCDELAY(){return INT2NUM(ESCDELAY);}
static VALUE set_ESCDELAY(VALUE dummy, VALUE new_delay)
{
ESCDELAY=NUM2INT(new_delay);
return INT2NUM(ESCDELAY);
}
#endif
/* This global is wrapper-specific. It denotes the interval after which the
terminal is periodically checked for having resized or not. */
/* time in milliseconds */
static VALUE get_RESIZEDELAY(){return rb_iv_get(mNcurses, "@resize_delay");}
static VALUE set_RESIZEDELAY(VALUE dummy, VALUE rb_new_delay)
{
int c_new_delay = NUM2INT(rb_new_delay);
if (c_new_delay <= 0)
rb_raise(rb_eArgError, "delay must be > 0");
rb_new_delay = INT2NUM(c_new_delay);
rb_iv_set(mNcurses, "@resize_delay", rb_new_delay);
return rb_new_delay ;
}
static
void
init_globals_2(void)
{
rb_iv_set(mNcurses, "@stdscr", Qnil);
rb_iv_set(mNcurses, "@curscr", Qnil);
rb_iv_set(mNcurses, "@newscr", Qnil);
rb_define_module_function(mNcurses, "stdscr",
(&get_stdscr), 0);
rb_define_module_function(mNcurses, "curscr",
(&get_curscr), 0);
#ifdef HAVE_NEWSCR
rb_define_module_function(mNcurses, "newscr",
(&get_newscr), 0);
#endif
rb_define_module_function(mNcurses, "LINES",
(&get_LINES), 0);
rb_define_module_function(mNcurses, "COLS",
(&get_COLS), 0);
#ifdef HAVE_TABSIZE
rb_define_module_function(mNcurses, "TABSIZE",
(&get_TABSIZE),0);
#endif
#ifdef HAVE_ESCDELAY
rb_define_module_function(mNcurses, "ESCDELAY",
(&get_ESCDELAY),0);
rb_define_module_function(mNcurses, "ESCDELAY=",
(&set_ESCDELAY),1);
#endif
/* The maximum delay before screen resize is detected, in milliseconds */
rb_iv_set(mNcurses, "@resize_delay", INT2FIX(333));
rb_define_module_function(mNcurses, "RESIZEDELAY",
(&get_RESIZEDELAY),0);
rb_define_module_function(mNcurses, "RESIZEDELAY=",
(&set_RESIZEDELAY),1);
}
#ifdef HAVE_KEYBOUND
static VALUE rbncurs_keybound(VALUE dummy, VALUE keycode, VALUE count)
{
char * str = keybound(NUM2INT(keycode), NUM2INT(count));
VALUE rb_str = Qnil;
if (str) {
rb_str = rb_str_new2(str);
free(str);
}
return rb_str;
}
#endif
#ifdef HAVE_CURSES_VERSION
static VALUE rbncurs_curses_version(){return rb_str_new2(curses_version());}
#endif
#ifdef HAVE_DEFINE_KEY
static VALUE rbncurs_define_key(VALUE dummy, VALUE definition, VALUE keycode)
{
return INT2NUM(define_key((definition != Qnil)
? STR2CSTR(definition)
: (char*)(NULL),
NUM2INT(keycode)));
}
#endif
#ifdef HAVE_KEYOK
static VALUE rbncurs_keyok(VALUE dummy, VALUE keycode, VALUE enable)
{
return INT2NUM(keyok(NUM2INT(keycode), RTEST(enable)));
}
#endif
#ifdef HAVE_RESIZETERM
static VALUE rbncurs_resizeterm(VALUE dummy, VALUE lines, VALUE columns)
{
return INT2NUM(resizeterm(NUM2INT(lines), NUM2INT(columns)));
}
#endif
#ifdef HAVE_USE_DEFAULT_COLORS
static VALUE rbncurs_use_default_colors()
{
return INT2NUM(use_default_colors());
}
#endif
#ifdef HAVE_USE_EXTENDED_NAMES
static VALUE rbncurs_use_extended_names(VALUE dummy, VALUE boolean)
{return INT2NUM(use_extended_names(RTEST(boolean)));}
#endif
#ifdef HAVE_WRESIZE
static VALUE rbncurs_wresize(VALUE dummy, VALUE win, VALUE lines, VALUE columns)
{
return INT2NUM(wresize(get_window(win), NUM2INT(lines), NUM2INT(columns)));
}
#endif
static
void
init_functions_1(void)
{
#ifdef HAVE_KEYBOUND
NCFUNC(keybound, 2);
#endif
#ifdef HAVE_CURSES_VERSION
NCFUNC(curses_version, 0);
#endif
#ifdef HAVE_DEFINE_KEY
NCFUNC(define_key, 2);
#endif
#ifdef HAVE_KEYOK
NCFUNC(keyok, 2);
#endif
#ifdef HAVE_RESIZETERM
NCFUNC(resizeterm, 2);
#endif
#ifdef HAVE_USE_DEFAULT_COLORS
NCFUNC(use_default_colors, 0);
#endif
#ifdef HAVE_USE_EXTENDED_NAMES
NCFUNC(use_extended_names, 1);
#endif
#ifdef HAVE_WRESIZE
NCFUNC(wresize, 3);
#endif
}
/* FIXME: what's this? */
/* extern char ttytype[]; */ /* needed for backward compatibility */
/* copy a chstr from ruby to c */
static chtype * RB2CHSTR(VALUE array)
{
if (rb_obj_is_instance_of(array, rb_cArray) != Qtrue) {
rb_raise(rb_eArgError,
"chtype string argument must be an empty Array");
return NULL;
}
{
size_t string_length =
NUM2ULONG(rb_funcall(array, rb_intern("size"), 0));
size_t vector_length =
string_length + 1; /* for terminating 0 */
chtype * chstr = ALLOC_N(chtype, vector_length);
unsigned long i;
for (i = 0; i < string_length; ++i) {
chstr[i] = (int) NUM2ULONG(rb_ary_entry(array, i));
}
chstr[string_length] = 0;
return chstr;
}
}
static VALUE rbncurs_addch(VALUE dummy, VALUE arg1) {
return INT2NUM(addch((int) NUM2ULONG(arg1)));
}
#ifdef HAVE_ADD_WCH
static VALUE rbncurs_add_wch(VALUE dummy, VALUE arg1) {
wchar_t c = NUM2ULONG(arg1);
return INT2NUM(add_wch((cchar_t *)&c));
}
#endif
static VALUE rbncurs_addchnstr(VALUE dummy, VALUE arg1, VALUE arg2) {
chtype * chstr = RB2CHSTR(arg1);
VALUE return_value = INT2NUM(addchnstr(chstr, NUM2INT(arg2)));
xfree(chstr);
return return_value;
}
static VALUE rbncurs_addchstr(VALUE dummy, VALUE arg1) {
chtype * chstr = RB2CHSTR(arg1);
VALUE return_value = INT2NUM(addchstr(chstr));
xfree(chstr);
return return_value;
}
static VALUE rbncurs_addnstr(VALUE dummy, VALUE arg1, VALUE arg2) {
return INT2NUM(addnstr(STR2CSTR(arg1), NUM2INT(arg2)));
}
static VALUE rbncurs_addstr(VALUE dummy, VALUE arg1) {
return INT2NUM(addstr(STR2CSTR(arg1)));
}
static VALUE rbncurs_attroff(VALUE dummy, VALUE arg1) {
return INT2NUM(attroff(NUM2ULONG(arg1)));
}
static VALUE rbncurs_attron(VALUE dummy, VALUE arg1) {
return INT2NUM(attron(NUM2ULONG(arg1)));
}
static VALUE rbncurs_attrset(VALUE dummy, VALUE arg1) {
return INT2NUM(attrset((int) NUM2ULONG(arg1)));
}
#if defined(NCURSES_VERSION_MAJOR) && NCURSES_VERSION_MAJOR > 4
#ifdef HAVE_ATTR_OFF
static VALUE rbncurs_attr_off(VALUE dummy, VALUE arg1, VALUE arg2) {
return INT2NUM(attr_off((int) NUM2ULONG(arg1), ((void)(arg2),NULL)));
}
#endif
#ifdef HAVE_ATTR_ON
static VALUE rbncurs_attr_on(VALUE dummy, VALUE arg1, VALUE arg2) {
return INT2NUM(attr_on((int) NUM2ULONG(arg1), ((void)(arg2),NULL)));
}
#endif
#ifdef HAVE_ATTR_SET
static VALUE rbncurs_attr_set(VALUE dummy, VALUE arg1, VALUE arg2, VALUE arg3) {
return INT2NUM(attr_set((int) NUM2ULONG(arg1), NUM2INT(arg2), ((void)(arg3),NULL)));
}
#endif
#if defined(HAVE_SLK_ATTR_OFF) || defined(slk_attr_off)
static VALUE rbncurs_slk_attr_off(VALUE dummy, VALUE arg1, VALUE arg2) {
return INT2NUM(slk_attr_off((int) NUM2ULONG(arg1), ((void)(arg2),NULL)));
}
#endif
#if defined(HAVE_SLK_ATTR_ON) || defined(slk_attr_on)
static VALUE rbncurs_slk_attr_on(VALUE dummy, VALUE arg1, VALUE arg2) {
return INT2NUM(slk_attr_on((int) NUM2ULONG(arg1), ((void)(arg2),NULL)));
}
#endif
#ifdef HAVE_SLK_ATTR_SET
static VALUE rbncurs_slk_attr_set(VALUE dummy, VALUE arg1, VALUE arg2, VALUE arg3) {
return INT2NUM(slk_attr_set((int) NUM2ULONG(arg1), NUM2INT(arg2), ((void)(arg3),NULL)));
}
#endif
#ifdef HAVE_WATTR_ON
static VALUE rbncurs_wattr_on(VALUE dummy, VALUE arg1, VALUE arg2, VALUE arg3) {
return INT2NUM(wattr_on(get_window(arg1), (int) NUM2ULONG(arg2), ((void)(arg3),NULL)));
}
#endif
#ifdef HAVE_WATTR_OFF
static VALUE rbncurs_wattr_off(VALUE dummy, VALUE arg1, VALUE arg2, VALUE arg3) {
return INT2NUM(wattr_off(get_window(arg1), (int) NUM2ULONG(arg2), ((void)(arg3),NULL)));
}
#endif
#ifdef HAVE_WATTR_SET
static VALUE rbncurs_wattr_set(VALUE dummy, VALUE arg1, VALUE arg2, VALUE arg3, VALUE arg4) {
return INT2NUM(wattr_set(get_window(arg1), (int) NUM2ULONG(arg2), NUM2INT(arg3), ((void)(arg4),NULL)));
}
#endif
#if defined(HAVE_VID_ATTR) || defined(vid_attr)
static VALUE rbncurs_vid_attr(VALUE dummy, VALUE arg1, VALUE arg2, VALUE arg3) {
return INT2NUM(vid_attr((int) NUM2ULONG(arg1), NUM2INT(arg2), ((void)(arg3),NULL)));
}
#endif
#ifdef HAVE_ATTR_GET
static VALUE rbncurs_attr_get(VALUE dummy, VALUE rb_attrs, VALUE rb_pair,
VALUE dummy2)
{
if ((rb_obj_is_instance_of(rb_attrs, rb_cArray) != Qtrue)
|| (rb_obj_is_instance_of(rb_pair, rb_cArray) != Qtrue)) {
rb_raise(rb_eArgError,
"attrs and pair arguments must be empty Arrays");
return Qnil;
}
{
attr_t attrs = 0;
short pair = 0;
int return_value = attr_get(&attrs, &pair, 0);
rb_ary_push(rb_attrs, INT2NUM(attrs));
rb_ary_push(rb_pair, INT2NUM(pair));
return INT2NUM(return_value);
}
}
static VALUE rbncurs_wattr_get(VALUE dummy,VALUE win, VALUE rb_attrs, VALUE rb_pair,
VALUE dummy2)
{
if ((rb_obj_is_instance_of(rb_attrs, rb_cArray) != Qtrue)
|| (rb_obj_is_instance_of(rb_pair, rb_cArray) != Qtrue)) {
rb_raise(rb_eArgError,
"attrs and pair arguments must be empty Arrays");
return Qnil;
}
{
attr_t attrs = 0;
short pair = 0;
int return_value = wattr_get(get_window(win), &attrs, &pair, 0);
rb_ary_push(rb_attrs, INT2NUM(attrs));
rb_ary_push(rb_pair, INT2NUM(pair));
return INT2NUM(return_value);
}
}
#endif /* HAVE_ATTR_GET */
#endif
static VALUE rbncurs_baudrate(VALUE dummy) {
return INT2NUM(baudrate());
}
static VALUE rbncurs_beep(VALUE dummy) {
return INT2NUM(beep());
}
static VALUE rbncurs_bkgd(VALUE dummy, VALUE arg1) {
return INT2NUM(bkgd((int) NUM2ULONG(arg1)));
}
static VALUE rbncurs_bkgdset(VALUE dummy, VALUE arg1) {
return ((bkgdset((int) NUM2ULONG(arg1))),Qnil);
}
static VALUE rbncurs_border(VALUE dummy, VALUE arg1, VALUE arg2, VALUE arg3, VALUE arg4, VALUE arg5, VALUE arg6, VALUE arg7, VALUE arg8) {
return INT2NUM(border((int) NUM2ULONG(arg1), (int) NUM2ULONG(arg2), (int) NUM2ULONG(arg3), (int) NUM2ULONG(arg4), (int) NUM2ULONG(arg5), (int) NUM2ULONG(arg6), (int) NUM2ULONG(arg7), (int) NUM2ULONG(arg8)));
}
static VALUE rbncurs_box(VALUE dummy, VALUE arg1, VALUE arg2, VALUE arg3) {
return INT2NUM(box(get_window(arg1), (int) NUM2ULONG(arg2), (int) NUM2ULONG(arg3)));
}
static VALUE rbncurs_can_change_color(VALUE dummy) {
return (can_change_color()) ? Qtrue : Qfalse;
}
static int rbncurshelper_halfdelay_cbreak(int tenths, int break_chars)
{
int status = break_chars ? cbreak() : nocbreak();
if (status != ERR) {
rb_iv_set(mNcurses, "@halfdelay", INT2NUM(tenths));
rb_iv_set(mNcurses, "@cbreak", break_chars ? Qtrue : Qfalse);
}
return status;
}
static void rbncurshelper_halfdelay_cbreak_restore()
{
if (RTEST(rb_iv_get(mNcurses, "@cbreak")))
cbreak();
else
nocbreak();
}
static VALUE rbncurs_cbreak(VALUE dummy) {
return INT2NUM(rbncurshelper_halfdelay_cbreak(0, 1));
}
#ifdef HAVE_CHGAT
static VALUE rbncurs_chgat(VALUE dummy, VALUE arg1, VALUE arg2, VALUE arg3, VALUE arg4) {
return INT2NUM(chgat(NUM2INT(arg1), (int) NUM2ULONG(arg2), NUM2INT(arg3),
((void)(arg4),NULL)));
}
#endif
static VALUE rbncurs_clear(VALUE dummy) {
return INT2NUM(clear());
}
static VALUE rbncurs_clearok(VALUE dummy, VALUE arg1, VALUE arg2) {
return INT2NUM(clearok(get_window(arg1), RTEST(arg2)));
}
static VALUE rbncurs_clrtobot(VALUE dummy) {
return INT2NUM(clrtobot());
}
static VALUE rbncurs_clrtoeol(VALUE dummy) {
return INT2NUM(clrtoeol());
}
#ifdef HAVE_COLOR_SET
static VALUE rbncurs_color_set(VALUE dummy, VALUE arg1, VALUE arg2) {
return INT2NUM(color_set(NUM2INT(arg1), ((void)(arg2),NULL)));
}
#endif
static VALUE rbncurs_COLOR_PAIR(VALUE dummy, VALUE arg1) {
return INT2NUM(COLOR_PAIR(NUM2INT(arg1)));
}
// alias for COLOR_PAIR for compatibilty with ruby Curses gem.
static VALUE rbncurs_color_pair(VALUE dummy, VALUE arg1) {
return rbncurs_COLOR_PAIR (dummy, arg1);
}
static VALUE rbncurs_copywin(VALUE dummy, VALUE arg1, VALUE arg2, VALUE arg3, VALUE arg4, VALUE arg5, VALUE arg6, VALUE arg7, VALUE arg8, VALUE arg9) {
return INT2NUM(copywin(get_window(arg1), get_window(arg2), NUM2INT(arg3), NUM2INT(arg4), NUM2INT(arg5), NUM2INT(arg6), NUM2INT(arg7), NUM2INT(arg8), NUM2INT(arg9)));
}
static VALUE rbncurs_curs_set(VALUE dummy, VALUE arg1) {
return INT2NUM(curs_set(NUM2INT(arg1)));
}
static VALUE rbncurs_def_prog_mode(VALUE dummy) {
return INT2NUM(def_prog_mode());
}
static VALUE rbncurs_def_shell_mode(VALUE dummy) {
return INT2NUM(def_shell_mode());
}
static VALUE rbncurs_delay_output(VALUE dummy, VALUE arg1) {
return INT2NUM(delay_output(NUM2INT(arg1)));
}
static VALUE rbncurs_delch(VALUE dummy) {
return INT2NUM(delch());
}
static VALUE rbncurs_deleteln(VALUE dummy) {
return INT2NUM(deleteln());
}
static VALUE rbncurs_derwin(VALUE dummy, VALUE arg1, VALUE arg2, VALUE arg3, VALUE arg4, VALUE arg5) {
return wrap_window(derwin(get_window(arg1), NUM2INT(arg2), NUM2INT(arg3), NUM2INT(arg4), NUM2INT(arg5)));
}
static VALUE rbncurs_doupdate(VALUE dummy) {
return INT2NUM(doupdate());
}
static VALUE rbncurs_dupwin(VALUE dummy, VALUE arg1) {
return wrap_window(dupwin(get_window(arg1)));
}
static VALUE rbncurs_echo(VALUE dummy) {
return INT2NUM(echo());
}
static VALUE rbncurs_echochar(VALUE dummy, VALUE arg1) {
return INT2NUM(echochar((int) NUM2ULONG(arg1)));
}
static VALUE rbncurs_endwin(VALUE dummy) {
return INT2NUM(endwin());
}
static VALUE rbncurs_erasechar(VALUE dummy) {
return INT2NUM(erasechar());
}
#ifdef HAVE_FILTER
static VALUE rbncurs_filter(VALUE dummy) {
return ((filter()),Qnil);
}
#endif
static VALUE rbncurs_flash(VALUE dummy) {
return INT2NUM(flash());
}
static VALUE rbncurs_flushinp(VALUE dummy) {
return INT2NUM(flushinp());
}
static VALUE rbncurs_getbkgd(VALUE dummy, VALUE arg1) {
return INT2NUM(getbkgd(get_window(arg1)));
}
/* typedef of a pointer to a wgetch function */
typedef int (*wgetch_func) (WINDOW *);
/* functor for getting a char nonblocking, pass getchar function */
static int rbncurshelper_do_wgetch_functor (WINDOW *c_win, wgetch_func _wgetch_func) {
/* nonblocking wgetch only implemented for Ncurses */
int halfdelay = NUM2INT(rb_iv_get(mNcurses, "@halfdelay"));
int infd = NUM2INT(rb_iv_get(mNcurses, "@infd"));
double screen_delay = halfdelay * 0.1;
#if defined(NCURSES_VERSION) && defined(NCURSES_OPAQUE) && !NCURSES_OPAQUE
int windelay = c_win->_delay;
#else
int windelay = 0;
#endif
double window_delay = (windelay >= 0) ? 0.001 * windelay : (1e200*1e200);
/* FIXME: ^ Infinity ^*/
double delay = (screen_delay > 0) ? screen_delay : window_delay;
int result;
double starttime, nowtime, finishtime;
double resize_delay = NUM2INT(get_RESIZEDELAY()) / 1000.0;
fd_set in_fds;
#ifdef HAVE_CLOCK_GETTIME
struct timespec tv;
struct timeval ts;
clock_gettime (CLOCK_MONOTONIC, &tv);
starttime = tv.tv_sec + tv.tv_nsec * 1e-9;
#else
struct timeval tv;
struct timezone tz = {0,0};
gettimeofday(&tv, &tz);
starttime = tv.tv_sec + tv.tv_usec * 1e-6;
#endif
finishtime = starttime + delay;
#if defined(NCURSES_VERSION) && defined(NCURSES_OPAQUE) && !NCURSES_OPAQUE
c_win->_delay = 0;
#endif
while (doupdate() /* detects resize */, (result = _wgetch_func(c_win)) == ERR) {
#ifdef HAVE_RB_THREAD_FD_SELECT
rb_fdset_t fdsets[3];
rb_fdset_t *rfds = NULL;
#endif
#ifdef HAVE_CLOCK_GETTIME
clock_gettime (CLOCK_MONOTONIC, &tv);
nowtime = tv.tv_sec + tv.tv_nsec * 1e-9;
#else
gettimeofday(&tv, &tz);
nowtime = tv.tv_sec + tv.tv_usec * 1e-6;
#endif
delay = finishtime - nowtime;
if (delay <= 0) break;
/* Check for terminal size change every resize_delay seconds */
if (resize_delay > delay) resize_delay = delay;
tv.tv_sec = (time_t)resize_delay;
#ifdef HAVE_CLOCK_GETTIME
tv.tv_nsec = (unsigned)( (resize_delay - tv.tv_sec) * 1e9 );
#else
tv.tv_usec = (unsigned)( (resize_delay - tv.tv_sec) * 1e6 );
#endif
#if HAVE_CLOCK_GETTIME
ts.tv_sec = tv.tv_sec;
ts.tv_usec = tv.tv_nsec * 1e-3;
#endif
/* sleep on infd until input is available or tv reaches timeout */
FD_ZERO(&in_fds);
FD_SET(infd, &in_fds);
#ifdef HAVE_RB_THREAD_FD_SELECT
rfds = &fdsets[0];
rb_fd_init(rfds);
rb_fd_copy(rfds, &in_fds, infd +1);
#if HAVE_CLOCK_GETTIME
rb_thread_fd_select(infd + 1, rfds, NULL, NULL, &ts);
#else
rb_thread_fd_select(infd + 1, rfds, NULL, NULL, &tv);
#endif
#else
#if HAVE_CLOCK_GETTIME
rb_thread_select(infd + 1, &in_fds, NULL, NULL, &ts);
#else
rb_thread_select(infd + 1, &in_fds, NULL, NULL, &tv);
#endif
#endif
}
#if defined(NCURSES_VERSION) && defined(NCURSES_OPAQUE) && !NCURSES_OPAQUE
c_win->_delay = windelay;
#endif
return result;
}
/* non-wide char getch */
static int rbncurshelper_nonblocking_wgetch(WINDOW *c_win) {
return rbncurshelper_do_wgetch_functor (c_win, &wgetch);
}
#ifdef HAVE_GET_WCH
/* not thread safe: wide char getch */
static wint_t wget_wch_back;
static int my_wget_wch (WINDOW *c_win) {
return wget_wch (c_win, &wget_wch_back);
}
/* return array with first element being return key code status,
* and second element the key code */
static VALUE rbncurshelper_nonblocking_wget_wch(WINDOW *c_win) {
int retcode = rbncurshelper_do_wgetch_functor (c_win, &my_wget_wch);
VALUE r = rb_assoc_new (INT2NUM(retcode), LONG2NUM(wget_wch_back));
return r;
}
#endif
static VALUE rbncurs_getch(VALUE dummy) {
return INT2NUM(rbncurshelper_nonblocking_wgetch(stdscr));
}
#ifdef HAVE_GET_WCH
static VALUE rbncurs_get_wch(VALUE dummy) {
return rbncurshelper_nonblocking_wget_wch(stdscr);
}
#endif
static VALUE rbncurs_halfdelay(VALUE dummy, VALUE arg1) {
return INT2NUM(rbncurshelper_halfdelay_cbreak(NUM2INT(arg1), 1));
}
static VALUE rbncurs_has_colors(VALUE dummy) {
return (has_colors()) ? Qtrue : Qfalse;
}
static VALUE rbncurs_has_ic(VALUE dummy) {
return (has_ic()) ? Qtrue : Qfalse;
}
static VALUE rbncurs_has_il(VALUE dummy) {
return (has_il()) ? Qtrue : Qfalse;
}
static VALUE rbncurs_hline(VALUE dummy, VALUE arg1, VALUE arg2) {
return INT2NUM(hline((int) NUM2ULONG(arg1), NUM2INT(arg2)));
}
static VALUE rbncurs_idcok(VALUE dummy, VALUE arg1, VALUE arg2) {
return ((idcok(get_window(arg1), RTEST(arg2))),Qnil);
}
static VALUE rbncurs_idlok(VALUE dummy, VALUE arg1, VALUE arg2) {
return INT2NUM(idlok(get_window(arg1), RTEST(arg2)));
}
static VALUE rbncurs_immedok(VALUE dummy, VALUE arg1, VALUE arg2) {
return ((immedok(get_window(arg1), RTEST(arg2))),Qnil);
}
static VALUE rbncurs_inch(VALUE dummy) {
return INT2NUM(inch());
}
static VALUE rbncurs_initscr(VALUE dummy) {
VALUE v = wrap_window(initscr());
if (!RTEST(v))
return v;
Init_ncurses_full();
/* Some constants defined by the initscr call. */
/* line graphics */
/* VT100 symbols begin here */