rb_termbox 0.1.0 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/.gitignore +2 -0
- data/Gemfile +1 -1
- data/Gemfile.lock +11 -13
- data/README.md +14 -0
- data/ext/termbox/bytebuffer.inl +78 -0
- data/ext/termbox/extconf.rb +3 -0
- data/ext/termbox/input.inl +96 -0
- data/ext/termbox/term.inl +291 -0
- data/ext/termbox/termbox.c +536 -0
- data/ext/termbox/termbox.h +226 -0
- data/ext/termbox/utf8.c +79 -0
- data/lib/termbox.rb +1 -1
- data/lib/termbox/colors.rb +9 -8
- data/lib/termbox/keys.rb +2 -1
- data/lib/termbox/version.rb +1 -1
- data/rb_termbox.gemspec +6 -7
- data/sample/all_colors.rb +37 -0
- data/sample/keyboard.rb +15 -15
- metadata +65 -73
- data/README +0 -10
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 987138e46b00b9460893570cc75437b50c569fa1
|
4
|
+
data.tar.gz: 80c60904af6281c8b8a90b9a021774b6b3402476
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 1eb154f3f71cb796a8e7d0ff30e16d8e3ba6db432cb45e1b15edd2d536e23cc529e5ec6417a888b99c3bed0681693be4eb5f8d6ad916d971efdb7bda69100c04
|
7
|
+
data.tar.gz: fb941fb5601b298a72f858c19b177cd2b322768e7245ad3ef9603a15c822eae50dc78cc6efae80576f9a74c8716de472a90c8c85b5274abc029d867a8a4f9f39
|
data/.gitignore
CHANGED
data/Gemfile
CHANGED
data/Gemfile.lock
CHANGED
@@ -5,20 +5,18 @@ PATH
|
|
5
5
|
ffi
|
6
6
|
|
7
7
|
GEM
|
8
|
-
remote:
|
8
|
+
remote: https://rubygems.org/
|
9
9
|
specs:
|
10
|
-
diff-lcs (1.
|
11
|
-
ffi (1.
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
rspec-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
rspec-
|
20
|
-
diff-lcs (~> 1.1.2)
|
21
|
-
rspec-mocks (2.5.0)
|
10
|
+
diff-lcs (1.2.5)
|
11
|
+
ffi (1.9.3)
|
12
|
+
rspec (2.14.1)
|
13
|
+
rspec-core (~> 2.14.0)
|
14
|
+
rspec-expectations (~> 2.14.0)
|
15
|
+
rspec-mocks (~> 2.14.0)
|
16
|
+
rspec-core (2.14.7)
|
17
|
+
rspec-expectations (2.14.4)
|
18
|
+
diff-lcs (>= 1.1.3, < 2.0)
|
19
|
+
rspec-mocks (2.14.4)
|
22
20
|
|
23
21
|
PLATFORMS
|
24
22
|
ruby
|
data/README.md
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
rb_termbox - [Termbox](https://github.com/nsf/termbox) binding
|
2
|
+
====================
|
3
|
+
|
4
|
+
### Development Notes ###
|
5
|
+
- Run ```ruby ext/termbox/extconf.rb && make```
|
6
|
+
- Install bundler and ````bundle install````
|
7
|
+
- Run ruby sample/keyboard.rb to get a feel for what you can do. It's a partial port of termbox's own sample keyboard application. (Ctrl + Q to quit)
|
8
|
+
|
9
|
+
WIP Keyboard example:
|
10
|
+
<img src="http://i.imgur.com/aslMxFi.png"/>
|
11
|
+
|
12
|
+
### Contributors ###
|
13
|
+
James Cook
|
14
|
+
Paul Schuegraf [@pscheugr](https://github.com/pschuegr)
|
@@ -0,0 +1,78 @@
|
|
1
|
+
struct bytebuffer {
|
2
|
+
char *buf;
|
3
|
+
int len;
|
4
|
+
int cap;
|
5
|
+
};
|
6
|
+
|
7
|
+
static void bytebuffer_reserve(struct bytebuffer *b, int cap) {
|
8
|
+
if (b->cap >= cap) {
|
9
|
+
return;
|
10
|
+
}
|
11
|
+
|
12
|
+
// prefer doubling capacity
|
13
|
+
if (b->cap * 2 >= cap) {
|
14
|
+
cap = b->cap * 2;
|
15
|
+
}
|
16
|
+
|
17
|
+
char *newbuf = malloc(cap);
|
18
|
+
if (b->len > 0) {
|
19
|
+
// copy what was there, b->len > 0 assumes b->buf != null
|
20
|
+
memcpy(newbuf, b->buf, b->len);
|
21
|
+
}
|
22
|
+
if (b->buf) {
|
23
|
+
// in case there was an allocated buffer, free it
|
24
|
+
free(b->buf);
|
25
|
+
}
|
26
|
+
b->buf = newbuf;
|
27
|
+
b->cap = cap;
|
28
|
+
}
|
29
|
+
|
30
|
+
static void bytebuffer_init(struct bytebuffer *b, int cap) {
|
31
|
+
b->cap = 0;
|
32
|
+
b->len = 0;
|
33
|
+
b->buf = 0;
|
34
|
+
|
35
|
+
if (cap > 0) {
|
36
|
+
b->cap = cap;
|
37
|
+
b->buf = malloc(cap); // just assume malloc works always
|
38
|
+
}
|
39
|
+
}
|
40
|
+
|
41
|
+
static void bytebuffer_free(struct bytebuffer *b) {
|
42
|
+
if (b->buf)
|
43
|
+
free(b->buf);
|
44
|
+
}
|
45
|
+
|
46
|
+
static void bytebuffer_clear(struct bytebuffer *b) {
|
47
|
+
b->len = 0;
|
48
|
+
}
|
49
|
+
|
50
|
+
static void bytebuffer_append(struct bytebuffer *b, const char *data, int len) {
|
51
|
+
bytebuffer_reserve(b, b->len + len);
|
52
|
+
memcpy(b->buf + b->len, data, len);
|
53
|
+
b->len += len;
|
54
|
+
}
|
55
|
+
|
56
|
+
static void bytebuffer_puts(struct bytebuffer *b, const char *str) {
|
57
|
+
bytebuffer_append(b, str, strlen(str));
|
58
|
+
}
|
59
|
+
|
60
|
+
static void bytebuffer_resize(struct bytebuffer *b, int len) {
|
61
|
+
bytebuffer_reserve(b, len);
|
62
|
+
b->len = len;
|
63
|
+
}
|
64
|
+
|
65
|
+
static void bytebuffer_flush(struct bytebuffer *b, int fd) {
|
66
|
+
write(fd, b->buf, b->len);
|
67
|
+
bytebuffer_clear(b);
|
68
|
+
}
|
69
|
+
|
70
|
+
static void bytebuffer_truncate(struct bytebuffer *b, int n) {
|
71
|
+
if (n <= 0)
|
72
|
+
return;
|
73
|
+
if (n > b->len)
|
74
|
+
n = b->len;
|
75
|
+
const int nmove = b->len - n;
|
76
|
+
memmove(b->buf, b->buf+n, nmove);
|
77
|
+
b->len -= n;
|
78
|
+
}
|
@@ -0,0 +1,96 @@
|
|
1
|
+
// if s1 starts with s2 returns true, else false
|
2
|
+
// len is the length of s1
|
3
|
+
// s2 should be null-terminated
|
4
|
+
static bool starts_with(const char *s1, int len, const char *s2)
|
5
|
+
{
|
6
|
+
int n = 0;
|
7
|
+
while (*s2 && n < len) {
|
8
|
+
if (*s1++ != *s2++)
|
9
|
+
return false;
|
10
|
+
n++;
|
11
|
+
}
|
12
|
+
return *s2 == 0;
|
13
|
+
}
|
14
|
+
|
15
|
+
// convert escape sequence to event, and return consumed bytes on success (failure == 0)
|
16
|
+
static int parse_escape_seq(struct tb_event *event, const char *buf, int len)
|
17
|
+
{
|
18
|
+
// it's pretty simple here, find 'starts_with' match and return
|
19
|
+
// success, else return failure
|
20
|
+
int i;
|
21
|
+
for (i = 0; keys[i]; i++) {
|
22
|
+
if (starts_with(buf, len, keys[i])) {
|
23
|
+
event->ch = 0;
|
24
|
+
event->key = 0xFFFF-i;
|
25
|
+
return strlen(keys[i]);
|
26
|
+
}
|
27
|
+
}
|
28
|
+
return 0;
|
29
|
+
}
|
30
|
+
|
31
|
+
static bool extract_event(struct tb_event *event, struct bytebuffer *inbuf, int inputmode)
|
32
|
+
{
|
33
|
+
const char *buf = inbuf->buf;
|
34
|
+
const int len = inbuf->len;
|
35
|
+
if (len == 0)
|
36
|
+
return false;
|
37
|
+
|
38
|
+
if (buf[0] == '\033') {
|
39
|
+
int n = parse_escape_seq(event, buf, len);
|
40
|
+
if (n) {
|
41
|
+
bytebuffer_truncate(inbuf, n);
|
42
|
+
return true;
|
43
|
+
} else {
|
44
|
+
// it's not escape sequence, then it's ALT or ESC,
|
45
|
+
// check inputmode
|
46
|
+
switch (inputmode) {
|
47
|
+
case TB_INPUT_ESC:
|
48
|
+
// if we're in escape mode, fill ESC event, pop
|
49
|
+
// buffer, return success
|
50
|
+
event->ch = 0;
|
51
|
+
event->key = TB_KEY_ESC;
|
52
|
+
event->mod = 0;
|
53
|
+
bytebuffer_truncate(inbuf, 1);
|
54
|
+
return true;
|
55
|
+
case TB_INPUT_ALT:
|
56
|
+
// if we're in alt mode, set ALT modifier to
|
57
|
+
// event and redo parsing
|
58
|
+
event->mod = TB_MOD_ALT;
|
59
|
+
bytebuffer_truncate(inbuf, 1);
|
60
|
+
return extract_event(event, inbuf, inputmode);
|
61
|
+
default:
|
62
|
+
assert(!"never got here");
|
63
|
+
break;
|
64
|
+
}
|
65
|
+
}
|
66
|
+
}
|
67
|
+
|
68
|
+
// if we're here, this is not an escape sequence and not an alt sequence
|
69
|
+
// so, it's a FUNCTIONAL KEY or a UNICODE character
|
70
|
+
|
71
|
+
// first of all check if it's a functional key
|
72
|
+
if ((unsigned char)buf[0] <= TB_KEY_SPACE ||
|
73
|
+
(unsigned char)buf[0] == TB_KEY_BACKSPACE2)
|
74
|
+
{
|
75
|
+
// fill event, pop buffer, return success */
|
76
|
+
event->ch = 0;
|
77
|
+
event->key = (uint16_t)buf[0];
|
78
|
+
bytebuffer_truncate(inbuf, 1);
|
79
|
+
return true;
|
80
|
+
}
|
81
|
+
|
82
|
+
// feh... we got utf8 here
|
83
|
+
|
84
|
+
// check if there is all bytes
|
85
|
+
if (len >= tb_utf8_char_length(buf[0])) {
|
86
|
+
/* everything ok, fill event, pop buffer, return success */
|
87
|
+
tb_utf8_char_to_unicode(&event->ch, buf);
|
88
|
+
event->key = 0;
|
89
|
+
bytebuffer_truncate(inbuf, tb_utf8_char_length(buf[0]));
|
90
|
+
return true;
|
91
|
+
}
|
92
|
+
|
93
|
+
// event isn't recognized, perhaps there is not enough bytes in utf8
|
94
|
+
// sequence
|
95
|
+
return false;
|
96
|
+
}
|
@@ -0,0 +1,291 @@
|
|
1
|
+
enum {
|
2
|
+
T_ENTER_CA,
|
3
|
+
T_EXIT_CA,
|
4
|
+
T_SHOW_CURSOR,
|
5
|
+
T_HIDE_CURSOR,
|
6
|
+
T_CLEAR_SCREEN,
|
7
|
+
T_SGR0,
|
8
|
+
T_UNDERLINE,
|
9
|
+
T_BOLD,
|
10
|
+
T_BLINK,
|
11
|
+
T_REVERSE,
|
12
|
+
T_ENTER_KEYPAD,
|
13
|
+
T_EXIT_KEYPAD,
|
14
|
+
T_FUNCS_NUM,
|
15
|
+
};
|
16
|
+
|
17
|
+
#define EUNSUPPORTED_TERM -1
|
18
|
+
|
19
|
+
// rxvt-256color
|
20
|
+
static const char *rxvt_256color_keys[] = {
|
21
|
+
"\033[11~","\033[12~","\033[13~","\033[14~","\033[15~","\033[17~","\033[18~","\033[19~","\033[20~","\033[21~","\033[23~","\033[24~","\033[2~","\033[3~","\033[7~","\033[8~","\033[5~","\033[6~","\033[A","\033[B","\033[D","\033[C", 0
|
22
|
+
};
|
23
|
+
static const char *rxvt_256color_funcs[] = {
|
24
|
+
"\0337\033[?47h", "\033[2J\033[?47l\0338", "\033[?25h", "\033[?25l", "\033[H\033[2J", "\033[m", "\033[4m", "\033[1m", "\033[5m", "\033[7m", "\033=", "\033>",
|
25
|
+
};
|
26
|
+
|
27
|
+
// Eterm
|
28
|
+
static const char *eterm_keys[] = {
|
29
|
+
"\033[11~","\033[12~","\033[13~","\033[14~","\033[15~","\033[17~","\033[18~","\033[19~","\033[20~","\033[21~","\033[23~","\033[24~","\033[2~","\033[3~","\033[7~","\033[8~","\033[5~","\033[6~","\033[A","\033[B","\033[D","\033[C", 0
|
30
|
+
};
|
31
|
+
static const char *eterm_funcs[] = {
|
32
|
+
"\0337\033[?47h", "\033[2J\033[?47l\0338", "\033[?25h", "\033[?25l", "\033[H\033[2J", "\033[m", "\033[4m", "\033[1m", "\033[5m", "\033[7m", "", "",
|
33
|
+
};
|
34
|
+
|
35
|
+
// screen
|
36
|
+
static const char *screen_keys[] = {
|
37
|
+
"\033OP","\033OQ","\033OR","\033OS","\033[15~","\033[17~","\033[18~","\033[19~","\033[20~","\033[21~","\033[23~","\033[24~","\033[2~","\033[3~","\033[1~","\033[4~","\033[5~","\033[6~","\033OA","\033OB","\033OD","\033OC", 0
|
38
|
+
};
|
39
|
+
static const char *screen_funcs[] = {
|
40
|
+
"\033[?1049h", "\033[?1049l", "\033[34h\033[?25h", "\033[?25l", "\033[H\033[J", "\033[m", "\033[4m", "\033[1m", "\033[5m", "\033[7m", "\033[?1h\033=", "\033[?1l\033>",
|
41
|
+
};
|
42
|
+
|
43
|
+
// rxvt-unicode
|
44
|
+
static const char *rxvt_unicode_keys[] = {
|
45
|
+
"\033[11~","\033[12~","\033[13~","\033[14~","\033[15~","\033[17~","\033[18~","\033[19~","\033[20~","\033[21~","\033[23~","\033[24~","\033[2~","\033[3~","\033[7~","\033[8~","\033[5~","\033[6~","\033[A","\033[B","\033[D","\033[C", 0
|
46
|
+
};
|
47
|
+
static const char *rxvt_unicode_funcs[] = {
|
48
|
+
"\033[?1049h", "\033[r\033[?1049l", "\033[?25h", "\033[?25l", "\033[H\033[2J", "\033[m\033(B", "\033[4m", "\033[1m", "\033[5m", "\033[7m", "\033=", "\033>",
|
49
|
+
};
|
50
|
+
|
51
|
+
// linux
|
52
|
+
static const char *linux_keys[] = {
|
53
|
+
"\033[[A","\033[[B","\033[[C","\033[[D","\033[[E","\033[17~","\033[18~","\033[19~","\033[20~","\033[21~","\033[23~","\033[24~","\033[2~","\033[3~","\033[1~","\033[4~","\033[5~","\033[6~","\033[A","\033[B","\033[D","\033[C", 0
|
54
|
+
};
|
55
|
+
static const char *linux_funcs[] = {
|
56
|
+
"", "", "\033[?25h\033[?0c", "\033[?25l\033[?1c", "\033[H\033[J", "\033[0;10m", "\033[4m", "\033[1m", "\033[5m", "\033[7m", "", "",
|
57
|
+
};
|
58
|
+
|
59
|
+
// xterm
|
60
|
+
static const char *xterm_keys[] = {
|
61
|
+
"\033OP","\033OQ","\033OR","\033OS","\033[15~","\033[17~","\033[18~","\033[19~","\033[20~","\033[21~","\033[23~","\033[24~","\033[2~","\033[3~","\033OH","\033OF","\033[5~","\033[6~","\033OA","\033OB","\033OD","\033OC", 0
|
62
|
+
};
|
63
|
+
static const char *xterm_funcs[] = {
|
64
|
+
"\033[?1049h", "\033[?1049l", "\033[?12l\033[?25h", "\033[?25l", "\033[H\033[2J", "\033(B\033[m", "\033[4m", "\033[1m", "\033[5m", "\033[7m", "\033[?1h\033=", "\033[?1l\033>",
|
65
|
+
};
|
66
|
+
|
67
|
+
static struct term {
|
68
|
+
const char *name;
|
69
|
+
const char **keys;
|
70
|
+
const char **funcs;
|
71
|
+
} terms[] = {
|
72
|
+
{"rxvt-256color", rxvt_256color_keys, rxvt_256color_funcs},
|
73
|
+
{"Eterm", eterm_keys, eterm_funcs},
|
74
|
+
{"screen", screen_keys, screen_funcs},
|
75
|
+
{"rxvt-unicode", rxvt_unicode_keys, rxvt_unicode_funcs},
|
76
|
+
{"linux", linux_keys, linux_funcs},
|
77
|
+
{"xterm", xterm_keys, xterm_funcs},
|
78
|
+
{0, 0, 0},
|
79
|
+
};
|
80
|
+
|
81
|
+
static bool init_from_terminfo = false;
|
82
|
+
static const char **keys;
|
83
|
+
static const char **funcs;
|
84
|
+
|
85
|
+
static int try_compatible(const char *term, const char *name,
|
86
|
+
const char **tkeys, const char **tfuncs)
|
87
|
+
{
|
88
|
+
if (strstr(term, name)) {
|
89
|
+
keys = tkeys;
|
90
|
+
funcs = tfuncs;
|
91
|
+
return 0;
|
92
|
+
}
|
93
|
+
|
94
|
+
return EUNSUPPORTED_TERM;
|
95
|
+
}
|
96
|
+
|
97
|
+
static int init_term_builtin(void)
|
98
|
+
{
|
99
|
+
int i;
|
100
|
+
const char *term = getenv("TERM");
|
101
|
+
|
102
|
+
if (term) {
|
103
|
+
for (i = 0; terms[i].name; i++) {
|
104
|
+
if (!strcmp(terms[i].name, term)) {
|
105
|
+
keys = terms[i].keys;
|
106
|
+
funcs = terms[i].funcs;
|
107
|
+
return 0;
|
108
|
+
}
|
109
|
+
}
|
110
|
+
|
111
|
+
/* let's do some heuristic, maybe it's a compatible terminal */
|
112
|
+
if (try_compatible(term, "xterm", xterm_keys, xterm_funcs) == 0)
|
113
|
+
return 0;
|
114
|
+
if (try_compatible(term, "rxvt", rxvt_unicode_keys, rxvt_unicode_funcs) == 0)
|
115
|
+
return 0;
|
116
|
+
if (try_compatible(term, "linux", linux_keys, linux_funcs) == 0)
|
117
|
+
return 0;
|
118
|
+
if (try_compatible(term, "Eterm", eterm_keys, eterm_funcs) == 0)
|
119
|
+
return 0;
|
120
|
+
if (try_compatible(term, "screen", screen_keys, screen_funcs) == 0)
|
121
|
+
return 0;
|
122
|
+
/* let's assume that 'cygwin' is xterm compatible */
|
123
|
+
if (try_compatible(term, "cygwin", xterm_keys, xterm_funcs) == 0)
|
124
|
+
return 0;
|
125
|
+
}
|
126
|
+
|
127
|
+
return EUNSUPPORTED_TERM;
|
128
|
+
}
|
129
|
+
|
130
|
+
//----------------------------------------------------------------------
|
131
|
+
// terminfo
|
132
|
+
//----------------------------------------------------------------------
|
133
|
+
|
134
|
+
static char *read_file(const char *file) {
|
135
|
+
FILE *f = fopen(file, "rb");
|
136
|
+
if (!f)
|
137
|
+
return 0;
|
138
|
+
|
139
|
+
struct stat st;
|
140
|
+
if (fstat(fileno(f), &st) != 0) {
|
141
|
+
fclose(f);
|
142
|
+
return 0;
|
143
|
+
}
|
144
|
+
|
145
|
+
char *data = malloc(st.st_size);
|
146
|
+
if (!data) {
|
147
|
+
fclose(f);
|
148
|
+
return 0;
|
149
|
+
}
|
150
|
+
|
151
|
+
if (fread(data, 1, st.st_size, f) != (size_t)st.st_size) {
|
152
|
+
fclose(f);
|
153
|
+
free(data);
|
154
|
+
return 0;
|
155
|
+
}
|
156
|
+
|
157
|
+
fclose(f);
|
158
|
+
return data;
|
159
|
+
}
|
160
|
+
|
161
|
+
static char *terminfo_try_path(const char *path, const char *term) {
|
162
|
+
char tmp[4096];
|
163
|
+
snprintf(tmp, sizeof(tmp), "%s/%c/%s", path, term[0], term);
|
164
|
+
tmp[sizeof(tmp)-1] = '\0';
|
165
|
+
char *data = read_file(tmp);
|
166
|
+
if (data) {
|
167
|
+
return data;
|
168
|
+
}
|
169
|
+
|
170
|
+
// fallback to darwin specific dirs structure
|
171
|
+
snprintf(tmp, sizeof(tmp), "%s/%x/%s", path, term[0], term);
|
172
|
+
tmp[sizeof(tmp)-1] = '\0';
|
173
|
+
return read_file(tmp);
|
174
|
+
}
|
175
|
+
|
176
|
+
static char *load_terminfo(void) {
|
177
|
+
char tmp[4096];
|
178
|
+
const char *term = getenv("TERM");
|
179
|
+
if (!term) {
|
180
|
+
return 0;
|
181
|
+
}
|
182
|
+
|
183
|
+
// if TERMINFO is set, no other directory should be searched
|
184
|
+
const char *terminfo = getenv("TERMINFO");
|
185
|
+
if (terminfo) {
|
186
|
+
return terminfo_try_path(terminfo, term);
|
187
|
+
}
|
188
|
+
|
189
|
+
// next, consider ~/.terminfo
|
190
|
+
const char *home = getenv("HOME");
|
191
|
+
if (home) {
|
192
|
+
snprintf(tmp, sizeof(tmp), "%s/.terminfo", home);
|
193
|
+
tmp[sizeof(tmp)-1] = '\0';
|
194
|
+
char *data = terminfo_try_path(tmp, term);
|
195
|
+
if (data)
|
196
|
+
return data;
|
197
|
+
}
|
198
|
+
|
199
|
+
// next, TERMINFO_DIRS
|
200
|
+
const char *dirs = getenv("TERMINFO_DIRS");
|
201
|
+
if (dirs) {
|
202
|
+
snprintf(tmp, sizeof(tmp), "%s", dirs);
|
203
|
+
tmp[sizeof(tmp)-1] = '\0';
|
204
|
+
char *dir = strtok(tmp, ":");
|
205
|
+
while (dir) {
|
206
|
+
const char *cdir = dir;
|
207
|
+
if (strcmp(cdir, "") == 0) {
|
208
|
+
cdir = "/usr/share/terminfo";
|
209
|
+
}
|
210
|
+
char *data = terminfo_try_path(cdir, term);
|
211
|
+
if (data)
|
212
|
+
return data;
|
213
|
+
dir = strtok(0, ":");
|
214
|
+
}
|
215
|
+
}
|
216
|
+
|
217
|
+
// fallback to /usr/share/terminfo
|
218
|
+
return terminfo_try_path("/usr/share/terminfo", term);
|
219
|
+
}
|
220
|
+
|
221
|
+
#define TI_MAGIC 0432
|
222
|
+
#define TI_HEADER_LENGTH 12
|
223
|
+
#define TB_KEYS_NUM 22
|
224
|
+
|
225
|
+
static const char *terminfo_copy_string(char *data, int str, int table) {
|
226
|
+
const int16_t off = *(int16_t*)(data + str);
|
227
|
+
const char *src = data + table + off;
|
228
|
+
int len = strlen(src);
|
229
|
+
char *dst = malloc(len+1);
|
230
|
+
strcpy(dst, src);
|
231
|
+
return dst;
|
232
|
+
}
|
233
|
+
|
234
|
+
static const int16_t ti_funcs[] = {
|
235
|
+
28, 40, 16, 13, 5, 39, 36, 27, 26, 34, 89, 88,
|
236
|
+
};
|
237
|
+
|
238
|
+
static const int16_t ti_keys[] = {
|
239
|
+
66, 68 /* apparently not a typo; 67 is F10 for whatever reason */, 69,
|
240
|
+
70, 71, 72, 73, 74, 75, 67, 216, 217, 77, 59, 76, 164, 82, 81, 87, 61,
|
241
|
+
79, 83,
|
242
|
+
};
|
243
|
+
|
244
|
+
static int init_term(void) {
|
245
|
+
int i;
|
246
|
+
char *data = load_terminfo();
|
247
|
+
if (!data) {
|
248
|
+
init_from_terminfo = false;
|
249
|
+
return init_term_builtin();
|
250
|
+
}
|
251
|
+
|
252
|
+
int16_t *header = (int16_t*)data;
|
253
|
+
if ((header[1] + header[2]) % 2) {
|
254
|
+
// old quirk to align everything on word boundaries
|
255
|
+
header[2] += 1;
|
256
|
+
}
|
257
|
+
|
258
|
+
const int str_offset = TI_HEADER_LENGTH +
|
259
|
+
header[1] + header[2] + 2 * header[3];
|
260
|
+
const int table_offset = str_offset + 2 * header[4];
|
261
|
+
|
262
|
+
keys = malloc(sizeof(const char*) * (TB_KEYS_NUM+1));
|
263
|
+
for (i = 0; i < TB_KEYS_NUM; i++) {
|
264
|
+
keys[i] = terminfo_copy_string(data,
|
265
|
+
str_offset + 2 * ti_keys[i], table_offset);
|
266
|
+
}
|
267
|
+
keys[TB_KEYS_NUM] = 0;
|
268
|
+
|
269
|
+
funcs = malloc(sizeof(const char*) * T_FUNCS_NUM);
|
270
|
+
for (i = 0; i < T_FUNCS_NUM; i++) {
|
271
|
+
funcs[i] = terminfo_copy_string(data,
|
272
|
+
str_offset + 2 * ti_funcs[i], table_offset);
|
273
|
+
}
|
274
|
+
|
275
|
+
init_from_terminfo = true;
|
276
|
+
return 0;
|
277
|
+
}
|
278
|
+
|
279
|
+
static void shutdown_term(void) {
|
280
|
+
if (init_from_terminfo) {
|
281
|
+
int i;
|
282
|
+
for (i = 0; i < TB_KEYS_NUM; i++) {
|
283
|
+
free((void*)keys[i]);
|
284
|
+
}
|
285
|
+
for (i = 0; i < T_FUNCS_NUM; i++) {
|
286
|
+
free((void*)funcs[i]);
|
287
|
+
}
|
288
|
+
free(keys);
|
289
|
+
free(funcs);
|
290
|
+
}
|
291
|
+
}
|