bestliner 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +15 -0
- data/Gemfile +4 -0
- data/Gemfile.lock +25 -0
- data/LICENSE +36 -0
- data/README.md +65 -0
- data/Rakefile +13 -0
- data/bestliner.gemspec +24 -0
- data/ext/bestliner/Makefile +266 -0
- data/ext/bestliner/bestline.c +3578 -0
- data/ext/bestliner/bestline.h +39 -0
- data/ext/bestliner/bestliner.c +136 -0
- data/ext/bestliner/extconf.rb +4 -0
- data/lib/bestliner/version.rb +5 -0
- data/lib/bestliner.rb +131 -0
- metadata +88 -0
@@ -0,0 +1,3578 @@
|
|
1
|
+
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:4;tab-width:8;coding:utf-8 -*-│
|
2
|
+
│vi: set net ft=c ts=4 sts=4 sw=4 fenc=utf-8 :vi│
|
3
|
+
╞══════════════════════════════════════════════════════════════════════════════╡
|
4
|
+
│ │
|
5
|
+
│ Bestline ── Library for interactive pseudoteletypewriter command │
|
6
|
+
│ sessions using ANSI Standard X3.64 control sequences │
|
7
|
+
│ │
|
8
|
+
│ OVERVIEW │
|
9
|
+
│ │
|
10
|
+
│ Bestline is a fork of linenoise (a popular readline alternative) │
|
11
|
+
│ that fixes its bugs and adds the missing features while reducing │
|
12
|
+
│ binary footprint (surprisingly) by removing bloated dependencies │
|
13
|
+
│ which means you can finally have a permissively-licensed command │
|
14
|
+
│ prompt w/ a 30kb footprint that's nearly as good as gnu readline │
|
15
|
+
│ │
|
16
|
+
│ EXAMPLE │
|
17
|
+
│ │
|
18
|
+
│ main() { │
|
19
|
+
│ char *line; │
|
20
|
+
│ while ((line = bestlineWithHistory("IN> ", "foo"))) { │
|
21
|
+
│ fputs("OUT> ", stdout); │
|
22
|
+
│ fputs(line, stdout); │
|
23
|
+
│ fputs("\n", stdout); │
|
24
|
+
│ free(line); │
|
25
|
+
│ } │
|
26
|
+
│ } │
|
27
|
+
│ │
|
28
|
+
│ CHANGES │
|
29
|
+
│ │
|
30
|
+
│ - Remove bell │
|
31
|
+
│ - Add kill ring │
|
32
|
+
│ - Fix flickering │
|
33
|
+
│ - Add UTF-8 editing │
|
34
|
+
│ - Add CTRL-R search │
|
35
|
+
│ - Support unlimited lines │
|
36
|
+
│ - Add parentheses awareness │
|
37
|
+
│ - React to terminal resizing │
|
38
|
+
│ - Don't generate .data section │
|
39
|
+
│ - Support terminal flow control │
|
40
|
+
│ - Make history loading 10x faster │
|
41
|
+
│ - Make multiline mode the only mode │
|
42
|
+
│ - Accommodate O_NONBLOCK file descriptors │
|
43
|
+
│ - Restore raw mode on process foregrounding │
|
44
|
+
│ - Make source code compatible with C++ compilers │
|
45
|
+
│ - Fix corruption issues by using generalized parsing │
|
46
|
+
│ - Implement nearly all GNU readline editing shortcuts │
|
47
|
+
│ - Remove heavyweight dependencies like printf/sprintf │
|
48
|
+
│ - Remove ISIG→^C→EAGAIN hack and use ephemeral handlers │
|
49
|
+
│ - Support running on Windows in MinTTY or CMD.EXE on Win10+ │
|
50
|
+
│ - Support diacratics, русский, Ελληνικά, 中国人, 日本語, 한국인 │
|
51
|
+
│ │
|
52
|
+
│ SHORTCUTS │
|
53
|
+
│ │
|
54
|
+
│ CTRL-E END │
|
55
|
+
│ CTRL-A START │
|
56
|
+
│ CTRL-B BACK │
|
57
|
+
│ CTRL-F FORWARD │
|
58
|
+
│ CTRL-L CLEAR │
|
59
|
+
│ CTRL-H BACKSPACE │
|
60
|
+
│ CTRL-D DELETE │
|
61
|
+
│ CTRL-Y YANK │
|
62
|
+
│ CTRL-D EOF (IF EMPTY) │
|
63
|
+
│ CTRL-N NEXT HISTORY │
|
64
|
+
│ CTRL-P PREVIOUS HISTORY │
|
65
|
+
│ CTRL-R SEARCH HISTORY │
|
66
|
+
│ CTRL-G CANCEL SEARCH │
|
67
|
+
│ ALT-< BEGINNING OF HISTORY │
|
68
|
+
│ ALT-> END OF HISTORY │
|
69
|
+
│ ALT-F FORWARD WORD │
|
70
|
+
│ ALT-B BACKWARD WORD │
|
71
|
+
│ CTRL-ALT-F FORWARD EXPR │
|
72
|
+
│ CTRL-ALT-B BACKWARD EXPR │
|
73
|
+
│ ALT-RIGHT FORWARD EXPR │
|
74
|
+
│ ALT-LEFT BACKWARD EXPR │
|
75
|
+
│ ALT-SHIFT-B BARF EXPR │
|
76
|
+
│ ALT-SHIFT-S SLURP EXPR │
|
77
|
+
│ ALT-SHIFT-R RAISE EXPR │
|
78
|
+
│ CTRL-K KILL LINE FORWARDS │
|
79
|
+
│ CTRL-U KILL LINE BACKWARDS │
|
80
|
+
│ ALT-H KILL WORD BACKWARDS │
|
81
|
+
│ CTRL-W KILL WORD BACKWARDS │
|
82
|
+
│ CTRL-ALT-H KILL WORD BACKWARDS │
|
83
|
+
│ ALT-D KILL WORD FORWARDS │
|
84
|
+
│ ALT-Y ROTATE KILL RING AND YANK AGAIN │
|
85
|
+
│ ALT-\ SQUEEZE ADJACENT WHITESPACE │
|
86
|
+
│ CTRL-T TRANSPOSE │
|
87
|
+
│ ALT-T TRANSPOSE WORD │
|
88
|
+
│ ALT-U UPPERCASE WORD │
|
89
|
+
│ ALT-L LOWERCASE WORD │
|
90
|
+
│ ALT-C CAPITALIZE WORD │
|
91
|
+
│ CTRL-Z SUSPEND PROCESS │
|
92
|
+
│ CTRL-\ QUIT PROCESS │
|
93
|
+
│ CTRL-S PAUSE OUTPUT │
|
94
|
+
│ CTRL-Q UNPAUSE OUTPUT (IF PAUSED) │
|
95
|
+
│ CTRL-Q ESCAPED INSERT │
|
96
|
+
│ CTRL-SPACE SET MARK │
|
97
|
+
│ CTRL-X CTRL-X GOTO MARK │
|
98
|
+
│ PROTIP REMAP CAPS LOCK TO CTRL │
|
99
|
+
│ │
|
100
|
+
╞══════════════════════════════════════════════════════════════════════════════╡
|
101
|
+
│ │
|
102
|
+
│ Copyright 2018-2021 Justine Tunney <jtunney@gmail.com> │
|
103
|
+
│ Copyright 2010-2016 Salvatore Sanfilippo <antirez@gmail.com> │
|
104
|
+
│ Copyright 2010-2013 Pieter Noordhuis <pcnoordhuis@gmail.com> │
|
105
|
+
│ │
|
106
|
+
│ All rights reserved. │
|
107
|
+
│ │
|
108
|
+
│ Redistribution and use in source and binary forms, with or without │
|
109
|
+
│ modification, are permitted provided that the following conditions are │
|
110
|
+
│ met: │
|
111
|
+
│ │
|
112
|
+
│ * Redistributions of source code must retain the above copyright │
|
113
|
+
│ notice, this list of conditions and the following disclaimer. │
|
114
|
+
│ │
|
115
|
+
│ * Redistributions in binary form must reproduce the above copyright │
|
116
|
+
│ notice, this list of conditions and the following disclaimer in the │
|
117
|
+
│ documentation and/or other materials provided with the distribution. │
|
118
|
+
│ │
|
119
|
+
│ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS │
|
120
|
+
│ "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT │
|
121
|
+
│ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR │
|
122
|
+
│ A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT │
|
123
|
+
│ HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, │
|
124
|
+
│ SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT │
|
125
|
+
│ LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, │
|
126
|
+
│ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY │
|
127
|
+
│ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT │
|
128
|
+
│ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE │
|
129
|
+
│ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. │
|
130
|
+
│ │
|
131
|
+
╚─────────────────────────────────────────────────────────────────────────────*/
|
132
|
+
#include "bestline.h"
|
133
|
+
|
134
|
+
#ifndef __COSMOPOLITAN__
|
135
|
+
#define _POSIX_C_SOURCE 1 /* so GCC builds in ANSI mode */
|
136
|
+
#define _XOPEN_SOURCE 700 /* so GCC builds in ANSI mode */
|
137
|
+
#define _DARWIN_C_SOURCE 1 /* so SIGWINCH / IUTF8 on XNU */
|
138
|
+
#include <termios.h>
|
139
|
+
#include <unistd.h>
|
140
|
+
#include <stdlib.h>
|
141
|
+
#include <stdio.h>
|
142
|
+
#include <errno.h>
|
143
|
+
#include <string.h>
|
144
|
+
#include <stdlib.h>
|
145
|
+
#include <ctype.h>
|
146
|
+
#include <sys/stat.h>
|
147
|
+
#include <sys/types.h>
|
148
|
+
#include <sys/ioctl.h>
|
149
|
+
#include <sys/mman.h>
|
150
|
+
#include <unistd.h>
|
151
|
+
#include <setjmp.h>
|
152
|
+
#include <poll.h>
|
153
|
+
#include <assert.h>
|
154
|
+
#include <signal.h>
|
155
|
+
#include <fcntl.h>
|
156
|
+
#include <limits.h>
|
157
|
+
#ifndef SIGWINCH
|
158
|
+
#define SIGWINCH 28 /* GNU/Systemd + XNU + FreeBSD + NetBSD + OpenBSD */
|
159
|
+
#endif
|
160
|
+
#ifndef IUTF8
|
161
|
+
#define IUTF8 0
|
162
|
+
#endif
|
163
|
+
#endif
|
164
|
+
|
165
|
+
__asm__(".ident\t\"\\n\\n\
|
166
|
+
Bestline (BSD-2)\\n\
|
167
|
+
Copyright 2018-2020 Justine Tunney <jtunney@gmail.com>\\n\
|
168
|
+
Copyright 2010-2016 Salvatore Sanfilippo <antirez@gmail.com>\\n\
|
169
|
+
Copyright 2010-2013 Pieter Noordhuis <pcnoordhuis@gmail.com>\"");
|
170
|
+
|
171
|
+
#ifndef BESTLINE_MAX_RING
|
172
|
+
#define BESTLINE_MAX_RING 8
|
173
|
+
#endif
|
174
|
+
|
175
|
+
#ifndef BESTLINE_MAX_HISTORY
|
176
|
+
#define BESTLINE_MAX_HISTORY 1024
|
177
|
+
#endif
|
178
|
+
|
179
|
+
#define BESTLINE_HISTORY_FIRST +BESTLINE_MAX_HISTORY
|
180
|
+
#define BESTLINE_HISTORY_PREV +1
|
181
|
+
#define BESTLINE_HISTORY_NEXT -1
|
182
|
+
#define BESTLINE_HISTORY_LAST -BESTLINE_MAX_HISTORY
|
183
|
+
|
184
|
+
#define Ctrl(C) ((C) ^ 0100)
|
185
|
+
#define Min(X, Y) ((Y) > (X) ? (X) : (Y))
|
186
|
+
#define Max(X, Y) ((Y) < (X) ? (X) : (Y))
|
187
|
+
#define Case(X, Y) case X: Y; break
|
188
|
+
#define Read16le(X) \
|
189
|
+
((255 & (X)[0]) << 000 | \
|
190
|
+
(255 & (X)[1]) << 010)
|
191
|
+
#define Read32le(X) \
|
192
|
+
((unsigned)(255 & (X)[0]) << 000 | \
|
193
|
+
(unsigned)(255 & (X)[1]) << 010 | \
|
194
|
+
(unsigned)(255 & (X)[2]) << 020 | \
|
195
|
+
(unsigned)(255 & (X)[3]) << 030)
|
196
|
+
|
197
|
+
struct abuf {
|
198
|
+
char *b;
|
199
|
+
unsigned len;
|
200
|
+
unsigned cap;
|
201
|
+
};
|
202
|
+
|
203
|
+
struct rune {
|
204
|
+
unsigned c;
|
205
|
+
unsigned n;
|
206
|
+
};
|
207
|
+
|
208
|
+
struct bestlineRing {
|
209
|
+
unsigned i;
|
210
|
+
char *p[BESTLINE_MAX_RING];
|
211
|
+
};
|
212
|
+
|
213
|
+
/* The bestlineState structure represents the state during line editing.
|
214
|
+
* We pass this state to functions implementing specific editing
|
215
|
+
* functionalities. */
|
216
|
+
struct bestlineState {
|
217
|
+
int ifd; /* terminal stdin file descriptor */
|
218
|
+
int ofd; /* terminal stdout file descriptor */
|
219
|
+
struct winsize ws; /* rows and columns in terminal */
|
220
|
+
char *buf; /* edited line buffer */
|
221
|
+
const char *prompt; /* prompt to display */
|
222
|
+
int hindex; /* history index */
|
223
|
+
int rows; /* rows being used */
|
224
|
+
int oldpos; /* previous refresh cursor position */
|
225
|
+
unsigned buflen; /* edited line buffer size */
|
226
|
+
unsigned pos; /* current buffer index */
|
227
|
+
unsigned len; /* current edited line length */
|
228
|
+
unsigned mark; /* saved cursor position */
|
229
|
+
unsigned yi, yj; /* boundaries of last yank */
|
230
|
+
char seq[2][16]; /* keystroke history for yanking code */
|
231
|
+
char final; /* set to true on last update */
|
232
|
+
char dirty; /* if an update was squashed */
|
233
|
+
};
|
234
|
+
|
235
|
+
static const char *const kUnsupported[] = {"dumb","cons25","emacs"};
|
236
|
+
|
237
|
+
static int gotint;
|
238
|
+
static int gotcont;
|
239
|
+
static int gotwinch;
|
240
|
+
static signed char rawmode;
|
241
|
+
static char maskmode;
|
242
|
+
static char ispaused;
|
243
|
+
static char iscapital;
|
244
|
+
static unsigned historylen;
|
245
|
+
static struct bestlineRing ring;
|
246
|
+
static struct sigaction orig_cont;
|
247
|
+
static struct sigaction orig_winch;
|
248
|
+
static struct termios orig_termios;
|
249
|
+
static char *history[BESTLINE_MAX_HISTORY];
|
250
|
+
static bestlineXlatCallback *xlatCallback;
|
251
|
+
static bestlineHintsCallback *hintsCallback;
|
252
|
+
static bestlineFreeHintsCallback *freeHintsCallback;
|
253
|
+
static bestlineCompletionCallback *completionCallback;
|
254
|
+
|
255
|
+
static void bestlineAtExit(void);
|
256
|
+
static void bestlineRefreshLine(struct bestlineState *);
|
257
|
+
|
258
|
+
static void bestlineOnInt(int sig) {
|
259
|
+
gotint = sig;
|
260
|
+
}
|
261
|
+
|
262
|
+
static void bestlineOnCont(int sig) {
|
263
|
+
gotcont = sig;
|
264
|
+
}
|
265
|
+
|
266
|
+
static void bestlineOnWinch(int sig) {
|
267
|
+
gotwinch = sig;
|
268
|
+
}
|
269
|
+
|
270
|
+
static char IsControl(unsigned c) {
|
271
|
+
return c <= 0x1F || (0x7F <= c && c <= 0x9F);
|
272
|
+
}
|
273
|
+
|
274
|
+
static int GetMonospaceCharacterWidth(unsigned c) {
|
275
|
+
return !IsControl(c)
|
276
|
+
+ (c >= 0x1100 &&
|
277
|
+
(c <= 0x115f || c == 0x2329 || c == 0x232a ||
|
278
|
+
(c >= 0x2e80 && c <= 0xa4cf && c != 0x303f) ||
|
279
|
+
(c >= 0xac00 && c <= 0xd7a3) ||
|
280
|
+
(c >= 0xf900 && c <= 0xfaff) ||
|
281
|
+
(c >= 0xfe10 && c <= 0xfe19) ||
|
282
|
+
(c >= 0xfe30 && c <= 0xfe6f) ||
|
283
|
+
(c >= 0xff00 && c <= 0xff60) ||
|
284
|
+
(c >= 0xffe0 && c <= 0xffe6) ||
|
285
|
+
(c >= 0x20000 && c <= 0x2fffd) ||
|
286
|
+
(c >= 0x30000 && c <= 0x3fffd)));
|
287
|
+
}
|
288
|
+
|
289
|
+
/**
|
290
|
+
* Returns nonzero if 𝑐 isn't alphanumeric.
|
291
|
+
*
|
292
|
+
* Line reading interfaces generally define this operation as UNICODE
|
293
|
+
* characters that aren't in the letter category (Lu, Ll, Lt, Lm, Lo)
|
294
|
+
* and aren't in the number categorie (Nd, Nl, No). We also add a few
|
295
|
+
* other things like blocks and emoji (So).
|
296
|
+
*/
|
297
|
+
char bestlineIsSeparator(unsigned c) {
|
298
|
+
int m, l, r, n;
|
299
|
+
if (c < 0200) {
|
300
|
+
return !(('0' <= c && c <= '9') ||
|
301
|
+
('A' <= c && c <= 'Z') ||
|
302
|
+
('a' <= c && c <= 'z'));
|
303
|
+
}
|
304
|
+
if (c <= 0xffff) {
|
305
|
+
static const unsigned short kGlyphs[][2] = {
|
306
|
+
{0x00aa, 0x00aa}, /* 1x English */
|
307
|
+
{0x00b2, 0x00b3}, /* 2x English Arabic */
|
308
|
+
{0x00b5, 0x00b5}, /* 1x Greek */
|
309
|
+
{0x00b9, 0x00ba}, /* 2x English Arabic */
|
310
|
+
{0x00bc, 0x00be}, /* 3x Vulgar English Arabic */
|
311
|
+
{0x00c0, 0x00d6}, /* 23x Watin */
|
312
|
+
{0x00d8, 0x00f6}, /* 31x Watin */
|
313
|
+
{0x0100, 0x02c1}, /* 450x Watin-AB,IPA,Spacemod */
|
314
|
+
{0x02c6, 0x02d1}, /* 12x Spacemod */
|
315
|
+
{0x02e0, 0x02e4}, /* 5x Spacemod */
|
316
|
+
{0x02ec, 0x02ec}, /* 1x Spacemod */
|
317
|
+
{0x02ee, 0x02ee}, /* 1x Spacemod */
|
318
|
+
{0x0370, 0x0374}, /* 5x Greek */
|
319
|
+
{0x0376, 0x0377}, /* 2x Greek */
|
320
|
+
{0x037a, 0x037d}, /* 4x Greek */
|
321
|
+
{0x037f, 0x037f}, /* 1x Greek */
|
322
|
+
{0x0386, 0x0386}, /* 1x Greek */
|
323
|
+
{0x0388, 0x038a}, /* 3x Greek */
|
324
|
+
{0x038c, 0x038c}, /* 1x Greek */
|
325
|
+
{0x038e, 0x03a1}, /* 20x Greek */
|
326
|
+
{0x03a3, 0x03f5}, /* 83x Greek */
|
327
|
+
{0x03f7, 0x0481}, /* 139x Greek */
|
328
|
+
{0x048a, 0x052f}, /* 166x Cyrillic */
|
329
|
+
{0x0531, 0x0556}, /* 38x Armenian */
|
330
|
+
{0x0560, 0x0588}, /* 41x Armenian */
|
331
|
+
{0x05d0, 0x05ea}, /* 27x Hebrew */
|
332
|
+
{0x0620, 0x064a}, /* 43x Arabic */
|
333
|
+
{0x0660, 0x0669}, /* 10x Arabic */
|
334
|
+
{0x0671, 0x06d3}, /* 99x Arabic */
|
335
|
+
{0x06ee, 0x06fc}, /* 15x Arabic */
|
336
|
+
{0x0712, 0x072f}, /* 30x Syriac */
|
337
|
+
{0x074d, 0x07a5}, /* 89x Syriac,Arabic2,Thaana */
|
338
|
+
{0x07c0, 0x07ea}, /* 43x NKo */
|
339
|
+
{0x0800, 0x0815}, /* 22x Samaritan */
|
340
|
+
{0x0840, 0x0858}, /* 25x Mandaic */
|
341
|
+
{0x0904, 0x0939}, /* 54x Devanagari */
|
342
|
+
{0x0993, 0x09a8}, /* 22x Bengali */
|
343
|
+
{0x09e6, 0x09f1}, /* 12x Bengali */
|
344
|
+
{0x0a13, 0x0a28}, /* 22x Gurmukhi */
|
345
|
+
{0x0a66, 0x0a6f}, /* 10x Gurmukhi */
|
346
|
+
{0x0a93, 0x0aa8}, /* 22x Gujarati */
|
347
|
+
{0x0b13, 0x0b28}, /* 22x Oriya */
|
348
|
+
{0x0c92, 0x0ca8}, /* 23x Kannada */
|
349
|
+
{0x0caa, 0x0cb3}, /* 10x Kannada */
|
350
|
+
{0x0ce6, 0x0cef}, /* 10x Kannada */
|
351
|
+
{0x0d12, 0x0d3a}, /* 41x Malayalam */
|
352
|
+
{0x0d85, 0x0d96}, /* 18x Sinhala */
|
353
|
+
{0x0d9a, 0x0db1}, /* 24x Sinhala */
|
354
|
+
{0x0de6, 0x0def}, /* 10x Sinhala */
|
355
|
+
{0x0e01, 0x0e30}, /* 48x Thai */
|
356
|
+
{0x0e8c, 0x0ea3}, /* 24x Lao */
|
357
|
+
{0x0f20, 0x0f33}, /* 20x Tibetan */
|
358
|
+
{0x0f49, 0x0f6c}, /* 36x Tibetan */
|
359
|
+
{0x109e, 0x10c5}, /* 40x Myanmar,Georgian */
|
360
|
+
{0x10d0, 0x10fa}, /* 43x Georgian */
|
361
|
+
{0x10fc, 0x1248}, /* 333x Georgian,Hangul,Ethiopic */
|
362
|
+
{0x13a0, 0x13f5}, /* 86x Cherokee */
|
363
|
+
{0x1401, 0x166d}, /* 621x Aboriginal */
|
364
|
+
{0x16a0, 0x16ea}, /* 75x Runic */
|
365
|
+
{0x1700, 0x170c}, /* 13x Tagalog */
|
366
|
+
{0x1780, 0x17b3}, /* 52x Khmer */
|
367
|
+
{0x1820, 0x1878}, /* 89x Mongolian */
|
368
|
+
{0x1a00, 0x1a16}, /* 23x Buginese */
|
369
|
+
{0x1a20, 0x1a54}, /* 53x Tai Tham */
|
370
|
+
{0x1a80, 0x1a89}, /* 10x Tai Tham */
|
371
|
+
{0x1a90, 0x1a99}, /* 10x Tai Tham */
|
372
|
+
{0x1b05, 0x1b33}, /* 47x Balinese */
|
373
|
+
{0x1b50, 0x1b59}, /* 10x Balinese */
|
374
|
+
{0x1b83, 0x1ba0}, /* 30x Sundanese */
|
375
|
+
{0x1bae, 0x1be5}, /* 56x Sundanese */
|
376
|
+
{0x1c90, 0x1cba}, /* 43x Georgian2 */
|
377
|
+
{0x1cbd, 0x1cbf}, /* 3x Georgian2 */
|
378
|
+
{0x1e00, 0x1f15}, /* 278x Watin-C,Greek2 */
|
379
|
+
{0x2070, 0x2071}, /* 2x Supersub */
|
380
|
+
{0x2074, 0x2079}, /* 6x Supersub */
|
381
|
+
{0x207f, 0x2089}, /* 11x Supersub */
|
382
|
+
{0x2090, 0x209c}, /* 13x Supersub */
|
383
|
+
{0x2100, 0x2117}, /* 24x Letterlike */
|
384
|
+
{0x2119, 0x213f}, /* 39x Letterlike */
|
385
|
+
{0x2145, 0x214a}, /* 6x Letterlike */
|
386
|
+
{0x214c, 0x218b}, /* 64x Letterlike,Numbery */
|
387
|
+
{0x21af, 0x21cd}, /* 31x Arrows */
|
388
|
+
{0x21d5, 0x21f3}, /* 31x Arrows */
|
389
|
+
{0x230c, 0x231f}, /* 20x Technical */
|
390
|
+
{0x232b, 0x237b}, /* 81x Technical */
|
391
|
+
{0x237d, 0x239a}, /* 30x Technical */
|
392
|
+
{0x23b4, 0x23db}, /* 40x Technical */
|
393
|
+
{0x23e2, 0x2426}, /* 69x Technical,ControlPictures */
|
394
|
+
{0x2460, 0x25b6}, /* 343x Enclosed,Boxes,Blocks,Shapes */
|
395
|
+
{0x25c2, 0x25f7}, /* 54x Shapes */
|
396
|
+
{0x2600, 0x266e}, /* 111x Symbols */
|
397
|
+
{0x2670, 0x2767}, /* 248x Symbols,Dingbats */
|
398
|
+
{0x2776, 0x27bf}, /* 74x Dingbats */
|
399
|
+
{0x2800, 0x28ff}, /* 256x Braille */
|
400
|
+
{0x2c00, 0x2c2e}, /* 47x Glagolitic */
|
401
|
+
{0x2c30, 0x2c5e}, /* 47x Glagolitic */
|
402
|
+
{0x2c60, 0x2ce4}, /* 133x Watin-D */
|
403
|
+
{0x2d00, 0x2d25}, /* 38x Georgian2 */
|
404
|
+
{0x2d30, 0x2d67}, /* 56x Tifinagh */
|
405
|
+
{0x2d80, 0x2d96}, /* 23x Ethiopic2 */
|
406
|
+
{0x2e2f, 0x2e2f}, /* 1x Punctuation2 */
|
407
|
+
{0x3005, 0x3007}, /* 3x CJK Symbols & Punctuation */
|
408
|
+
{0x3021, 0x3029}, /* 9x CJK Symbols & Punctuation */
|
409
|
+
{0x3031, 0x3035}, /* 5x CJK Symbols & Punctuation */
|
410
|
+
{0x3038, 0x303c}, /* 5x CJK Symbols & Punctuation */
|
411
|
+
{0x3041, 0x3096}, /* 86x Hiragana */
|
412
|
+
{0x30a1, 0x30fa}, /* 90x Katakana */
|
413
|
+
{0x3105, 0x312f}, /* 43x Bopomofo */
|
414
|
+
{0x3131, 0x318e}, /* 94x Hangul Compatibility Jamo */
|
415
|
+
{0x31a0, 0x31ba}, /* 27x Bopomofo Extended */
|
416
|
+
{0x31f0, 0x31ff}, /* 16x Katakana Phonetic Extensions */
|
417
|
+
{0x3220, 0x3229}, /* 10x Enclosed CJK Letters & Months */
|
418
|
+
{0x3248, 0x324f}, /* 8x Enclosed CJK Letters & Months */
|
419
|
+
{0x3251, 0x325f}, /* 15x Enclosed CJK Letters & Months */
|
420
|
+
{0x3280, 0x3289}, /* 10x Enclosed CJK Letters & Months */
|
421
|
+
{0x32b1, 0x32bf}, /* 15x Enclosed CJK Letters & Months */
|
422
|
+
{0x3400, 0x4db5}, /* 6582x CJK Unified Ideographs Extension A */
|
423
|
+
{0x4dc0, 0x9fef}, /* 21040x Yijing Hexagram, CJK Unified Ideographs */
|
424
|
+
{0xa000, 0xa48c}, /* 1165x Yi Syllables */
|
425
|
+
{0xa4d0, 0xa4fd}, /* 46x Lisu */
|
426
|
+
{0xa500, 0xa60c}, /* 269x Vai */
|
427
|
+
{0xa610, 0xa62b}, /* 28x Vai */
|
428
|
+
{0xa6a0, 0xa6ef}, /* 80x Bamum */
|
429
|
+
{0xa80c, 0xa822}, /* 23x Syloti Nagri */
|
430
|
+
{0xa840, 0xa873}, /* 52x Phags-pa */
|
431
|
+
{0xa882, 0xa8b3}, /* 50x Saurashtra */
|
432
|
+
{0xa8d0, 0xa8d9}, /* 10x Saurashtra */
|
433
|
+
{0xa900, 0xa925}, /* 38x Kayah Li */
|
434
|
+
{0xa930, 0xa946}, /* 23x Rejang */
|
435
|
+
{0xa960, 0xa97c}, /* 29x Hangul Jamo Extended-A */
|
436
|
+
{0xa984, 0xa9b2}, /* 47x Javanese */
|
437
|
+
{0xa9cf, 0xa9d9}, /* 11x Javanese */
|
438
|
+
{0xaa00, 0xaa28}, /* 41x Cham */
|
439
|
+
{0xaa50, 0xaa59}, /* 10x Cham */
|
440
|
+
{0xabf0, 0xabf9}, /* 10x Meetei Mayek */
|
441
|
+
{0xac00, 0xd7a3}, /* 11172x Hangul Syllables */
|
442
|
+
{0xf900, 0xfa6d}, /* 366x CJK Compatibility Ideographs */
|
443
|
+
{0xfa70, 0xfad9}, /* 106x CJK Compatibility Ideographs */
|
444
|
+
{0xfb1f, 0xfb28}, /* 10x Alphabetic Presentation Forms */
|
445
|
+
{0xfb2a, 0xfb36}, /* 13x Alphabetic Presentation Forms */
|
446
|
+
{0xfb46, 0xfbb1}, /* 108x Alphabetic Presentation Forms */
|
447
|
+
{0xfbd3, 0xfd3d}, /* 363x Arabic Presentation Forms-A */
|
448
|
+
{0xfe76, 0xfefc}, /* 135x Arabic Presentation Forms-B */
|
449
|
+
{0xff10, 0xff19}, /* 10x Dubs */
|
450
|
+
{0xff21, 0xff3a}, /* 26x Dubs */
|
451
|
+
{0xff41, 0xff5a}, /* 26x Dubs */
|
452
|
+
{0xff66, 0xffbe}, /* 89x Dubs */
|
453
|
+
{0xffc2, 0xffc7}, /* 6x Dubs */
|
454
|
+
{0xffca, 0xffcf}, /* 6x Dubs */
|
455
|
+
{0xffd2, 0xffd7}, /* 6x Dubs */
|
456
|
+
{0xffda, 0xffdc}, /* 3x Dubs */
|
457
|
+
};
|
458
|
+
l = 0;
|
459
|
+
r = n = sizeof(kGlyphs) / sizeof(kGlyphs[0]);
|
460
|
+
while (l < r) {
|
461
|
+
m = (l + r) >> 1;
|
462
|
+
if (kGlyphs[m][1] < c) {
|
463
|
+
l = m + 1;
|
464
|
+
} else {
|
465
|
+
r = m;
|
466
|
+
}
|
467
|
+
}
|
468
|
+
return !(l < n && kGlyphs[l][0] <= c && c <= kGlyphs[l][1]);
|
469
|
+
} else {
|
470
|
+
static const unsigned kAstralGlyphs[][2] = {
|
471
|
+
{0x10107, 0x10133}, /* 45x Aegean */
|
472
|
+
{0x10140, 0x10178}, /* 57x Ancient Greek Numbers */
|
473
|
+
{0x1018a, 0x1018b}, /* 2x Ancient Greek Numbers */
|
474
|
+
{0x10280, 0x1029c}, /* 29x Lycian */
|
475
|
+
{0x102a0, 0x102d0}, /* 49x Carian */
|
476
|
+
{0x102e1, 0x102fb}, /* 27x Coptic Epact Numbers */
|
477
|
+
{0x10300, 0x10323}, /* 36x Old Italic */
|
478
|
+
{0x1032d, 0x1034a}, /* 30x Old Italic, Gothic */
|
479
|
+
{0x10350, 0x10375}, /* 38x Old Permic */
|
480
|
+
{0x10380, 0x1039d}, /* 30x Ugaritic */
|
481
|
+
{0x103a0, 0x103c3}, /* 36x Old Persian */
|
482
|
+
{0x103c8, 0x103cf}, /* 8x Old Persian */
|
483
|
+
{0x103d1, 0x103d5}, /* 5x Old Persian */
|
484
|
+
{0x10400, 0x1049d}, /* 158x Deseret, Shavian, Osmanya */
|
485
|
+
{0x104b0, 0x104d3}, /* 36x Osage */
|
486
|
+
{0x104d8, 0x104fb}, /* 36x Osage */
|
487
|
+
{0x10500, 0x10527}, /* 40x Elbasan */
|
488
|
+
{0x10530, 0x10563}, /* 52x Caucasian Albanian */
|
489
|
+
{0x10600, 0x10736}, /* 311x Linear A */
|
490
|
+
{0x10800, 0x10805}, /* 6x Cypriot Syllabary */
|
491
|
+
{0x1080a, 0x10835}, /* 44x Cypriot Syllabary */
|
492
|
+
{0x10837, 0x10838}, /* 2x Cypriot Syllabary */
|
493
|
+
{0x1083f, 0x1089e}, /* 86x Cypriot,ImperialAramaic,Palmyrene,Nabataean */
|
494
|
+
{0x108e0, 0x108f2}, /* 19x Hatran */
|
495
|
+
{0x108f4, 0x108f5}, /* 2x Hatran */
|
496
|
+
{0x108fb, 0x1091b}, /* 33x Hatran */
|
497
|
+
{0x10920, 0x10939}, /* 26x Lydian */
|
498
|
+
{0x10980, 0x109b7}, /* 56x Meroitic Hieroglyphs */
|
499
|
+
{0x109bc, 0x109cf}, /* 20x Meroitic Cursive */
|
500
|
+
{0x109d2, 0x10a00}, /* 47x Meroitic Cursive */
|
501
|
+
{0x10a10, 0x10a13}, /* 4x Kharoshthi */
|
502
|
+
{0x10a15, 0x10a17}, /* 3x Kharoshthi */
|
503
|
+
{0x10a19, 0x10a35}, /* 29x Kharoshthi */
|
504
|
+
{0x10a40, 0x10a48}, /* 9x Kharoshthi */
|
505
|
+
{0x10a60, 0x10a7e}, /* 31x Old South Arabian */
|
506
|
+
{0x10a80, 0x10a9f}, /* 32x Old North Arabian */
|
507
|
+
{0x10ac0, 0x10ac7}, /* 8x Manichaean */
|
508
|
+
{0x10ac9, 0x10ae4}, /* 28x Manichaean */
|
509
|
+
{0x10aeb, 0x10aef}, /* 5x Manichaean */
|
510
|
+
{0x10b00, 0x10b35}, /* 54x Avestan */
|
511
|
+
{0x10b40, 0x10b55}, /* 22x Inscriptional Parthian */
|
512
|
+
{0x10b58, 0x10b72}, /* 27x Inscriptional Parthian and Pahlavi */
|
513
|
+
{0x10b78, 0x10b91}, /* 26x Inscriptional Pahlavi, Psalter Pahlavi */
|
514
|
+
{0x10c00, 0x10c48}, /* 73x Old Turkic */
|
515
|
+
{0x10c80, 0x10cb2}, /* 51x Old Hungarian */
|
516
|
+
{0x10cc0, 0x10cf2}, /* 51x Old Hungarian */
|
517
|
+
{0x10cfa, 0x10d23}, /* 42x Old Hungarian, Hanifi Rohingya */
|
518
|
+
{0x10d30, 0x10d39}, /* 10x Hanifi Rohingya */
|
519
|
+
{0x10e60, 0x10e7e}, /* 31x Rumi Numeral Symbols */
|
520
|
+
{0x10f00, 0x10f27}, /* 40x Old Sogdian */
|
521
|
+
{0x10f30, 0x10f45}, /* 22x Sogdian */
|
522
|
+
{0x10f51, 0x10f54}, /* 4x Sogdian */
|
523
|
+
{0x10fe0, 0x10ff6}, /* 23x Elymaic */
|
524
|
+
{0x11003, 0x11037}, /* 53x Brahmi */
|
525
|
+
{0x11052, 0x1106f}, /* 30x Brahmi */
|
526
|
+
{0x11083, 0x110af}, /* 45x Kaithi */
|
527
|
+
{0x110d0, 0x110e8}, /* 25x Sora Sompeng */
|
528
|
+
{0x110f0, 0x110f9}, /* 10x Sora Sompeng */
|
529
|
+
{0x11103, 0x11126}, /* 36x Chakma */
|
530
|
+
{0x11136, 0x1113f}, /* 10x Chakma */
|
531
|
+
{0x11144, 0x11144}, /* 1x Chakma */
|
532
|
+
{0x11150, 0x11172}, /* 35x Mahajani */
|
533
|
+
{0x11176, 0x11176}, /* 1x Mahajani */
|
534
|
+
{0x11183, 0x111b2}, /* 48x Sharada */
|
535
|
+
{0x111c1, 0x111c4}, /* 4x Sharada */
|
536
|
+
{0x111d0, 0x111da}, /* 11x Sharada */
|
537
|
+
{0x111dc, 0x111dc}, /* 1x Sharada */
|
538
|
+
{0x111e1, 0x111f4}, /* 20x Sinhala Archaic Numbers */
|
539
|
+
{0x11200, 0x11211}, /* 18x Khojki */
|
540
|
+
{0x11213, 0x1122b}, /* 25x Khojki */
|
541
|
+
{0x11280, 0x11286}, /* 7x Multani */
|
542
|
+
{0x11288, 0x11288}, /* 1x Multani */
|
543
|
+
{0x1128a, 0x1128d}, /* 4x Multani */
|
544
|
+
{0x1128f, 0x1129d}, /* 15x Multani */
|
545
|
+
{0x1129f, 0x112a8}, /* 10x Multani */
|
546
|
+
{0x112b0, 0x112de}, /* 47x Khudawadi */
|
547
|
+
{0x112f0, 0x112f9}, /* 10x Khudawadi */
|
548
|
+
{0x11305, 0x1130c}, /* 8x Grantha */
|
549
|
+
{0x1130f, 0x11310}, /* 2x Grantha */
|
550
|
+
{0x11313, 0x11328}, /* 22x Grantha */
|
551
|
+
{0x1132a, 0x11330}, /* 7x Grantha */
|
552
|
+
{0x11332, 0x11333}, /* 2x Grantha */
|
553
|
+
{0x11335, 0x11339}, /* 5x Grantha */
|
554
|
+
{0x1133d, 0x1133d}, /* 1x Grantha */
|
555
|
+
{0x11350, 0x11350}, /* 1x Grantha */
|
556
|
+
{0x1135d, 0x11361}, /* 5x Grantha */
|
557
|
+
{0x11400, 0x11434}, /* 53x Newa */
|
558
|
+
{0x11447, 0x1144a}, /* 4x Newa */
|
559
|
+
{0x11450, 0x11459}, /* 10x Newa */
|
560
|
+
{0x1145f, 0x1145f}, /* 1x Newa */
|
561
|
+
{0x11480, 0x114af}, /* 48x Tirhuta */
|
562
|
+
{0x114c4, 0x114c5}, /* 2x Tirhuta */
|
563
|
+
{0x114c7, 0x114c7}, /* 1x Tirhuta */
|
564
|
+
{0x114d0, 0x114d9}, /* 10x Tirhuta */
|
565
|
+
{0x11580, 0x115ae}, /* 47x Siddham */
|
566
|
+
{0x115d8, 0x115db}, /* 4x Siddham */
|
567
|
+
{0x11600, 0x1162f}, /* 48x Modi */
|
568
|
+
{0x11644, 0x11644}, /* 1x Modi */
|
569
|
+
{0x11650, 0x11659}, /* 10x Modi */
|
570
|
+
{0x11680, 0x116aa}, /* 43x Takri */
|
571
|
+
{0x116b8, 0x116b8}, /* 1x Takri */
|
572
|
+
{0x116c0, 0x116c9}, /* 10x Takri */
|
573
|
+
{0x11700, 0x1171a}, /* 27x Ahom */
|
574
|
+
{0x11730, 0x1173b}, /* 12x Ahom */
|
575
|
+
{0x11800, 0x1182b}, /* 44x Dogra */
|
576
|
+
{0x118a0, 0x118f2}, /* 83x Warang Citi */
|
577
|
+
{0x118ff, 0x118ff}, /* 1x Warang Citi */
|
578
|
+
{0x119a0, 0x119a7}, /* 8x Nandinagari */
|
579
|
+
{0x119aa, 0x119d0}, /* 39x Nandinagari */
|
580
|
+
{0x119e1, 0x119e1}, /* 1x Nandinagari */
|
581
|
+
{0x119e3, 0x119e3}, /* 1x Nandinagari */
|
582
|
+
{0x11a00, 0x11a00}, /* 1x Zanabazar Square */
|
583
|
+
{0x11a0b, 0x11a32}, /* 40x Zanabazar Square */
|
584
|
+
{0x11a3a, 0x11a3a}, /* 1x Zanabazar Square */
|
585
|
+
{0x11a50, 0x11a50}, /* 1x Soyombo */
|
586
|
+
{0x11a5c, 0x11a89}, /* 46x Soyombo */
|
587
|
+
{0x11a9d, 0x11a9d}, /* 1x Soyombo */
|
588
|
+
{0x11ac0, 0x11af8}, /* 57x Pau Cin Hau */
|
589
|
+
{0x11c00, 0x11c08}, /* 9x Bhaiksuki */
|
590
|
+
{0x11c0a, 0x11c2e}, /* 37x Bhaiksuki */
|
591
|
+
{0x11c40, 0x11c40}, /* 1x Bhaiksuki */
|
592
|
+
{0x11c50, 0x11c6c}, /* 29x Bhaiksuki */
|
593
|
+
{0x11c72, 0x11c8f}, /* 30x Marchen */
|
594
|
+
{0x11d00, 0x11d06}, /* 7x Masaram Gondi */
|
595
|
+
{0x11d08, 0x11d09}, /* 2x Masaram Gondi */
|
596
|
+
{0x11d0b, 0x11d30}, /* 38x Masaram Gondi */
|
597
|
+
{0x11d46, 0x11d46}, /* 1x Masaram Gondi */
|
598
|
+
{0x11d50, 0x11d59}, /* 10x Masaram Gondi */
|
599
|
+
{0x11d60, 0x11d65}, /* 6x Gunjala Gondi */
|
600
|
+
{0x11d67, 0x11d68}, /* 2x Gunjala Gondi */
|
601
|
+
{0x11d6a, 0x11d89}, /* 32x Gunjala Gondi */
|
602
|
+
{0x11d98, 0x11d98}, /* 1x Gunjala Gondi */
|
603
|
+
{0x11da0, 0x11da9}, /* 10x Gunjala Gondi */
|
604
|
+
{0x11ee0, 0x11ef2}, /* 19x Makasar */
|
605
|
+
{0x11fc0, 0x11fd4}, /* 21x Tamil Supplement */
|
606
|
+
{0x12000, 0x12399}, /* 922x Cuneiform */
|
607
|
+
{0x12400, 0x1246e}, /* 111x Cuneiform Numbers & Punctuation */
|
608
|
+
{0x12480, 0x12543}, /* 196x Early Dynastic Cuneiform */
|
609
|
+
{0x13000, 0x1342e}, /* 1071x Egyptian Hieroglyphs */
|
610
|
+
{0x14400, 0x14646}, /* 583x Anatolian Hieroglyphs */
|
611
|
+
{0x16800, 0x16a38}, /* 569x Bamum Supplement */
|
612
|
+
{0x16a40, 0x16a5e}, /* 31x Mro */
|
613
|
+
{0x16a60, 0x16a69}, /* 10x Mro */
|
614
|
+
{0x16ad0, 0x16aed}, /* 30x Bassa Vah */
|
615
|
+
{0x16b00, 0x16b2f}, /* 48x Pahawh Hmong */
|
616
|
+
{0x16b40, 0x16b43}, /* 4x Pahawh Hmong */
|
617
|
+
{0x16b50, 0x16b59}, /* 10x Pahawh Hmong */
|
618
|
+
{0x16b5b, 0x16b61}, /* 7x Pahawh Hmong */
|
619
|
+
{0x16b63, 0x16b77}, /* 21x Pahawh Hmong */
|
620
|
+
{0x16b7d, 0x16b8f}, /* 19x Pahawh Hmong */
|
621
|
+
{0x16e40, 0x16e96}, /* 87x Medefaidrin */
|
622
|
+
{0x16f00, 0x16f4a}, /* 75x Miao */
|
623
|
+
{0x16f50, 0x16f50}, /* 1x Miao */
|
624
|
+
{0x16f93, 0x16f9f}, /* 13x Miao */
|
625
|
+
{0x16fe0, 0x16fe1}, /* 2x Ideographic Symbols & Punctuation */
|
626
|
+
{0x16fe3, 0x16fe3}, /* 1x Ideographic Symbols & Punctuation */
|
627
|
+
{0x17000, 0x187f7}, /* 6136x Tangut */
|
628
|
+
{0x18800, 0x18af2}, /* 755x Tangut Components */
|
629
|
+
{0x1b000, 0x1b11e}, /* 287x Kana Supplement */
|
630
|
+
{0x1b150, 0x1b152}, /* 3x Small Kana Extension */
|
631
|
+
{0x1b164, 0x1b167}, /* 4x Small Kana Extension */
|
632
|
+
{0x1b170, 0x1b2fb}, /* 396x Nushu */
|
633
|
+
{0x1bc00, 0x1bc6a}, /* 107x Duployan */
|
634
|
+
{0x1bc70, 0x1bc7c}, /* 13x Duployan */
|
635
|
+
{0x1bc80, 0x1bc88}, /* 9x Duployan */
|
636
|
+
{0x1bc90, 0x1bc99}, /* 10x Duployan */
|
637
|
+
{0x1d2e0, 0x1d2f3}, /* 20x Mayan Numerals */
|
638
|
+
{0x1d360, 0x1d378}, /* 25x Counting Rod Numerals */
|
639
|
+
{0x1d400, 0x1d454}, /* 85x 𝐀..𝑔 Math */
|
640
|
+
{0x1d456, 0x1d49c}, /* 71x 𝑖..𝒜 Math */
|
641
|
+
{0x1d49e, 0x1d49f}, /* 2x 𝒞..𝒟 Math */
|
642
|
+
{0x1d4a2, 0x1d4a2}, /* 1x 𝒢..𝒢 Math */
|
643
|
+
{0x1d4a5, 0x1d4a6}, /* 2x 𝒥..𝒦 Math */
|
644
|
+
{0x1d4a9, 0x1d4ac}, /* 4x 𝒩..𝒬 Math */
|
645
|
+
{0x1d4ae, 0x1d4b9}, /* 12x 𝒮..𝒹 Math */
|
646
|
+
{0x1d4bb, 0x1d4bb}, /* 1x 𝒻..𝒻 Math */
|
647
|
+
{0x1d4bd, 0x1d4c3}, /* 7x 𝒽..𝓃 Math */
|
648
|
+
{0x1d4c5, 0x1d505}, /* 65x 𝓅..𝔅 Math */
|
649
|
+
{0x1d507, 0x1d50a}, /* 4x 𝔇..𝔊 Math */
|
650
|
+
{0x1d50d, 0x1d514}, /* 8x 𝔍..𝔔 Math */
|
651
|
+
{0x1d516, 0x1d51c}, /* 7x 𝔖..𝔜 Math */
|
652
|
+
{0x1d51e, 0x1d539}, /* 28x 𝔞..𝔹 Math */
|
653
|
+
{0x1d53b, 0x1d53e}, /* 4x 𝔻..𝔾 Math */
|
654
|
+
{0x1d540, 0x1d544}, /* 5x 𝕀..𝕄 Math */
|
655
|
+
{0x1d546, 0x1d546}, /* 1x 𝕆..𝕆 Math */
|
656
|
+
{0x1d54a, 0x1d550}, /* 7x 𝕊..𝕐 Math */
|
657
|
+
{0x1d552, 0x1d6a5}, /* 340x 𝕒..𝚥 Math */
|
658
|
+
{0x1d6a8, 0x1d6c0}, /* 25x 𝚨..𝛀 Math */
|
659
|
+
{0x1d6c2, 0x1d6da}, /* 25x 𝛂..𝛚 Math */
|
660
|
+
{0x1d6dc, 0x1d6fa}, /* 31x 𝛜..𝛺 Math */
|
661
|
+
{0x1d6fc, 0x1d714}, /* 25x 𝛼..𝜔 Math */
|
662
|
+
{0x1d716, 0x1d734}, /* 31x 𝜖..𝜴 Math */
|
663
|
+
{0x1d736, 0x1d74e}, /* 25x 𝜶..𝝎 Math */
|
664
|
+
{0x1d750, 0x1d76e}, /* 31x 𝝐..𝝮 Math */
|
665
|
+
{0x1d770, 0x1d788}, /* 25x 𝝰..𝞈 Math */
|
666
|
+
{0x1d78a, 0x1d7a8}, /* 31x 𝞊..𝞨 Math */
|
667
|
+
{0x1d7aa, 0x1d7c2}, /* 25x 𝞪..𝟂 Math */
|
668
|
+
{0x1d7c4, 0x1d7cb}, /* 8x 𝟄..𝟋 Math */
|
669
|
+
{0x1d7ce, 0x1d9ff}, /* 562x Math, Sutton SignWriting */
|
670
|
+
{0x1f100, 0x1f10c}, /* 13x Enclosed Alphanumeric Supplement */
|
671
|
+
{0x20000, 0x2a6d6}, /* 42711x CJK Unified Ideographs Extension B */
|
672
|
+
{0x2a700, 0x2b734}, /* 4149x CJK Unified Ideographs Extension C */
|
673
|
+
{0x2b740, 0x2b81d}, /* 222x CJK Unified Ideographs Extension D */
|
674
|
+
{0x2b820, 0x2cea1}, /* 5762x CJK Unified Ideographs Extension E */
|
675
|
+
{0x2ceb0, 0x2ebe0}, /* 7473x CJK Unified Ideographs Extension F */
|
676
|
+
{0x2f800, 0x2fa1d}, /* 542x CJK Compatibility Ideographs Supplement */
|
677
|
+
};
|
678
|
+
l = 0;
|
679
|
+
r = n = sizeof(kAstralGlyphs) / sizeof(kAstralGlyphs[0]);
|
680
|
+
while (l < r) {
|
681
|
+
m = (l + r) >> 1;
|
682
|
+
if (kAstralGlyphs[m][1] < c) {
|
683
|
+
l = m + 1;
|
684
|
+
} else {
|
685
|
+
r = m;
|
686
|
+
}
|
687
|
+
}
|
688
|
+
return !(l < n && kAstralGlyphs[l][0] <= c && c <= kAstralGlyphs[l][1]);
|
689
|
+
}
|
690
|
+
}
|
691
|
+
|
692
|
+
unsigned bestlineLowercase(unsigned c) {
|
693
|
+
int m, l, r, n;
|
694
|
+
if (c < 0200) {
|
695
|
+
if ('A' <= c && c <= 'Z') {
|
696
|
+
return c + 32;
|
697
|
+
} else {
|
698
|
+
return c;
|
699
|
+
}
|
700
|
+
} else if (c <= 0xffff) {
|
701
|
+
if ((0x0100 <= c && c <= 0x0176) || /* 60x Ā..ā → ā..ŵ Watin-A */
|
702
|
+
(0x01de <= c && c <= 0x01ee) || /* 9x Ǟ..Ǯ → ǟ..ǯ Watin-B */
|
703
|
+
(0x01f8 <= c && c <= 0x021e) || /* 20x Ǹ..Ȟ → ǹ..ȟ Watin-B */
|
704
|
+
(0x0222 <= c && c <= 0x0232) || /* 9x Ȣ..Ȳ → ȣ..ȳ Watin-B */
|
705
|
+
(0x1e00 <= c && c <= 0x1eff)) { /*256x Ḁ..Ỿ → ḁ..ỿ Watin-C */
|
706
|
+
if (c == 0x0130) return c - 199;
|
707
|
+
if (c == 0x1e9e) return c;
|
708
|
+
return c + (~c & 1);
|
709
|
+
} else if (0x01cf <= c && c <= 0x01db) {
|
710
|
+
return c + (c & 1); /* 7x Ǐ..Ǜ → ǐ..ǜ Watin-B */
|
711
|
+
} else if (0x13a0 <= c && c <= 0x13ef) {
|
712
|
+
return c + 38864; /* 80x Ꭰ ..Ꮿ → ꭰ ..ꮿ Cherokee */
|
713
|
+
} else {
|
714
|
+
static const struct {
|
715
|
+
unsigned short a;
|
716
|
+
unsigned short b;
|
717
|
+
short d;
|
718
|
+
} kLower[] = {
|
719
|
+
{0x00c0, 0x00d6, +32}, /* 23x À ..Ö → à ..ö Watin */
|
720
|
+
{0x00d8, 0x00de, +32}, /* 7x Ø ..Þ → ø ..þ Watin */
|
721
|
+
{0x0178, 0x0178, -121}, /* 1x Ÿ ..Ÿ → ÿ ..ÿ Watin-A */
|
722
|
+
{0x0179, 0x0179, +1}, /* 1x Ź ..Ź → ź ..ź Watin-A */
|
723
|
+
{0x017b, 0x017b, +1}, /* 1x Ż ..Ż → ż ..ż Watin-A */
|
724
|
+
{0x017d, 0x017d, +1}, /* 1x Ž ..Ž → ž ..ž Watin-A */
|
725
|
+
{0x0181, 0x0181, +210}, /* 1x Ɓ ..Ɓ → ɓ ..ɓ Watin-B */
|
726
|
+
{0x0182, 0x0182, +1}, /* 1x Ƃ ..Ƃ → ƃ ..ƃ Watin-B */
|
727
|
+
{0x0184, 0x0184, +1}, /* 1x Ƅ ..Ƅ → ƅ ..ƅ Watin-B */
|
728
|
+
{0x0186, 0x0186, +206}, /* 1x Ɔ ..Ɔ → ɔ ..ɔ Watin-B */
|
729
|
+
{0x0187, 0x0187, +1}, /* 1x Ƈ ..Ƈ → ƈ ..ƈ Watin-B */
|
730
|
+
{0x0189, 0x018a, +205}, /* 2x Ɖ ..Ɗ → ɖ ..ɗ Watin-B */
|
731
|
+
{0x018b, 0x018b, +1}, /* 1x Ƌ ..Ƌ → ƌ ..ƌ Watin-B */
|
732
|
+
{0x018e, 0x018e, +79}, /* 1x Ǝ ..Ǝ → ǝ ..ǝ Watin-B */
|
733
|
+
{0x018f, 0x018f, +202}, /* 1x Ə ..Ə → ə ..ə Watin-B */
|
734
|
+
{0x0190, 0x0190, +203}, /* 1x Ɛ ..Ɛ → ɛ ..ɛ Watin-B */
|
735
|
+
{0x0191, 0x0191, +1}, /* 1x Ƒ ..Ƒ → ƒ ..ƒ Watin-B */
|
736
|
+
{0x0193, 0x0193, +205}, /* 1x Ɠ ..Ɠ → ɠ ..ɠ Watin-B */
|
737
|
+
{0x0194, 0x0194, +207}, /* 1x Ɣ ..Ɣ → ɣ ..ɣ Watin-B */
|
738
|
+
{0x0196, 0x0196, +211}, /* 1x Ɩ ..Ɩ → ɩ ..ɩ Watin-B */
|
739
|
+
{0x0197, 0x0197, +209}, /* 1x Ɨ ..Ɨ → ɨ ..ɨ Watin-B */
|
740
|
+
{0x0198, 0x0198, +1}, /* 1x Ƙ ..Ƙ → ƙ ..ƙ Watin-B */
|
741
|
+
{0x019c, 0x019c, +211}, /* 1x Ɯ ..Ɯ → ɯ ..ɯ Watin-B */
|
742
|
+
{0x019d, 0x019d, +213}, /* 1x Ɲ ..Ɲ → ɲ ..ɲ Watin-B */
|
743
|
+
{0x019f, 0x019f, +214}, /* 1x Ɵ ..Ɵ → ɵ ..ɵ Watin-B */
|
744
|
+
{0x01a0, 0x01a0, +1}, /* 1x Ơ ..Ơ → ơ ..ơ Watin-B */
|
745
|
+
{0x01a2, 0x01a2, +1}, /* 1x Ƣ ..Ƣ → ƣ ..ƣ Watin-B */
|
746
|
+
{0x01a4, 0x01a4, +1}, /* 1x Ƥ ..Ƥ → ƥ ..ƥ Watin-B */
|
747
|
+
{0x01a6, 0x01a6, +218}, /* 1x Ʀ ..Ʀ → ʀ ..ʀ Watin-B */
|
748
|
+
{0x01a7, 0x01a7, +1}, /* 1x Ƨ ..Ƨ → ƨ ..ƨ Watin-B */
|
749
|
+
{0x01a9, 0x01a9, +218}, /* 1x Ʃ ..Ʃ → ʃ ..ʃ Watin-B */
|
750
|
+
{0x01ac, 0x01ac, +1}, /* 1x Ƭ ..Ƭ → ƭ ..ƭ Watin-B */
|
751
|
+
{0x01ae, 0x01ae, +218}, /* 1x Ʈ ..Ʈ → ʈ ..ʈ Watin-B */
|
752
|
+
{0x01af, 0x01af, +1}, /* 1x Ư ..Ư → ư ..ư Watin-B */
|
753
|
+
{0x01b1, 0x01b2, +217}, /* 2x Ʊ ..Ʋ → ʊ ..ʋ Watin-B */
|
754
|
+
{0x01b3, 0x01b3, +1}, /* 1x Ƴ ..Ƴ → ƴ ..ƴ Watin-B */
|
755
|
+
{0x01b5, 0x01b5, +1}, /* 1x Ƶ ..Ƶ → ƶ ..ƶ Watin-B */
|
756
|
+
{0x01b7, 0x01b7, +219}, /* 1x Ʒ ..Ʒ → ʒ ..ʒ Watin-B */
|
757
|
+
{0x01b8, 0x01b8, +1}, /* 1x Ƹ ..Ƹ → ƹ ..ƹ Watin-B */
|
758
|
+
{0x01bc, 0x01bc, +1}, /* 1x Ƽ ..Ƽ → ƽ ..ƽ Watin-B */
|
759
|
+
{0x01c4, 0x01c4, +2}, /* 1x DŽ ..DŽ → dž ..dž Watin-B */
|
760
|
+
{0x01c5, 0x01c5, +1}, /* 1x Dž ..Dž → dž ..dž Watin-B */
|
761
|
+
{0x01c7, 0x01c7, +2}, /* 1x LJ ..LJ → lj ..lj Watin-B */
|
762
|
+
{0x01c8, 0x01c8, +1}, /* 1x Lj ..Lj → lj ..lj Watin-B */
|
763
|
+
{0x01ca, 0x01ca, +2}, /* 1x NJ ..NJ → nj ..nj Watin-B */
|
764
|
+
{0x01cb, 0x01cb, +1}, /* 1x Nj ..Nj → nj ..nj Watin-B */
|
765
|
+
{0x01cd, 0x01cd, +1}, /* 1x Ǎ ..Ǎ → ǎ ..ǎ Watin-B */
|
766
|
+
{0x01f1, 0x01f1, +2}, /* 1x DZ ..DZ → dz ..dz Watin-B */
|
767
|
+
{0x01f2, 0x01f2, +1}, /* 1x Dz ..Dz → dz ..dz Watin-B */
|
768
|
+
{0x01f4, 0x01f4, +1}, /* 1x Ǵ ..Ǵ → ǵ ..ǵ Watin-B */
|
769
|
+
{0x01f6, 0x01f6, -97}, /* 1x Ƕ ..Ƕ → ƕ ..ƕ Watin-B */
|
770
|
+
{0x01f7, 0x01f7, -56}, /* 1x Ƿ ..Ƿ → ƿ ..ƿ Watin-B */
|
771
|
+
{0x0220, 0x0220, -130}, /* 1x Ƞ ..Ƞ → ƞ ..ƞ Watin-B */
|
772
|
+
{0x023b, 0x023b, +1}, /* 1x Ȼ ..Ȼ → ȼ ..ȼ Watin-B */
|
773
|
+
{0x023d, 0x023d, -163}, /* 1x Ƚ ..Ƚ → ƚ ..ƚ Watin-B */
|
774
|
+
{0x0241, 0x0241, +1}, /* 1x Ɂ ..Ɂ → ɂ ..ɂ Watin-B */
|
775
|
+
{0x0243, 0x0243, -195}, /* 1x Ƀ ..Ƀ → ƀ ..ƀ Watin-B */
|
776
|
+
{0x0244, 0x0244, +69}, /* 1x Ʉ ..Ʉ → ʉ ..ʉ Watin-B */
|
777
|
+
{0x0245, 0x0245, +71}, /* 1x Ʌ ..Ʌ → ʌ ..ʌ Watin-B */
|
778
|
+
{0x0246, 0x0246, +1}, /* 1x Ɇ ..Ɇ → ɇ ..ɇ Watin-B */
|
779
|
+
{0x0248, 0x0248, +1}, /* 1x Ɉ ..Ɉ → ɉ ..ɉ Watin-B */
|
780
|
+
{0x024a, 0x024a, +1}, /* 1x Ɋ ..Ɋ → ɋ ..ɋ Watin-B */
|
781
|
+
{0x024c, 0x024c, +1}, /* 1x Ɍ ..Ɍ → ɍ ..ɍ Watin-B */
|
782
|
+
{0x024e, 0x024e, +1}, /* 1x Ɏ ..Ɏ → ɏ ..ɏ Watin-B */
|
783
|
+
{0x0386, 0x0386, +38}, /* 1x Ά ..Ά → ά ..ά Greek */
|
784
|
+
{0x0388, 0x038a, +37}, /* 3x Έ ..Ί → έ ..ί Greek */
|
785
|
+
{0x038c, 0x038c, +64}, /* 1x Ό ..Ό → ό ..ό Greek */
|
786
|
+
{0x038e, 0x038f, +63}, /* 2x Ύ ..Ώ → ύ ..ώ Greek */
|
787
|
+
{0x0391, 0x03a1, +32}, /* 17x Α ..Ρ → α ..ρ Greek */
|
788
|
+
{0x03a3, 0x03ab, +32}, /* 9x Σ ..Ϋ → σ ..ϋ Greek */
|
789
|
+
{0x03dc, 0x03dc, +1}, /* 1x Ϝ ..Ϝ → ϝ ..ϝ Greek */
|
790
|
+
{0x03f4, 0x03f4, -60}, /* 1x ϴ ..ϴ → θ ..θ Greek */
|
791
|
+
{0x0400, 0x040f, +80}, /* 16x Ѐ ..Џ → ѐ ..џ Cyrillic */
|
792
|
+
{0x0410, 0x042f, +32}, /* 32x А ..Я → а ..я Cyrillic */
|
793
|
+
{0x0460, 0x0460, +1}, /* 1x Ѡ ..Ѡ → ѡ ..ѡ Cyrillic */
|
794
|
+
{0x0462, 0x0462, +1}, /* 1x Ѣ ..Ѣ → ѣ ..ѣ Cyrillic */
|
795
|
+
{0x0464, 0x0464, +1}, /* 1x Ѥ ..Ѥ → ѥ ..ѥ Cyrillic */
|
796
|
+
{0x0472, 0x0472, +1}, /* 1x Ѳ ..Ѳ → ѳ ..ѳ Cyrillic */
|
797
|
+
{0x0490, 0x0490, +1}, /* 1x Ґ ..Ґ → ґ ..ґ Cyrillic */
|
798
|
+
{0x0498, 0x0498, +1}, /* 1x Ҙ ..Ҙ → ҙ ..ҙ Cyrillic */
|
799
|
+
{0x049a, 0x049a, +1}, /* 1x Қ ..Қ → қ ..қ Cyrillic */
|
800
|
+
{0x0531, 0x0556, +48}, /* 38x Ա ..Ֆ → ա ..ֆ Armenian */
|
801
|
+
{0x10a0, 0x10c5, +7264}, /* 38x Ⴀ ..Ⴥ → ⴀ ..ⴥ Georgian */
|
802
|
+
{0x10c7, 0x10c7, +7264}, /* 1x Ⴧ ..Ⴧ → ⴧ ..ⴧ Georgian */
|
803
|
+
{0x10cd, 0x10cd, +7264}, /* 1x Ⴭ ..Ⴭ → ⴭ ..ⴭ Georgian */
|
804
|
+
{0x13f0, 0x13f5, +8}, /* 6x Ᏸ ..Ᏽ → ᏸ ..ᏽ Cherokee */
|
805
|
+
{0x1c90, 0x1cba, -3008}, /* 43x Ა ..Ჺ → ა ..ჺ Georgian2 */
|
806
|
+
{0x1cbd, 0x1cbf, -3008}, /* 3x Ჽ ..Ჿ → ჽ ..ჿ Georgian2 */
|
807
|
+
{0x1f08, 0x1f0f, -8}, /* 8x Ἀ ..Ἇ → ἀ ..ἇ Greek2 */
|
808
|
+
{0x1f18, 0x1f1d, -8}, /* 6x Ἐ ..Ἕ → ἐ ..ἕ Greek2 */
|
809
|
+
{0x1f28, 0x1f2f, -8}, /* 8x Ἠ ..Ἧ → ἠ ..ἧ Greek2 */
|
810
|
+
{0x1f38, 0x1f3f, -8}, /* 8x Ἰ ..Ἷ → ἰ ..ἷ Greek2 */
|
811
|
+
{0x1f48, 0x1f4d, -8}, /* 6x Ὀ ..Ὅ → ὀ ..ὅ Greek2 */
|
812
|
+
{0x1f59, 0x1f59, -8}, /* 1x Ὑ ..Ὑ → ὑ ..ὑ Greek2 */
|
813
|
+
{0x1f5b, 0x1f5b, -8}, /* 1x Ὓ ..Ὓ → ὓ ..ὓ Greek2 */
|
814
|
+
{0x1f5d, 0x1f5d, -8}, /* 1x Ὕ ..Ὕ → ὕ ..ὕ Greek2 */
|
815
|
+
{0x1f5f, 0x1f5f, -8}, /* 1x Ὗ ..Ὗ → ὗ ..ὗ Greek2 */
|
816
|
+
{0x1f68, 0x1f6f, -8}, /* 8x Ὠ ..Ὧ → ὠ ..ὧ Greek2 */
|
817
|
+
{0x1f88, 0x1f8f, -8}, /* 8x ᾈ ..ᾏ → ᾀ ..ᾇ Greek2 */
|
818
|
+
{0x1f98, 0x1f9f, -8}, /* 8x ᾘ ..ᾟ → ᾐ ..ᾗ Greek2 */
|
819
|
+
{0x1fa8, 0x1faf, -8}, /* 8x ᾨ ..ᾯ → ᾠ ..ᾧ Greek2 */
|
820
|
+
{0x1fb8, 0x1fb9, -8}, /* 2x Ᾰ ..Ᾱ → ᾰ ..ᾱ Greek2 */
|
821
|
+
{0x1fba, 0x1fbb, -74}, /* 2x Ὰ ..Ά → ὰ ..ά Greek2 */
|
822
|
+
{0x1fbc, 0x1fbc, -9}, /* 1x ᾼ ..ᾼ → ᾳ ..ᾳ Greek2 */
|
823
|
+
{0x1fc8, 0x1fcb, -86}, /* 4x Ὲ ..Ή → ὲ ..ή Greek2 */
|
824
|
+
{0x1fcc, 0x1fcc, -9}, /* 1x ῌ ..ῌ → ῃ ..ῃ Greek2 */
|
825
|
+
{0x1fd8, 0x1fd9, -8}, /* 2x Ῐ ..Ῑ → ῐ ..ῑ Greek2 */
|
826
|
+
{0x1fda, 0x1fdb, -100}, /* 2x Ὶ ..Ί → ὶ ..ί Greek2 */
|
827
|
+
{0x1fe8, 0x1fe9, -8}, /* 2x Ῠ ..Ῡ → ῠ ..ῡ Greek2 */
|
828
|
+
{0x1fea, 0x1feb, -112}, /* 2x Ὺ ..Ύ → ὺ ..ύ Greek2 */
|
829
|
+
{0x1fec, 0x1fec, -7}, /* 1x Ῥ ..Ῥ → ῥ ..ῥ Greek2 */
|
830
|
+
{0x1ff8, 0x1ff9, -128}, /* 2x Ὸ ..Ό → ὸ ..ό Greek2 */
|
831
|
+
{0x1ffa, 0x1ffb, -126}, /* 2x Ὼ ..Ώ → ὼ ..ώ Greek2 */
|
832
|
+
{0x1ffc, 0x1ffc, -9}, /* 1x ῼ ..ῼ → ῳ ..ῳ Greek2 */
|
833
|
+
{0x2126, 0x2126, -7517}, /* 1x Ω ..Ω → ω ..ω Letterlike */
|
834
|
+
{0x212a, 0x212a, -8383}, /* 1x K ..K → k ..k Letterlike */
|
835
|
+
{0x212b, 0x212b, -8262}, /* 1x Å ..Å → å ..å Letterlike */
|
836
|
+
{0x2132, 0x2132, +28}, /* 1x Ⅎ ..Ⅎ → ⅎ ..ⅎ Letterlike */
|
837
|
+
{0x2160, 0x216f, +16}, /* 16x Ⅰ ..Ⅿ → ⅰ ..ⅿ Numbery */
|
838
|
+
{0x2183, 0x2183, +1}, /* 1x Ↄ ..Ↄ → ↄ ..ↄ Numbery */
|
839
|
+
{0x24b6, 0x24cf, +26}, /* 26x Ⓐ ..Ⓩ → ⓐ ..ⓩ Enclosed */
|
840
|
+
{0x2c00, 0x2c2e, +48}, /* 47x Ⰰ ..Ⱞ → ⰰ ..ⱞ Glagolitic */
|
841
|
+
{0xff21, 0xff3a, +32}, /* 26x A..Z → a..z Dubs */
|
842
|
+
};
|
843
|
+
l = 0;
|
844
|
+
r = n = sizeof(kLower) / sizeof(kLower[0]);
|
845
|
+
while (l < r) {
|
846
|
+
m = (l + r) >> 1;
|
847
|
+
if (kLower[m].b < c) {
|
848
|
+
l = m + 1;
|
849
|
+
} else {
|
850
|
+
r = m;
|
851
|
+
}
|
852
|
+
}
|
853
|
+
if (l < n && kLower[l].a <= c && c <= kLower[l].b) {
|
854
|
+
return c + kLower[l].d;
|
855
|
+
} else {
|
856
|
+
return c;
|
857
|
+
}
|
858
|
+
}
|
859
|
+
} else {
|
860
|
+
static struct {
|
861
|
+
unsigned a;
|
862
|
+
unsigned b;
|
863
|
+
short d;
|
864
|
+
} kAstralLower[] = {
|
865
|
+
{0x10400, 0x10427, +40}, /* 40x 𐐀 ..𐐧 → 𐐨 ..𐑏 Deseret */
|
866
|
+
{0x104b0, 0x104d3, +40}, /* 36x 𐒰 ..𐓓 → 𐓘 ..𐓻 Osage */
|
867
|
+
{0x1d400, 0x1d419, +26}, /* 26x 𝐀 ..𝐙 → 𝐚 ..𝐳 Math */
|
868
|
+
{0x1d43c, 0x1d44d, +26}, /* 18x 𝐼 ..𝑍 → 𝑖 ..𝑧 Math */
|
869
|
+
{0x1d468, 0x1d481, +26}, /* 26x 𝑨 ..𝒁 → 𝒂 ..𝒛 Math */
|
870
|
+
{0x1d4ae, 0x1d4b5, +26}, /* 8x 𝒮 ..𝒵 → 𝓈 ..𝓏 Math */
|
871
|
+
{0x1d4d0, 0x1d4e9, +26}, /* 26x 𝓐 ..𝓩 → 𝓪 ..𝔃 Math */
|
872
|
+
{0x1d50d, 0x1d514, +26}, /* 8x 𝔍 ..𝔔 → 𝔧 ..𝔮 Math */
|
873
|
+
{0x1d56c, 0x1d585, +26}, /* 26x 𝕬 ..𝖅 → 𝖆 ..𝖟 Math */
|
874
|
+
{0x1d5a0, 0x1d5b9, +26}, /* 26x 𝖠 ..𝖹 → 𝖺 ..𝗓 Math */
|
875
|
+
{0x1d5d4, 0x1d5ed, +26}, /* 26x 𝗔 ..𝗭 → 𝗮 ..𝘇 Math */
|
876
|
+
{0x1d608, 0x1d621, +26}, /* 26x 𝘈 ..𝘡 → 𝘢 ..𝘻 Math */
|
877
|
+
{0x1d63c, 0x1d655, -442}, /* 26x 𝘼 ..𝙕 → 𝒂 ..𝒛 Math */
|
878
|
+
{0x1d670, 0x1d689, +26}, /* 26x 𝙰 ..𝚉 → 𝚊 ..𝚣 Math */
|
879
|
+
{0x1d6a8, 0x1d6b8, +26}, /* 17x 𝚨 ..𝚸 → 𝛂 ..𝛒 Math */
|
880
|
+
{0x1d6e2, 0x1d6f2, +26}, /* 17x 𝛢 ..𝛲 → 𝛼 ..𝜌 Math */
|
881
|
+
{0x1d71c, 0x1d72c, +26}, /* 17x 𝜜 ..𝜬 → 𝜶 ..𝝆 Math */
|
882
|
+
{0x1d756, 0x1d766, +26}, /* 17x 𝝖 ..𝝦 → 𝝰 ..𝞀 Math */
|
883
|
+
{0x1d790, 0x1d7a0, -90}, /* 17x 𝞐 ..𝞠 → 𝜶 ..𝝆 Math */
|
884
|
+
};
|
885
|
+
l = 0;
|
886
|
+
r = n = sizeof(kAstralLower) / sizeof(kAstralLower[0]);
|
887
|
+
while (l < r) {
|
888
|
+
m = (l + r) >> 1;
|
889
|
+
if (kAstralLower[m].b < c) {
|
890
|
+
l = m + 1;
|
891
|
+
} else {
|
892
|
+
r = m;
|
893
|
+
}
|
894
|
+
}
|
895
|
+
if (l < n && kAstralLower[l].a <= c && c <= kAstralLower[l].b) {
|
896
|
+
return c + kAstralLower[l].d;
|
897
|
+
} else {
|
898
|
+
return c;
|
899
|
+
}
|
900
|
+
}
|
901
|
+
}
|
902
|
+
|
903
|
+
unsigned bestlineUppercase(unsigned c) {
|
904
|
+
int m, l, r, n;
|
905
|
+
if (c < 0200) {
|
906
|
+
if ('a' <= c && c <= 'z') {
|
907
|
+
return c - 32;
|
908
|
+
} else {
|
909
|
+
return c;
|
910
|
+
}
|
911
|
+
} else if (c <= 0xffff) {
|
912
|
+
if ((0x0101 <= c && c <= 0x0177) || /* 60x ā..ŵ → Ā..ā Watin-A */
|
913
|
+
(0x01df <= c && c <= 0x01ef) || /* 9x ǟ..ǯ → Ǟ..Ǯ Watin-B */
|
914
|
+
(0x01f8 <= c && c <= 0x021e) || /* 20x ǹ..ȟ → Ǹ..Ȟ Watin-B */
|
915
|
+
(0x0222 <= c && c <= 0x0232) || /* 9x ȣ..ȳ → Ȣ..Ȳ Watin-B */
|
916
|
+
(0x1e01 <= c && c <= 0x1eff)) { /*256x ḁ..ỿ → Ḁ..Ỿ Watin-C */
|
917
|
+
if (c == 0x0131) return c + 232;
|
918
|
+
if (c == 0x1e9e) return c;
|
919
|
+
return c - (c & 1);
|
920
|
+
} else if (0x01d0 <= c && c <= 0x01dc) {
|
921
|
+
return c - (~c & 1); /* 7x ǐ..ǜ → Ǐ..Ǜ Watin-B */
|
922
|
+
} else if (0xab70 <= c && c <= 0xabbf) {
|
923
|
+
return c - 38864; /* 80x ꭰ ..ꮿ → Ꭰ ..Ꮿ Cherokee Supplement */
|
924
|
+
} else {
|
925
|
+
static const struct {
|
926
|
+
unsigned short a;
|
927
|
+
unsigned short b;
|
928
|
+
short d;
|
929
|
+
} kUpper[] = {
|
930
|
+
{0x00b5, 0x00b5, +743}, /* 1x µ ..µ → Μ ..Μ Watin */
|
931
|
+
{0x00e0, 0x00f6, -32}, /* 23x à ..ö → À ..Ö Watin */
|
932
|
+
{0x00f8, 0x00fe, -32}, /* 7x ø ..þ → Ø ..Þ Watin */
|
933
|
+
{0x00ff, 0x00ff, +121}, /* 1x ÿ ..ÿ → Ÿ ..Ÿ Watin */
|
934
|
+
{0x017a, 0x017a, -1}, /* 1x ź ..ź → Ź ..Ź Watin-A */
|
935
|
+
{0x017c, 0x017c, -1}, /* 1x ż ..ż → Ż ..Ż Watin-A */
|
936
|
+
{0x017e, 0x017e, -1}, /* 1x ž ..ž → Ž ..Ž Watin-A */
|
937
|
+
{0x017f, 0x017f, -300}, /* 1x ſ ..ſ → S ..S Watin-A */
|
938
|
+
{0x0180, 0x0180, +195}, /* 1x ƀ ..ƀ → Ƀ ..Ƀ Watin-B */
|
939
|
+
{0x0183, 0x0183, -1}, /* 1x ƃ ..ƃ → Ƃ ..Ƃ Watin-B */
|
940
|
+
{0x0185, 0x0185, -1}, /* 1x ƅ ..ƅ → Ƅ ..Ƅ Watin-B */
|
941
|
+
{0x0188, 0x0188, -1}, /* 1x ƈ ..ƈ → Ƈ ..Ƈ Watin-B */
|
942
|
+
{0x018c, 0x018c, -1}, /* 1x ƌ ..ƌ → Ƌ ..Ƌ Watin-B */
|
943
|
+
{0x0192, 0x0192, -1}, /* 1x ƒ ..ƒ → Ƒ ..Ƒ Watin-B */
|
944
|
+
{0x0195, 0x0195, +97}, /* 1x ƕ ..ƕ → Ƕ ..Ƕ Watin-B */
|
945
|
+
{0x0199, 0x0199, -1}, /* 1x ƙ ..ƙ → Ƙ ..Ƙ Watin-B */
|
946
|
+
{0x019a, 0x019a, +163}, /* 1x ƚ ..ƚ → Ƚ ..Ƚ Watin-B */
|
947
|
+
{0x019e, 0x019e, +130}, /* 1x ƞ ..ƞ → Ƞ ..Ƞ Watin-B */
|
948
|
+
{0x01a1, 0x01a1, -1}, /* 1x ơ ..ơ → Ơ ..Ơ Watin-B */
|
949
|
+
{0x01a3, 0x01a3, -1}, /* 1x ƣ ..ƣ → Ƣ ..Ƣ Watin-B */
|
950
|
+
{0x01a5, 0x01a5, -1}, /* 1x ƥ ..ƥ → Ƥ ..Ƥ Watin-B */
|
951
|
+
{0x01a8, 0x01a8, -1}, /* 1x ƨ ..ƨ → Ƨ ..Ƨ Watin-B */
|
952
|
+
{0x01ad, 0x01ad, -1}, /* 1x ƭ ..ƭ → Ƭ ..Ƭ Watin-B */
|
953
|
+
{0x01b0, 0x01b0, -1}, /* 1x ư ..ư → Ư ..Ư Watin-B */
|
954
|
+
{0x01b4, 0x01b4, -1}, /* 1x ƴ ..ƴ → Ƴ ..Ƴ Watin-B */
|
955
|
+
{0x01b6, 0x01b6, -1}, /* 1x ƶ ..ƶ → Ƶ ..Ƶ Watin-B */
|
956
|
+
{0x01b9, 0x01b9, -1}, /* 1x ƹ ..ƹ → Ƹ ..Ƹ Watin-B */
|
957
|
+
{0x01bd, 0x01bd, -1}, /* 1x ƽ ..ƽ → Ƽ ..Ƽ Watin-B */
|
958
|
+
{0x01bf, 0x01bf, +56}, /* 1x ƿ ..ƿ → Ƿ ..Ƿ Watin-B */
|
959
|
+
{0x01c5, 0x01c5, -1}, /* 1x Dž ..Dž → DŽ ..DŽ Watin-B */
|
960
|
+
{0x01c6, 0x01c6, -2}, /* 1x dž ..dž → DŽ ..DŽ Watin-B */
|
961
|
+
{0x01c8, 0x01c8, -1}, /* 1x Lj ..Lj → LJ ..LJ Watin-B */
|
962
|
+
{0x01c9, 0x01c9, -2}, /* 1x lj ..lj → LJ ..LJ Watin-B */
|
963
|
+
{0x01cb, 0x01cb, -1}, /* 1x Nj ..Nj → NJ ..NJ Watin-B */
|
964
|
+
{0x01cc, 0x01cc, -2}, /* 1x nj ..nj → NJ ..NJ Watin-B */
|
965
|
+
{0x01ce, 0x01ce, -1}, /* 1x ǎ ..ǎ → Ǎ ..Ǎ Watin-B */
|
966
|
+
{0x01dd, 0x01dd, -79}, /* 1x ǝ ..ǝ → Ǝ ..Ǝ Watin-B */
|
967
|
+
{0x01f2, 0x01f2, -1}, /* 1x Dz ..Dz → DZ ..DZ Watin-B */
|
968
|
+
{0x01f3, 0x01f3, -2}, /* 1x dz ..dz → DZ ..DZ Watin-B */
|
969
|
+
{0x01f5, 0x01f5, -1}, /* 1x ǵ ..ǵ → Ǵ ..Ǵ Watin-B */
|
970
|
+
{0x023c, 0x023c, -1}, /* 1x ȼ ..ȼ → Ȼ ..Ȼ Watin-B */
|
971
|
+
{0x023f, 0x0240,+10815}, /* 2x ȿ ..ɀ → Ȿ ..Ɀ Watin-B */
|
972
|
+
{0x0242, 0x0242, -1}, /* 1x ɂ ..ɂ → Ɂ ..Ɂ Watin-B */
|
973
|
+
{0x0247, 0x0247, -1}, /* 1x ɇ ..ɇ → Ɇ ..Ɇ Watin-B */
|
974
|
+
{0x0249, 0x0249, -1}, /* 1x ɉ ..ɉ → Ɉ ..Ɉ Watin-B */
|
975
|
+
{0x024b, 0x024b, -1}, /* 1x ɋ ..ɋ → Ɋ ..Ɋ Watin-B */
|
976
|
+
{0x024d, 0x024d, -1}, /* 1x ɍ ..ɍ → Ɍ ..Ɍ Watin-B */
|
977
|
+
{0x024f, 0x024f, -1}, /* 1x ɏ ..ɏ → Ɏ ..Ɏ Watin-B */
|
978
|
+
{0x037b, 0x037d, +130}, /* 3x ͻ ..ͽ → Ͻ ..Ͽ Greek */
|
979
|
+
{0x03ac, 0x03ac, -38}, /* 1x ά ..ά → Ά ..Ά Greek */
|
980
|
+
{0x03ad, 0x03af, -37}, /* 3x έ ..ί → Έ ..Ί Greek */
|
981
|
+
{0x03b1, 0x03c1, -32}, /* 17x α ..ρ → Α ..Ρ Greek */
|
982
|
+
{0x03c2, 0x03c2, -31}, /* 1x ς ..ς → Σ ..Σ Greek */
|
983
|
+
{0x03c3, 0x03cb, -32}, /* 9x σ ..ϋ → Σ ..Ϋ Greek */
|
984
|
+
{0x03cc, 0x03cc, -64}, /* 1x ό ..ό → Ό ..Ό Greek */
|
985
|
+
{0x03cd, 0x03ce, -63}, /* 2x ύ ..ώ → Ύ ..Ώ Greek */
|
986
|
+
{0x03d0, 0x03d0, -62}, /* 1x ϐ ..ϐ → Β ..Β Greek */
|
987
|
+
{0x03d1, 0x03d1, -57}, /* 1x ϑ ..ϑ → Θ ..Θ Greek */
|
988
|
+
{0x03d5, 0x03d5, -47}, /* 1x ϕ ..ϕ → Φ ..Φ Greek */
|
989
|
+
{0x03d6, 0x03d6, -54}, /* 1x ϖ ..ϖ → Π ..Π Greek */
|
990
|
+
{0x03dd, 0x03dd, -1}, /* 1x ϝ ..ϝ → Ϝ ..Ϝ Greek */
|
991
|
+
{0x03f0, 0x03f0, -86}, /* 1x ϰ ..ϰ → Κ ..Κ Greek */
|
992
|
+
{0x03f1, 0x03f1, -80}, /* 1x ϱ ..ϱ → Ρ ..Ρ Greek */
|
993
|
+
{0x03f5, 0x03f5, -96}, /* 1x ϵ ..ϵ → Ε ..Ε Greek */
|
994
|
+
{0x0430, 0x044f, -32}, /* 32x а ..я → А ..Я Cyrillic */
|
995
|
+
{0x0450, 0x045f, -80}, /* 16x ѐ ..џ → Ѐ ..Џ Cyrillic */
|
996
|
+
{0x0461, 0x0461, -1}, /* 1x ѡ ..ѡ → Ѡ ..Ѡ Cyrillic */
|
997
|
+
{0x0463, 0x0463, -1}, /* 1x ѣ ..ѣ → Ѣ ..Ѣ Cyrillic */
|
998
|
+
{0x0465, 0x0465, -1}, /* 1x ѥ ..ѥ → Ѥ ..Ѥ Cyrillic */
|
999
|
+
{0x0473, 0x0473, -1}, /* 1x ѳ ..ѳ → Ѳ ..Ѳ Cyrillic */
|
1000
|
+
{0x0491, 0x0491, -1}, /* 1x ґ ..ґ → Ґ ..Ґ Cyrillic */
|
1001
|
+
{0x0499, 0x0499, -1}, /* 1x ҙ ..ҙ → Ҙ ..Ҙ Cyrillic */
|
1002
|
+
{0x049b, 0x049b, -1}, /* 1x қ ..қ → Қ ..Қ Cyrillic */
|
1003
|
+
{0x0561, 0x0586, -48}, /* 38x ա ..ֆ → Ա ..Ֆ Armenian */
|
1004
|
+
{0x10d0, 0x10fa, +3008}, /* 43x ა ..ჺ → Ა ..Ჺ Georgian */
|
1005
|
+
{0x10fd, 0x10ff, +3008}, /* 3x ჽ ..ჿ → Ჽ ..Ჿ Georgian */
|
1006
|
+
{0x13f8, 0x13fd, -8}, /* 6x ᏸ ..ᏽ → Ᏸ ..Ᏽ Cherokee */
|
1007
|
+
{0x214e, 0x214e, -28}, /* 1x ⅎ ..ⅎ → Ⅎ ..Ⅎ Letterlike */
|
1008
|
+
{0x2170, 0x217f, -16}, /* 16x ⅰ ..ⅿ → Ⅰ ..Ⅿ Numbery */
|
1009
|
+
{0x2184, 0x2184, -1}, /* 1x ↄ ..ↄ → Ↄ ..Ↄ Numbery */
|
1010
|
+
{0x24d0, 0x24e9, -26}, /* 26x ⓐ ..ⓩ → Ⓐ ..Ⓩ Enclosed */
|
1011
|
+
{0x2c30, 0x2c5e, -48}, /* 47x ⰰ ..ⱞ → Ⰰ ..Ⱞ Glagolitic */
|
1012
|
+
{0x2d00, 0x2d25, -7264}, /* 38x ⴀ ..ⴥ → Ⴀ ..Ⴥ Georgian2 */
|
1013
|
+
{0x2d27, 0x2d27, -7264}, /* 1x ⴧ ..ⴧ → Ⴧ ..Ⴧ Georgian2 */
|
1014
|
+
{0x2d2d, 0x2d2d, -7264}, /* 1x ⴭ ..ⴭ → Ⴭ ..Ⴭ Georgian2 */
|
1015
|
+
{0xff41, 0xff5a, -32}, /* 26x a..z → A..Z Dubs */
|
1016
|
+
};
|
1017
|
+
l = 0;
|
1018
|
+
r = n = sizeof(kUpper) / sizeof(kUpper[0]);
|
1019
|
+
while (l < r) {
|
1020
|
+
m = (l + r) >> 1;
|
1021
|
+
if (kUpper[m].b < c) {
|
1022
|
+
l = m + 1;
|
1023
|
+
} else {
|
1024
|
+
r = m;
|
1025
|
+
}
|
1026
|
+
}
|
1027
|
+
if (l < n && kUpper[l].a <= c && c <= kUpper[l].b) {
|
1028
|
+
return c + kUpper[l].d;
|
1029
|
+
} else {
|
1030
|
+
return c;
|
1031
|
+
}
|
1032
|
+
}
|
1033
|
+
} else {
|
1034
|
+
static const struct {
|
1035
|
+
unsigned a;
|
1036
|
+
unsigned b;
|
1037
|
+
short d;
|
1038
|
+
} kAstralUpper[] = {
|
1039
|
+
{0x10428, 0x1044f, -40}, /* 40x 𐐨..𐑏 → 𐐀..𐐧 Deseret */
|
1040
|
+
{0x104d8, 0x104fb, -40}, /* 36x 𐓘..𐓻 → 𐒰..𐓓 Osage */
|
1041
|
+
{0x1d41a, 0x1d433, -26}, /* 26x 𝐚..𝐳 → 𝐀..𝐙 Math */
|
1042
|
+
{0x1d456, 0x1d467, -26}, /* 18x 𝑖..𝑧 → 𝐼..𝑍 Math */
|
1043
|
+
{0x1d482, 0x1d49b, -26}, /* 26x 𝒂..𝒛 → 𝑨..𝒁 Math */
|
1044
|
+
{0x1d4c8, 0x1d4cf, -26}, /* 8x 𝓈..𝓏 → 𝒮..𝒵 Math */
|
1045
|
+
{0x1d4ea, 0x1d503, -26}, /* 26x 𝓪..𝔃 → 𝓐..𝓩 Math */
|
1046
|
+
{0x1d527, 0x1d52e, -26}, /* 8x 𝔧..𝔮 → 𝔍..𝔔 Math */
|
1047
|
+
{0x1d586, 0x1d59f, -26}, /* 26x 𝖆..𝖟 → 𝕬..𝖅 Math */
|
1048
|
+
{0x1d5ba, 0x1d5d3, -26}, /* 26x 𝖺..𝗓 → 𝖠..𝖹 Math */
|
1049
|
+
{0x1d5ee, 0x1d607, -26}, /* 26x 𝗮..𝘇 → 𝗔..𝗭 Math */
|
1050
|
+
{0x1d622, 0x1d63b, -26}, /* 26x 𝘢..𝘻 → 𝘈..𝘡 Math */
|
1051
|
+
{0x1d68a, 0x1d6a3, +442}, /* 26x 𝒂..𝒛 → 𝘼..𝙕 Math */
|
1052
|
+
{0x1d6c2, 0x1d6d2, -26}, /* 26x 𝚊..𝚣 → 𝙰..𝚉 Math */
|
1053
|
+
{0x1d6fc, 0x1d70c, -26}, /* 17x 𝛂..𝛒 → 𝚨..𝚸 Math */
|
1054
|
+
{0x1d736, 0x1d746, -26}, /* 17x 𝛼..𝜌 → 𝛢..𝛲 Math */
|
1055
|
+
{0x1d770, 0x1d780, -26}, /* 17x 𝜶..𝝆 → 𝜜..𝜬 Math */
|
1056
|
+
{0x1d770, 0x1d756, -26}, /* 17x 𝝰..𝞀 → 𝝖..𝝦 Math */
|
1057
|
+
{0x1d736, 0x1d790, -90}, /* 17x 𝜶..𝝆 → 𝞐..𝞠 Math */
|
1058
|
+
};
|
1059
|
+
l = 0;
|
1060
|
+
r = n = sizeof(kAstralUpper) / sizeof(kAstralUpper[0]);
|
1061
|
+
while (l < r) {
|
1062
|
+
m = (l + r) >> 1;
|
1063
|
+
if (kAstralUpper[m].b < c) {
|
1064
|
+
l = m + 1;
|
1065
|
+
} else {
|
1066
|
+
r = m;
|
1067
|
+
}
|
1068
|
+
}
|
1069
|
+
if (l < n && kAstralUpper[l].a <= c && c <= kAstralUpper[l].b) {
|
1070
|
+
return c + kAstralUpper[l].d;
|
1071
|
+
} else {
|
1072
|
+
return c;
|
1073
|
+
}
|
1074
|
+
}
|
1075
|
+
}
|
1076
|
+
|
1077
|
+
char bestlineNotSeparator(unsigned c) {
|
1078
|
+
return !bestlineIsSeparator(c);
|
1079
|
+
}
|
1080
|
+
|
1081
|
+
static unsigned GetMirror(const unsigned short A[][2], size_t n, unsigned c) {
|
1082
|
+
int l, m, r;
|
1083
|
+
l = 0;
|
1084
|
+
r = n - 1;
|
1085
|
+
while (l <= r) {
|
1086
|
+
m = (l + r) >> 1;
|
1087
|
+
if (A[m][0] < c) {
|
1088
|
+
l = m + 1;
|
1089
|
+
} else if (A[m][0] > c) {
|
1090
|
+
r = m - 1;
|
1091
|
+
} else {
|
1092
|
+
return A[m][1];
|
1093
|
+
}
|
1094
|
+
}
|
1095
|
+
return 0;
|
1096
|
+
}
|
1097
|
+
|
1098
|
+
unsigned bestlineMirrorLeft(unsigned c) {
|
1099
|
+
static const unsigned short kMirrorRight[][2] = {
|
1100
|
+
{L')', L'('}, {L']', L'['}, {L'}', L'{'}, {L'⁆', L'⁅'},
|
1101
|
+
{L'⁾', L'⁽'}, {L'₎', L'₍'}, {L'⌉', L'⌈'}, {L'⌋', L'⌊'},
|
1102
|
+
{L'〉', L'〈'}, {L'❩', L'❨'}, {L'❫', L'❪'}, {L'❭', L'❬'},
|
1103
|
+
{L'❯', L'❮'}, {L'❱', L'❰'}, {L'❳', L'❲'}, {L'❵', L'❴'},
|
1104
|
+
{L'⟆', L'⟅'}, {L'⟧', L'⟦'}, {L'⟩', L'⟨'}, {L'⟫', L'⟪'},
|
1105
|
+
{L'⟭', L'⟬'}, {L'⟯', L'⟮'}, {L'⦄', L'⦃'}, {L'⦆', L'⦅'},
|
1106
|
+
{L'⦈', L'⦇'}, {L'⦊', L'⦉'}, {L'⦌', L'⦋'}, {L'⦎', L'⦏'},
|
1107
|
+
{L'⦐', L'⦍'}, {L'⦒', L'⦑'}, {L'⦔', L'⦓'}, {L'⦘', L'⦗'},
|
1108
|
+
{L'⧙', L'⧘'}, {L'⧛', L'⧚'}, {L'⧽', L'⧼'}, {L'﹚', L'﹙'},
|
1109
|
+
{L'﹜', L'﹛'}, {L'﹞', L'﹝'}, {L')', L'('}, {L']', L'['},
|
1110
|
+
{L'}', L'{'}, {L'」', L'「'},
|
1111
|
+
};
|
1112
|
+
return GetMirror(kMirrorRight,
|
1113
|
+
sizeof(kMirrorRight) / sizeof(kMirrorRight[0]),
|
1114
|
+
c);
|
1115
|
+
}
|
1116
|
+
|
1117
|
+
unsigned bestlineMirrorRight(unsigned c) {
|
1118
|
+
static const unsigned short kMirrorLeft[][2] = {
|
1119
|
+
{L'(', L')'}, {L'[', L']'}, {L'{', L'}'}, {L'⁅', L'⁆'},
|
1120
|
+
{L'⁽', L'⁾'}, {L'₍', L'₎'}, {L'⌈', L'⌉'}, {L'⌊', L'⌋'},
|
1121
|
+
{L'〈', L'〉'}, {L'❨', L'❩'}, {L'❪', L'❫'}, {L'❬', L'❭'},
|
1122
|
+
{L'❮', L'❯'}, {L'❰', L'❱'}, {L'❲', L'❳'}, {L'❴', L'❵'},
|
1123
|
+
{L'⟅', L'⟆'}, {L'⟦', L'⟧'}, {L'⟨', L'⟩'}, {L'⟪', L'⟫'},
|
1124
|
+
{L'⟬', L'⟭'}, {L'⟮', L'⟯'}, {L'⦃', L'⦄'}, {L'⦅', L'⦆'},
|
1125
|
+
{L'⦇', L'⦈'}, {L'⦉', L'⦊'}, {L'⦋', L'⦌'}, {L'⦍', L'⦐'},
|
1126
|
+
{L'⦏', L'⦎'}, {L'⦑', L'⦒'}, {L'⦓', L'⦔'}, {L'⦗', L'⦘'},
|
1127
|
+
{L'⧘', L'⧙'}, {L'⧚', L'⧛'}, {L'⧼', L'⧽'}, {L'﹙', L'﹚'},
|
1128
|
+
{L'﹛', L'﹜'}, {L'﹝', L'﹞'}, {L'(', L')'}, {L'[', L']'},
|
1129
|
+
{L'{', L'}'}, {L'「', L'」'},
|
1130
|
+
};
|
1131
|
+
return GetMirror(kMirrorLeft,
|
1132
|
+
sizeof(kMirrorLeft) / sizeof(kMirrorLeft[0]),
|
1133
|
+
c);
|
1134
|
+
}
|
1135
|
+
|
1136
|
+
char bestlineIsXeparator(unsigned c) {
|
1137
|
+
return (bestlineIsSeparator(c) &&
|
1138
|
+
!bestlineMirrorLeft(c) &&
|
1139
|
+
!bestlineMirrorRight(c));
|
1140
|
+
}
|
1141
|
+
|
1142
|
+
static unsigned Capitalize(unsigned c) {
|
1143
|
+
if (!iscapital) {
|
1144
|
+
c = bestlineUppercase(c);
|
1145
|
+
iscapital = 1;
|
1146
|
+
}
|
1147
|
+
return c;
|
1148
|
+
}
|
1149
|
+
|
1150
|
+
static inline int Bsr(unsigned long long x) {
|
1151
|
+
#if defined(__GNUC__) && !defined(__STRICT_ANSI__)
|
1152
|
+
int b;
|
1153
|
+
b = __builtin_clzll(x);
|
1154
|
+
b ^= sizeof(unsigned long long) * CHAR_BIT - 1;
|
1155
|
+
return b;
|
1156
|
+
#else
|
1157
|
+
static const char kDebruijn[64] = {
|
1158
|
+
0, 47, 1, 56, 48, 27, 2, 60, 57, 49, 41, 37, 28, 16, 3, 61,
|
1159
|
+
54, 58, 35, 52, 50, 42, 21, 44, 38, 32, 29, 23, 17, 11, 4, 62,
|
1160
|
+
46, 55, 26, 59, 40, 36, 15, 53, 34, 51, 20, 43, 31, 22, 10, 45,
|
1161
|
+
25, 39, 14, 33, 19, 30, 9, 24, 13, 18, 8, 12, 7, 6, 5, 63,
|
1162
|
+
};
|
1163
|
+
x |= x >> 1;
|
1164
|
+
x |= x >> 2;
|
1165
|
+
x |= x >> 4;
|
1166
|
+
x |= x >> 8;
|
1167
|
+
x |= x >> 16;
|
1168
|
+
x |= x >> 32;
|
1169
|
+
return kDebruijn[(x * 0x03f79d71b4cb0a89) >> 58];
|
1170
|
+
#endif
|
1171
|
+
}
|
1172
|
+
|
1173
|
+
static struct rune DecodeUtf8(int c) {
|
1174
|
+
struct rune r;
|
1175
|
+
if (c < 252) {
|
1176
|
+
r.n = Bsr(255 & ~c);
|
1177
|
+
r.c = c & (((1 << r.n) - 1) | 3);
|
1178
|
+
r.n = 6 - r.n;
|
1179
|
+
} else {
|
1180
|
+
r.c = c & 3;
|
1181
|
+
r.n = 5;
|
1182
|
+
}
|
1183
|
+
return r;
|
1184
|
+
}
|
1185
|
+
|
1186
|
+
static unsigned long long EncodeUtf8(unsigned c) {
|
1187
|
+
static const unsigned short kTpEnc[32 - 7] = {
|
1188
|
+
1|0300<<8, 1|0300<<8, 1|0300<<8, 1|0300<<8, 2|0340<<8,
|
1189
|
+
2|0340<<8, 2|0340<<8, 2|0340<<8, 2|0340<<8, 3|0360<<8,
|
1190
|
+
3|0360<<8, 3|0360<<8, 3|0360<<8, 3|0360<<8, 4|0370<<8,
|
1191
|
+
4|0370<<8, 4|0370<<8, 4|0370<<8, 4|0370<<8, 5|0374<<8,
|
1192
|
+
5|0374<<8, 5|0374<<8, 5|0374<<8, 5|0374<<8, 5|0374<<8,
|
1193
|
+
};
|
1194
|
+
int e, n;
|
1195
|
+
unsigned long long w;
|
1196
|
+
if (c < 0200) return c;
|
1197
|
+
e = kTpEnc[Bsr(c) - 7];
|
1198
|
+
n = e & 0xff;
|
1199
|
+
w = 0;
|
1200
|
+
do {
|
1201
|
+
w |= 0200 | (c & 077);
|
1202
|
+
w <<= 8;
|
1203
|
+
c >>= 6;
|
1204
|
+
} while (--n);
|
1205
|
+
return c | w | e >> 8;
|
1206
|
+
}
|
1207
|
+
|
1208
|
+
static struct rune GetUtf8(const char *p, size_t n) {
|
1209
|
+
struct rune r;
|
1210
|
+
if ((r.n = r.c = 0) < n && (r.c = p[r.n++] & 255) >= 0300) {
|
1211
|
+
r.c = DecodeUtf8(r.c).c;
|
1212
|
+
while (r.n < n && (p[r.n] & 0300) == 0200) {
|
1213
|
+
r.c = r.c << 6 | (p[r.n++] & 077);
|
1214
|
+
}
|
1215
|
+
}
|
1216
|
+
return r;
|
1217
|
+
}
|
1218
|
+
|
1219
|
+
static char *FormatUnsigned(char *p, unsigned x) {
|
1220
|
+
char t;
|
1221
|
+
size_t i, a, b;
|
1222
|
+
i = 0;
|
1223
|
+
do {
|
1224
|
+
p[i++] = x % 10 + '0';
|
1225
|
+
x = x / 10;
|
1226
|
+
} while (x > 0);
|
1227
|
+
p[i] = '\0';
|
1228
|
+
if (i) {
|
1229
|
+
for (a = 0, b = i - 1; a < b; ++a, --b) {
|
1230
|
+
t = p[a];
|
1231
|
+
p[a] = p[b];
|
1232
|
+
p[b] = t;
|
1233
|
+
}
|
1234
|
+
}
|
1235
|
+
return p + i;
|
1236
|
+
}
|
1237
|
+
|
1238
|
+
static void abInit(struct abuf *a) {
|
1239
|
+
a->len = 0;
|
1240
|
+
a->cap = 16;
|
1241
|
+
a->b = (char *)malloc(a->cap);
|
1242
|
+
a->b[0] = 0;
|
1243
|
+
}
|
1244
|
+
|
1245
|
+
static char abGrow(struct abuf *a, int need) {
|
1246
|
+
int cap;
|
1247
|
+
char *b;
|
1248
|
+
cap = a->cap;
|
1249
|
+
do cap += cap / 2;
|
1250
|
+
while (cap < need);
|
1251
|
+
if (!(b = (char *)realloc(a->b, cap * sizeof(*a->b)))) return 0;
|
1252
|
+
a->cap = cap;
|
1253
|
+
a->b = b;
|
1254
|
+
return 1;
|
1255
|
+
}
|
1256
|
+
|
1257
|
+
static void abAppendw(struct abuf *a, unsigned long long w) {
|
1258
|
+
char *p;
|
1259
|
+
if (a->len + 8 > a->cap && !abGrow(a, a->len + 8)) return;
|
1260
|
+
p = a->b + a->len;
|
1261
|
+
p[0] = (0x00000000000000FF & w) >> 000;
|
1262
|
+
p[1] = (0x000000000000FF00 & w) >> 010;
|
1263
|
+
p[2] = (0x0000000000FF0000 & w) >> 020;
|
1264
|
+
p[3] = (0x00000000FF000000 & w) >> 030;
|
1265
|
+
p[4] = (0x000000FF00000000 & w) >> 040;
|
1266
|
+
p[5] = (0x0000FF0000000000 & w) >> 050;
|
1267
|
+
p[6] = (0x00FF000000000000 & w) >> 060;
|
1268
|
+
p[7] = (0xFF00000000000000 & w) >> 070;
|
1269
|
+
a->len += w ? (Bsr(w) >> 3) + 1 : 1;
|
1270
|
+
}
|
1271
|
+
|
1272
|
+
static void abAppend(struct abuf *a, const char *s, int len) {
|
1273
|
+
if (a->len + len + 1 > a->cap && !abGrow(a, a->len + len + 1)) return;
|
1274
|
+
memcpy(a->b + a->len, s, len);
|
1275
|
+
a->b[a->len + len] = 0;
|
1276
|
+
a->len += len;
|
1277
|
+
}
|
1278
|
+
|
1279
|
+
static void abAppends(struct abuf *a, const char *s) {
|
1280
|
+
abAppend(a, s, strlen(s));
|
1281
|
+
}
|
1282
|
+
|
1283
|
+
static void abAppendu(struct abuf *a, unsigned u) {
|
1284
|
+
char b[11];
|
1285
|
+
abAppend(a, b, FormatUnsigned(b, u) - b);
|
1286
|
+
}
|
1287
|
+
|
1288
|
+
static void abFree(struct abuf *a) {
|
1289
|
+
free(a->b);
|
1290
|
+
a->b = 0;
|
1291
|
+
}
|
1292
|
+
|
1293
|
+
static size_t GetFdSize(int fd) {
|
1294
|
+
struct stat st;
|
1295
|
+
st.st_size = 0;
|
1296
|
+
fstat(fd, &st);
|
1297
|
+
return st.st_size;
|
1298
|
+
}
|
1299
|
+
|
1300
|
+
static char IsCharDev(int fd) {
|
1301
|
+
struct stat st;
|
1302
|
+
st.st_mode = 0;
|
1303
|
+
fstat(fd, &st);
|
1304
|
+
return (st.st_mode & S_IFMT) == S_IFCHR;
|
1305
|
+
}
|
1306
|
+
|
1307
|
+
static int WaitUntilReady(int fd, int events) {
|
1308
|
+
struct pollfd p[1];
|
1309
|
+
p[0].fd = fd;
|
1310
|
+
p[0].events = events;
|
1311
|
+
return poll(p, 1, -1);
|
1312
|
+
}
|
1313
|
+
|
1314
|
+
static char HasPendingInput(int fd) {
|
1315
|
+
struct pollfd p[1];
|
1316
|
+
p[0].fd = fd;
|
1317
|
+
p[0].events = POLLIN;
|
1318
|
+
return poll(p, 1, 0) == 1;
|
1319
|
+
}
|
1320
|
+
|
1321
|
+
static char *GetLineBlock(FILE *f) {
|
1322
|
+
ssize_t rc;
|
1323
|
+
char *p = 0;
|
1324
|
+
size_t n, c = 0;
|
1325
|
+
if ((rc = getdelim(&p, &c, '\n', f)) != EOF) {
|
1326
|
+
for (n = rc; n; --n) {
|
1327
|
+
if (p[n - 1] == '\r' || p[n - 1] == '\n') {
|
1328
|
+
p[n - 1] = 0;
|
1329
|
+
} else {
|
1330
|
+
break;
|
1331
|
+
}
|
1332
|
+
}
|
1333
|
+
return p;
|
1334
|
+
} else {
|
1335
|
+
free(p);
|
1336
|
+
return 0;
|
1337
|
+
}
|
1338
|
+
}
|
1339
|
+
|
1340
|
+
long bestlineReadCharacter(int fd, char *p, unsigned long n) {
|
1341
|
+
int e;
|
1342
|
+
size_t i;
|
1343
|
+
ssize_t rc;
|
1344
|
+
struct rune r;
|
1345
|
+
unsigned char c;
|
1346
|
+
enum { kAscii, kUtf8, kEsc, kCsi1, kCsi2, kSs, kNf, kStr, kStr2, kDone } t;
|
1347
|
+
i = 0;
|
1348
|
+
r.c = 0;
|
1349
|
+
r.n = 0;
|
1350
|
+
e = errno;
|
1351
|
+
t = kAscii;
|
1352
|
+
if (n) p[0] = 0;
|
1353
|
+
do {
|
1354
|
+
for (;;) {
|
1355
|
+
if (gotint) {
|
1356
|
+
errno = EINTR;
|
1357
|
+
return -1;
|
1358
|
+
}
|
1359
|
+
if (n) {
|
1360
|
+
rc = read(fd,&c,1);
|
1361
|
+
} else {
|
1362
|
+
rc = read(fd,0,0);
|
1363
|
+
}
|
1364
|
+
if (rc == -1 && errno == EINTR) {
|
1365
|
+
if (!i) {
|
1366
|
+
return -1;
|
1367
|
+
}
|
1368
|
+
} else if (rc == -1 && (errno == EAGAIN || errno == EWOULDBLOCK)) {
|
1369
|
+
if (WaitUntilReady(fd, POLLIN) == -1) {
|
1370
|
+
if (rc == -1 && errno == EINTR) {
|
1371
|
+
if (!i) {
|
1372
|
+
return -1;
|
1373
|
+
}
|
1374
|
+
} else {
|
1375
|
+
return -1;
|
1376
|
+
}
|
1377
|
+
}
|
1378
|
+
} else if (rc == -1) {
|
1379
|
+
return -1;
|
1380
|
+
} else if (!rc) {
|
1381
|
+
if (!i) {
|
1382
|
+
errno = e;
|
1383
|
+
return 0;
|
1384
|
+
} else {
|
1385
|
+
errno = EILSEQ;
|
1386
|
+
return -1;
|
1387
|
+
}
|
1388
|
+
} else {
|
1389
|
+
break;
|
1390
|
+
}
|
1391
|
+
}
|
1392
|
+
if (i + 1 < n) {
|
1393
|
+
p[i] = c;
|
1394
|
+
p[i+1] = 0;
|
1395
|
+
} else if (i < n) {
|
1396
|
+
p[i] = 0;
|
1397
|
+
}
|
1398
|
+
++i;
|
1399
|
+
switch (t) {
|
1400
|
+
Whoopsie:
|
1401
|
+
if (n) p[0] = c;
|
1402
|
+
t = kAscii;
|
1403
|
+
i = 1;
|
1404
|
+
/* fallthrough */
|
1405
|
+
case kAscii:
|
1406
|
+
if (c < 0200) {
|
1407
|
+
if (c == 033) {
|
1408
|
+
t = kEsc;
|
1409
|
+
} else {
|
1410
|
+
t = kDone;
|
1411
|
+
}
|
1412
|
+
} else if (c >= 0300) {
|
1413
|
+
t = kUtf8;
|
1414
|
+
r = DecodeUtf8(c);
|
1415
|
+
} else {
|
1416
|
+
/* ignore overlong sequences */
|
1417
|
+
}
|
1418
|
+
break;
|
1419
|
+
case kUtf8:
|
1420
|
+
if ((c & 0300) == 0200) {
|
1421
|
+
r.c <<= 6;
|
1422
|
+
r.c |= c & 077;
|
1423
|
+
if (!--r.n) {
|
1424
|
+
switch (r.c) {
|
1425
|
+
case 033:
|
1426
|
+
t = kEsc; /* parsed but not canonicalized */
|
1427
|
+
break;
|
1428
|
+
case 0x9b:
|
1429
|
+
t = kCsi1; /* unusual but legal */
|
1430
|
+
break;
|
1431
|
+
case 0x8e: /* SS2 (Single Shift Two) */
|
1432
|
+
case 0x8f: /* SS3 (Single Shift Three) */
|
1433
|
+
t = kSs;
|
1434
|
+
break;
|
1435
|
+
case 0x90: /* DCS (Device Control String) */
|
1436
|
+
case 0x98: /* SOS (Start of String) */
|
1437
|
+
case 0x9d: /* OSC (Operating System Command) */
|
1438
|
+
case 0x9e: /* PM (Privacy Message) */
|
1439
|
+
case 0x9f: /* APC (Application Program Command) */
|
1440
|
+
t = kStr;
|
1441
|
+
break;
|
1442
|
+
default:
|
1443
|
+
t = kDone;
|
1444
|
+
break;
|
1445
|
+
}
|
1446
|
+
}
|
1447
|
+
} else {
|
1448
|
+
goto Whoopsie; /* ignore underlong sequences if not eof */
|
1449
|
+
}
|
1450
|
+
break;
|
1451
|
+
case kEsc:
|
1452
|
+
if (0x20 <= c && c <= 0x2f) { /* Nf */
|
1453
|
+
/*
|
1454
|
+
* Almost no one uses ANSI Nf sequences
|
1455
|
+
* They overlaps with alt+graphic keystrokes
|
1456
|
+
* We care more about being able to type alt-/
|
1457
|
+
*/
|
1458
|
+
if (c == ' ' || c == '#') {
|
1459
|
+
t = kNf;
|
1460
|
+
} else {
|
1461
|
+
t = kDone;
|
1462
|
+
}
|
1463
|
+
} else if (0x30 <= c && c <= 0x3f) { /* Fp */
|
1464
|
+
t = kDone;
|
1465
|
+
} else if (0x20 <= c && c <= 0x5F) { /* Fe */
|
1466
|
+
switch (c) {
|
1467
|
+
case '[':
|
1468
|
+
t = kCsi1;
|
1469
|
+
break;
|
1470
|
+
case 'N': /* SS2 (Single Shift Two) */
|
1471
|
+
case 'O': /* SS3 (Single Shift Three) */
|
1472
|
+
t = kSs;
|
1473
|
+
break;
|
1474
|
+
case 'P': /* DCS (Device Control String) */
|
1475
|
+
case 'X': /* SOS (Start of String) */
|
1476
|
+
case ']': /* OSC (Operating System Command) */
|
1477
|
+
case '^': /* PM (Privacy Message) */
|
1478
|
+
case '_': /* APC (Application Program Command) */
|
1479
|
+
t = kStr;
|
1480
|
+
break;
|
1481
|
+
default:
|
1482
|
+
t = kDone;
|
1483
|
+
break;
|
1484
|
+
}
|
1485
|
+
} else if (0x60 <= c && c <= 0x7e) { /* Fs */
|
1486
|
+
t = kDone;
|
1487
|
+
} else if (c == 033) {
|
1488
|
+
if (i < 3) {
|
1489
|
+
/* alt chording */
|
1490
|
+
} else {
|
1491
|
+
t = kDone; /* esc mashing */
|
1492
|
+
i = 1;
|
1493
|
+
}
|
1494
|
+
} else {
|
1495
|
+
t = kDone;
|
1496
|
+
}
|
1497
|
+
break;
|
1498
|
+
case kSs:
|
1499
|
+
t = kDone;
|
1500
|
+
break;
|
1501
|
+
case kNf:
|
1502
|
+
if (0x30 <= c && c <= 0x7e) {
|
1503
|
+
t = kDone;
|
1504
|
+
} else if (!(0x20 <= c && c <= 0x2f)) {
|
1505
|
+
goto Whoopsie;
|
1506
|
+
}
|
1507
|
+
break;
|
1508
|
+
case kCsi1:
|
1509
|
+
if (0x20 <= c && c <= 0x2f) {
|
1510
|
+
t = kCsi2;
|
1511
|
+
} else if (c == '[' && ((i == 3) ||
|
1512
|
+
(i == 4 && p[1] == 033))) {
|
1513
|
+
/* linux function keys */
|
1514
|
+
} else if (0x40 <= c && c <= 0x7e) {
|
1515
|
+
t = kDone;
|
1516
|
+
} else if (!(0x30 <= c && c <= 0x3f)) {
|
1517
|
+
goto Whoopsie;
|
1518
|
+
}
|
1519
|
+
break;
|
1520
|
+
case kCsi2:
|
1521
|
+
if (0x40 <= c && c <= 0x7e) {
|
1522
|
+
t = kDone;
|
1523
|
+
} else if (!(0x20 <= c && c <= 0x2f)) {
|
1524
|
+
goto Whoopsie;
|
1525
|
+
}
|
1526
|
+
break;
|
1527
|
+
case kStr:
|
1528
|
+
switch (c) {
|
1529
|
+
case '\a':
|
1530
|
+
t = kDone;
|
1531
|
+
break;
|
1532
|
+
case 0033: /* ESC */
|
1533
|
+
case 0302: /* C1 (UTF-8) */
|
1534
|
+
t = kStr2;
|
1535
|
+
break;
|
1536
|
+
default:
|
1537
|
+
break;
|
1538
|
+
}
|
1539
|
+
break;
|
1540
|
+
case kStr2:
|
1541
|
+
switch (c) {
|
1542
|
+
case '\a':
|
1543
|
+
case '\\': /* ST (ASCII) */
|
1544
|
+
case 0234: /* ST (UTF-8) */
|
1545
|
+
t = kDone;
|
1546
|
+
break;
|
1547
|
+
default:
|
1548
|
+
t = kStr;
|
1549
|
+
break;
|
1550
|
+
}
|
1551
|
+
break;
|
1552
|
+
default:
|
1553
|
+
assert(0);
|
1554
|
+
}
|
1555
|
+
} while (t != kDone);
|
1556
|
+
errno = e;
|
1557
|
+
return i;
|
1558
|
+
}
|
1559
|
+
|
1560
|
+
static char *GetLineChar(int fin, int fout) {
|
1561
|
+
size_t got;
|
1562
|
+
ssize_t rc;
|
1563
|
+
char seq[16];
|
1564
|
+
struct abuf a;
|
1565
|
+
struct sigaction sa[3];
|
1566
|
+
abInit(&a);
|
1567
|
+
gotint = 0;
|
1568
|
+
sigemptyset(&sa->sa_mask);
|
1569
|
+
sa->sa_flags = 0;
|
1570
|
+
sa->sa_handler = bestlineOnInt;
|
1571
|
+
sigaction(SIGINT,sa,sa+1);
|
1572
|
+
sigaction(SIGQUIT,sa,sa+2);
|
1573
|
+
for (;;) {
|
1574
|
+
if (gotint) {
|
1575
|
+
rc = -1;
|
1576
|
+
break;
|
1577
|
+
}
|
1578
|
+
if ((rc = bestlineReadCharacter(fin, seq, sizeof(seq))) == -1) {
|
1579
|
+
if (errno == EAGAIN || errno == EWOULDBLOCK) {
|
1580
|
+
if (WaitUntilReady(fin, POLLIN) > 0) {
|
1581
|
+
continue;
|
1582
|
+
}
|
1583
|
+
}
|
1584
|
+
if (errno == EINTR) {
|
1585
|
+
continue;
|
1586
|
+
} else {
|
1587
|
+
break;
|
1588
|
+
}
|
1589
|
+
}
|
1590
|
+
if (!(got = rc)) {
|
1591
|
+
if (a.len) {
|
1592
|
+
break;
|
1593
|
+
} else {
|
1594
|
+
rc = -1;
|
1595
|
+
break;
|
1596
|
+
}
|
1597
|
+
}
|
1598
|
+
if (seq[0] == '\r') {
|
1599
|
+
if (HasPendingInput(fin)) {
|
1600
|
+
if ((rc = bestlineReadCharacter(fin, seq + 1, sizeof(seq) - 1)) > 0) {
|
1601
|
+
if (seq[0] == '\n') {
|
1602
|
+
break;
|
1603
|
+
}
|
1604
|
+
} else {
|
1605
|
+
rc = -1;
|
1606
|
+
break;
|
1607
|
+
}
|
1608
|
+
} else {
|
1609
|
+
write(fout, "\n", 1);
|
1610
|
+
break;
|
1611
|
+
}
|
1612
|
+
} else if (seq[0] == Ctrl('D')) {
|
1613
|
+
break;
|
1614
|
+
} else if (seq[0] == '\n') {
|
1615
|
+
break;
|
1616
|
+
} else if (seq[0] == '\b') {
|
1617
|
+
while (a.len && (a.b[a.len - 1] & 0300) == 0200) --a.len;
|
1618
|
+
if (a.len) --a.len;
|
1619
|
+
}
|
1620
|
+
if (!IsControl(seq[0])) {
|
1621
|
+
abAppend(&a, seq, got);
|
1622
|
+
}
|
1623
|
+
}
|
1624
|
+
sigaction(SIGQUIT,sa+2,0);
|
1625
|
+
sigaction(SIGINT,sa+1,0);
|
1626
|
+
if (gotint) {
|
1627
|
+
abFree(&a);
|
1628
|
+
raise(gotint);
|
1629
|
+
errno = EINTR;
|
1630
|
+
rc = -1;
|
1631
|
+
}
|
1632
|
+
if (rc != -1) {
|
1633
|
+
return a.b;
|
1634
|
+
} else {
|
1635
|
+
abFree(&a);
|
1636
|
+
return 0;
|
1637
|
+
}
|
1638
|
+
}
|
1639
|
+
|
1640
|
+
static char *GetLine(FILE *in, FILE *out) {
|
1641
|
+
if (!IsCharDev(fileno(in))) {
|
1642
|
+
return GetLineBlock(in);
|
1643
|
+
} else {
|
1644
|
+
return GetLineChar(fileno(in), fileno(out));
|
1645
|
+
}
|
1646
|
+
}
|
1647
|
+
|
1648
|
+
static char *Copy(char *d, const char *s, size_t n) {
|
1649
|
+
memcpy(d, s, n);
|
1650
|
+
return d + n;
|
1651
|
+
}
|
1652
|
+
|
1653
|
+
static int CompareStrings(const char *a, const char *b) {
|
1654
|
+
size_t i;
|
1655
|
+
int x, y, c;
|
1656
|
+
for (i = 0;; ++i) {
|
1657
|
+
x = bestlineLowercase(a[i] & 255);
|
1658
|
+
y = bestlineLowercase(b[i] & 255);
|
1659
|
+
if ((c = x - y) || !x) {
|
1660
|
+
return c;
|
1661
|
+
}
|
1662
|
+
}
|
1663
|
+
}
|
1664
|
+
|
1665
|
+
static const char *FindSubstringReverse(const char *p, size_t n,
|
1666
|
+
const char *q, size_t m) {
|
1667
|
+
size_t i;
|
1668
|
+
if (m <= n) {
|
1669
|
+
n -= m;
|
1670
|
+
do {
|
1671
|
+
for (i = 0; i < m; ++i) {
|
1672
|
+
if (p[n + i] != q[i]) {
|
1673
|
+
break;
|
1674
|
+
}
|
1675
|
+
}
|
1676
|
+
if (i == m) {
|
1677
|
+
return p + n;
|
1678
|
+
}
|
1679
|
+
} while (n--);
|
1680
|
+
}
|
1681
|
+
return 0;
|
1682
|
+
}
|
1683
|
+
|
1684
|
+
static int ParseUnsigned(const char *s, void *e) {
|
1685
|
+
int c, x;
|
1686
|
+
for (x = 0; (c = *s++);) {
|
1687
|
+
if ('0' <= c && c <= '9') {
|
1688
|
+
x = Min(c - '0' + x * 10, 32767);
|
1689
|
+
} else {
|
1690
|
+
break;
|
1691
|
+
}
|
1692
|
+
}
|
1693
|
+
if (e) *(const char **)e = s;
|
1694
|
+
return x;
|
1695
|
+
}
|
1696
|
+
|
1697
|
+
/**
|
1698
|
+
* Returns UNICODE CJK Monospace Width of string.
|
1699
|
+
*
|
1700
|
+
* Control codes and ANSI sequences have a width of zero. We only parse
|
1701
|
+
* a limited subset of ANSI here since we don't store ANSI codes in the
|
1702
|
+
* linenoiseState::buf, but we do encourage CSI color codes in prompts.
|
1703
|
+
*/
|
1704
|
+
static size_t GetMonospaceWidth(const char *p, size_t n, char *out_haswides) {
|
1705
|
+
int c, d;
|
1706
|
+
size_t i, w;
|
1707
|
+
struct rune r;
|
1708
|
+
char haswides;
|
1709
|
+
enum { kAscii, kUtf8, kEsc, kCsi1, kCsi2 } t;
|
1710
|
+
for (haswides = r.c = r.n = w = i = 0, t = kAscii; i < n; ++i) {
|
1711
|
+
c = p[i] & 255;
|
1712
|
+
switch (t) {
|
1713
|
+
Whoopsie:
|
1714
|
+
t = kAscii;
|
1715
|
+
/* fallthrough */
|
1716
|
+
case kAscii:
|
1717
|
+
if (c < 0200) {
|
1718
|
+
if (c == 033) {
|
1719
|
+
t = kEsc;
|
1720
|
+
} else {
|
1721
|
+
++w;
|
1722
|
+
}
|
1723
|
+
} else if (c >= 0300) {
|
1724
|
+
t = kUtf8;
|
1725
|
+
r = DecodeUtf8(c);
|
1726
|
+
}
|
1727
|
+
break;
|
1728
|
+
case kUtf8:
|
1729
|
+
if ((c & 0300) == 0200) {
|
1730
|
+
r.c <<= 6;
|
1731
|
+
r.c |= c & 077;
|
1732
|
+
if (!--r.n) {
|
1733
|
+
d = GetMonospaceCharacterWidth(r.c);
|
1734
|
+
d = Max(0, d);
|
1735
|
+
w += d;
|
1736
|
+
haswides |= d > 1;
|
1737
|
+
t = kAscii;
|
1738
|
+
break;
|
1739
|
+
}
|
1740
|
+
} else {
|
1741
|
+
goto Whoopsie;
|
1742
|
+
}
|
1743
|
+
break;
|
1744
|
+
case kEsc:
|
1745
|
+
if (c == '[') {
|
1746
|
+
t = kCsi1;
|
1747
|
+
} else {
|
1748
|
+
t = kAscii;
|
1749
|
+
}
|
1750
|
+
break;
|
1751
|
+
case kCsi1:
|
1752
|
+
if (0x20 <= c && c <= 0x2f) {
|
1753
|
+
t = kCsi2;
|
1754
|
+
} else if (0x40 <= c && c <= 0x7e) {
|
1755
|
+
t = kAscii;
|
1756
|
+
} else if (!(0x30 <= c && c <= 0x3f)) {
|
1757
|
+
goto Whoopsie;
|
1758
|
+
}
|
1759
|
+
break;
|
1760
|
+
case kCsi2:
|
1761
|
+
if (0x40 <= c && c <= 0x7e) {
|
1762
|
+
t = kAscii;
|
1763
|
+
} else if (!(0x20 <= c && c <= 0x2f)) {
|
1764
|
+
goto Whoopsie;
|
1765
|
+
}
|
1766
|
+
break;
|
1767
|
+
default:
|
1768
|
+
assert(0);
|
1769
|
+
}
|
1770
|
+
}
|
1771
|
+
if (out_haswides) {
|
1772
|
+
*out_haswides = haswides;
|
1773
|
+
}
|
1774
|
+
return w;
|
1775
|
+
}
|
1776
|
+
|
1777
|
+
static int bestlineIsUnsupportedTerm(void) {
|
1778
|
+
size_t i;
|
1779
|
+
char *term;
|
1780
|
+
static char once, res;
|
1781
|
+
if (!once) {
|
1782
|
+
if ((term = getenv("TERM"))) {
|
1783
|
+
for (i = 0; i < sizeof(kUnsupported) / sizeof(*kUnsupported); i++) {
|
1784
|
+
if (!CompareStrings(term,kUnsupported[i])) {
|
1785
|
+
res = 1;
|
1786
|
+
break;
|
1787
|
+
}
|
1788
|
+
}
|
1789
|
+
}
|
1790
|
+
once = 1;
|
1791
|
+
}
|
1792
|
+
return res;
|
1793
|
+
}
|
1794
|
+
|
1795
|
+
static int enableRawMode(int fd) {
|
1796
|
+
struct termios raw;
|
1797
|
+
struct sigaction sa;
|
1798
|
+
if (tcgetattr(fd,&orig_termios) != -1) {
|
1799
|
+
raw = orig_termios;
|
1800
|
+
raw.c_iflag &= ~(BRKINT | ICRNL | INPCK | ISTRIP | IXON);
|
1801
|
+
raw.c_lflag &= ~(ECHO | ICANON | IEXTEN | ISIG);
|
1802
|
+
raw.c_oflag &= ~OPOST;
|
1803
|
+
raw.c_iflag |= IUTF8;
|
1804
|
+
raw.c_cflag |= CS8;
|
1805
|
+
raw.c_cc[VMIN] = 1;
|
1806
|
+
raw.c_cc[VTIME] = 0;
|
1807
|
+
if (tcsetattr(fd,TCSANOW,&raw) != -1) {
|
1808
|
+
sa.sa_flags = 0;
|
1809
|
+
sa.sa_handler = bestlineOnCont;
|
1810
|
+
sigemptyset(&sa.sa_mask);
|
1811
|
+
sigaction(SIGCONT,&sa,&orig_cont);
|
1812
|
+
sa.sa_handler = bestlineOnWinch;
|
1813
|
+
sigaction(SIGWINCH,&sa,&orig_winch);
|
1814
|
+
rawmode = fd;
|
1815
|
+
gotwinch = 0;
|
1816
|
+
gotcont = 0;
|
1817
|
+
return 0;
|
1818
|
+
}
|
1819
|
+
}
|
1820
|
+
errno = ENOTTY;
|
1821
|
+
return -1;
|
1822
|
+
}
|
1823
|
+
|
1824
|
+
static void bestlineUnpause(int fd) {
|
1825
|
+
if (ispaused) {
|
1826
|
+
tcflow(fd, TCOON);
|
1827
|
+
ispaused = 0;
|
1828
|
+
}
|
1829
|
+
}
|
1830
|
+
|
1831
|
+
void bestlineDisableRawMode(void) {
|
1832
|
+
if (rawmode != -1) {
|
1833
|
+
bestlineUnpause(rawmode);
|
1834
|
+
sigaction(SIGCONT,&orig_cont,0);
|
1835
|
+
sigaction(SIGWINCH,&orig_winch,0);
|
1836
|
+
tcsetattr(rawmode,TCSANOW,&orig_termios);
|
1837
|
+
rawmode = -1;
|
1838
|
+
}
|
1839
|
+
}
|
1840
|
+
|
1841
|
+
static int bestlineWrite(int fd, const void *p, size_t n) {
|
1842
|
+
ssize_t rc;
|
1843
|
+
size_t wrote;
|
1844
|
+
do {
|
1845
|
+
for (;;) {
|
1846
|
+
if (gotint) {
|
1847
|
+
errno = EINTR;
|
1848
|
+
return -1;
|
1849
|
+
}
|
1850
|
+
if (ispaused) {
|
1851
|
+
return 0;
|
1852
|
+
}
|
1853
|
+
rc = write(fd, p, n);
|
1854
|
+
if (rc == -1 && errno == EINTR) {
|
1855
|
+
continue;
|
1856
|
+
} else if (rc == -1 && (errno == EAGAIN || errno == EWOULDBLOCK)) {
|
1857
|
+
if (WaitUntilReady(fd, POLLOUT) == -1) {
|
1858
|
+
if (errno == EINTR) {
|
1859
|
+
continue;
|
1860
|
+
} else {
|
1861
|
+
return -1;
|
1862
|
+
}
|
1863
|
+
}
|
1864
|
+
} else {
|
1865
|
+
break;
|
1866
|
+
}
|
1867
|
+
}
|
1868
|
+
if (rc != -1) {
|
1869
|
+
wrote = rc;
|
1870
|
+
n -= wrote;
|
1871
|
+
p = (char *)p + wrote;
|
1872
|
+
} else {
|
1873
|
+
return -1;
|
1874
|
+
}
|
1875
|
+
} while (n);
|
1876
|
+
return 0;
|
1877
|
+
}
|
1878
|
+
|
1879
|
+
static int bestlineWriteStr(int fd, const char *p) {
|
1880
|
+
return bestlineWrite(fd, p, strlen(p));
|
1881
|
+
}
|
1882
|
+
|
1883
|
+
static ssize_t bestlineRead(int fd, char *buf, size_t size,
|
1884
|
+
struct bestlineState *l) {
|
1885
|
+
size_t got;
|
1886
|
+
ssize_t rc;
|
1887
|
+
int refreshme;
|
1888
|
+
do {
|
1889
|
+
refreshme = 0;
|
1890
|
+
if (gotint) {
|
1891
|
+
errno = EINTR;
|
1892
|
+
return -1;
|
1893
|
+
}
|
1894
|
+
if (gotcont && rawmode != -1) {
|
1895
|
+
enableRawMode(rawmode);
|
1896
|
+
if (l) refreshme = 1;
|
1897
|
+
}
|
1898
|
+
if (gotwinch && l) {
|
1899
|
+
refreshme = 1;
|
1900
|
+
}
|
1901
|
+
if (refreshme) bestlineRefreshLine(l);
|
1902
|
+
rc = bestlineReadCharacter(fd, buf, size);
|
1903
|
+
} while (rc == -1 && errno == EINTR);
|
1904
|
+
if (rc != -1) {
|
1905
|
+
got = rc;
|
1906
|
+
if (got > 0 && l) {
|
1907
|
+
memcpy(l->seq[1], l->seq[0], sizeof(l->seq[0]));
|
1908
|
+
memset(l->seq[0], 0, sizeof(l->seq[0]));
|
1909
|
+
memcpy(l->seq[0], buf, Min(Min(size, got), sizeof(l->seq[0]) - 1));
|
1910
|
+
}
|
1911
|
+
}
|
1912
|
+
return rc;
|
1913
|
+
}
|
1914
|
+
|
1915
|
+
/**
|
1916
|
+
* Returns number of columns in current terminal.
|
1917
|
+
*
|
1918
|
+
* 1. Checks COLUMNS environment variable (set by Emacs)
|
1919
|
+
* 2. Tries asking termios (works for pseudoteletypewriters)
|
1920
|
+
* 3. Falls back to inband signalling (works w/ pipe or serial)
|
1921
|
+
* 4. Otherwise we conservatively assume 80 columns
|
1922
|
+
*
|
1923
|
+
* @param ws should be initialized by caller to zero before first call
|
1924
|
+
* @param ifd is input file descriptor
|
1925
|
+
* @param ofd is output file descriptor
|
1926
|
+
* @return window size
|
1927
|
+
*/
|
1928
|
+
static struct winsize GetTerminalSize(struct winsize ws, int ifd, int ofd) {
|
1929
|
+
int x;
|
1930
|
+
ssize_t n;
|
1931
|
+
char *p, *s, b[16];
|
1932
|
+
ioctl(ofd, TIOCGWINSZ, &ws);
|
1933
|
+
if ((!ws.ws_row &&
|
1934
|
+
(s = getenv("ROWS")) &&
|
1935
|
+
(x = ParseUnsigned(s, 0)))) {
|
1936
|
+
ws.ws_row = x;
|
1937
|
+
}
|
1938
|
+
if ((!ws.ws_col &&
|
1939
|
+
(s = getenv("COLUMNS")) &&
|
1940
|
+
(x = ParseUnsigned(s, 0)))) {
|
1941
|
+
ws.ws_col = x;
|
1942
|
+
}
|
1943
|
+
if (((!ws.ws_col || !ws.ws_row) &&
|
1944
|
+
bestlineRead(ifd,0,0,0) != -1 &&
|
1945
|
+
bestlineWriteStr(ofd,
|
1946
|
+
"\0337" /* save position */
|
1947
|
+
"\033[9979;9979H" /* move cursor to bottom right corner */
|
1948
|
+
"\033[6n" /* report position */
|
1949
|
+
"\0338") != -1 && /* restore position */
|
1950
|
+
(n = bestlineRead(ifd,b,sizeof(b),0)) != -1 &&
|
1951
|
+
n && b[0] == 033 && b[1] == '[' && b[n - 1] == 'R')) {
|
1952
|
+
p = b+2;
|
1953
|
+
if ((x = ParseUnsigned(p,&p))) ws.ws_row = x;
|
1954
|
+
if (*p++ == ';' && (x = ParseUnsigned(p,0))) ws.ws_col = x;
|
1955
|
+
}
|
1956
|
+
if (!ws.ws_col) ws.ws_col = 80;
|
1957
|
+
if (!ws.ws_row) ws.ws_row = 24;
|
1958
|
+
return ws;
|
1959
|
+
}
|
1960
|
+
|
1961
|
+
/* Clear the screen. Used to handle ctrl+l */
|
1962
|
+
void bestlineClearScreen(int fd) {
|
1963
|
+
bestlineWriteStr(fd,
|
1964
|
+
"\033[H" /* move cursor to top left corner */
|
1965
|
+
"\033[2J"); /* erase display */
|
1966
|
+
}
|
1967
|
+
|
1968
|
+
static void bestlineBeep(void) {
|
1969
|
+
/* THE TERMINAL BELL IS DEAD - HISTORY HAS KILLED IT */
|
1970
|
+
}
|
1971
|
+
|
1972
|
+
static char bestlineGrow(struct bestlineState *ls, size_t n) {
|
1973
|
+
char *p;
|
1974
|
+
size_t m;
|
1975
|
+
m = ls->buflen;
|
1976
|
+
if (m >= n) return 1;
|
1977
|
+
do m += m >> 1;
|
1978
|
+
while (m < n);
|
1979
|
+
if (!(p = (char *)realloc(ls->buf, m * sizeof(*ls->buf)))) return 0;
|
1980
|
+
ls->buf = p;
|
1981
|
+
ls->buflen = m;
|
1982
|
+
return 1;
|
1983
|
+
}
|
1984
|
+
|
1985
|
+
/* This is an helper function for bestlineEdit() and is called when the
|
1986
|
+
* user types the <tab> key in order to complete the string currently in the
|
1987
|
+
* input.
|
1988
|
+
*
|
1989
|
+
* The state of the editing is encapsulated into the pointed bestlineState
|
1990
|
+
* structure as described in the structure definition. */
|
1991
|
+
static ssize_t bestlineCompleteLine(struct bestlineState *ls, char *seq, int size) {
|
1992
|
+
ssize_t nread;
|
1993
|
+
size_t i, n, stop;
|
1994
|
+
bestlineCompletions lc;
|
1995
|
+
struct bestlineState saved;
|
1996
|
+
nread=0;
|
1997
|
+
memset(&lc,0,sizeof(lc));
|
1998
|
+
completionCallback(ls->buf,&lc);
|
1999
|
+
if (!lc.len) {
|
2000
|
+
bestlineBeep();
|
2001
|
+
} else {
|
2002
|
+
i = 0;
|
2003
|
+
stop = 0;
|
2004
|
+
while (!stop) {
|
2005
|
+
/* Show completion or original buffer */
|
2006
|
+
if (i < lc.len) {
|
2007
|
+
saved = *ls;
|
2008
|
+
ls->len = ls->pos = strlen(lc.cvec[i]);
|
2009
|
+
ls->buf = lc.cvec[i];
|
2010
|
+
bestlineRefreshLine(ls);
|
2011
|
+
ls->len = saved.len;
|
2012
|
+
ls->pos = saved.pos;
|
2013
|
+
ls->buf = saved.buf;
|
2014
|
+
} else {
|
2015
|
+
bestlineRefreshLine(ls);
|
2016
|
+
}
|
2017
|
+
if ((nread = bestlineRead(ls->ifd,seq,size,ls)) <= 0) {
|
2018
|
+
bestlineFreeCompletions(&lc);
|
2019
|
+
return -1;
|
2020
|
+
}
|
2021
|
+
switch (seq[0]) {
|
2022
|
+
case '\t':
|
2023
|
+
i = (i+1) % (lc.len+1);
|
2024
|
+
if (i == lc.len) {
|
2025
|
+
bestlineBeep();
|
2026
|
+
}
|
2027
|
+
break;
|
2028
|
+
default:
|
2029
|
+
if (i < lc.len) {
|
2030
|
+
n = strlen(lc.cvec[i]);
|
2031
|
+
if (bestlineGrow(ls, n + 1)) {
|
2032
|
+
memcpy(ls->buf, lc.cvec[i], n + 1);
|
2033
|
+
ls->len = ls->pos = n;
|
2034
|
+
}
|
2035
|
+
}
|
2036
|
+
stop = 1;
|
2037
|
+
break;
|
2038
|
+
}
|
2039
|
+
}
|
2040
|
+
}
|
2041
|
+
bestlineFreeCompletions(&lc);
|
2042
|
+
return nread;
|
2043
|
+
}
|
2044
|
+
|
2045
|
+
static void bestlineEditHistoryGoto(struct bestlineState *l, unsigned i) {
|
2046
|
+
size_t n;
|
2047
|
+
if (historylen <= 1) return;
|
2048
|
+
i = Max(Min(i,historylen-1),0);
|
2049
|
+
free(history[historylen - 1 - l->hindex]);
|
2050
|
+
history[historylen - 1 - l->hindex] = strdup(l->buf);
|
2051
|
+
l->hindex = i;
|
2052
|
+
n = strlen(history[historylen - 1 - l->hindex]);
|
2053
|
+
bestlineGrow(l, n + 1);
|
2054
|
+
n = Min(n, l->buflen - 1);
|
2055
|
+
memcpy(l->buf, history[historylen - 1 - l->hindex], n);
|
2056
|
+
l->buf[n] = 0;
|
2057
|
+
l->len = l->pos = n;
|
2058
|
+
bestlineRefreshLine(l);
|
2059
|
+
}
|
2060
|
+
|
2061
|
+
static void bestlineEditHistoryMove(struct bestlineState *l, int dx) {
|
2062
|
+
bestlineEditHistoryGoto(l,l->hindex+dx);
|
2063
|
+
}
|
2064
|
+
|
2065
|
+
static char *bestlineMakeSearchPrompt(struct abuf *ab, int fail, const char *s, int n) {
|
2066
|
+
ab->len=0;
|
2067
|
+
abAppendw(ab,'(');
|
2068
|
+
if (fail) abAppends(ab,"failed ");
|
2069
|
+
abAppends(ab,"reverse-i-search `\033[4m");
|
2070
|
+
abAppend(ab,s,n);
|
2071
|
+
abAppends(ab,"\033[24m");
|
2072
|
+
abAppends(ab,s+n);
|
2073
|
+
abAppendw(ab,Read32le("') "));
|
2074
|
+
return ab->b;
|
2075
|
+
}
|
2076
|
+
|
2077
|
+
static int bestlineSearch(struct bestlineState *l, char *seq, int size) {
|
2078
|
+
char *p;
|
2079
|
+
char isstale;
|
2080
|
+
struct abuf ab;
|
2081
|
+
struct abuf prompt;
|
2082
|
+
unsigned i, j, k, matlen;
|
2083
|
+
const char *oldprompt, *q;
|
2084
|
+
int rc, fail, added, oldpos, oldindex;
|
2085
|
+
if (historylen <= 1) return 0;
|
2086
|
+
abInit(&ab);
|
2087
|
+
abInit(&prompt);
|
2088
|
+
oldpos = l->pos;
|
2089
|
+
oldprompt = l->prompt;
|
2090
|
+
oldindex = l->hindex;
|
2091
|
+
for (fail=matlen=0;;) {
|
2092
|
+
l->prompt = bestlineMakeSearchPrompt(&prompt,fail,ab.b,matlen);
|
2093
|
+
bestlineRefreshLine(l);
|
2094
|
+
fail = 1;
|
2095
|
+
added = 0;
|
2096
|
+
j = l->pos;
|
2097
|
+
i = l->hindex;
|
2098
|
+
rc = bestlineRead(l->ifd,seq,size,l);
|
2099
|
+
if (rc > 0) {
|
2100
|
+
if (seq[0] == Ctrl('?') || seq[0] == Ctrl('H')) {
|
2101
|
+
if (ab.len) {
|
2102
|
+
--ab.len;
|
2103
|
+
matlen = Min(matlen, ab.len);
|
2104
|
+
}
|
2105
|
+
} else if (seq[0] == Ctrl('R')) {
|
2106
|
+
if (j) {
|
2107
|
+
--j;
|
2108
|
+
} else if (i + 1 < historylen) {
|
2109
|
+
++i;
|
2110
|
+
j = strlen(history[historylen - 1 - i]);
|
2111
|
+
}
|
2112
|
+
} else if (seq[0] == Ctrl('G')) {
|
2113
|
+
bestlineEditHistoryGoto(l,oldindex);
|
2114
|
+
l->pos = oldpos;
|
2115
|
+
rc = 0;
|
2116
|
+
break;
|
2117
|
+
} else if (IsControl(seq[0])) { /* only sees canonical c0 */
|
2118
|
+
break;
|
2119
|
+
} else {
|
2120
|
+
abAppend(&ab,seq,rc);
|
2121
|
+
added = rc;
|
2122
|
+
}
|
2123
|
+
} else {
|
2124
|
+
break;
|
2125
|
+
}
|
2126
|
+
isstale = 0;
|
2127
|
+
while (i < historylen) {
|
2128
|
+
p = history[historylen - 1 - i];
|
2129
|
+
k = strlen(p);
|
2130
|
+
if (!isstale) {
|
2131
|
+
j = Min(k, j + ab.len);
|
2132
|
+
} else {
|
2133
|
+
isstale = 0;
|
2134
|
+
j = k;
|
2135
|
+
}
|
2136
|
+
if ((q = FindSubstringReverse(p, j, ab.b, ab.len))) {
|
2137
|
+
bestlineEditHistoryGoto(l,i);
|
2138
|
+
l->pos = q - p;
|
2139
|
+
fail = 0;
|
2140
|
+
if (added) {
|
2141
|
+
matlen += added;
|
2142
|
+
added = 0;
|
2143
|
+
}
|
2144
|
+
break;
|
2145
|
+
} else {
|
2146
|
+
isstale = 1;
|
2147
|
+
++i;
|
2148
|
+
}
|
2149
|
+
}
|
2150
|
+
}
|
2151
|
+
l->prompt = oldprompt;
|
2152
|
+
bestlineRefreshLine(l);
|
2153
|
+
abFree(&prompt);
|
2154
|
+
abFree(&ab);
|
2155
|
+
bestlineRefreshLine(l);
|
2156
|
+
return rc;
|
2157
|
+
}
|
2158
|
+
|
2159
|
+
static void bestlineRingFree(void) {
|
2160
|
+
size_t i;
|
2161
|
+
for (i = 0; i < BESTLINE_MAX_RING; ++i) {
|
2162
|
+
if (ring.p[i]) {
|
2163
|
+
free(ring.p[i]);
|
2164
|
+
ring.p[i] = 0;
|
2165
|
+
}
|
2166
|
+
}
|
2167
|
+
}
|
2168
|
+
|
2169
|
+
static void bestlineRingPush(const char *p, size_t n) {
|
2170
|
+
char *q;
|
2171
|
+
if (!n) return;
|
2172
|
+
if (!(q = (char *)malloc(n + 1))) return;
|
2173
|
+
ring.i = (ring.i + 1) % BESTLINE_MAX_RING;
|
2174
|
+
free(ring.p[ring.i]);
|
2175
|
+
ring.p[ring.i] = (char *)memcpy(q, p, n);
|
2176
|
+
ring.p[ring.i][n] = 0;
|
2177
|
+
}
|
2178
|
+
|
2179
|
+
static void bestlineRingRotate(void) {
|
2180
|
+
size_t i;
|
2181
|
+
for (i = 0; i < BESTLINE_MAX_RING; ++i) {
|
2182
|
+
ring.i = (ring.i - 1) % BESTLINE_MAX_RING;
|
2183
|
+
if (ring.p[ring.i]) break;
|
2184
|
+
}
|
2185
|
+
}
|
2186
|
+
|
2187
|
+
static char *bestlineRefreshHints(struct bestlineState *l) {
|
2188
|
+
char *hint;
|
2189
|
+
struct abuf ab;
|
2190
|
+
const char *ansi1 = "\033[90m", *ansi2 = "\033[39m";
|
2191
|
+
if (!hintsCallback) return 0;
|
2192
|
+
if (!(hint = hintsCallback(l->buf, &ansi1, &ansi2))) return 0;
|
2193
|
+
abInit(&ab);
|
2194
|
+
if (ansi1) abAppends(&ab, ansi1);
|
2195
|
+
abAppends(&ab, hint);
|
2196
|
+
if (ansi2) abAppends(&ab, ansi2);
|
2197
|
+
if (freeHintsCallback) freeHintsCallback(hint);
|
2198
|
+
return ab.b;
|
2199
|
+
}
|
2200
|
+
|
2201
|
+
static size_t Backward(struct bestlineState *l, size_t pos) {
|
2202
|
+
if (pos) {
|
2203
|
+
do --pos;
|
2204
|
+
while (pos && (l->buf[pos] & 0300) == 0200);
|
2205
|
+
}
|
2206
|
+
return pos;
|
2207
|
+
}
|
2208
|
+
|
2209
|
+
static int bestlineEditMirrorLeft(struct bestlineState *l, int res[2]) {
|
2210
|
+
unsigned c, pos, left, right, depth, index;
|
2211
|
+
if ((pos = Backward(l, l->pos))) {
|
2212
|
+
right = GetUtf8(l->buf + pos, l->len - pos).c;
|
2213
|
+
if ((left = bestlineMirrorLeft(right))) {
|
2214
|
+
depth = 0;
|
2215
|
+
index = pos;
|
2216
|
+
do {
|
2217
|
+
pos = Backward(l, pos);
|
2218
|
+
c = GetUtf8(l->buf + pos, l->len - pos).c;
|
2219
|
+
if (c == right) {
|
2220
|
+
++depth;
|
2221
|
+
} else if (c == left) {
|
2222
|
+
if (depth) {
|
2223
|
+
--depth;
|
2224
|
+
} else {
|
2225
|
+
res[0] = pos;
|
2226
|
+
res[1] = index;
|
2227
|
+
return 0;
|
2228
|
+
}
|
2229
|
+
}
|
2230
|
+
} while (pos);
|
2231
|
+
}
|
2232
|
+
}
|
2233
|
+
return -1;
|
2234
|
+
}
|
2235
|
+
|
2236
|
+
static int bestlineEditMirrorRight(struct bestlineState *l, int res[2]) {
|
2237
|
+
struct rune rune;
|
2238
|
+
unsigned pos, left, right, depth, index;
|
2239
|
+
pos = l->pos;
|
2240
|
+
rune = GetUtf8(l->buf + pos, l->len - pos);
|
2241
|
+
left = rune.c;
|
2242
|
+
if ((right = bestlineMirrorRight(left))) {
|
2243
|
+
depth = 0;
|
2244
|
+
index = pos;
|
2245
|
+
do {
|
2246
|
+
pos += rune.n;
|
2247
|
+
rune = GetUtf8(l->buf + pos, l->len - pos);
|
2248
|
+
if (rune.c == left) {
|
2249
|
+
++depth;
|
2250
|
+
} else if (rune.c == right) {
|
2251
|
+
if (depth) {
|
2252
|
+
--depth;
|
2253
|
+
} else {
|
2254
|
+
res[0] = index;
|
2255
|
+
res[1] = pos;
|
2256
|
+
return 0;
|
2257
|
+
}
|
2258
|
+
}
|
2259
|
+
} while (pos + rune.n < l->len);
|
2260
|
+
}
|
2261
|
+
return -1;
|
2262
|
+
}
|
2263
|
+
|
2264
|
+
static int bestlineEditMirror(struct bestlineState *l, int res[2]) {
|
2265
|
+
int rc;
|
2266
|
+
rc = bestlineEditMirrorLeft(l, res);
|
2267
|
+
if (rc == -1) rc = bestlineEditMirrorRight(l, res);
|
2268
|
+
return rc;
|
2269
|
+
}
|
2270
|
+
|
2271
|
+
static void bestlineRefreshLineImpl(struct bestlineState *l, int force) {
|
2272
|
+
char *hint;
|
2273
|
+
char flipit;
|
2274
|
+
char hasflip;
|
2275
|
+
char haswides;
|
2276
|
+
struct abuf ab;
|
2277
|
+
const char *buf;
|
2278
|
+
struct rune rune;
|
2279
|
+
struct winsize oldsize;
|
2280
|
+
int fd, plen, rows, len, pos;
|
2281
|
+
unsigned x, xn, yn, width, pwidth;
|
2282
|
+
int i, t, cx, cy, tn, resized, flip[2];
|
2283
|
+
|
2284
|
+
/*
|
2285
|
+
* synchonize the i/o state
|
2286
|
+
*/
|
2287
|
+
if (ispaused) {
|
2288
|
+
if (force) {
|
2289
|
+
bestlineUnpause(l->ofd);
|
2290
|
+
} else {
|
2291
|
+
return;
|
2292
|
+
}
|
2293
|
+
}
|
2294
|
+
if (!force && HasPendingInput(l->ifd)) {
|
2295
|
+
l->dirty = 1;
|
2296
|
+
return;
|
2297
|
+
}
|
2298
|
+
oldsize = l->ws;
|
2299
|
+
if ((resized = gotwinch) && rawmode != -1) {
|
2300
|
+
gotwinch = 0;
|
2301
|
+
l->ws = GetTerminalSize(l->ws, l->ifd, l->ofd);
|
2302
|
+
}
|
2303
|
+
hasflip = !l->final && !bestlineEditMirror(l, flip);
|
2304
|
+
|
2305
|
+
StartOver:
|
2306
|
+
fd = l->ofd;
|
2307
|
+
buf = l->buf;
|
2308
|
+
pos = l->pos;
|
2309
|
+
len = l->len;
|
2310
|
+
xn = l->ws.ws_col;
|
2311
|
+
yn = l->ws.ws_row;
|
2312
|
+
plen = strlen(l->prompt);
|
2313
|
+
pwidth = GetMonospaceWidth(l->prompt, plen, 0);
|
2314
|
+
width = GetMonospaceWidth(buf, len, &haswides);
|
2315
|
+
|
2316
|
+
/*
|
2317
|
+
* handle the case where the line is larger than the whole display
|
2318
|
+
* gnu readline actually isn't able to deal with this situation!!!
|
2319
|
+
* we kludge xn to address the edge case of wide chars on the edge
|
2320
|
+
*/
|
2321
|
+
for (tn = xn - haswides * 2;;) {
|
2322
|
+
if (pwidth + width + 1 < tn * yn) break; /* we're fine */
|
2323
|
+
if (!len || width < 2) break; /* we can't do anything */
|
2324
|
+
if (pwidth + 2 > tn * yn) break; /* we can't do anything */
|
2325
|
+
if (pos > len / 2) {
|
2326
|
+
/* hide content on the left if we're editing on the right */
|
2327
|
+
rune = GetUtf8(buf, len);
|
2328
|
+
buf += rune.n;
|
2329
|
+
len -= rune.n;
|
2330
|
+
pos -= rune.n;
|
2331
|
+
} else {
|
2332
|
+
/* hide content on the right if we're editing on left */
|
2333
|
+
t = len;
|
2334
|
+
while (len && (buf[len - 1] & 0300) == 0200) --len;
|
2335
|
+
if (len) --len;
|
2336
|
+
rune = GetUtf8(buf + len, t - len);
|
2337
|
+
}
|
2338
|
+
if ((t = GetMonospaceCharacterWidth(rune.c)) > 0) {
|
2339
|
+
width -= t;
|
2340
|
+
}
|
2341
|
+
}
|
2342
|
+
pos = Max(0, Min(pos, len));
|
2343
|
+
|
2344
|
+
/*
|
2345
|
+
* now generate the terminal codes to update the line
|
2346
|
+
*
|
2347
|
+
* since we support unlimited lines it's important that we don't
|
2348
|
+
* clear the screen before we draw the screen. doing that causes
|
2349
|
+
* flickering. the key with terminals is to overwrite cells, and
|
2350
|
+
* then use \e[K and \e[J to clear everything else.
|
2351
|
+
*
|
2352
|
+
* we make the assumption that prompts and hints may contain ansi
|
2353
|
+
* sequences, but the buffer does not.
|
2354
|
+
*
|
2355
|
+
* we need to handle the edge case where a wide character like 度
|
2356
|
+
* might be at the edge of the window, when there's one cell left.
|
2357
|
+
* so we can't use division based on string width to compute the
|
2358
|
+
* coordinates and have to track it as we go.
|
2359
|
+
*/
|
2360
|
+
cy = -1;
|
2361
|
+
cx = -1;
|
2362
|
+
rows = 1;
|
2363
|
+
abInit(&ab);
|
2364
|
+
abAppendw(&ab, '\r'); /* start of line */
|
2365
|
+
if (l->rows - l->oldpos - 1 > 0) {
|
2366
|
+
abAppends(&ab, "\033[");
|
2367
|
+
abAppendu(&ab, l->rows - l->oldpos - 1);
|
2368
|
+
abAppendw(&ab, 'A'); /* cursor up clamped */
|
2369
|
+
}
|
2370
|
+
abAppends(&ab, l->prompt);
|
2371
|
+
x = pwidth;
|
2372
|
+
for (i = 0; i < len; i += rune.n) {
|
2373
|
+
rune = GetUtf8(buf + i, len - i);
|
2374
|
+
if (x && x + rune.n > xn) {
|
2375
|
+
if (cy >= 0) ++cy;
|
2376
|
+
if (x < xn) {
|
2377
|
+
abAppends(&ab, "\033[K"); /* clear line forward */
|
2378
|
+
}
|
2379
|
+
abAppends(&ab, "\r" /* start of line */
|
2380
|
+
"\n"); /* cursor down unclamped */
|
2381
|
+
++rows;
|
2382
|
+
x = 0;
|
2383
|
+
}
|
2384
|
+
if (i == pos) {
|
2385
|
+
cy = 0;
|
2386
|
+
cx = x;
|
2387
|
+
}
|
2388
|
+
if (maskmode) {
|
2389
|
+
abAppendw(&ab, '*');
|
2390
|
+
} else {
|
2391
|
+
flipit = hasflip && (i == flip[0] || i == flip[1]);
|
2392
|
+
if (flipit) abAppends(&ab, "\033[1m");
|
2393
|
+
abAppendw(&ab, EncodeUtf8(rune.c));
|
2394
|
+
if (flipit) abAppends(&ab, "\033[22m");
|
2395
|
+
}
|
2396
|
+
t = GetMonospaceCharacterWidth(rune.c);
|
2397
|
+
t = Max(0, t);
|
2398
|
+
x += t;
|
2399
|
+
}
|
2400
|
+
if (!l->final && (hint = bestlineRefreshHints(l))) {
|
2401
|
+
if (GetMonospaceWidth(hint, strlen(hint), 0) < xn - x) {
|
2402
|
+
if (cx < 0) {
|
2403
|
+
cx = x;
|
2404
|
+
}
|
2405
|
+
abAppends(&ab, hint);
|
2406
|
+
}
|
2407
|
+
free(hint);
|
2408
|
+
}
|
2409
|
+
abAppendw(&ab, Read32le("\033[J")); /* erase display forwards */
|
2410
|
+
|
2411
|
+
/*
|
2412
|
+
* if we are at the very end of the screen with our prompt, we need
|
2413
|
+
* to emit a newline and move the prompt to the first column.
|
2414
|
+
*/
|
2415
|
+
if (pos && pos == len && x >= xn) {
|
2416
|
+
abAppendw(&ab, Read32le("\n\r\0"));
|
2417
|
+
++rows;
|
2418
|
+
}
|
2419
|
+
|
2420
|
+
/*
|
2421
|
+
* move cursor to right position
|
2422
|
+
*/
|
2423
|
+
if (cy > 0) {
|
2424
|
+
abAppends(&ab, "\033[");
|
2425
|
+
abAppendu(&ab, cy);
|
2426
|
+
abAppendw(&ab, 'A'); /* cursor up */
|
2427
|
+
}
|
2428
|
+
if (cx > 0) {
|
2429
|
+
abAppendw(&ab, Read32le("\r\033["));
|
2430
|
+
abAppendu(&ab, cx);
|
2431
|
+
abAppendw(&ab, 'C'); /* cursor right */
|
2432
|
+
} else if (!cx) {
|
2433
|
+
abAppendw(&ab, '\r'); /* start */
|
2434
|
+
}
|
2435
|
+
|
2436
|
+
/*
|
2437
|
+
* now get ready to progress state
|
2438
|
+
* we use a mostly correct kludge when the tty resizes
|
2439
|
+
*/
|
2440
|
+
l->rows = rows;
|
2441
|
+
if (resized && oldsize.ws_col > l->ws.ws_col) {
|
2442
|
+
resized = 0;
|
2443
|
+
abFree(&ab);
|
2444
|
+
goto StartOver;
|
2445
|
+
}
|
2446
|
+
l->dirty = 0;
|
2447
|
+
l->oldpos = Max(0, cy);
|
2448
|
+
|
2449
|
+
/*
|
2450
|
+
* send codes to terminal
|
2451
|
+
*/
|
2452
|
+
bestlineWrite(fd, ab.b, ab.len);
|
2453
|
+
abFree(&ab);
|
2454
|
+
}
|
2455
|
+
|
2456
|
+
static void bestlineRefreshLine(struct bestlineState *l) {
|
2457
|
+
bestlineRefreshLineImpl(l, 0);
|
2458
|
+
}
|
2459
|
+
|
2460
|
+
static void bestlineRefreshLineForce(struct bestlineState *l) {
|
2461
|
+
bestlineRefreshLineImpl(l, 1);
|
2462
|
+
}
|
2463
|
+
|
2464
|
+
static void bestlineEditInsert(struct bestlineState *l,
|
2465
|
+
const char *p, size_t n) {
|
2466
|
+
if (!bestlineGrow(l, l->len + n + 1)) return;
|
2467
|
+
memmove(l->buf + l->pos + n, l->buf + l->pos, l->len - l->pos);
|
2468
|
+
memcpy(l->buf + l->pos, p, n);
|
2469
|
+
l->pos += n;
|
2470
|
+
l->len += n;
|
2471
|
+
l->buf[l->len] = 0;
|
2472
|
+
bestlineRefreshLine(l);
|
2473
|
+
}
|
2474
|
+
|
2475
|
+
static void bestlineEditHome(struct bestlineState *l) {
|
2476
|
+
l->pos = 0;
|
2477
|
+
bestlineRefreshLine(l);
|
2478
|
+
}
|
2479
|
+
|
2480
|
+
static void bestlineEditEnd(struct bestlineState *l) {
|
2481
|
+
l->pos = l->len;
|
2482
|
+
bestlineRefreshLine(l);
|
2483
|
+
}
|
2484
|
+
|
2485
|
+
static void bestlineEditUp(struct bestlineState *l) {
|
2486
|
+
bestlineEditHistoryMove(l,BESTLINE_HISTORY_PREV);
|
2487
|
+
}
|
2488
|
+
|
2489
|
+
static void bestlineEditDown(struct bestlineState *l) {
|
2490
|
+
bestlineEditHistoryMove(l,BESTLINE_HISTORY_NEXT);
|
2491
|
+
}
|
2492
|
+
|
2493
|
+
static void bestlineEditBof(struct bestlineState *l) {
|
2494
|
+
bestlineEditHistoryMove(l,BESTLINE_HISTORY_FIRST);
|
2495
|
+
}
|
2496
|
+
|
2497
|
+
static void bestlineEditEof(struct bestlineState *l) {
|
2498
|
+
bestlineEditHistoryMove(l,BESTLINE_HISTORY_LAST);
|
2499
|
+
}
|
2500
|
+
|
2501
|
+
static void bestlineEditRefresh(struct bestlineState *l) {
|
2502
|
+
bestlineClearScreen(l->ofd);
|
2503
|
+
bestlineRefreshLine(l);
|
2504
|
+
}
|
2505
|
+
|
2506
|
+
static size_t Forward(struct bestlineState *l, size_t pos) {
|
2507
|
+
return pos + GetUtf8(l->buf + pos, l->len - pos).n;
|
2508
|
+
}
|
2509
|
+
|
2510
|
+
static size_t Backwards(struct bestlineState *l, size_t pos, char pred(unsigned)) {
|
2511
|
+
size_t i;
|
2512
|
+
struct rune r;
|
2513
|
+
while (pos) {
|
2514
|
+
i = Backward(l, pos);
|
2515
|
+
r = GetUtf8(l->buf + i, l->len - i);
|
2516
|
+
if (pred(r.c)) {
|
2517
|
+
pos = i;
|
2518
|
+
} else {
|
2519
|
+
break;
|
2520
|
+
}
|
2521
|
+
}
|
2522
|
+
return pos;
|
2523
|
+
}
|
2524
|
+
|
2525
|
+
static size_t Forwards(struct bestlineState *l, size_t pos, char pred(unsigned)) {
|
2526
|
+
struct rune r;
|
2527
|
+
while (pos < l->len) {
|
2528
|
+
r = GetUtf8(l->buf + pos, l->len - pos);
|
2529
|
+
if (pred(r.c)) {
|
2530
|
+
pos += r.n;
|
2531
|
+
} else {
|
2532
|
+
break;
|
2533
|
+
}
|
2534
|
+
}
|
2535
|
+
return pos;
|
2536
|
+
}
|
2537
|
+
|
2538
|
+
static size_t ForwardWord(struct bestlineState *l, size_t pos) {
|
2539
|
+
pos = Forwards(l, pos, bestlineIsSeparator);
|
2540
|
+
pos = Forwards(l, pos, bestlineNotSeparator);
|
2541
|
+
return pos;
|
2542
|
+
}
|
2543
|
+
|
2544
|
+
static size_t BackwardWord(struct bestlineState *l, size_t pos) {
|
2545
|
+
pos = Backwards(l, pos, bestlineIsSeparator);
|
2546
|
+
pos = Backwards(l, pos, bestlineNotSeparator);
|
2547
|
+
return pos;
|
2548
|
+
}
|
2549
|
+
|
2550
|
+
static size_t EscapeWord(struct bestlineState *l, size_t i) {
|
2551
|
+
size_t j;
|
2552
|
+
struct rune r;
|
2553
|
+
for (; i && i < l->len; i += r.n) {
|
2554
|
+
if (i < l->len) {
|
2555
|
+
r = GetUtf8(l->buf + i, l->len - i);
|
2556
|
+
if (bestlineIsSeparator(r.c)) break;
|
2557
|
+
}
|
2558
|
+
if ((j = i)) {
|
2559
|
+
do --j;
|
2560
|
+
while (j && (l->buf[j] & 0300) == 0200);
|
2561
|
+
r = GetUtf8(l->buf + j, l->len - j);
|
2562
|
+
if (bestlineIsSeparator(r.c)) break;
|
2563
|
+
}
|
2564
|
+
}
|
2565
|
+
return i;
|
2566
|
+
}
|
2567
|
+
|
2568
|
+
static void bestlineEditLeft(struct bestlineState *l) {
|
2569
|
+
l->pos = Backward(l, l->pos);
|
2570
|
+
bestlineRefreshLine(l);
|
2571
|
+
}
|
2572
|
+
|
2573
|
+
static void bestlineEditRight(struct bestlineState *l) {
|
2574
|
+
if (l->pos == l->len) return;
|
2575
|
+
do l->pos++;
|
2576
|
+
while (l->pos < l->len && (l->buf[l->pos] & 0300) == 0200);
|
2577
|
+
bestlineRefreshLine(l);
|
2578
|
+
}
|
2579
|
+
|
2580
|
+
static void bestlineEditLeftWord(struct bestlineState *l) {
|
2581
|
+
l->pos = BackwardWord(l, l->pos);
|
2582
|
+
bestlineRefreshLine(l);
|
2583
|
+
}
|
2584
|
+
|
2585
|
+
static void bestlineEditRightWord(struct bestlineState *l) {
|
2586
|
+
l->pos = ForwardWord(l, l->pos);
|
2587
|
+
bestlineRefreshLine(l);
|
2588
|
+
}
|
2589
|
+
|
2590
|
+
static void bestlineEditLeftExpr(struct bestlineState *l) {
|
2591
|
+
int mark[2];
|
2592
|
+
l->pos = Backwards(l, l->pos, bestlineIsXeparator);
|
2593
|
+
if (!bestlineEditMirrorLeft(l, mark)) {
|
2594
|
+
l->pos = mark[0];
|
2595
|
+
} else {
|
2596
|
+
l->pos = Backwards(l, l->pos, bestlineNotSeparator);
|
2597
|
+
}
|
2598
|
+
bestlineRefreshLine(l);
|
2599
|
+
}
|
2600
|
+
|
2601
|
+
static void bestlineEditRightExpr(struct bestlineState *l) {
|
2602
|
+
int mark[2];
|
2603
|
+
l->pos = Forwards(l, l->pos, bestlineIsXeparator);
|
2604
|
+
if (!bestlineEditMirrorRight(l, mark)) {
|
2605
|
+
l->pos = Forward(l, mark[1]);
|
2606
|
+
} else {
|
2607
|
+
l->pos = Forwards(l, l->pos, bestlineNotSeparator);
|
2608
|
+
}
|
2609
|
+
bestlineRefreshLine(l);
|
2610
|
+
}
|
2611
|
+
|
2612
|
+
static void bestlineEditDelete(struct bestlineState *l) {
|
2613
|
+
size_t i;
|
2614
|
+
if (l->pos == l->len) return;
|
2615
|
+
i = Forward(l, l->pos);
|
2616
|
+
memmove(l->buf+l->pos, l->buf+i, l->len-i+1);
|
2617
|
+
l->len -= i - l->pos;
|
2618
|
+
bestlineRefreshLine(l);
|
2619
|
+
}
|
2620
|
+
|
2621
|
+
static void bestlineEditRubout(struct bestlineState *l) {
|
2622
|
+
size_t i;
|
2623
|
+
if (!l->pos) return;
|
2624
|
+
i = Backward(l, l->pos);
|
2625
|
+
memmove(l->buf+i, l->buf+l->pos, l->len-l->pos+1);
|
2626
|
+
l->len -= l->pos - i;
|
2627
|
+
l->pos = i;
|
2628
|
+
bestlineRefreshLine(l);
|
2629
|
+
}
|
2630
|
+
|
2631
|
+
static void bestlineEditDeleteWord(struct bestlineState *l) {
|
2632
|
+
size_t i;
|
2633
|
+
if (l->pos == l->len) return;
|
2634
|
+
i = ForwardWord(l, l->pos);
|
2635
|
+
bestlineRingPush(l->buf + l->pos, i - l->pos);
|
2636
|
+
memmove(l->buf + l->pos, l->buf + i, l->len - i + 1);
|
2637
|
+
l->len -= i - l->pos;
|
2638
|
+
bestlineRefreshLine(l);
|
2639
|
+
}
|
2640
|
+
|
2641
|
+
static void bestlineEditRuboutWord(struct bestlineState *l) {
|
2642
|
+
size_t i;
|
2643
|
+
if (!l->pos) return;
|
2644
|
+
i = BackwardWord(l, l->pos);
|
2645
|
+
bestlineRingPush(l->buf + i, l->pos - i);
|
2646
|
+
memmove(l->buf + i, l->buf + l->pos, l->len - l->pos + 1);
|
2647
|
+
l->len -= l->pos - i;
|
2648
|
+
l->pos = i;
|
2649
|
+
bestlineRefreshLine(l);
|
2650
|
+
}
|
2651
|
+
|
2652
|
+
static void bestlineEditXlatWord(struct bestlineState *l, unsigned xlat(unsigned)) {
|
2653
|
+
unsigned c;
|
2654
|
+
size_t i, j;
|
2655
|
+
struct rune r;
|
2656
|
+
struct abuf ab;
|
2657
|
+
abInit(&ab);
|
2658
|
+
i = Forwards(l, l->pos, bestlineIsSeparator);
|
2659
|
+
for (j = i; j < l->len; j += r.n) {
|
2660
|
+
r = GetUtf8(l->buf + j, l->len - j);
|
2661
|
+
if (bestlineIsSeparator(r.c)) break;
|
2662
|
+
if ((c = xlat(r.c)) != r.c) {
|
2663
|
+
abAppendw(&ab, EncodeUtf8(c));
|
2664
|
+
} else { /* avoid canonicalization */
|
2665
|
+
abAppend(&ab, l->buf + j, r.n);
|
2666
|
+
}
|
2667
|
+
}
|
2668
|
+
if (ab.len && bestlineGrow(l, i + ab.len + l->len - j + 1)) {
|
2669
|
+
l->pos = i + ab.len;
|
2670
|
+
abAppend(&ab, l->buf + j, l->len - j);
|
2671
|
+
l->len = i + ab.len;
|
2672
|
+
memcpy(l->buf + i, ab.b, ab.len + 1);
|
2673
|
+
bestlineRefreshLine(l);
|
2674
|
+
}
|
2675
|
+
abFree(&ab);
|
2676
|
+
}
|
2677
|
+
|
2678
|
+
static void bestlineEditLowercaseWord(struct bestlineState *l) {
|
2679
|
+
bestlineEditXlatWord(l, bestlineLowercase);
|
2680
|
+
}
|
2681
|
+
|
2682
|
+
static void bestlineEditUppercaseWord(struct bestlineState *l) {
|
2683
|
+
bestlineEditXlatWord(l, bestlineUppercase);
|
2684
|
+
}
|
2685
|
+
|
2686
|
+
static void bestlineEditCapitalizeWord(struct bestlineState *l) {
|
2687
|
+
iscapital = 0;
|
2688
|
+
bestlineEditXlatWord(l, Capitalize);
|
2689
|
+
}
|
2690
|
+
|
2691
|
+
static void bestlineEditKillLeft(struct bestlineState *l) {
|
2692
|
+
size_t diff, old_pos;
|
2693
|
+
bestlineRingPush(l->buf, l->pos);
|
2694
|
+
old_pos = l->pos;
|
2695
|
+
l->pos = 0;
|
2696
|
+
diff = old_pos - l->pos;
|
2697
|
+
memmove(l->buf+l->pos,l->buf+old_pos,l->len-old_pos+1);
|
2698
|
+
l->len -= diff;
|
2699
|
+
bestlineRefreshLine(l);
|
2700
|
+
}
|
2701
|
+
|
2702
|
+
static void bestlineEditKillRight(struct bestlineState *l) {
|
2703
|
+
bestlineRingPush(l->buf + l->pos, l->len - l->pos);
|
2704
|
+
l->buf[l->pos] = '\0';
|
2705
|
+
l->len = l->pos;
|
2706
|
+
bestlineRefreshLine(l);
|
2707
|
+
}
|
2708
|
+
|
2709
|
+
static void bestlineEditYank(struct bestlineState *l) {
|
2710
|
+
char *p;
|
2711
|
+
size_t n;
|
2712
|
+
if (!ring.p[ring.i]) return;
|
2713
|
+
n = strlen(ring.p[ring.i]);
|
2714
|
+
if (!bestlineGrow(l, l->len + n + 1)) return;
|
2715
|
+
if (!(p = (char *)malloc(l->len - l->pos + 1))) return;
|
2716
|
+
memcpy(p, l->buf + l->pos, l->len - l->pos + 1);
|
2717
|
+
memcpy(l->buf + l->pos, ring.p[ring.i], n);
|
2718
|
+
memcpy(l->buf + l->pos + n, p, l->len - l->pos + 1);
|
2719
|
+
free(p);
|
2720
|
+
l->yi = l->pos;
|
2721
|
+
l->yj = l->pos + n;
|
2722
|
+
l->pos += n;
|
2723
|
+
l->len += n;
|
2724
|
+
bestlineRefreshLine(l);
|
2725
|
+
}
|
2726
|
+
|
2727
|
+
static void bestlineEditRotate(struct bestlineState *l) {
|
2728
|
+
if ((l->seq[1][0] == Ctrl('Y') ||
|
2729
|
+
(l->seq[1][0] == 033 && l->seq[1][1] == 'y'))) {
|
2730
|
+
if (l->yi < l->len && l->yj <= l->len) {
|
2731
|
+
memmove(l->buf + l->yi, l->buf + l->yj, l->len - l->yj + 1);
|
2732
|
+
l->len -= l->yj - l->yi;
|
2733
|
+
l->pos -= l->yj - l->yi;
|
2734
|
+
}
|
2735
|
+
bestlineRingRotate();
|
2736
|
+
bestlineEditYank(l);
|
2737
|
+
}
|
2738
|
+
}
|
2739
|
+
|
2740
|
+
static void bestlineEditTranspose(struct bestlineState *l) {
|
2741
|
+
char *q, *p;
|
2742
|
+
size_t a, b, c;
|
2743
|
+
b = l->pos;
|
2744
|
+
if (b == l->len) --b;
|
2745
|
+
a = Backward(l, b);
|
2746
|
+
c = Forward(l, b);
|
2747
|
+
if (!(a < b && b < c)) return;
|
2748
|
+
p = q = (char *)malloc(c - a);
|
2749
|
+
p = Copy(p, l->buf + b, c - b);
|
2750
|
+
p = Copy(p, l->buf + a, b - a);
|
2751
|
+
assert((size_t)(p - q) == c - a);
|
2752
|
+
memcpy(l->buf + a, q, p - q);
|
2753
|
+
l->pos = c;
|
2754
|
+
free(q);
|
2755
|
+
bestlineRefreshLine(l);
|
2756
|
+
}
|
2757
|
+
|
2758
|
+
static void bestlineEditTransposeWords(struct bestlineState *l) {
|
2759
|
+
char *q, *p;
|
2760
|
+
size_t i, pi, xi, xj, yi, yj;
|
2761
|
+
i = l->pos;
|
2762
|
+
if (i == l->len) {
|
2763
|
+
i = Backwards(l, i, bestlineIsSeparator);
|
2764
|
+
i = Backwards(l, i, bestlineNotSeparator);
|
2765
|
+
}
|
2766
|
+
pi = EscapeWord(l, i);
|
2767
|
+
xj = Backwards(l, pi, bestlineIsSeparator);
|
2768
|
+
xi = Backwards(l, xj, bestlineNotSeparator);
|
2769
|
+
yi = Forwards(l, pi, bestlineIsSeparator);
|
2770
|
+
yj = Forwards(l, yi, bestlineNotSeparator);
|
2771
|
+
if (!(xi < xj && xj < yi && yi < yj)) return;
|
2772
|
+
p = q = (char *)malloc(yj - xi);
|
2773
|
+
p = Copy(p, l->buf + yi, yj - yi);
|
2774
|
+
p = Copy(p, l->buf + xj, yi - xj);
|
2775
|
+
p = Copy(p, l->buf + xi, xj - xi);
|
2776
|
+
assert((size_t)(p - q) == yj - xi);
|
2777
|
+
memcpy(l->buf + xi, q, p - q);
|
2778
|
+
l->pos = yj;
|
2779
|
+
free(q);
|
2780
|
+
bestlineRefreshLine(l);
|
2781
|
+
}
|
2782
|
+
|
2783
|
+
static void bestlineEditSqueeze(struct bestlineState *l) {
|
2784
|
+
size_t i, j;
|
2785
|
+
i = Backwards(l, l->pos, bestlineIsSeparator);
|
2786
|
+
j = Forwards(l, l->pos, bestlineIsSeparator);
|
2787
|
+
if (!(i < j)) return;
|
2788
|
+
memmove(l->buf + i, l->buf + j, l->len - j + 1);
|
2789
|
+
l->len -= j - i;
|
2790
|
+
l->pos = i;
|
2791
|
+
bestlineRefreshLine(l);
|
2792
|
+
}
|
2793
|
+
|
2794
|
+
static void bestlineEditMark(struct bestlineState *l) {
|
2795
|
+
l->mark = l->pos;
|
2796
|
+
}
|
2797
|
+
|
2798
|
+
static void bestlineEditGoto(struct bestlineState *l) {
|
2799
|
+
if (l->mark > l->len) return;
|
2800
|
+
l->pos = Min(l->mark, l->len);
|
2801
|
+
bestlineRefreshLine(l);
|
2802
|
+
}
|
2803
|
+
|
2804
|
+
static size_t bestlineEscape(char *d, const char *s, size_t n) {
|
2805
|
+
char *p;
|
2806
|
+
size_t i;
|
2807
|
+
unsigned c, w, l;
|
2808
|
+
for (p = d, l = i = 0; i < n; ++i) {
|
2809
|
+
switch ((c = s[i] & 255)) {
|
2810
|
+
Case('\a', w = Read16le("\\a"));
|
2811
|
+
Case('\b', w = Read16le("\\b"));
|
2812
|
+
Case('\t', w = Read16le("\\t"));
|
2813
|
+
Case('\n', w = Read16le("\\n"));
|
2814
|
+
Case('\v', w = Read16le("\\v"));
|
2815
|
+
Case('\f', w = Read16le("\\f"));
|
2816
|
+
Case('\r', w = Read16le("\\r"));
|
2817
|
+
Case('"', w = Read16le("\\\""));
|
2818
|
+
Case('\'', w = Read16le("\\\'"));
|
2819
|
+
Case('\\', w = Read16le("\\\\"));
|
2820
|
+
default:
|
2821
|
+
if (c <= 0x1F || c == 0x7F ||
|
2822
|
+
(c == '?' && l == '?')) {
|
2823
|
+
w = Read16le("\\x");
|
2824
|
+
w |= "0123456789abcdef"[(c & 0xF0) >> 4] << 020;
|
2825
|
+
w |= "0123456789abcdef"[(c & 0x0F) >> 0] << 030;
|
2826
|
+
} else {
|
2827
|
+
w = c;
|
2828
|
+
}
|
2829
|
+
break;
|
2830
|
+
}
|
2831
|
+
p[0] = (w & 0x000000ff) >> 000;
|
2832
|
+
p[1] = (w & 0x0000ff00) >> 010;
|
2833
|
+
p[2] = (w & 0x00ff0000) >> 020;
|
2834
|
+
p[3] = (w & 0xff000000) >> 030;
|
2835
|
+
p += (Bsr(w) >> 3) + 1;
|
2836
|
+
l = w;
|
2837
|
+
}
|
2838
|
+
return p - d;
|
2839
|
+
}
|
2840
|
+
|
2841
|
+
static void bestlineEditInsertEscape(struct bestlineState *l) {
|
2842
|
+
size_t m;
|
2843
|
+
ssize_t n;
|
2844
|
+
char seq[16];
|
2845
|
+
char esc[sizeof(seq) * 4];
|
2846
|
+
if ((n = bestlineRead(l->ifd, seq, sizeof(seq), l)) > 0) {
|
2847
|
+
m = bestlineEscape(esc, seq, n);
|
2848
|
+
bestlineEditInsert(l, esc, m);
|
2849
|
+
}
|
2850
|
+
}
|
2851
|
+
|
2852
|
+
static void bestlineEditInterrupt(void) {
|
2853
|
+
gotint = SIGINT;
|
2854
|
+
}
|
2855
|
+
|
2856
|
+
static void bestlineEditQuit(void) {
|
2857
|
+
gotint = SIGQUIT;
|
2858
|
+
}
|
2859
|
+
|
2860
|
+
static void bestlineEditSuspend(void) {
|
2861
|
+
raise(SIGSTOP);
|
2862
|
+
}
|
2863
|
+
|
2864
|
+
static void bestlineEditPause(struct bestlineState *l) {
|
2865
|
+
tcflow(l->ofd, TCOOFF);
|
2866
|
+
ispaused = 1;
|
2867
|
+
}
|
2868
|
+
|
2869
|
+
static void bestlineEditCtrlq(struct bestlineState *l) {
|
2870
|
+
if (ispaused) {
|
2871
|
+
bestlineUnpause(l->ofd);
|
2872
|
+
bestlineRefreshLineForce(l);
|
2873
|
+
} else {
|
2874
|
+
bestlineEditInsertEscape(l);
|
2875
|
+
}
|
2876
|
+
}
|
2877
|
+
|
2878
|
+
/**
|
2879
|
+
* Moves last item inside current s-expression to outside, e.g.
|
2880
|
+
*
|
2881
|
+
* (a| b c)
|
2882
|
+
* (a| b) c
|
2883
|
+
*
|
2884
|
+
* The cursor position changes only if a paren is moved before it:
|
2885
|
+
*
|
2886
|
+
* (a b c |)
|
2887
|
+
* (a b) c |
|
2888
|
+
*
|
2889
|
+
* To accommodate non-LISP languages we connect unspaced outer symbols:
|
2890
|
+
*
|
2891
|
+
* f(a,| b, g())
|
2892
|
+
* f(a,| b), g()
|
2893
|
+
*
|
2894
|
+
* Our standard keybinding is ALT-SHIFT-B.
|
2895
|
+
*/
|
2896
|
+
static void bestlineEditBarf(struct bestlineState *l) {
|
2897
|
+
struct rune r;
|
2898
|
+
unsigned long w;
|
2899
|
+
size_t i, pos, depth = 0;
|
2900
|
+
unsigned lhs, rhs, end, *stack = 0;
|
2901
|
+
/* go as far right within current s-expr as possible */
|
2902
|
+
for (pos = l->pos;; pos += r.n) {
|
2903
|
+
if (pos == l->len) goto Finish;
|
2904
|
+
r = GetUtf8(l->buf + pos, l->len - pos);
|
2905
|
+
if (depth) {
|
2906
|
+
if (r.c == stack[depth - 1]) {
|
2907
|
+
--depth;
|
2908
|
+
}
|
2909
|
+
} else {
|
2910
|
+
if ((rhs = bestlineMirrorRight(r.c))) {
|
2911
|
+
stack = (unsigned *)realloc(stack, ++depth * sizeof(*stack));
|
2912
|
+
stack[depth - 1] = rhs;
|
2913
|
+
} else if (bestlineMirrorLeft(r.c)) {
|
2914
|
+
end = pos;
|
2915
|
+
break;
|
2916
|
+
}
|
2917
|
+
}
|
2918
|
+
}
|
2919
|
+
/* go back one item */
|
2920
|
+
pos = Backwards(l, pos, bestlineIsXeparator);
|
2921
|
+
for (;; pos = i) {
|
2922
|
+
if (!pos) goto Finish;
|
2923
|
+
i = Backward(l, pos);
|
2924
|
+
r = GetUtf8(l->buf + i, l->len - i);
|
2925
|
+
if (depth) {
|
2926
|
+
if (r.c == stack[depth - 1]) {
|
2927
|
+
--depth;
|
2928
|
+
}
|
2929
|
+
} else {
|
2930
|
+
if ((lhs = bestlineMirrorLeft(r.c))) {
|
2931
|
+
stack = (unsigned *)realloc(stack, ++depth * sizeof(*stack));
|
2932
|
+
stack[depth - 1] = lhs;
|
2933
|
+
} else if (bestlineIsSeparator(r.c)) {
|
2934
|
+
break;
|
2935
|
+
}
|
2936
|
+
}
|
2937
|
+
}
|
2938
|
+
pos = Backwards(l, pos, bestlineIsXeparator);
|
2939
|
+
/* now move the text */
|
2940
|
+
r = GetUtf8(l->buf + end, l->len - end);
|
2941
|
+
memmove(l->buf + pos + r.n, l->buf + pos, end - pos);
|
2942
|
+
w = EncodeUtf8(r.c);
|
2943
|
+
for (i = 0; i < r.n; ++i) {
|
2944
|
+
l->buf[pos + i] = w;
|
2945
|
+
w >>= 8;
|
2946
|
+
}
|
2947
|
+
if (l->pos > pos) {
|
2948
|
+
l->pos += r.n;
|
2949
|
+
}
|
2950
|
+
bestlineRefreshLine(l);
|
2951
|
+
Finish:
|
2952
|
+
free(stack);
|
2953
|
+
}
|
2954
|
+
|
2955
|
+
/**
|
2956
|
+
* Moves first item outside current s-expression to inside, e.g.
|
2957
|
+
*
|
2958
|
+
* (a| b) c d
|
2959
|
+
* (a| b c) d
|
2960
|
+
*
|
2961
|
+
* To accommodate non-LISP languages we connect unspaced outer symbols:
|
2962
|
+
*
|
2963
|
+
* f(a,| b), g()
|
2964
|
+
* f(a,| b, g())
|
2965
|
+
*
|
2966
|
+
* Our standard keybinding is ALT-SHIFT-S.
|
2967
|
+
*/
|
2968
|
+
static void bestlineEditSlurp(struct bestlineState *l) {
|
2969
|
+
char rp[6];
|
2970
|
+
struct rune r;
|
2971
|
+
size_t pos, depth = 0;
|
2972
|
+
unsigned rhs, point = 0, start = 0, *stack = 0;
|
2973
|
+
/* go to outside edge of current s-expr */
|
2974
|
+
for (pos = l->pos; pos < l->len; pos += r.n) {
|
2975
|
+
r = GetUtf8(l->buf + pos, l->len - pos);
|
2976
|
+
if (depth) {
|
2977
|
+
if (r.c == stack[depth - 1]) {
|
2978
|
+
--depth;
|
2979
|
+
}
|
2980
|
+
} else {
|
2981
|
+
if ((rhs = bestlineMirrorRight(r.c))) {
|
2982
|
+
stack = (unsigned *)realloc(stack, ++depth * sizeof(*stack));
|
2983
|
+
stack[depth - 1] = rhs;
|
2984
|
+
} else if (bestlineMirrorLeft(r.c)) {
|
2985
|
+
point = pos;
|
2986
|
+
pos += r.n;
|
2987
|
+
start = pos;
|
2988
|
+
break;
|
2989
|
+
}
|
2990
|
+
}
|
2991
|
+
}
|
2992
|
+
/* go forward one item */
|
2993
|
+
pos = Forwards(l, pos, bestlineIsXeparator);
|
2994
|
+
for (; pos < l->len ; pos += r.n) {
|
2995
|
+
r = GetUtf8(l->buf + pos, l->len - pos);
|
2996
|
+
if (depth) {
|
2997
|
+
if (r.c == stack[depth - 1]) {
|
2998
|
+
--depth;
|
2999
|
+
}
|
3000
|
+
} else {
|
3001
|
+
if ((rhs = bestlineMirrorRight(r.c))) {
|
3002
|
+
stack = (unsigned *)realloc(stack, ++depth * sizeof(*stack));
|
3003
|
+
stack[depth - 1] = rhs;
|
3004
|
+
} else if (bestlineIsSeparator(r.c)) {
|
3005
|
+
break;
|
3006
|
+
}
|
3007
|
+
}
|
3008
|
+
}
|
3009
|
+
/* now move the text */
|
3010
|
+
memcpy(rp, l->buf + point, start - point);
|
3011
|
+
memmove(l->buf + point, l->buf + start, pos - start);
|
3012
|
+
memcpy(l->buf + pos - (start - point), rp, start - point);
|
3013
|
+
bestlineRefreshLine(l);
|
3014
|
+
free(stack);
|
3015
|
+
}
|
3016
|
+
|
3017
|
+
static void bestlineEditRaise(struct bestlineState *l) {
|
3018
|
+
(void)l;
|
3019
|
+
}
|
3020
|
+
|
3021
|
+
/**
|
3022
|
+
* Runs bestline engine.
|
3023
|
+
*
|
3024
|
+
* This function is the core of the line editing capability of bestline.
|
3025
|
+
* It expects 'fd' to be already in "raw mode" so that every key pressed
|
3026
|
+
* will be returned ASAP to read().
|
3027
|
+
*
|
3028
|
+
* The resulting string is put into 'buf' when the user type enter, or
|
3029
|
+
* when ctrl+d is typed.
|
3030
|
+
*
|
3031
|
+
* Returns chomped character count in buf >=0 or -1 on eof / error
|
3032
|
+
*/
|
3033
|
+
static ssize_t bestlineEdit(int stdin_fd, int stdout_fd, const char *prompt,
|
3034
|
+
char **obuf) {
|
3035
|
+
ssize_t rc;
|
3036
|
+
size_t nread;
|
3037
|
+
struct rune rune;
|
3038
|
+
char *p, seq[16];
|
3039
|
+
unsigned long long w;
|
3040
|
+
struct bestlineState l;
|
3041
|
+
memset(&l,0,sizeof(l));
|
3042
|
+
if (!(l.buf = (char *)malloc((l.buflen = 32)))) return -1;
|
3043
|
+
l.buf[0] = 0;
|
3044
|
+
l.ifd = stdin_fd;
|
3045
|
+
l.ofd = stdout_fd;
|
3046
|
+
l.prompt = prompt ? prompt : "";
|
3047
|
+
l.ws = GetTerminalSize(l.ws,l.ifd,l.ofd);
|
3048
|
+
bestlineHistoryAdd("");
|
3049
|
+
bestlineWriteStr(l.ofd,l.prompt);
|
3050
|
+
while (1) {
|
3051
|
+
if (l.dirty) bestlineRefreshLineForce(&l);
|
3052
|
+
rc = bestlineRead(l.ifd,seq,sizeof(seq),&l);
|
3053
|
+
if (rc > 0) {
|
3054
|
+
if (seq[0] == Ctrl('R')) {
|
3055
|
+
rc = bestlineSearch(&l,seq,sizeof(seq));
|
3056
|
+
if (!rc) continue;
|
3057
|
+
} else if (seq[0] == '\t' && completionCallback) {
|
3058
|
+
rc = bestlineCompleteLine(&l,seq,sizeof(seq));
|
3059
|
+
if (!rc) continue;
|
3060
|
+
}
|
3061
|
+
}
|
3062
|
+
if (rc > 0) {
|
3063
|
+
nread = rc;
|
3064
|
+
} else if (!rc && l.len) {
|
3065
|
+
nread = 1;
|
3066
|
+
seq[0] = '\r';
|
3067
|
+
seq[1] = 0;
|
3068
|
+
} else {
|
3069
|
+
free(history[--historylen]);
|
3070
|
+
history[historylen] = 0;
|
3071
|
+
free(l.buf);
|
3072
|
+
return -1;
|
3073
|
+
}
|
3074
|
+
switch (seq[0]) {
|
3075
|
+
Case(Ctrl('P'), bestlineEditUp(&l));
|
3076
|
+
Case(Ctrl('E'), bestlineEditEnd(&l));
|
3077
|
+
Case(Ctrl('N'), bestlineEditDown(&l));
|
3078
|
+
Case(Ctrl('A'), bestlineEditHome(&l));
|
3079
|
+
Case(Ctrl('B'), bestlineEditLeft(&l));
|
3080
|
+
Case(Ctrl('@'), bestlineEditMark(&l));
|
3081
|
+
Case(Ctrl('Y'), bestlineEditYank(&l));
|
3082
|
+
Case(Ctrl('Q'), bestlineEditCtrlq(&l));
|
3083
|
+
Case(Ctrl('F'), bestlineEditRight(&l));
|
3084
|
+
Case(Ctrl('\\'), bestlineEditQuit());
|
3085
|
+
Case(Ctrl('S'), bestlineEditPause(&l));
|
3086
|
+
Case(Ctrl('?'), bestlineEditRubout(&l));
|
3087
|
+
Case(Ctrl('H'), bestlineEditRubout(&l));
|
3088
|
+
Case(Ctrl('L'), bestlineEditRefresh(&l));
|
3089
|
+
Case(Ctrl('Z'), bestlineEditSuspend());
|
3090
|
+
Case(Ctrl('U'), bestlineEditKillLeft(&l));
|
3091
|
+
Case(Ctrl('T'), bestlineEditTranspose(&l));
|
3092
|
+
Case(Ctrl('K'), bestlineEditKillRight(&l));
|
3093
|
+
Case(Ctrl('W'), bestlineEditRuboutWord(&l));
|
3094
|
+
case Ctrl('C'):
|
3095
|
+
if (bestlineRead(l.ifd,seq,sizeof(seq),&l) != 1) break;
|
3096
|
+
switch (seq[0]) {
|
3097
|
+
Case(Ctrl('C'), bestlineEditInterrupt());
|
3098
|
+
Case(Ctrl('B'), bestlineEditBarf(&l));
|
3099
|
+
Case(Ctrl('S'), bestlineEditSlurp(&l));
|
3100
|
+
Case(Ctrl('R'), bestlineEditRaise(&l));
|
3101
|
+
default:
|
3102
|
+
break;
|
3103
|
+
}
|
3104
|
+
break;
|
3105
|
+
case Ctrl('X'):
|
3106
|
+
if (l.seq[1][0] == Ctrl('X')) {
|
3107
|
+
bestlineEditGoto(&l);
|
3108
|
+
}
|
3109
|
+
break;
|
3110
|
+
case Ctrl('D'):
|
3111
|
+
if (l.len) {
|
3112
|
+
bestlineEditDelete(&l);
|
3113
|
+
} else {
|
3114
|
+
free(history[--historylen]);
|
3115
|
+
history[historylen] = 0;
|
3116
|
+
free(l.buf);
|
3117
|
+
return -1;
|
3118
|
+
}
|
3119
|
+
break;
|
3120
|
+
case '\r':
|
3121
|
+
l.final = 1;
|
3122
|
+
free(history[--historylen]);
|
3123
|
+
history[historylen] = 0;
|
3124
|
+
bestlineEditEnd(&l);
|
3125
|
+
bestlineRefreshLineForce(&l);
|
3126
|
+
if ((p = (char *)realloc(l.buf, l.len + 1))) l.buf = p;
|
3127
|
+
*obuf = l.buf;
|
3128
|
+
return l.len;
|
3129
|
+
case 033:
|
3130
|
+
if (nread < 2) break;
|
3131
|
+
switch (seq[1]) {
|
3132
|
+
Case('<', bestlineEditBof(&l));
|
3133
|
+
Case('>', bestlineEditEof(&l));
|
3134
|
+
Case('B', bestlineEditBarf(&l));
|
3135
|
+
Case('S', bestlineEditSlurp(&l));
|
3136
|
+
Case('R', bestlineEditRaise(&l));
|
3137
|
+
Case('y', bestlineEditRotate(&l));
|
3138
|
+
Case('\\', bestlineEditSqueeze(&l));
|
3139
|
+
Case('b', bestlineEditLeftWord(&l));
|
3140
|
+
Case('f', bestlineEditRightWord(&l));
|
3141
|
+
Case('h', bestlineEditRuboutWord(&l));
|
3142
|
+
Case('d', bestlineEditDeleteWord(&l));
|
3143
|
+
Case('l', bestlineEditLowercaseWord(&l));
|
3144
|
+
Case('u', bestlineEditUppercaseWord(&l));
|
3145
|
+
Case('c', bestlineEditCapitalizeWord(&l));
|
3146
|
+
Case('t', bestlineEditTransposeWords(&l));
|
3147
|
+
Case(Ctrl('B'), bestlineEditLeftExpr(&l));
|
3148
|
+
Case(Ctrl('F'), bestlineEditRightExpr(&l));
|
3149
|
+
Case(Ctrl('H'), bestlineEditRuboutWord(&l));
|
3150
|
+
case '[':
|
3151
|
+
if (nread < 3) break;
|
3152
|
+
if (seq[2] >= '0' && seq[2] <= '9') {
|
3153
|
+
if (nread < 4) break;
|
3154
|
+
if (seq[3] == '~') {
|
3155
|
+
switch (seq[2]) {
|
3156
|
+
Case('1', bestlineEditHome(&l)); /* \e[1~ */
|
3157
|
+
Case('3', bestlineEditDelete(&l)); /* \e[3~ */
|
3158
|
+
Case('4', bestlineEditEnd(&l)); /* \e[4~ */
|
3159
|
+
default:
|
3160
|
+
break;
|
3161
|
+
}
|
3162
|
+
}
|
3163
|
+
} else {
|
3164
|
+
switch (seq[2]) {
|
3165
|
+
Case('A', bestlineEditUp(&l));
|
3166
|
+
Case('B', bestlineEditDown(&l));
|
3167
|
+
Case('C', bestlineEditRight(&l));
|
3168
|
+
Case('D', bestlineEditLeft(&l));
|
3169
|
+
Case('H', bestlineEditHome(&l));
|
3170
|
+
Case('F', bestlineEditEnd(&l));
|
3171
|
+
default:
|
3172
|
+
break;
|
3173
|
+
}
|
3174
|
+
}
|
3175
|
+
break;
|
3176
|
+
case 'O':
|
3177
|
+
if (nread < 3) break;
|
3178
|
+
switch (seq[2]) {
|
3179
|
+
Case('A', bestlineEditUp(&l));
|
3180
|
+
Case('B', bestlineEditDown(&l));
|
3181
|
+
Case('C', bestlineEditRight(&l));
|
3182
|
+
Case('D', bestlineEditLeft(&l));
|
3183
|
+
Case('H', bestlineEditHome(&l));
|
3184
|
+
Case('F', bestlineEditEnd(&l));
|
3185
|
+
default:
|
3186
|
+
break;
|
3187
|
+
}
|
3188
|
+
break;
|
3189
|
+
case 033:
|
3190
|
+
if (nread < 3) break;
|
3191
|
+
switch (seq[2]) {
|
3192
|
+
case '[':
|
3193
|
+
if (nread < 4) break;
|
3194
|
+
switch (seq[3]) {
|
3195
|
+
Case('C', bestlineEditRightExpr(&l)); /* \e\e[C alt-right */
|
3196
|
+
Case('D', bestlineEditLeftExpr(&l)); /* \e\e[D alt-left */
|
3197
|
+
default:
|
3198
|
+
break;
|
3199
|
+
}
|
3200
|
+
break;
|
3201
|
+
case 'O':
|
3202
|
+
if (nread < 4) break;
|
3203
|
+
switch (seq[3]) {
|
3204
|
+
Case('C', bestlineEditRightExpr(&l)); /* \e\eOC alt-right */
|
3205
|
+
Case('D', bestlineEditLeftExpr(&l)); /* \e\eOD alt-left */
|
3206
|
+
default:
|
3207
|
+
break;
|
3208
|
+
}
|
3209
|
+
break;
|
3210
|
+
default:
|
3211
|
+
break;
|
3212
|
+
}
|
3213
|
+
break;
|
3214
|
+
default:
|
3215
|
+
break;
|
3216
|
+
}
|
3217
|
+
break;
|
3218
|
+
default:
|
3219
|
+
if (!IsControl(seq[0])) { /* only sees canonical c0 */
|
3220
|
+
if (xlatCallback) {
|
3221
|
+
rune = GetUtf8(seq,nread);
|
3222
|
+
w = EncodeUtf8(xlatCallback(rune.c));
|
3223
|
+
nread = 0;
|
3224
|
+
do {
|
3225
|
+
seq[nread++] = w;
|
3226
|
+
} while ((w >>= 8));
|
3227
|
+
}
|
3228
|
+
bestlineEditInsert(&l,seq,nread);
|
3229
|
+
}
|
3230
|
+
break;
|
3231
|
+
}
|
3232
|
+
}
|
3233
|
+
}
|
3234
|
+
|
3235
|
+
void bestlineFree(void *ptr) {
|
3236
|
+
free(ptr);
|
3237
|
+
}
|
3238
|
+
|
3239
|
+
void bestlineHistoryFree(void) {
|
3240
|
+
size_t i;
|
3241
|
+
for (i = 0; i < BESTLINE_MAX_HISTORY; i++) {
|
3242
|
+
if (history[i]) {
|
3243
|
+
free(history[i]);
|
3244
|
+
history[i] = 0;
|
3245
|
+
}
|
3246
|
+
}
|
3247
|
+
historylen = 0;
|
3248
|
+
}
|
3249
|
+
|
3250
|
+
static void bestlineAtExit(void) {
|
3251
|
+
bestlineDisableRawMode();
|
3252
|
+
bestlineHistoryFree();
|
3253
|
+
bestlineRingFree();
|
3254
|
+
}
|
3255
|
+
|
3256
|
+
int bestlineHistoryAdd(const char *line) {
|
3257
|
+
char *linecopy;
|
3258
|
+
if (!BESTLINE_MAX_HISTORY) return 0;
|
3259
|
+
if (historylen && !strcmp(history[historylen-1], line)) return 0;
|
3260
|
+
if (!(linecopy = strdup(line))) return 0;
|
3261
|
+
if (historylen == BESTLINE_MAX_HISTORY) {
|
3262
|
+
free(history[0]);
|
3263
|
+
memmove(history,history+1,sizeof(char*)*(BESTLINE_MAX_HISTORY-1));
|
3264
|
+
historylen--;
|
3265
|
+
}
|
3266
|
+
history[historylen++] = linecopy;
|
3267
|
+
return 1;
|
3268
|
+
}
|
3269
|
+
|
3270
|
+
/**
|
3271
|
+
* Saves line editing history to file.
|
3272
|
+
*
|
3273
|
+
* @return 0 on success, or -1 w/ errno
|
3274
|
+
*/
|
3275
|
+
int bestlineHistorySave(const char *filename) {
|
3276
|
+
FILE *fp;
|
3277
|
+
unsigned j;
|
3278
|
+
mode_t old_umask;
|
3279
|
+
old_umask = umask(S_IXUSR|S_IRWXG|S_IRWXO);
|
3280
|
+
fp = fopen(filename,"w");
|
3281
|
+
umask(old_umask);
|
3282
|
+
if (!fp) return -1;
|
3283
|
+
chmod(filename,S_IRUSR|S_IWUSR);
|
3284
|
+
for (j = 0; j < historylen; j++) {
|
3285
|
+
fputs(history[j],fp);
|
3286
|
+
fputc('\n',fp);
|
3287
|
+
}
|
3288
|
+
fclose(fp);
|
3289
|
+
return 0;
|
3290
|
+
}
|
3291
|
+
|
3292
|
+
/**
|
3293
|
+
* Loads history from the specified file.
|
3294
|
+
*
|
3295
|
+
* If the file doesn't exist, zero is returned and this will do nothing.
|
3296
|
+
* If the file does exists and the operation succeeded zero is returned
|
3297
|
+
* otherwise on error -1 is returned.
|
3298
|
+
*
|
3299
|
+
* @return 0 on success, or -1 w/ errno
|
3300
|
+
*/
|
3301
|
+
int bestlineHistoryLoad(const char *filename) {
|
3302
|
+
char **h;
|
3303
|
+
int rc, fd, err;
|
3304
|
+
size_t i, j, k, n, t;
|
3305
|
+
char *m, *e, *p, *q, *f, *s;
|
3306
|
+
err = errno, rc = 0;
|
3307
|
+
if (!BESTLINE_MAX_HISTORY) return 0;
|
3308
|
+
if (!(h = (char**)calloc(2*BESTLINE_MAX_HISTORY,sizeof(char*)))) return -1;
|
3309
|
+
if ((fd = open(filename,O_RDONLY)) != -1) {
|
3310
|
+
if ((n = GetFdSize(fd))) {
|
3311
|
+
if ((m = (char *)mmap(0,n,PROT_READ,MAP_SHARED,fd,0))!=MAP_FAILED) {
|
3312
|
+
for (i = 0, e = (p = m) + n; p < e; p = f + 1) {
|
3313
|
+
if (!(q = (char *)memchr(p, '\n', e - p))) q = e;
|
3314
|
+
for (f = q; q > p; --q) {
|
3315
|
+
if (q[-1] != '\n' && q[-1] != '\r') break;
|
3316
|
+
}
|
3317
|
+
if (q > p) {
|
3318
|
+
h[i * 2 + 0] = p;
|
3319
|
+
h[i * 2 + 1] = q;
|
3320
|
+
i = (i + 1) % BESTLINE_MAX_HISTORY;
|
3321
|
+
}
|
3322
|
+
}
|
3323
|
+
bestlineHistoryFree();
|
3324
|
+
for (j = 0; j < BESTLINE_MAX_HISTORY; ++j) {
|
3325
|
+
if (h[(k = (i + j) % BESTLINE_MAX_HISTORY) * 2]) {
|
3326
|
+
if ((s = (char *)malloc((t=h[k*2+1]-h[k*2])+1))) {
|
3327
|
+
memcpy(s,h[k*2],t),s[t]=0;
|
3328
|
+
history[historylen++] = s;
|
3329
|
+
}
|
3330
|
+
}
|
3331
|
+
}
|
3332
|
+
munmap(m,n);
|
3333
|
+
} else {
|
3334
|
+
rc = -1;
|
3335
|
+
}
|
3336
|
+
}
|
3337
|
+
close(fd);
|
3338
|
+
} else if (errno == ENOENT) {
|
3339
|
+
errno = err;
|
3340
|
+
} else {
|
3341
|
+
rc = -1;
|
3342
|
+
}
|
3343
|
+
free(h);
|
3344
|
+
return rc;
|
3345
|
+
}
|
3346
|
+
|
3347
|
+
/**
|
3348
|
+
* Reads line interactively.
|
3349
|
+
*
|
3350
|
+
* This function can be used instead of bestline() in cases where we
|
3351
|
+
* know for certain we're dealing with a terminal, which means we can
|
3352
|
+
* avoid linking any stdio code.
|
3353
|
+
*
|
3354
|
+
* @return chomped allocated string of read line or null on eof/error
|
3355
|
+
*/
|
3356
|
+
char *bestlineRaw(const char *prompt, int infd, int outfd) {
|
3357
|
+
char *buf;
|
3358
|
+
ssize_t rc;
|
3359
|
+
static char once;
|
3360
|
+
struct sigaction sa[3];
|
3361
|
+
if (!once) atexit(bestlineAtExit), once = 1;
|
3362
|
+
if (enableRawMode(infd) == -1) return 0;
|
3363
|
+
buf = 0;
|
3364
|
+
gotint = 0;
|
3365
|
+
sigemptyset(&sa->sa_mask);
|
3366
|
+
sa->sa_flags = 0;
|
3367
|
+
sa->sa_handler = bestlineOnInt;
|
3368
|
+
sigaction(SIGINT,sa,sa+1);
|
3369
|
+
sigaction(SIGQUIT,sa,sa+2);
|
3370
|
+
rc = bestlineEdit(infd,outfd,prompt,&buf);
|
3371
|
+
bestlineDisableRawMode();
|
3372
|
+
sigaction(SIGQUIT,sa+2,0);
|
3373
|
+
sigaction(SIGINT,sa+1,0);
|
3374
|
+
if (gotint) {
|
3375
|
+
free(buf);
|
3376
|
+
buf = 0;
|
3377
|
+
raise(gotint);
|
3378
|
+
errno = EINTR;
|
3379
|
+
rc = -1;
|
3380
|
+
}
|
3381
|
+
if (rc != -1) {
|
3382
|
+
bestlineWriteStr(outfd,"\n");
|
3383
|
+
return buf;
|
3384
|
+
} else {
|
3385
|
+
free(buf);
|
3386
|
+
return 0;
|
3387
|
+
}
|
3388
|
+
}
|
3389
|
+
|
3390
|
+
/**
|
3391
|
+
* Reads line intelligently.
|
3392
|
+
*
|
3393
|
+
* The high level function that is the main API of the bestline library.
|
3394
|
+
* This function checks if the terminal has basic capabilities, just checking
|
3395
|
+
* for a blacklist of inarticulate terminals, and later either calls the line
|
3396
|
+
* editing function or uses dummy fgets() so that you will be able to type
|
3397
|
+
* something even in the most desperate of the conditions.
|
3398
|
+
*
|
3399
|
+
* @param prompt is printed before asking for input if we have a term
|
3400
|
+
* and this may be set to empty or null to disable and prompt may
|
3401
|
+
* contain ansi escape sequences, color, utf8, etc.
|
3402
|
+
* @return chomped allocated string of read line or null on eof/error
|
3403
|
+
*/
|
3404
|
+
char *bestline(const char *prompt) {
|
3405
|
+
if (prompt && *prompt &&
|
3406
|
+
(strchr(prompt, '\n') || strchr(prompt, '\t') ||
|
3407
|
+
strchr(prompt + 1, '\r'))) {
|
3408
|
+
errno = EINVAL;
|
3409
|
+
return 0;
|
3410
|
+
}
|
3411
|
+
if ((!isatty(fileno(stdin)) ||
|
3412
|
+
!isatty(fileno(stdout)))) {
|
3413
|
+
if (prompt && *prompt && (IsCharDev(fileno(stdin)) &&
|
3414
|
+
IsCharDev(fileno(stdout)))) {
|
3415
|
+
fputs(prompt,stdout);
|
3416
|
+
fflush(stdout);
|
3417
|
+
}
|
3418
|
+
return GetLine(stdin, stdout);
|
3419
|
+
} else if (bestlineIsUnsupportedTerm()) {
|
3420
|
+
if (prompt && *prompt) {
|
3421
|
+
fputs(prompt,stdout);
|
3422
|
+
fflush(stdout);
|
3423
|
+
}
|
3424
|
+
return GetLine(stdin, stdout);
|
3425
|
+
} else {
|
3426
|
+
fflush(stdout);
|
3427
|
+
return bestlineRaw(prompt,fileno(stdin),fileno(stdout));
|
3428
|
+
}
|
3429
|
+
}
|
3430
|
+
|
3431
|
+
/**
|
3432
|
+
* Reads line intelligently w/ history, e.g.
|
3433
|
+
*
|
3434
|
+
* // see ~/.foo_history
|
3435
|
+
* main() {
|
3436
|
+
* char *line;
|
3437
|
+
* while ((line = bestlineWithHistory("IN> ", "foo"))) {
|
3438
|
+
* printf("OUT> %s\n", line);
|
3439
|
+
* free(line);
|
3440
|
+
* }
|
3441
|
+
* }
|
3442
|
+
*
|
3443
|
+
* @param prompt is printed before asking for input if we have a term
|
3444
|
+
* and this may be set to empty or null to disable and prompt may
|
3445
|
+
* contain ansi escape sequences, color, utf8, etc.
|
3446
|
+
* @param prog is name of your app, used to generate history filename
|
3447
|
+
* however if it contains a slash / dot then we'll assume prog is
|
3448
|
+
* the history filename which as determined by the caller
|
3449
|
+
* @return chomped allocated string of read line or null on eof/error
|
3450
|
+
*/
|
3451
|
+
char *bestlineWithHistory(const char *prompt, const char *prog) {
|
3452
|
+
char *line;
|
3453
|
+
struct abuf path;
|
3454
|
+
const char *a, *b;
|
3455
|
+
abInit(&path);
|
3456
|
+
if (prog) {
|
3457
|
+
if (strchr(prog, '/') || strchr(prog, '.')) {
|
3458
|
+
abAppends(&path, prog);
|
3459
|
+
} else {
|
3460
|
+
b = "";
|
3461
|
+
if (!(a = getenv("HOME"))) {
|
3462
|
+
if (!(a = getenv("HOMEDRIVE")) ||
|
3463
|
+
!(b = getenv("HOMEPATH"))) {
|
3464
|
+
a = "";
|
3465
|
+
}
|
3466
|
+
}
|
3467
|
+
if (*a) {
|
3468
|
+
abAppends(&path, a);
|
3469
|
+
abAppends(&path, b);
|
3470
|
+
abAppendw(&path, '/');
|
3471
|
+
}
|
3472
|
+
abAppendw(&path, '.');
|
3473
|
+
abAppends(&path, prog);
|
3474
|
+
abAppends(&path, "_history");
|
3475
|
+
}
|
3476
|
+
}
|
3477
|
+
if (path.len) {
|
3478
|
+
bestlineHistoryLoad(path.b);
|
3479
|
+
}
|
3480
|
+
line = bestline(prompt);
|
3481
|
+
if (path.len && line && *line) {
|
3482
|
+
/* history here is inefficient but helpful when the user has multiple
|
3483
|
+
* repls open at the same time, so history propagates between them */
|
3484
|
+
bestlineHistoryLoad(path.b);
|
3485
|
+
bestlineHistoryAdd(line);
|
3486
|
+
bestlineHistorySave(path.b);
|
3487
|
+
}
|
3488
|
+
abFree(&path);
|
3489
|
+
return line;
|
3490
|
+
}
|
3491
|
+
|
3492
|
+
/**
|
3493
|
+
* Registers tab completion callback.
|
3494
|
+
*/
|
3495
|
+
void bestlineSetCompletionCallback(bestlineCompletionCallback *fn) {
|
3496
|
+
completionCallback = fn;
|
3497
|
+
}
|
3498
|
+
|
3499
|
+
/**
|
3500
|
+
* Registers hints callback.
|
3501
|
+
*
|
3502
|
+
* Register a hits function to be called to show hits to the user at the
|
3503
|
+
* right of the prompt.
|
3504
|
+
*/
|
3505
|
+
void bestlineSetHintsCallback(bestlineHintsCallback *fn) {
|
3506
|
+
hintsCallback = fn;
|
3507
|
+
}
|
3508
|
+
|
3509
|
+
/**
|
3510
|
+
* Sets free hints callback.
|
3511
|
+
*
|
3512
|
+
* This registers a function to free the hints returned by the hints
|
3513
|
+
* callback registered with bestlineSetHintsCallback().
|
3514
|
+
*/
|
3515
|
+
void bestlineSetFreeHintsCallback(bestlineFreeHintsCallback *fn) {
|
3516
|
+
freeHintsCallback = fn;
|
3517
|
+
}
|
3518
|
+
|
3519
|
+
/**
|
3520
|
+
* Sets character translation callback.
|
3521
|
+
*/
|
3522
|
+
void bestlineSetXlatCallback(bestlineXlatCallback *fn) {
|
3523
|
+
xlatCallback = fn;
|
3524
|
+
}
|
3525
|
+
|
3526
|
+
/**
|
3527
|
+
* Adds completion.
|
3528
|
+
*
|
3529
|
+
* This function is used by the callback function registered by the user
|
3530
|
+
* in order to add completion options given the input string when the
|
3531
|
+
* user typed <tab>. See the example.c source code for a very easy to
|
3532
|
+
* understand example.
|
3533
|
+
*/
|
3534
|
+
void bestlineAddCompletion(bestlineCompletions *lc, const char *str) {
|
3535
|
+
size_t len;
|
3536
|
+
char *copy, **cvec;
|
3537
|
+
if ((copy = (char *)malloc((len = strlen(str))+1))) {
|
3538
|
+
memcpy(copy,str,len+1);
|
3539
|
+
if ((cvec = (char **)realloc(lc->cvec,(lc->len+1)*sizeof(*lc->cvec)))) {
|
3540
|
+
lc->cvec = cvec;
|
3541
|
+
lc->cvec[lc->len++] = copy;
|
3542
|
+
} else {
|
3543
|
+
free(copy);
|
3544
|
+
}
|
3545
|
+
}
|
3546
|
+
}
|
3547
|
+
|
3548
|
+
/**
|
3549
|
+
* Frees list of completion option populated by bestlineAddCompletion().
|
3550
|
+
*/
|
3551
|
+
void bestlineFreeCompletions(bestlineCompletions *lc) {
|
3552
|
+
size_t i;
|
3553
|
+
for (i = 0; i < lc->len; i++)
|
3554
|
+
free(lc->cvec[i]);
|
3555
|
+
if (lc->cvec)
|
3556
|
+
free(lc->cvec);
|
3557
|
+
}
|
3558
|
+
|
3559
|
+
/**
|
3560
|
+
* Enables "mask mode".
|
3561
|
+
*
|
3562
|
+
* When it is enabled, instead of the input that the user is typing, the
|
3563
|
+
* terminal will just display a corresponding number of asterisks, like
|
3564
|
+
* "****". This is useful for passwords and other secrets that should
|
3565
|
+
* not be displayed.
|
3566
|
+
*
|
3567
|
+
* @see bestlineMaskModeDisable()
|
3568
|
+
*/
|
3569
|
+
void bestlineMaskModeEnable(void) {
|
3570
|
+
maskmode = 1;
|
3571
|
+
}
|
3572
|
+
|
3573
|
+
/**
|
3574
|
+
* Disables "mask mode".
|
3575
|
+
*/
|
3576
|
+
void bestlineMaskModeDisable(void) {
|
3577
|
+
maskmode = 0;
|
3578
|
+
}
|