-
Notifications
You must be signed in to change notification settings - Fork 0
/
io.c
141 lines (113 loc) · 2.46 KB
/
io.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
#include <stdarg.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <assert.h>
#include <stdio.h>
#include "ncurses.h"
#include "mem.h"
#include "io.h"
#include "bufmode.h"
#include "map.h"
#include "str.h"
#ifndef CHAR_BIT
# define CHAR_BIT 8
#endif
static struct fifo_ent
{
unsigned ch : CHAR_BIT * sizeof(char);
unsigned needs_map : 1;
} *io_fifo;
static size_t io_fifoused, io_fifosz;
static void io_fifo_realloc(size_t len)
{
if(io_fifoused + len > io_fifosz){
io_fifo = urealloc(io_fifo,
sizeof(*io_fifo) * (io_fifosz = io_fifoused + len));
}
io_fifoused += len;
}
static void io_fifo_ins(char c, bool need_map)
{
io_fifo_realloc(1);
memmove(io_fifo + 1, io_fifo, (io_fifoused - 1) * sizeof(*io_fifo));
io_fifo->ch = c;
io_fifo->needs_map = need_map;
}
static int io_fifo_pop(bool *need_map)
{
/* pull a char from the fifo */
int ret = io_fifo->ch;
*need_map = io_fifo->needs_map;
io_fifoused--;
if(io_fifoused)
memmove(io_fifo, io_fifo + 1, sizeof(*io_fifo) * io_fifoused);
return ret;
}
static const keymap_t *io_findmap(int ch, enum io mode_mask)
{
extern const keymap_t maps[];
for(const keymap_t *m = maps; m->to; m++)
if(m->mode & mode_mask && m->from == ch)
return m;
return NULL;
}
size_t io_bufsz(void)
{
return io_fifoused;
}
enum io bufmode_to_iomap(enum buf_mode bufmode)
{
if(bufmode & UI_INSERT_ANY)
return IO_MAPI;
if(bufmode & UI_VISUAL_ANY)
return IO_MAPV;
return IO_MAP;
}
int io_getch(enum io ty, bool *wasraw, bool domaps)
{
if(wasraw)
*wasraw = false;
int ch;
bool need_map = false;
if(io_fifoused)
ch = io_fifo_pop(&need_map);
else
ch = nc_getch(ty & IO_MAPRAW, wasraw);
/* don't run maps for raw keys */
if(domaps && (!wasraw || !*wasraw || need_map)){
const keymap_t *map = io_findmap(ch, ty & ~IO_MAPRAW);
if(map){
for(size_t i = strlen(map->to); i > 0; i--)
io_ungetch(map->to[i-1], false);
ch = io_fifo_pop(&need_map);
assert(!need_map); /* corresponds to the false above */
return ch;
}
}
return ch;
}
void io_ungetch(int ch, bool needmap)
{
io_fifo_ins(ch, needmap);
}
unsigned io_read_repeat(enum io io_mode)
{
unsigned repeat = 0;
bool raw;
int ch = io_getch(io_mode, &raw, true);
(void)raw;
if(isdigit(ch) && ch != '0'){
repeat = ch - '0';
/* more repeats */
for(;;){
ch = io_getch(io_mode, &raw, true);
if('0' <= ch && ch <= '9')
repeat = repeat * 10 + ch - '0';
else
break;
}
}
io_ungetch(ch, false);
return repeat;
}