summaryrefslogtreecommitdiffstats
path: root/sinksh/repl/linenoise.hpp
diff options
context:
space:
mode:
authorChristian Mollekopf <chrigi_1@fastmail.fm>2018-05-23 16:49:49 +0200
committerChristian Mollekopf <chrigi_1@fastmail.fm>2018-05-23 16:52:00 +0200
commit426392f71d5f45aad8c57969643fd6c365ce2362 (patch)
tree3e5b6ddfc395e26f1a931f9a97516ede9b7c68d3 /sinksh/repl/linenoise.hpp
parent1ec240e3df3e9c8571c0df174b9f239b451dbf3a (diff)
downloadsink-426392f71d5f45aad8c57969643fd6c365ce2362.tar.gz
sink-426392f71d5f45aad8c57969643fd6c365ce2362.zip
Replaced readline with cpp-linenoise
... a single header readline replacement that works on all linux, osx and windows (or so they claim). Besides cleaning up the code considerably, it should help us build sinksh on windows where readline is not really (there are some ancient broken readline ports) available. cpp-readline comes from here: https://github.com/yhirose/cpp-linenoise
Diffstat (limited to 'sinksh/repl/linenoise.hpp')
-rw-r--r--sinksh/repl/linenoise.hpp2412
1 files changed, 2412 insertions, 0 deletions
diff --git a/sinksh/repl/linenoise.hpp b/sinksh/repl/linenoise.hpp
new file mode 100644
index 0000000..fa7aa7f
--- /dev/null
+++ b/sinksh/repl/linenoise.hpp
@@ -0,0 +1,2412 @@
1/*
2 * linenoise.hpp -- Multi-platfrom C++ header-only linenoise library.
3 * https://github.com/yhirose/cpp-linenoise
4 *
5 * All credits and commendations have to go to the authors of the
6 * following excellent libraries.
7 *
8 * - linenoise.h and linenose.c (https://github.com/antirez/linenoise)
9 * - ANSI.c (https://github.com/adoxa/ansicon)
10 * - Win32_ANSI.h and Win32_ANSI.c (https://github.com/MSOpenTech/redis)
11 *
12 * ------------------------------------------------------------------------
13 *
14 * Copyright (c) 2015 yhirose
15 * All rights reserved.
16 *
17 * Redistribution and use in source and binary forms, with or without
18 * modification, are permitted provided that the following conditions are met:
19 *
20 * 1. Redistributions of source code must retain the above copyright notice, this
21 * list of conditions and the following disclaimer.
22 * 2. Redistributions in binary form must reproduce the above copyright notice,
23 * this list of conditions and the following disclaimer in the documentation
24 * and/or other materials provided with the distribution.
25 *
26 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
27 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
28 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
29 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
30 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
31 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
32 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
33 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
34 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
35 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
36 */
37
38/* linenoise.h -- guerrilla line editing library against the idea that a
39 * line editing lib needs to be 20,000 lines of C code.
40 *
41 * See linenoise.c for more information.
42 *
43 * ------------------------------------------------------------------------
44 *
45 * Copyright (c) 2010, Salvatore Sanfilippo <antirez at gmail dot com>
46 * Copyright (c) 2010, Pieter Noordhuis <pcnoordhuis at gmail dot com>
47 *
48 * All rights reserved.
49 *
50 * Redistribution and use in source and binary forms, with or without
51 * modification, are permitted provided that the following conditions are
52 * met:
53 *
54 * * Redistributions of source code must retain the above copyright
55 * notice, this list of conditions and the following disclaimer.
56 *
57 * * Redistributions in binary form must reproduce the above copyright
58 * notice, this list of conditions and the following disclaimer in the
59 * documentation and/or other materials provided with the distribution.
60 *
61 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
62 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
63 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
64 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
65 * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
66 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
67 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
68 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
69 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
70 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
71 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
72 */
73
74/*
75 * ANSI.c - ANSI escape sequence console driver.
76 *
77 * Copyright (C) 2005-2014 Jason Hood
78 * This software is provided 'as-is', without any express or implied
79 * warranty. In no event will the author be held liable for any damages
80 * arising from the use of this software.
81 *
82 * Permission is granted to anyone to use this software for any purpose,
83 * including commercial applications, and to alter it and redistribute it
84 * freely, subject to the following restrictions:
85 *
86 * 1. The origin of this software must not be misrepresented; you must not
87 * claim that you wrote the original software. If you use this software
88 * in a product, an acknowledgment in the product documentation would be
89 * appreciated but is not required.
90 * 2. Altered source versions must be plainly marked as such, and must not be
91 * misrepresented as being the original software.
92 * 3. This notice may not be removed or altered from any source distribution.
93 *
94 * Jason Hood
95 * jadoxa@yahoo.com.au
96 */
97
98/*
99 * Win32_ANSI.h and Win32_ANSI.c
100 *
101 * Derived from ANSI.c by Jason Hood, from his ansicon project (https://github.com/adoxa/ansicon), with modifications.
102 *
103 * Copyright (c), Microsoft Open Technologies, Inc.
104 * All rights reserved.
105 * Redistribution and use in source and binary forms, with or without
106 * modification, are permitted provided that the following conditions are met:
107 * - Redistributions of source code must retain the above copyright notice,
108 * this list of conditions and the following disclaimer.
109 * - Redistributions in binary form must reproduce the above copyright notice,
110 * this list of conditions and the following disclaimer in the documentation
111 * and/or other materials provided with the distribution.
112 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
113 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
114 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
115 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
116 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
117 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
118 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
119 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
120 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
121 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
122 */
123
124#ifndef __LINENOISE_HPP
125#define __LINENOISE_HPP
126
127#ifndef _WIN32
128#include <termios.h>
129#include <unistd.h>
130#include <sys/ioctl.h>
131#else
132#ifndef NOMINMAX
133#define NOMINMAX
134#endif
135#include <Windows.h>
136#include <io.h>
137#ifndef STDIN_FILENO
138#define STDIN_FILENO (_fileno(stdin))
139#endif
140#ifndef STDOUT_FILENO
141#define STDOUT_FILENO 1
142#endif
143#define isatty _isatty
144#define write win32_write
145#define read _read
146#endif
147#include <stdlib.h>
148#include <stdio.h>
149#include <errno.h>
150#include <string.h>
151#include <stdlib.h>
152#include <ctype.h>
153#include <sys/types.h>
154#include <string>
155#include <fstream>
156#include <functional>
157#include <vector>
158#include <iostream>
159
160namespace linenoise {
161
162typedef std::function<void (const char*, std::vector<std::string>&)> CompletionCallback;
163
164#ifdef _WIN32
165
166namespace ansi {
167
168#define lenof(array) (sizeof(array)/sizeof(*(array)))
169
170typedef struct
171{
172 BYTE foreground; // ANSI base color (0 to 7; add 30)
173 BYTE background; // ANSI base color (0 to 7; add 40)
174 BYTE bold; // console FOREGROUND_INTENSITY bit
175 BYTE underline; // console BACKGROUND_INTENSITY bit
176 BYTE rvideo; // swap foreground/bold & background/underline
177 BYTE concealed; // set foreground/bold to background/underline
178 BYTE reverse; // swap console foreground & background attributes
179} GRM, *PGRM; // Graphic Rendition Mode
180
181
182inline bool is_digit(char c) { return '0' <= c && c <= '9'; }
183
184// ========== Global variables and constants
185
186HANDLE hConOut; // handle to CONOUT$
187
188const char ESC = '\x1B'; // ESCape character
189const char BEL = '\x07';
190const char SO = '\x0E'; // Shift Out
191const char SI = '\x0F'; // Shift In
192
193const int MAX_ARG = 16; // max number of args in an escape sequence
194int state; // automata state
195WCHAR prefix; // escape sequence prefix ( '[', ']' or '(' );
196WCHAR prefix2; // secondary prefix ( '?' or '>' );
197WCHAR suffix; // escape sequence suffix
198int es_argc; // escape sequence args count
199int es_argv[MAX_ARG]; // escape sequence args
200WCHAR Pt_arg[MAX_PATH * 2]; // text parameter for Operating System Command
201int Pt_len;
202BOOL shifted;
203
204
205// DEC Special Graphics Character Set from
206// http://vt100.net/docs/vt220-rm/table2-4.html
207// Some of these may not look right, depending on the font and code page (in
208// particular, the Control Pictures probably won't work at all).
209const WCHAR G1[] =
210{
211 ' ', // _ - blank
212 L'\x2666', // ` - Black Diamond Suit
213 L'\x2592', // a - Medium Shade
214 L'\x2409', // b - HT
215 L'\x240c', // c - FF
216 L'\x240d', // d - CR
217 L'\x240a', // e - LF
218 L'\x00b0', // f - Degree Sign
219 L'\x00b1', // g - Plus-Minus Sign
220 L'\x2424', // h - NL
221 L'\x240b', // i - VT
222 L'\x2518', // j - Box Drawings Light Up And Left
223 L'\x2510', // k - Box Drawings Light Down And Left
224 L'\x250c', // l - Box Drawings Light Down And Right
225 L'\x2514', // m - Box Drawings Light Up And Right
226 L'\x253c', // n - Box Drawings Light Vertical And Horizontal
227 L'\x00af', // o - SCAN 1 - Macron
228 L'\x25ac', // p - SCAN 3 - Black Rectangle
229 L'\x2500', // q - SCAN 5 - Box Drawings Light Horizontal
230 L'_', // r - SCAN 7 - Low Line
231 L'_', // s - SCAN 9 - Low Line
232 L'\x251c', // t - Box Drawings Light Vertical And Right
233 L'\x2524', // u - Box Drawings Light Vertical And Left
234 L'\x2534', // v - Box Drawings Light Up And Horizontal
235 L'\x252c', // w - Box Drawings Light Down And Horizontal
236 L'\x2502', // x - Box Drawings Light Vertical
237 L'\x2264', // y - Less-Than Or Equal To
238 L'\x2265', // z - Greater-Than Or Equal To
239 L'\x03c0', // { - Greek Small Letter Pi
240 L'\x2260', // | - Not Equal To
241 L'\x00a3', // } - Pound Sign
242 L'\x00b7', // ~ - Middle Dot
243};
244
245#define FIRST_G1 '_'
246#define LAST_G1 '~'
247
248
249// color constants
250
251#define FOREGROUND_BLACK 0
252#define FOREGROUND_WHITE FOREGROUND_RED|FOREGROUND_GREEN|FOREGROUND_BLUE
253
254#define BACKGROUND_BLACK 0
255#define BACKGROUND_WHITE BACKGROUND_RED|BACKGROUND_GREEN|BACKGROUND_BLUE
256
257const BYTE foregroundcolor[8] =
258 {
259 FOREGROUND_BLACK, // black foreground
260 FOREGROUND_RED, // red foreground
261 FOREGROUND_GREEN, // green foreground
262 FOREGROUND_RED | FOREGROUND_GREEN, // yellow foreground
263 FOREGROUND_BLUE, // blue foreground
264 FOREGROUND_BLUE | FOREGROUND_RED, // magenta foreground
265 FOREGROUND_BLUE | FOREGROUND_GREEN, // cyan foreground
266 FOREGROUND_WHITE // white foreground
267 };
268
269const BYTE backgroundcolor[8] =
270 {
271 BACKGROUND_BLACK, // black background
272 BACKGROUND_RED, // red background
273 BACKGROUND_GREEN, // green background
274 BACKGROUND_RED | BACKGROUND_GREEN, // yellow background
275 BACKGROUND_BLUE, // blue background
276 BACKGROUND_BLUE | BACKGROUND_RED, // magenta background
277 BACKGROUND_BLUE | BACKGROUND_GREEN, // cyan background
278 BACKGROUND_WHITE, // white background
279 };
280
281const BYTE attr2ansi[8] = // map console attribute to ANSI number
282{
283 0, // black
284 4, // blue
285 2, // green
286 6, // cyan
287 1, // red
288 5, // magenta
289 3, // yellow
290 7 // white
291};
292
293GRM grm;
294
295// saved cursor position
296COORD SavePos;
297
298// ========== Print Buffer functions
299
300#define BUFFER_SIZE 2048
301
302int nCharInBuffer;
303WCHAR ChBuffer[BUFFER_SIZE];
304
305//-----------------------------------------------------------------------------
306// FlushBuffer()
307// Writes the buffer to the console and empties it.
308//-----------------------------------------------------------------------------
309
310inline void FlushBuffer(void)
311{
312 DWORD nWritten;
313 if (nCharInBuffer <= 0) return;
314 WriteConsoleW(hConOut, ChBuffer, nCharInBuffer, &nWritten, NULL);
315 nCharInBuffer = 0;
316}
317
318//-----------------------------------------------------------------------------
319// PushBuffer( WCHAR c )
320// Adds a character in the buffer.
321//-----------------------------------------------------------------------------
322
323inline void PushBuffer(WCHAR c)
324{
325 if (shifted && c >= FIRST_G1 && c <= LAST_G1)
326 c = G1[c - FIRST_G1];
327 ChBuffer[nCharInBuffer] = c;
328 if (++nCharInBuffer == BUFFER_SIZE)
329 FlushBuffer();
330}
331
332//-----------------------------------------------------------------------------
333// SendSequence( LPWSTR seq )
334// Send the string to the input buffer.
335//-----------------------------------------------------------------------------
336
337inline void SendSequence(LPWSTR seq)
338{
339 DWORD out;
340 INPUT_RECORD in;
341 HANDLE hStdIn = GetStdHandle(STD_INPUT_HANDLE);
342
343 in.EventType = KEY_EVENT;
344 in.Event.KeyEvent.bKeyDown = TRUE;
345 in.Event.KeyEvent.wRepeatCount = 1;
346 in.Event.KeyEvent.wVirtualKeyCode = 0;
347 in.Event.KeyEvent.wVirtualScanCode = 0;
348 in.Event.KeyEvent.dwControlKeyState = 0;
349 for (; *seq; ++seq)
350 {
351 in.Event.KeyEvent.uChar.UnicodeChar = *seq;
352 WriteConsoleInput(hStdIn, &in, 1, &out);
353 }
354}
355
356// ========== Print functions
357
358//-----------------------------------------------------------------------------
359// InterpretEscSeq()
360// Interprets the last escape sequence scanned by ParseAndPrintANSIString
361// prefix escape sequence prefix
362// es_argc escape sequence args count
363// es_argv[] escape sequence args array
364// suffix escape sequence suffix
365//
366// for instance, with \e[33;45;1m we have
367// prefix = '[',
368// es_argc = 3, es_argv[0] = 33, es_argv[1] = 45, es_argv[2] = 1
369// suffix = 'm'
370//-----------------------------------------------------------------------------
371
372inline void InterpretEscSeq(void)
373{
374 int i;
375 WORD attribut;
376 CONSOLE_SCREEN_BUFFER_INFO Info;
377 CONSOLE_CURSOR_INFO CursInfo;
378 DWORD len, NumberOfCharsWritten;
379 COORD Pos;
380 SMALL_RECT Rect;
381 CHAR_INFO CharInfo;
382
383 if (prefix == '[')
384 {
385 if (prefix2 == '?' && (suffix == 'h' || suffix == 'l'))
386 {
387 if (es_argc == 1 && es_argv[0] == 25)
388 {
389 GetConsoleCursorInfo(hConOut, &CursInfo);
390 CursInfo.bVisible = (suffix == 'h');
391 SetConsoleCursorInfo(hConOut, &CursInfo);
392 return;
393 }
394 }
395 // Ignore any other \e[? or \e[> sequences.
396 if (prefix2 != 0)
397 return;
398
399 GetConsoleScreenBufferInfo(hConOut, &Info);
400 switch (suffix)
401 {
402 case 'm':
403 if (es_argc == 0) es_argv[es_argc++] = 0;
404 for (i = 0; i < es_argc; i++)
405 {
406 if (30 <= es_argv[i] && es_argv[i] <= 37)
407 grm.foreground = es_argv[i] - 30;
408 else if (40 <= es_argv[i] && es_argv[i] <= 47)
409 grm.background = es_argv[i] - 40;
410 else switch (es_argv[i])
411 {
412 case 0:
413 case 39:
414 case 49:
415 {
416 WCHAR def[4];
417 int a;
418 *def = '7'; def[1] = '\0';
419 GetEnvironmentVariableW(L"ANSICON_DEF", def, lenof(def));
420 a = wcstol(def, NULL, 16);
421 grm.reverse = FALSE;
422 if (a < 0)
423 {
424 grm.reverse = TRUE;
425 a = -a;
426 }
427 if (es_argv[i] != 49)
428 grm.foreground = attr2ansi[a & 7];
429 if (es_argv[i] != 39)
430 grm.background = attr2ansi[(a >> 4) & 7];
431 if (es_argv[i] == 0)
432 {
433 if (es_argc == 1)
434 {
435 grm.bold = a & FOREGROUND_INTENSITY;
436 grm.underline = a & BACKGROUND_INTENSITY;
437 }
438 else
439 {
440 grm.bold = 0;
441 grm.underline = 0;
442 }
443 grm.rvideo = 0;
444 grm.concealed = 0;
445 }
446 }
447 break;
448
449 case 1: grm.bold = FOREGROUND_INTENSITY; break;
450 case 5: // blink
451 case 4: grm.underline = BACKGROUND_INTENSITY; break;
452 case 7: grm.rvideo = 1; break;
453 case 8: grm.concealed = 1; break;
454 case 21: // oops, this actually turns on double underline
455 case 22: grm.bold = 0; break;
456 case 25:
457 case 24: grm.underline = 0; break;
458 case 27: grm.rvideo = 0; break;
459 case 28: grm.concealed = 0; break;
460 }
461 }
462 if (grm.concealed)
463 {
464 if (grm.rvideo)
465 {
466 attribut = foregroundcolor[grm.foreground]
467 | backgroundcolor[grm.foreground];
468 if (grm.bold)
469 attribut |= FOREGROUND_INTENSITY | BACKGROUND_INTENSITY;
470 }
471 else
472 {
473 attribut = foregroundcolor[grm.background]
474 | backgroundcolor[grm.background];
475 if (grm.underline)
476 attribut |= FOREGROUND_INTENSITY | BACKGROUND_INTENSITY;
477 }
478 }
479 else if (grm.rvideo)
480 {
481 attribut = foregroundcolor[grm.background]
482 | backgroundcolor[grm.foreground];
483 if (grm.bold)
484 attribut |= BACKGROUND_INTENSITY;
485 if (grm.underline)
486 attribut |= FOREGROUND_INTENSITY;
487 }
488 else
489 attribut = foregroundcolor[grm.foreground] | grm.bold
490 | backgroundcolor[grm.background] | grm.underline;
491 if (grm.reverse)
492 attribut = ((attribut >> 4) & 15) | ((attribut & 15) << 4);
493 SetConsoleTextAttribute(hConOut, attribut);
494 return;
495
496 case 'J':
497 if (es_argc == 0) es_argv[es_argc++] = 0; // ESC[J == ESC[0J
498 if (es_argc != 1) return;
499 switch (es_argv[0])
500 {
501 case 0: // ESC[0J erase from cursor to end of display
502 len = (Info.dwSize.Y - Info.dwCursorPosition.Y - 1) * Info.dwSize.X
503 + Info.dwSize.X - Info.dwCursorPosition.X - 1;
504 FillConsoleOutputCharacter(hConOut, ' ', len,
505 Info.dwCursorPosition,
506 &NumberOfCharsWritten);
507 FillConsoleOutputAttribute(hConOut, Info.wAttributes, len,
508 Info.dwCursorPosition,
509 &NumberOfCharsWritten);
510 return;
511
512 case 1: // ESC[1J erase from start to cursor.
513 Pos.X = 0;
514 Pos.Y = 0;
515 len = Info.dwCursorPosition.Y * Info.dwSize.X
516 + Info.dwCursorPosition.X + 1;
517 FillConsoleOutputCharacter(hConOut, ' ', len, Pos,
518 &NumberOfCharsWritten);
519 FillConsoleOutputAttribute(hConOut, Info.wAttributes, len, Pos,
520 &NumberOfCharsWritten);
521 return;
522
523 case 2: // ESC[2J Clear screen and home cursor
524 Pos.X = 0;
525 Pos.Y = 0;
526 len = Info.dwSize.X * Info.dwSize.Y;
527 FillConsoleOutputCharacter(hConOut, ' ', len, Pos,
528 &NumberOfCharsWritten);
529 FillConsoleOutputAttribute(hConOut, Info.wAttributes, len, Pos,
530 &NumberOfCharsWritten);
531 SetConsoleCursorPosition(hConOut, Pos);
532 return;
533
534 default:
535 return;
536 }
537
538 case 'K':
539 if (es_argc == 0) es_argv[es_argc++] = 0; // ESC[K == ESC[0K
540 if (es_argc != 1) return;
541 switch (es_argv[0])
542 {
543 case 0: // ESC[0K Clear to end of line
544 len = Info.dwSize.X - Info.dwCursorPosition.X + 1;
545 FillConsoleOutputCharacter(hConOut, ' ', len,
546 Info.dwCursorPosition,
547 &NumberOfCharsWritten);
548 FillConsoleOutputAttribute(hConOut, Info.wAttributes, len,
549 Info.dwCursorPosition,
550 &NumberOfCharsWritten);
551 return;
552
553 case 1: // ESC[1K Clear from start of line to cursor
554 Pos.X = 0;
555 Pos.Y = Info.dwCursorPosition.Y;
556 FillConsoleOutputCharacter(hConOut, ' ',
557 Info.dwCursorPosition.X + 1, Pos,
558 &NumberOfCharsWritten);
559 FillConsoleOutputAttribute(hConOut, Info.wAttributes,
560 Info.dwCursorPosition.X + 1, Pos,
561 &NumberOfCharsWritten);
562 return;
563
564 case 2: // ESC[2K Clear whole line.
565 Pos.X = 0;
566 Pos.Y = Info.dwCursorPosition.Y;
567 FillConsoleOutputCharacter(hConOut, ' ', Info.dwSize.X, Pos,
568 &NumberOfCharsWritten);
569 FillConsoleOutputAttribute(hConOut, Info.wAttributes,
570 Info.dwSize.X, Pos,
571 &NumberOfCharsWritten);
572 return;
573
574 default:
575 return;
576 }
577
578 case 'X': // ESC[#X Erase # characters.
579 if (es_argc == 0) es_argv[es_argc++] = 1; // ESC[X == ESC[1X
580 if (es_argc != 1) return;
581 FillConsoleOutputCharacter(hConOut, ' ', es_argv[0],
582 Info.dwCursorPosition,
583 &NumberOfCharsWritten);
584 FillConsoleOutputAttribute(hConOut, Info.wAttributes, es_argv[0],
585 Info.dwCursorPosition,
586 &NumberOfCharsWritten);
587 return;
588
589 case 'L': // ESC[#L Insert # blank lines.
590 if (es_argc == 0) es_argv[es_argc++] = 1; // ESC[L == ESC[1L
591 if (es_argc != 1) return;
592 Rect.Left = 0;
593 Rect.Top = Info.dwCursorPosition.Y;
594 Rect.Right = Info.dwSize.X - 1;
595 Rect.Bottom = Info.dwSize.Y - 1;
596 Pos.X = 0;
597 Pos.Y = Info.dwCursorPosition.Y + es_argv[0];
598 CharInfo.Char.UnicodeChar = ' ';
599 CharInfo.Attributes = Info.wAttributes;
600 ScrollConsoleScreenBuffer(hConOut, &Rect, NULL, Pos, &CharInfo);
601 return;
602
603 case 'M': // ESC[#M Delete # lines.
604 if (es_argc == 0) es_argv[es_argc++] = 1; // ESC[M == ESC[1M
605 if (es_argc != 1) return;
606 if (es_argv[0] > Info.dwSize.Y - Info.dwCursorPosition.Y)
607 es_argv[0] = Info.dwSize.Y - Info.dwCursorPosition.Y;
608 Rect.Left = 0;
609 Rect.Top = Info.dwCursorPosition.Y + es_argv[0];
610 Rect.Right = Info.dwSize.X - 1;
611 Rect.Bottom = Info.dwSize.Y - 1;
612 Pos.X = 0;
613 Pos.Y = Info.dwCursorPosition.Y;
614 CharInfo.Char.UnicodeChar = ' ';
615 CharInfo.Attributes = Info.wAttributes;
616 ScrollConsoleScreenBuffer(hConOut, &Rect, NULL, Pos, &CharInfo);
617 return;
618
619 case 'P': // ESC[#P Delete # characters.
620 if (es_argc == 0) es_argv[es_argc++] = 1; // ESC[P == ESC[1P
621 if (es_argc != 1) return;
622 if (Info.dwCursorPosition.X + es_argv[0] > Info.dwSize.X - 1)
623 es_argv[0] = Info.dwSize.X - Info.dwCursorPosition.X;
624 Rect.Left = Info.dwCursorPosition.X + es_argv[0];
625 Rect.Top = Info.dwCursorPosition.Y;
626 Rect.Right = Info.dwSize.X - 1;
627 Rect.Bottom = Info.dwCursorPosition.Y;
628 CharInfo.Char.UnicodeChar = ' ';
629 CharInfo.Attributes = Info.wAttributes;
630 ScrollConsoleScreenBuffer(hConOut, &Rect, NULL, Info.dwCursorPosition,
631 &CharInfo);
632 return;
633
634 case '@': // ESC[#@ Insert # blank characters.
635 if (es_argc == 0) es_argv[es_argc++] = 1; // ESC[@ == ESC[1@
636 if (es_argc != 1) return;
637 if (Info.dwCursorPosition.X + es_argv[0] > Info.dwSize.X - 1)
638 es_argv[0] = Info.dwSize.X - Info.dwCursorPosition.X;
639 Rect.Left = Info.dwCursorPosition.X;
640 Rect.Top = Info.dwCursorPosition.Y;
641 Rect.Right = Info.dwSize.X - 1 - es_argv[0];
642 Rect.Bottom = Info.dwCursorPosition.Y;
643 Pos.X = Info.dwCursorPosition.X + es_argv[0];
644 Pos.Y = Info.dwCursorPosition.Y;
645 CharInfo.Char.UnicodeChar = ' ';
646 CharInfo.Attributes = Info.wAttributes;
647 ScrollConsoleScreenBuffer(hConOut, &Rect, NULL, Pos, &CharInfo);
648 return;
649
650 case 'k': // ESC[#k
651 case 'A': // ESC[#A Moves cursor up # lines
652 if (es_argc == 0) es_argv[es_argc++] = 1; // ESC[A == ESC[1A
653 if (es_argc != 1) return;
654 Pos.Y = Info.dwCursorPosition.Y - es_argv[0];
655 if (Pos.Y < 0) Pos.Y = 0;
656 Pos.X = Info.dwCursorPosition.X;
657 SetConsoleCursorPosition(hConOut, Pos);
658 return;
659
660 case 'e': // ESC[#e
661 case 'B': // ESC[#B Moves cursor down # lines
662 if (es_argc == 0) es_argv[es_argc++] = 1; // ESC[B == ESC[1B
663 if (es_argc != 1) return;
664 Pos.Y = Info.dwCursorPosition.Y + es_argv[0];
665 if (Pos.Y >= Info.dwSize.Y) Pos.Y = Info.dwSize.Y - 1;
666 Pos.X = Info.dwCursorPosition.X;
667 SetConsoleCursorPosition(hConOut, Pos);
668 return;
669
670 case 'a': // ESC[#a
671 case 'C': // ESC[#C Moves cursor forward # spaces
672 if (es_argc == 0) es_argv[es_argc++] = 1; // ESC[C == ESC[1C
673 if (es_argc != 1) return;
674 Pos.X = Info.dwCursorPosition.X + es_argv[0];
675 if (Pos.X >= Info.dwSize.X) Pos.X = Info.dwSize.X - 1;
676 Pos.Y = Info.dwCursorPosition.Y;
677 SetConsoleCursorPosition(hConOut, Pos);
678 return;
679
680 case 'j': // ESC[#j
681 case 'D': // ESC[#D Moves cursor back # spaces
682 if (es_argc == 0) es_argv[es_argc++] = 1; // ESC[D == ESC[1D
683 if (es_argc != 1) return;
684 Pos.X = Info.dwCursorPosition.X - es_argv[0];
685 if (Pos.X < 0) Pos.X = 0;
686 Pos.Y = Info.dwCursorPosition.Y;
687 SetConsoleCursorPosition(hConOut, Pos);
688 return;
689
690 case 'E': // ESC[#E Moves cursor down # lines, column 1.
691 if (es_argc == 0) es_argv[es_argc++] = 1; // ESC[E == ESC[1E
692 if (es_argc != 1) return;
693 Pos.Y = Info.dwCursorPosition.Y + es_argv[0];
694 if (Pos.Y >= Info.dwSize.Y) Pos.Y = Info.dwSize.Y - 1;
695 Pos.X = 0;
696 SetConsoleCursorPosition(hConOut, Pos);
697 return;
698
699 case 'F': // ESC[#F Moves cursor up # lines, column 1.
700 if (es_argc == 0) es_argv[es_argc++] = 1; // ESC[F == ESC[1F
701 if (es_argc != 1) return;
702 Pos.Y = Info.dwCursorPosition.Y - es_argv[0];
703 if (Pos.Y < 0) Pos.Y = 0;
704 Pos.X = 0;
705 SetConsoleCursorPosition(hConOut, Pos);
706 return;
707
708 case '`': // ESC[#`
709 case 'G': // ESC[#G Moves cursor column # in current row.
710 if (es_argc == 0) es_argv[es_argc++] = 1; // ESC[G == ESC[1G
711 if (es_argc != 1) return;
712 Pos.X = es_argv[0] - 1;
713 if (Pos.X >= Info.dwSize.X) Pos.X = Info.dwSize.X - 1;
714 if (Pos.X < 0) Pos.X = 0;
715 Pos.Y = Info.dwCursorPosition.Y;
716 SetConsoleCursorPosition(hConOut, Pos);
717 return;
718
719 case 'd': // ESC[#d Moves cursor row #, current column.
720 if (es_argc == 0) es_argv[es_argc++] = 1; // ESC[d == ESC[1d
721 if (es_argc != 1) return;
722 Pos.Y = es_argv[0] - 1;
723 if (Pos.Y < 0) Pos.Y = 0;
724 if (Pos.Y >= Info.dwSize.Y) Pos.Y = Info.dwSize.Y - 1;
725 SetConsoleCursorPosition(hConOut, Pos);
726 return;
727
728 case 'f': // ESC[#;#f
729 case 'H': // ESC[#;#H Moves cursor to line #, column #
730 if (es_argc == 0)
731 es_argv[es_argc++] = 1; // ESC[H == ESC[1;1H
732 if (es_argc == 1)
733 es_argv[es_argc++] = 1; // ESC[#H == ESC[#;1H
734 if (es_argc > 2) return;
735 Pos.X = es_argv[1] - 1;
736 if (Pos.X < 0) Pos.X = 0;
737 if (Pos.X >= Info.dwSize.X) Pos.X = Info.dwSize.X - 1;
738 Pos.Y = es_argv[0] - 1;
739 if (Pos.Y < 0) Pos.Y = 0;
740 if (Pos.Y >= Info.dwSize.Y) Pos.Y = Info.dwSize.Y - 1;
741 SetConsoleCursorPosition(hConOut, Pos);
742 return;
743
744 case 's': // ESC[s Saves cursor position for recall later
745 if (es_argc != 0) return;
746 SavePos = Info.dwCursorPosition;
747 return;
748
749 case 'u': // ESC[u Return to saved cursor position
750 if (es_argc != 0) return;
751 SetConsoleCursorPosition(hConOut, SavePos);
752 return;
753
754 case 'n': // ESC[#n Device status report
755 if (es_argc != 1) return; // ESC[n == ESC[0n -> ignored
756 switch (es_argv[0])
757 {
758 case 5: // ESC[5n Report status
759 SendSequence(L"\33[0n"); // "OK"
760 return;
761
762 case 6: // ESC[6n Report cursor position
763 {
764 WCHAR buf[32];
765 swprintf(buf, 32, L"\33[%d;%dR", Info.dwCursorPosition.Y + 1,
766 Info.dwCursorPosition.X + 1);
767 SendSequence(buf);
768 }
769 return;
770
771 default:
772 return;
773 }
774
775 case 't': // ESC[#t Window manipulation
776 if (es_argc != 1) return;
777 if (es_argv[0] == 21) // ESC[21t Report xterm window's title
778 {
779 WCHAR buf[MAX_PATH * 2];
780 DWORD len = GetConsoleTitleW(buf + 3, lenof(buf) - 3 - 2);
781 // Too bad if it's too big or fails.
782 buf[0] = ESC;
783 buf[1] = ']';
784 buf[2] = 'l';
785 buf[3 + len] = ESC;
786 buf[3 + len + 1] = '\\';
787 buf[3 + len + 2] = '\0';
788 SendSequence(buf);
789 }
790 return;
791
792 default:
793 return;
794 }
795 }
796 else // (prefix == ']')
797 {
798 // Ignore any \e]? or \e]> sequences.
799 if (prefix2 != 0)
800 return;
801
802 if (es_argc == 1 && es_argv[0] == 0) // ESC]0;titleST
803 {
804 SetConsoleTitleW(Pt_arg);
805 }
806 }
807}
808
809//-----------------------------------------------------------------------------
810// ParseAndPrintANSIString(hDev, lpBuffer, nNumberOfBytesToWrite)
811// Parses the string lpBuffer, interprets the escapes sequences and prints the
812// characters in the device hDev (console).
813// The lexer is a three states automata.
814// If the number of arguments es_argc > MAX_ARG, only the MAX_ARG-1 firsts and
815// the last arguments are processed (no es_argv[] overflow).
816//-----------------------------------------------------------------------------
817
818inline BOOL ParseAndPrintANSIString(HANDLE hDev, LPCVOID lpBuffer, DWORD nNumberOfBytesToWrite, LPDWORD lpNumberOfBytesWritten)
819{
820 DWORD i;
821 LPCSTR s;
822
823 if (hDev != hConOut) // reinit if device has changed
824 {
825 hConOut = hDev;
826 state = 1;
827 shifted = FALSE;
828 }
829 for (i = nNumberOfBytesToWrite, s = (LPCSTR)lpBuffer; i > 0; i--, s++)
830 {
831 if (state == 1)
832 {
833 if (*s == ESC) state = 2;
834 else if (*s == SO) shifted = TRUE;
835 else if (*s == SI) shifted = FALSE;
836 else PushBuffer(*s);
837 }
838 else if (state == 2)
839 {
840 if (*s == ESC); // \e\e...\e == \e
841 else if ((*s == '[') || (*s == ']'))
842 {
843 FlushBuffer();
844 prefix = *s;
845 prefix2 = 0;
846 state = 3;
847 Pt_len = 0;
848 *Pt_arg = '\0';
849 }
850 else if (*s == ')' || *s == '(') state = 6;
851 else state = 1;
852 }
853 else if (state == 3)
854 {
855 if (is_digit(*s))
856 {
857 es_argc = 0;
858 es_argv[0] = *s - '0';
859 state = 4;
860 }
861 else if (*s == ';')
862 {
863 es_argc = 1;
864 es_argv[0] = 0;
865 es_argv[1] = 0;
866 state = 4;
867 }
868 else if (*s == '?' || *s == '>')
869 {
870 prefix2 = *s;
871 }
872 else
873 {
874 es_argc = 0;
875 suffix = *s;
876 InterpretEscSeq();
877 state = 1;
878 }
879 }
880 else if (state == 4)
881 {
882 if (is_digit(*s))
883 {
884 es_argv[es_argc] = 10 * es_argv[es_argc] + (*s - '0');
885 }
886 else if (*s == ';')
887 {
888 if (es_argc < MAX_ARG - 1) es_argc++;
889 es_argv[es_argc] = 0;
890 if (prefix == ']')
891 state = 5;
892 }
893 else
894 {
895 es_argc++;
896 suffix = *s;
897 InterpretEscSeq();
898 state = 1;
899 }
900 }
901 else if (state == 5)
902 {
903 if (*s == BEL)
904 {
905 Pt_arg[Pt_len] = '\0';
906 InterpretEscSeq();
907 state = 1;
908 }
909 else if (*s == '\\' && Pt_len > 0 && Pt_arg[Pt_len - 1] == ESC)
910 {
911 Pt_arg[--Pt_len] = '\0';
912 InterpretEscSeq();
913 state = 1;
914 }
915 else if (Pt_len < lenof(Pt_arg) - 1)
916 Pt_arg[Pt_len++] = *s;
917 }
918 else if (state == 6)
919 {
920 // Ignore it (ESC ) 0 is implicit; nothing else is supported).
921 state = 1;
922 }
923 }
924 FlushBuffer();
925 if (lpNumberOfBytesWritten != NULL)
926 *lpNumberOfBytesWritten = nNumberOfBytesToWrite - i;
927 return (i == 0);
928}
929
930} // namespace ansi
931
932HANDLE hOut;
933HANDLE hIn;
934DWORD consolemodeIn = 0;
935
936inline int win32read(int *c) {
937 DWORD foo;
938 INPUT_RECORD b;
939 KEY_EVENT_RECORD e;
940 BOOL altgr;
941
942 while (1) {
943 if (!ReadConsoleInput(hIn, &b, 1, &foo)) return 0;
944 if (!foo) return 0;
945
946 if (b.EventType == KEY_EVENT && b.Event.KeyEvent.bKeyDown) {
947
948 e = b.Event.KeyEvent;
949 *c = b.Event.KeyEvent.uChar.AsciiChar;
950
951 altgr = e.dwControlKeyState & (LEFT_CTRL_PRESSED | RIGHT_ALT_PRESSED);
952
953 if (e.dwControlKeyState & (LEFT_CTRL_PRESSED | RIGHT_CTRL_PRESSED) && !altgr) {
954
955 /* Ctrl+Key */
956 switch (*c) {
957 case 'D':
958 *c = 4;
959 return 1;
960 case 'C':
961 *c = 3;
962 return 1;
963 case 'H':
964 *c = 8;
965 return 1;
966 case 'T':
967 *c = 20;
968 return 1;
969 case 'B': /* ctrl-b, left_arrow */
970 *c = 2;
971 return 1;
972 case 'F': /* ctrl-f right_arrow*/
973 *c = 6;
974 return 1;
975 case 'P': /* ctrl-p up_arrow*/
976 *c = 16;
977 return 1;
978 case 'N': /* ctrl-n down_arrow*/
979 *c = 14;
980 return 1;
981 case 'U': /* Ctrl+u, delete the whole line. */
982 *c = 21;
983 return 1;
984 case 'K': /* Ctrl+k, delete from current to end of line. */
985 *c = 11;
986 return 1;
987 case 'A': /* Ctrl+a, go to the start of the line */
988 *c = 1;
989 return 1;
990 case 'E': /* ctrl+e, go to the end of the line */
991 *c = 5;
992 return 1;
993 }
994
995 /* Other Ctrl+KEYs ignored */
996 } else {
997
998 switch (e.wVirtualKeyCode) {
999
1000 case VK_ESCAPE: /* ignore - send ctrl-c, will return -1 */
1001 *c = 3;
1002 return 1;
1003 case VK_RETURN: /* enter */
1004 *c = 13;
1005 return 1;
1006 case VK_LEFT: /* left */
1007 *c = 2;
1008 return 1;
1009 case VK_RIGHT: /* right */
1010 *c = 6;
1011 return 1;
1012 case VK_UP: /* up */
1013 *c = 16;
1014 return 1;
1015 case VK_DOWN: /* down */
1016 *c = 14;
1017 return 1;
1018 case VK_HOME:
1019 *c = 1;
1020 return 1;
1021 case VK_END:
1022 *c = 5;
1023 return 1;
1024 case VK_BACK:
1025 *c = 8;
1026 return 1;
1027 case VK_DELETE:
1028 *c = 127;
1029 return 1;
1030 default:
1031 if (*c) return 1;
1032 }
1033 }
1034 }
1035 }
1036
1037 return -1; /* Makes compiler happy */
1038}
1039
1040inline int win32_write(int fd, const void *buffer, unsigned int count) {
1041 if (fd == _fileno(stdout)) {
1042 DWORD bytesWritten = 0;
1043 if (FALSE != ansi::ParseAndPrintANSIString(GetStdHandle(STD_OUTPUT_HANDLE), buffer, (DWORD)count, &bytesWritten)) {
1044 return (int)bytesWritten;
1045 } else {
1046 errno = GetLastError();
1047 return 0;
1048 }
1049 } else if (fd == _fileno(stderr)) {
1050 DWORD bytesWritten = 0;
1051 if (FALSE != ansi::ParseAndPrintANSIString(GetStdHandle(STD_ERROR_HANDLE), buffer, (DWORD)count, &bytesWritten)) {
1052 return (int)bytesWritten;
1053 } else {
1054 errno = GetLastError();
1055 return 0;
1056 }
1057 } else {
1058 return _write(fd, buffer, count);
1059 }
1060}
1061#endif // _WIN32
1062
1063#define LINENOISE_DEFAULT_HISTORY_MAX_LEN 100
1064#define LINENOISE_MAX_LINE 4096
1065static const char *unsupported_term[] = {"dumb","cons25","emacs",NULL};
1066static CompletionCallback completionCallback;
1067
1068#ifndef _WIN32
1069static struct termios orig_termios; /* In order to restore at exit.*/
1070#endif
1071static bool rawmode = false; /* For atexit() function to check if restore is needed*/
1072static bool mlmode = false; /* Multi line mode. Default is single line. */
1073static bool atexit_registered = false; /* Register atexit just 1 time. */
1074static size_t history_max_len = LINENOISE_DEFAULT_HISTORY_MAX_LEN;
1075static std::vector<std::string> history;
1076
1077/* The linenoiseState structure represents the state during line editing.
1078 * We pass this state to functions implementing specific editing
1079 * functionalities. */
1080struct linenoiseState {
1081 int ifd; /* Terminal stdin file descriptor. */
1082 int ofd; /* Terminal stdout file descriptor. */
1083 char *buf; /* Edited line buffer. */
1084 int buflen; /* Edited line buffer size. */
1085 std::string prompt; /* Prompt to display. */
1086 int pos; /* Current cursor position. */
1087 int oldcolpos; /* Previous refresh cursor column position. */
1088 int len; /* Current edited line length. */
1089 int cols; /* Number of columns in terminal. */
1090 int maxrows; /* Maximum num of rows used so far (multiline mode) */
1091 int history_index; /* The history index we are currently editing. */
1092};
1093
1094enum KEY_ACTION {
1095 KEY_NULL = 0, /* NULL */
1096 CTRL_A = 1, /* Ctrl+a */
1097 CTRL_B = 2, /* Ctrl-b */
1098 CTRL_C = 3, /* Ctrl-c */
1099 CTRL_D = 4, /* Ctrl-d */
1100 CTRL_E = 5, /* Ctrl-e */
1101 CTRL_F = 6, /* Ctrl-f */
1102 CTRL_H = 8, /* Ctrl-h */
1103 TAB = 9, /* Tab */
1104 CTRL_K = 11, /* Ctrl+k */
1105 CTRL_L = 12, /* Ctrl+l */
1106 ENTER = 13, /* Enter */
1107 CTRL_N = 14, /* Ctrl-n */
1108 CTRL_P = 16, /* Ctrl-p */
1109 CTRL_T = 20, /* Ctrl-t */
1110 CTRL_U = 21, /* Ctrl+u */
1111 CTRL_W = 23, /* Ctrl+w */
1112 ESC = 27, /* Escape */
1113 BACKSPACE = 127 /* Backspace */
1114};
1115
1116void linenoiseAtExit(void);
1117bool AddHistory(const char *line);
1118void refreshLine(struct linenoiseState *l);
1119
1120/* ============================ UTF8 utilities ============================== */
1121
1122static unsigned long unicodeWideCharTable[][2] = {
1123 { 0x1100, 0x115F }, { 0x2329, 0x232A }, { 0x2E80, 0x2E99, }, { 0x2E9B, 0x2EF3, },
1124 { 0x2F00, 0x2FD5, }, { 0x2FF0, 0x2FFB, }, { 0x3000, 0x303E, }, { 0x3041, 0x3096, },
1125 { 0x3099, 0x30FF, }, { 0x3105, 0x312D, }, { 0x3131, 0x318E, }, { 0x3190, 0x31BA, },
1126 { 0x31C0, 0x31E3, }, { 0x31F0, 0x321E, }, { 0x3220, 0x3247, }, { 0x3250, 0x4DBF, },
1127 { 0x4E00, 0xA48C, }, { 0xA490, 0xA4C6, }, { 0xA960, 0xA97C, }, { 0xAC00, 0xD7A3, },
1128 { 0xF900, 0xFAFF, }, { 0xFE10, 0xFE19, }, { 0xFE30, 0xFE52, }, { 0xFE54, 0xFE66, },
1129 { 0xFE68, 0xFE6B, }, { 0xFF01, 0xFFE6, },
1130 { 0x1B000, 0x1B001, }, { 0x1F200, 0x1F202, }, { 0x1F210, 0x1F23A, },
1131 { 0x1F240, 0x1F248, }, { 0x1F250, 0x1F251, }, { 0x20000, 0x3FFFD, },
1132};
1133
1134static int unicodeWideCharTableSize = sizeof(unicodeWideCharTable) / sizeof(unicodeWideCharTable[0]);
1135
1136static int unicodeIsWideChar(unsigned long cp)
1137{
1138 int i;
1139 for (i = 0; i < unicodeWideCharTableSize; i++) {
1140 if (unicodeWideCharTable[i][0] <= cp && cp <= unicodeWideCharTable[i][1]) {
1141 return 1;
1142 }
1143 }
1144 return 0;
1145}
1146
1147static unsigned long unicodeCombiningCharTable[] = {
1148 0x0300,0x0301,0x0302,0x0303,0x0304,0x0305,0x0306,0x0307,
1149 0x0308,0x0309,0x030A,0x030B,0x030C,0x030D,0x030E,0x030F,
1150 0x0310,0x0311,0x0312,0x0313,0x0314,0x0315,0x0316,0x0317,
1151 0x0318,0x0319,0x031A,0x031B,0x031C,0x031D,0x031E,0x031F,
1152 0x0320,0x0321,0x0322,0x0323,0x0324,0x0325,0x0326,0x0327,
1153 0x0328,0x0329,0x032A,0x032B,0x032C,0x032D,0x032E,0x032F,
1154 0x0330,0x0331,0x0332,0x0333,0x0334,0x0335,0x0336,0x0337,
1155 0x0338,0x0339,0x033A,0x033B,0x033C,0x033D,0x033E,0x033F,
1156 0x0340,0x0341,0x0342,0x0343,0x0344,0x0345,0x0346,0x0347,
1157 0x0348,0x0349,0x034A,0x034B,0x034C,0x034D,0x034E,0x034F,
1158 0x0350,0x0351,0x0352,0x0353,0x0354,0x0355,0x0356,0x0357,
1159 0x0358,0x0359,0x035A,0x035B,0x035C,0x035D,0x035E,0x035F,
1160 0x0360,0x0361,0x0362,0x0363,0x0364,0x0365,0x0366,0x0367,
1161 0x0368,0x0369,0x036A,0x036B,0x036C,0x036D,0x036E,0x036F,
1162 0x0483,0x0484,0x0485,0x0486,0x0487,0x0591,0x0592,0x0593,
1163 0x0594,0x0595,0x0596,0x0597,0x0598,0x0599,0x059A,0x059B,
1164 0x059C,0x059D,0x059E,0x059F,0x05A0,0x05A1,0x05A2,0x05A3,
1165 0x05A4,0x05A5,0x05A6,0x05A7,0x05A8,0x05A9,0x05AA,0x05AB,
1166 0x05AC,0x05AD,0x05AE,0x05AF,0x05B0,0x05B1,0x05B2,0x05B3,
1167 0x05B4,0x05B5,0x05B6,0x05B7,0x05B8,0x05B9,0x05BA,0x05BB,
1168 0x05BC,0x05BD,0x05BF,0x05C1,0x05C2,0x05C4,0x05C5,0x05C7,
1169 0x0610,0x0611,0x0612,0x0613,0x0614,0x0615,0x0616,0x0617,
1170 0x0618,0x0619,0x061A,0x064B,0x064C,0x064D,0x064E,0x064F,
1171 0x0650,0x0651,0x0652,0x0653,0x0654,0x0655,0x0656,0x0657,
1172 0x0658,0x0659,0x065A,0x065B,0x065C,0x065D,0x065E,0x065F,
1173 0x0670,0x06D6,0x06D7,0x06D8,0x06D9,0x06DA,0x06DB,0x06DC,
1174 0x06DF,0x06E0,0x06E1,0x06E2,0x06E3,0x06E4,0x06E7,0x06E8,
1175 0x06EA,0x06EB,0x06EC,0x06ED,0x0711,0x0730,0x0731,0x0732,
1176 0x0733,0x0734,0x0735,0x0736,0x0737,0x0738,0x0739,0x073A,
1177 0x073B,0x073C,0x073D,0x073E,0x073F,0x0740,0x0741,0x0742,
1178 0x0743,0x0744,0x0745,0x0746,0x0747,0x0748,0x0749,0x074A,
1179 0x07A6,0x07A7,0x07A8,0x07A9,0x07AA,0x07AB,0x07AC,0x07AD,
1180 0x07AE,0x07AF,0x07B0,0x07EB,0x07EC,0x07ED,0x07EE,0x07EF,
1181 0x07F0,0x07F1,0x07F2,0x07F3,0x0816,0x0817,0x0818,0x0819,
1182 0x081B,0x081C,0x081D,0x081E,0x081F,0x0820,0x0821,0x0822,
1183 0x0823,0x0825,0x0826,0x0827,0x0829,0x082A,0x082B,0x082C,
1184 0x082D,0x0859,0x085A,0x085B,0x08E3,0x08E4,0x08E5,0x08E6,
1185 0x08E7,0x08E8,0x08E9,0x08EA,0x08EB,0x08EC,0x08ED,0x08EE,
1186 0x08EF,0x08F0,0x08F1,0x08F2,0x08F3,0x08F4,0x08F5,0x08F6,
1187 0x08F7,0x08F8,0x08F9,0x08FA,0x08FB,0x08FC,0x08FD,0x08FE,
1188 0x08FF,0x0900,0x0901,0x0902,0x093A,0x093C,0x0941,0x0942,
1189 0x0943,0x0944,0x0945,0x0946,0x0947,0x0948,0x094D,0x0951,
1190 0x0952,0x0953,0x0954,0x0955,0x0956,0x0957,0x0962,0x0963,
1191 0x0981,0x09BC,0x09C1,0x09C2,0x09C3,0x09C4,0x09CD,0x09E2,
1192 0x09E3,0x0A01,0x0A02,0x0A3C,0x0A41,0x0A42,0x0A47,0x0A48,
1193 0x0A4B,0x0A4C,0x0A4D,0x0A51,0x0A70,0x0A71,0x0A75,0x0A81,
1194 0x0A82,0x0ABC,0x0AC1,0x0AC2,0x0AC3,0x0AC4,0x0AC5,0x0AC7,
1195 0x0AC8,0x0ACD,0x0AE2,0x0AE3,0x0B01,0x0B3C,0x0B3F,0x0B41,
1196 0x0B42,0x0B43,0x0B44,0x0B4D,0x0B56,0x0B62,0x0B63,0x0B82,
1197 0x0BC0,0x0BCD,0x0C00,0x0C3E,0x0C3F,0x0C40,0x0C46,0x0C47,
1198 0x0C48,0x0C4A,0x0C4B,0x0C4C,0x0C4D,0x0C55,0x0C56,0x0C62,
1199 0x0C63,0x0C81,0x0CBC,0x0CBF,0x0CC6,0x0CCC,0x0CCD,0x0CE2,
1200 0x0CE3,0x0D01,0x0D41,0x0D42,0x0D43,0x0D44,0x0D4D,0x0D62,
1201 0x0D63,0x0DCA,0x0DD2,0x0DD3,0x0DD4,0x0DD6,0x0E31,0x0E34,
1202 0x0E35,0x0E36,0x0E37,0x0E38,0x0E39,0x0E3A,0x0E47,0x0E48,
1203 0x0E49,0x0E4A,0x0E4B,0x0E4C,0x0E4D,0x0E4E,0x0EB1,0x0EB4,
1204 0x0EB5,0x0EB6,0x0EB7,0x0EB8,0x0EB9,0x0EBB,0x0EBC,0x0EC8,
1205 0x0EC9,0x0ECA,0x0ECB,0x0ECC,0x0ECD,0x0F18,0x0F19,0x0F35,
1206 0x0F37,0x0F39,0x0F71,0x0F72,0x0F73,0x0F74,0x0F75,0x0F76,
1207 0x0F77,0x0F78,0x0F79,0x0F7A,0x0F7B,0x0F7C,0x0F7D,0x0F7E,
1208 0x0F80,0x0F81,0x0F82,0x0F83,0x0F84,0x0F86,0x0F87,0x0F8D,
1209 0x0F8E,0x0F8F,0x0F90,0x0F91,0x0F92,0x0F93,0x0F94,0x0F95,
1210 0x0F96,0x0F97,0x0F99,0x0F9A,0x0F9B,0x0F9C,0x0F9D,0x0F9E,
1211 0x0F9F,0x0FA0,0x0FA1,0x0FA2,0x0FA3,0x0FA4,0x0FA5,0x0FA6,
1212 0x0FA7,0x0FA8,0x0FA9,0x0FAA,0x0FAB,0x0FAC,0x0FAD,0x0FAE,
1213 0x0FAF,0x0FB0,0x0FB1,0x0FB2,0x0FB3,0x0FB4,0x0FB5,0x0FB6,
1214 0x0FB7,0x0FB8,0x0FB9,0x0FBA,0x0FBB,0x0FBC,0x0FC6,0x102D,
1215 0x102E,0x102F,0x1030,0x1032,0x1033,0x1034,0x1035,0x1036,
1216 0x1037,0x1039,0x103A,0x103D,0x103E,0x1058,0x1059,0x105E,
1217 0x105F,0x1060,0x1071,0x1072,0x1073,0x1074,0x1082,0x1085,
1218 0x1086,0x108D,0x109D,0x135D,0x135E,0x135F,0x1712,0x1713,
1219 0x1714,0x1732,0x1733,0x1734,0x1752,0x1753,0x1772,0x1773,
1220 0x17B4,0x17B5,0x17B7,0x17B8,0x17B9,0x17BA,0x17BB,0x17BC,
1221 0x17BD,0x17C6,0x17C9,0x17CA,0x17CB,0x17CC,0x17CD,0x17CE,
1222 0x17CF,0x17D0,0x17D1,0x17D2,0x17D3,0x17DD,0x180B,0x180C,
1223 0x180D,0x18A9,0x1920,0x1921,0x1922,0x1927,0x1928,0x1932,
1224 0x1939,0x193A,0x193B,0x1A17,0x1A18,0x1A1B,0x1A56,0x1A58,
1225 0x1A59,0x1A5A,0x1A5B,0x1A5C,0x1A5D,0x1A5E,0x1A60,0x1A62,
1226 0x1A65,0x1A66,0x1A67,0x1A68,0x1A69,0x1A6A,0x1A6B,0x1A6C,
1227 0x1A73,0x1A74,0x1A75,0x1A76,0x1A77,0x1A78,0x1A79,0x1A7A,
1228 0x1A7B,0x1A7C,0x1A7F,0x1AB0,0x1AB1,0x1AB2,0x1AB3,0x1AB4,
1229 0x1AB5,0x1AB6,0x1AB7,0x1AB8,0x1AB9,0x1ABA,0x1ABB,0x1ABC,
1230 0x1ABD,0x1B00,0x1B01,0x1B02,0x1B03,0x1B34,0x1B36,0x1B37,
1231 0x1B38,0x1B39,0x1B3A,0x1B3C,0x1B42,0x1B6B,0x1B6C,0x1B6D,
1232 0x1B6E,0x1B6F,0x1B70,0x1B71,0x1B72,0x1B73,0x1B80,0x1B81,
1233 0x1BA2,0x1BA3,0x1BA4,0x1BA5,0x1BA8,0x1BA9,0x1BAB,0x1BAC,
1234 0x1BAD,0x1BE6,0x1BE8,0x1BE9,0x1BED,0x1BEF,0x1BF0,0x1BF1,
1235 0x1C2C,0x1C2D,0x1C2E,0x1C2F,0x1C30,0x1C31,0x1C32,0x1C33,
1236 0x1C36,0x1C37,0x1CD0,0x1CD1,0x1CD2,0x1CD4,0x1CD5,0x1CD6,
1237 0x1CD7,0x1CD8,0x1CD9,0x1CDA,0x1CDB,0x1CDC,0x1CDD,0x1CDE,
1238 0x1CDF,0x1CE0,0x1CE2,0x1CE3,0x1CE4,0x1CE5,0x1CE6,0x1CE7,
1239 0x1CE8,0x1CED,0x1CF4,0x1CF8,0x1CF9,0x1DC0,0x1DC1,0x1DC2,
1240 0x1DC3,0x1DC4,0x1DC5,0x1DC6,0x1DC7,0x1DC8,0x1DC9,0x1DCA,
1241 0x1DCB,0x1DCC,0x1DCD,0x1DCE,0x1DCF,0x1DD0,0x1DD1,0x1DD2,
1242 0x1DD3,0x1DD4,0x1DD5,0x1DD6,0x1DD7,0x1DD8,0x1DD9,0x1DDA,
1243 0x1DDB,0x1DDC,0x1DDD,0x1DDE,0x1DDF,0x1DE0,0x1DE1,0x1DE2,
1244 0x1DE3,0x1DE4,0x1DE5,0x1DE6,0x1DE7,0x1DE8,0x1DE9,0x1DEA,
1245 0x1DEB,0x1DEC,0x1DED,0x1DEE,0x1DEF,0x1DF0,0x1DF1,0x1DF2,
1246 0x1DF3,0x1DF4,0x1DF5,0x1DFC,0x1DFD,0x1DFE,0x1DFF,0x20D0,
1247 0x20D1,0x20D2,0x20D3,0x20D4,0x20D5,0x20D6,0x20D7,0x20D8,
1248 0x20D9,0x20DA,0x20DB,0x20DC,0x20E1,0x20E5,0x20E6,0x20E7,
1249 0x20E8,0x20E9,0x20EA,0x20EB,0x20EC,0x20ED,0x20EE,0x20EF,
1250 0x20F0,0x2CEF,0x2CF0,0x2CF1,0x2D7F,0x2DE0,0x2DE1,0x2DE2,
1251 0x2DE3,0x2DE4,0x2DE5,0x2DE6,0x2DE7,0x2DE8,0x2DE9,0x2DEA,
1252 0x2DEB,0x2DEC,0x2DED,0x2DEE,0x2DEF,0x2DF0,0x2DF1,0x2DF2,
1253 0x2DF3,0x2DF4,0x2DF5,0x2DF6,0x2DF7,0x2DF8,0x2DF9,0x2DFA,
1254 0x2DFB,0x2DFC,0x2DFD,0x2DFE,0x2DFF,0x302A,0x302B,0x302C,
1255 0x302D,0x3099,0x309A,0xA66F,0xA674,0xA675,0xA676,0xA677,
1256 0xA678,0xA679,0xA67A,0xA67B,0xA67C,0xA67D,0xA69E,0xA69F,
1257 0xA6F0,0xA6F1,0xA802,0xA806,0xA80B,0xA825,0xA826,0xA8C4,
1258 0xA8E0,0xA8E1,0xA8E2,0xA8E3,0xA8E4,0xA8E5,0xA8E6,0xA8E7,
1259 0xA8E8,0xA8E9,0xA8EA,0xA8EB,0xA8EC,0xA8ED,0xA8EE,0xA8EF,
1260 0xA8F0,0xA8F1,0xA926,0xA927,0xA928,0xA929,0xA92A,0xA92B,
1261 0xA92C,0xA92D,0xA947,0xA948,0xA949,0xA94A,0xA94B,0xA94C,
1262 0xA94D,0xA94E,0xA94F,0xA950,0xA951,0xA980,0xA981,0xA982,
1263 0xA9B3,0xA9B6,0xA9B7,0xA9B8,0xA9B9,0xA9BC,0xA9E5,0xAA29,
1264 0xAA2A,0xAA2B,0xAA2C,0xAA2D,0xAA2E,0xAA31,0xAA32,0xAA35,
1265 0xAA36,0xAA43,0xAA4C,0xAA7C,0xAAB0,0xAAB2,0xAAB3,0xAAB4,
1266 0xAAB7,0xAAB8,0xAABE,0xAABF,0xAAC1,0xAAEC,0xAAED,0xAAF6,
1267 0xABE5,0xABE8,0xABED,0xFB1E,0xFE00,0xFE01,0xFE02,0xFE03,
1268 0xFE04,0xFE05,0xFE06,0xFE07,0xFE08,0xFE09,0xFE0A,0xFE0B,
1269 0xFE0C,0xFE0D,0xFE0E,0xFE0F,0xFE20,0xFE21,0xFE22,0xFE23,
1270 0xFE24,0xFE25,0xFE26,0xFE27,0xFE28,0xFE29,0xFE2A,0xFE2B,
1271 0xFE2C,0xFE2D,0xFE2E,0xFE2F,
1272 0x101FD,0x102E0,0x10376,0x10377,0x10378,0x10379,0x1037A,0x10A01,
1273 0x10A02,0x10A03,0x10A05,0x10A06,0x10A0C,0x10A0D,0x10A0E,0x10A0F,
1274 0x10A38,0x10A39,0x10A3A,0x10A3F,0x10AE5,0x10AE6,0x11001,0x11038,
1275 0x11039,0x1103A,0x1103B,0x1103C,0x1103D,0x1103E,0x1103F,0x11040,
1276 0x11041,0x11042,0x11043,0x11044,0x11045,0x11046,0x1107F,0x11080,
1277 0x11081,0x110B3,0x110B4,0x110B5,0x110B6,0x110B9,0x110BA,0x11100,
1278 0x11101,0x11102,0x11127,0x11128,0x11129,0x1112A,0x1112B,0x1112D,
1279 0x1112E,0x1112F,0x11130,0x11131,0x11132,0x11133,0x11134,0x11173,
1280 0x11180,0x11181,0x111B6,0x111B7,0x111B8,0x111B9,0x111BA,0x111BB,
1281 0x111BC,0x111BD,0x111BE,0x111CA,0x111CB,0x111CC,0x1122F,0x11230,
1282 0x11231,0x11234,0x11236,0x11237,0x112DF,0x112E3,0x112E4,0x112E5,
1283 0x112E6,0x112E7,0x112E8,0x112E9,0x112EA,0x11300,0x11301,0x1133C,
1284 0x11340,0x11366,0x11367,0x11368,0x11369,0x1136A,0x1136B,0x1136C,
1285 0x11370,0x11371,0x11372,0x11373,0x11374,0x114B3,0x114B4,0x114B5,
1286 0x114B6,0x114B7,0x114B8,0x114BA,0x114BF,0x114C0,0x114C2,0x114C3,
1287 0x115B2,0x115B3,0x115B4,0x115B5,0x115BC,0x115BD,0x115BF,0x115C0,
1288 0x115DC,0x115DD,0x11633,0x11634,0x11635,0x11636,0x11637,0x11638,
1289 0x11639,0x1163A,0x1163D,0x1163F,0x11640,0x116AB,0x116AD,0x116B0,
1290 0x116B1,0x116B2,0x116B3,0x116B4,0x116B5,0x116B7,0x1171D,0x1171E,
1291 0x1171F,0x11722,0x11723,0x11724,0x11725,0x11727,0x11728,0x11729,
1292 0x1172A,0x1172B,0x16AF0,0x16AF1,0x16AF2,0x16AF3,0x16AF4,0x16B30,
1293 0x16B31,0x16B32,0x16B33,0x16B34,0x16B35,0x16B36,0x16F8F,0x16F90,
1294 0x16F91,0x16F92,0x1BC9D,0x1BC9E,0x1D167,0x1D168,0x1D169,0x1D17B,
1295 0x1D17C,0x1D17D,0x1D17E,0x1D17F,0x1D180,0x1D181,0x1D182,0x1D185,
1296 0x1D186,0x1D187,0x1D188,0x1D189,0x1D18A,0x1D18B,0x1D1AA,0x1D1AB,
1297 0x1D1AC,0x1D1AD,0x1D242,0x1D243,0x1D244,0x1DA00,0x1DA01,0x1DA02,
1298 0x1DA03,0x1DA04,0x1DA05,0x1DA06,0x1DA07,0x1DA08,0x1DA09,0x1DA0A,
1299 0x1DA0B,0x1DA0C,0x1DA0D,0x1DA0E,0x1DA0F,0x1DA10,0x1DA11,0x1DA12,
1300 0x1DA13,0x1DA14,0x1DA15,0x1DA16,0x1DA17,0x1DA18,0x1DA19,0x1DA1A,
1301 0x1DA1B,0x1DA1C,0x1DA1D,0x1DA1E,0x1DA1F,0x1DA20,0x1DA21,0x1DA22,
1302 0x1DA23,0x1DA24,0x1DA25,0x1DA26,0x1DA27,0x1DA28,0x1DA29,0x1DA2A,
1303 0x1DA2B,0x1DA2C,0x1DA2D,0x1DA2E,0x1DA2F,0x1DA30,0x1DA31,0x1DA32,
1304 0x1DA33,0x1DA34,0x1DA35,0x1DA36,0x1DA3B,0x1DA3C,0x1DA3D,0x1DA3E,
1305 0x1DA3F,0x1DA40,0x1DA41,0x1DA42,0x1DA43,0x1DA44,0x1DA45,0x1DA46,
1306 0x1DA47,0x1DA48,0x1DA49,0x1DA4A,0x1DA4B,0x1DA4C,0x1DA4D,0x1DA4E,
1307 0x1DA4F,0x1DA50,0x1DA51,0x1DA52,0x1DA53,0x1DA54,0x1DA55,0x1DA56,
1308 0x1DA57,0x1DA58,0x1DA59,0x1DA5A,0x1DA5B,0x1DA5C,0x1DA5D,0x1DA5E,
1309 0x1DA5F,0x1DA60,0x1DA61,0x1DA62,0x1DA63,0x1DA64,0x1DA65,0x1DA66,
1310 0x1DA67,0x1DA68,0x1DA69,0x1DA6A,0x1DA6B,0x1DA6C,0x1DA75,0x1DA84,
1311 0x1DA9B,0x1DA9C,0x1DA9D,0x1DA9E,0x1DA9F,0x1DAA1,0x1DAA2,0x1DAA3,
1312 0x1DAA4,0x1DAA5,0x1DAA6,0x1DAA7,0x1DAA8,0x1DAA9,0x1DAAA,0x1DAAB,
1313 0x1DAAC,0x1DAAD,0x1DAAE,0x1DAAF,0x1E8D0,0x1E8D1,0x1E8D2,0x1E8D3,
1314 0x1E8D4,0x1E8D5,0x1E8D6,0xE0100,0xE0101,0xE0102,0xE0103,0xE0104,
1315 0xE0105,0xE0106,0xE0107,0xE0108,0xE0109,0xE010A,0xE010B,0xE010C,
1316 0xE010D,0xE010E,0xE010F,0xE0110,0xE0111,0xE0112,0xE0113,0xE0114,
1317 0xE0115,0xE0116,0xE0117,0xE0118,0xE0119,0xE011A,0xE011B,0xE011C,
1318 0xE011D,0xE011E,0xE011F,0xE0120,0xE0121,0xE0122,0xE0123,0xE0124,
1319 0xE0125,0xE0126,0xE0127,0xE0128,0xE0129,0xE012A,0xE012B,0xE012C,
1320 0xE012D,0xE012E,0xE012F,0xE0130,0xE0131,0xE0132,0xE0133,0xE0134,
1321 0xE0135,0xE0136,0xE0137,0xE0138,0xE0139,0xE013A,0xE013B,0xE013C,
1322 0xE013D,0xE013E,0xE013F,0xE0140,0xE0141,0xE0142,0xE0143,0xE0144,
1323 0xE0145,0xE0146,0xE0147,0xE0148,0xE0149,0xE014A,0xE014B,0xE014C,
1324 0xE014D,0xE014E,0xE014F,0xE0150,0xE0151,0xE0152,0xE0153,0xE0154,
1325 0xE0155,0xE0156,0xE0157,0xE0158,0xE0159,0xE015A,0xE015B,0xE015C,
1326 0xE015D,0xE015E,0xE015F,0xE0160,0xE0161,0xE0162,0xE0163,0xE0164,
1327 0xE0165,0xE0166,0xE0167,0xE0168,0xE0169,0xE016A,0xE016B,0xE016C,
1328 0xE016D,0xE016E,0xE016F,0xE0170,0xE0171,0xE0172,0xE0173,0xE0174,
1329 0xE0175,0xE0176,0xE0177,0xE0178,0xE0179,0xE017A,0xE017B,0xE017C,
1330 0xE017D,0xE017E,0xE017F,0xE0180,0xE0181,0xE0182,0xE0183,0xE0184,
1331 0xE0185,0xE0186,0xE0187,0xE0188,0xE0189,0xE018A,0xE018B,0xE018C,
1332 0xE018D,0xE018E,0xE018F,0xE0190,0xE0191,0xE0192,0xE0193,0xE0194,
1333 0xE0195,0xE0196,0xE0197,0xE0198,0xE0199,0xE019A,0xE019B,0xE019C,
1334 0xE019D,0xE019E,0xE019F,0xE01A0,0xE01A1,0xE01A2,0xE01A3,0xE01A4,
1335 0xE01A5,0xE01A6,0xE01A7,0xE01A8,0xE01A9,0xE01AA,0xE01AB,0xE01AC,
1336 0xE01AD,0xE01AE,0xE01AF,0xE01B0,0xE01B1,0xE01B2,0xE01B3,0xE01B4,
1337 0xE01B5,0xE01B6,0xE01B7,0xE01B8,0xE01B9,0xE01BA,0xE01BB,0xE01BC,
1338 0xE01BD,0xE01BE,0xE01BF,0xE01C0,0xE01C1,0xE01C2,0xE01C3,0xE01C4,
1339 0xE01C5,0xE01C6,0xE01C7,0xE01C8,0xE01C9,0xE01CA,0xE01CB,0xE01CC,
1340 0xE01CD,0xE01CE,0xE01CF,0xE01D0,0xE01D1,0xE01D2,0xE01D3,0xE01D4,
1341 0xE01D5,0xE01D6,0xE01D7,0xE01D8,0xE01D9,0xE01DA,0xE01DB,0xE01DC,
1342 0xE01DD,0xE01DE,0xE01DF,0xE01E0,0xE01E1,0xE01E2,0xE01E3,0xE01E4,
1343 0xE01E5,0xE01E6,0xE01E7,0xE01E8,0xE01E9,0xE01EA,0xE01EB,0xE01EC,
1344 0xE01ED,0xE01EE,0xE01EF,
1345};
1346
1347static int unicodeCombiningCharTableSize = sizeof(unicodeCombiningCharTable) / sizeof(unicodeCombiningCharTable[0]);
1348
1349inline int unicodeIsCombiningChar(unsigned long cp)
1350{
1351 int i;
1352 for (i = 0; i < unicodeCombiningCharTableSize; i++) {
1353 if (unicodeCombiningCharTable[i] == cp) {
1354 return 1;
1355 }
1356 }
1357 return 0;
1358}
1359
1360/* Get length of previous UTF8 character
1361 */
1362inline int unicodePrevUTF8CharLen(char* buf, int pos)
1363{
1364 int end = pos--;
1365 while (pos >= 0 && ((unsigned char)buf[pos] & 0xC0) == 0x80) {
1366 pos--;
1367 }
1368 return end - pos;
1369}
1370
1371/* Get length of previous UTF8 character
1372 */
1373inline int unicodeUTF8CharLen(char* buf, int buf_len, int pos)
1374{
1375 if (pos == buf_len) { return 0; }
1376 unsigned char ch = buf[pos];
1377 if (ch < 0x80) { return 1; }
1378 else if (ch < 0xE0) { return 2; }
1379 else if (ch < 0xF0) { return 3; }
1380 else { return 4; }
1381}
1382
1383/* Convert UTF8 to Unicode code point
1384 */
1385inline int unicodeUTF8CharToCodePoint(
1386 const char* buf,
1387 int len,
1388 int* cp)
1389{
1390 if (len) {
1391 unsigned char byte = buf[0];
1392 if ((byte & 0x80) == 0) {
1393 *cp = byte;
1394 return 1;
1395 } else if ((byte & 0xE0) == 0xC0) {
1396 if (len >= 2) {
1397 *cp = (((unsigned long)(buf[0] & 0x1F)) << 6) |
1398 ((unsigned long)(buf[1] & 0x3F));
1399 return 2;
1400 }
1401 } else if ((byte & 0xF0) == 0xE0) {
1402 if (len >= 3) {
1403 *cp = (((unsigned long)(buf[0] & 0x0F)) << 12) |
1404 (((unsigned long)(buf[1] & 0x3F)) << 6) |
1405 ((unsigned long)(buf[2] & 0x3F));
1406 return 3;
1407 }
1408 } else if ((byte & 0xF8) == 0xF0) {
1409 if (len >= 4) {
1410 *cp = (((unsigned long)(buf[0] & 0x07)) << 18) |
1411 (((unsigned long)(buf[1] & 0x3F)) << 12) |
1412 (((unsigned long)(buf[2] & 0x3F)) << 6) |
1413 ((unsigned long)(buf[3] & 0x3F));
1414 return 4;
1415 }
1416 }
1417 }
1418 return 0;
1419}
1420
1421/* Get length of grapheme
1422 */
1423inline int unicodeGraphemeLen(char* buf, int buf_len, int pos)
1424{
1425 if (pos == buf_len) {
1426 return 0;
1427 }
1428 int beg = pos;
1429 pos += unicodeUTF8CharLen(buf, buf_len, pos);
1430 while (pos < buf_len) {
1431 int len = unicodeUTF8CharLen(buf, buf_len, pos);
1432 int cp = 0;
1433 unicodeUTF8CharToCodePoint(buf + pos, len, &cp);
1434 if (!unicodeIsCombiningChar(cp)) {
1435 return pos - beg;
1436 }
1437 pos += len;
1438 }
1439 return pos - beg;
1440}
1441
1442/* Get length of previous grapheme
1443 */
1444inline int unicodePrevGraphemeLen(char* buf, int pos)
1445{
1446 if (pos == 0) {
1447 return 0;
1448 }
1449 int end = pos;
1450 while (pos > 0) {
1451 int len = unicodePrevUTF8CharLen(buf, pos);
1452 pos -= len;
1453 int cp = 0;
1454 unicodeUTF8CharToCodePoint(buf + pos, len, &cp);
1455 if (!unicodeIsCombiningChar(cp)) {
1456 return end - pos;
1457 }
1458 }
1459 return 0;
1460}
1461
1462inline int isAnsiEscape(const char* buf, int buf_len, int* len)
1463{
1464 if (buf_len > 2 && !memcmp("\033[", buf, 2)) {
1465 int off = 2;
1466 while (off < buf_len) {
1467 switch (buf[off++]) {
1468 case 'A': case 'B': case 'C': case 'D':
1469 case 'E': case 'F': case 'G': case 'H':
1470 case 'J': case 'K': case 'S': case 'T':
1471 case 'f': case 'm':
1472 *len = off;
1473 return 1;
1474 }
1475 }
1476 }
1477 return 0;
1478}
1479
1480/* Get column position for the single line mode.
1481 */
1482inline int unicodeColumnPos(const char* buf, int buf_len)
1483{
1484 int ret = 0;
1485
1486 int off = 0;
1487 while (off < buf_len) {
1488 int len;
1489 if (isAnsiEscape(buf + off, buf_len - off, &len)) {
1490 off += len;
1491 continue;
1492 }
1493
1494 int cp = 0;
1495 len = unicodeUTF8CharToCodePoint(buf + off, buf_len - off, &cp);
1496
1497 if (!unicodeIsCombiningChar(cp)) {
1498 ret += unicodeIsWideChar(cp) ? 2 : 1;
1499 }
1500
1501 off += len;
1502 }
1503
1504 return ret;
1505}
1506
1507/* Get column position for the multi line mode.
1508 */
1509inline int unicodeColumnPosForMultiLine(char* buf, int buf_len, int pos, int cols, int ini_pos)
1510{
1511 int ret = 0;
1512 int colwid = ini_pos;
1513
1514 int off = 0;
1515 while (off < buf_len) {
1516 int cp = 0;
1517 int len = unicodeUTF8CharToCodePoint(buf + off, buf_len - off, &cp);
1518
1519 int wid = 0;
1520 if (!unicodeIsCombiningChar(cp)) {
1521 wid = unicodeIsWideChar(cp) ? 2 : 1;
1522 }
1523
1524 int dif = (int)(colwid + wid) - (int)cols;
1525 if (dif > 0) {
1526 ret += dif;
1527 colwid = wid;
1528 } else if (dif == 0) {
1529 colwid = 0;
1530 } else {
1531 colwid += wid;
1532 }
1533
1534 if (off >= pos) {
1535 break;
1536 }
1537
1538 off += len;
1539 ret += wid;
1540 }
1541
1542 return ret;
1543}
1544
1545/* Read UTF8 character from file.
1546 */
1547inline int unicodeReadUTF8Char(int fd, char* buf, int* cp)
1548{
1549 int nread = read(fd,&buf[0],1);
1550
1551 if (nread <= 0) { return nread; }
1552
1553 unsigned char byte = buf[0];
1554
1555 if ((byte & 0x80) == 0) {
1556 ;
1557 } else if ((byte & 0xE0) == 0xC0) {
1558 nread = read(fd,&buf[1],1);
1559 if (nread <= 0) { return nread; }
1560 } else if ((byte & 0xF0) == 0xE0) {
1561 nread = read(fd,&buf[1],2);
1562 if (nread <= 0) { return nread; }
1563 } else if ((byte & 0xF8) == 0xF0) {
1564 nread = read(fd,&buf[1],3);
1565 if (nread <= 0) { return nread; }
1566 } else {
1567 return -1;
1568 }
1569
1570 return unicodeUTF8CharToCodePoint(buf, 4, cp);
1571}
1572
1573/* ======================= Low level terminal handling ====================== */
1574
1575/* Set if to use or not the multi line mode. */
1576inline void SetMultiLine(bool ml) {
1577 mlmode = ml;
1578}
1579
1580/* Return true if the terminal name is in the list of terminals we know are
1581 * not able to understand basic escape sequences. */
1582inline bool isUnsupportedTerm(void) {
1583#ifndef _WIN32
1584 char *term = getenv("TERM");
1585 int j;
1586
1587 if (term == NULL) return false;
1588 for (j = 0; unsupported_term[j]; j++)
1589 if (!strcasecmp(term,unsupported_term[j])) return true;
1590#endif
1591 return false;
1592}
1593
1594/* Raw mode: 1960 magic shit. */
1595inline bool enableRawMode(int fd) {
1596#ifndef _WIN32
1597 struct termios raw;
1598
1599 if (!isatty(STDIN_FILENO)) goto fatal;
1600 if (!atexit_registered) {
1601 atexit(linenoiseAtExit);
1602 atexit_registered = true;
1603 }
1604 if (tcgetattr(fd,&orig_termios) == -1) goto fatal;
1605
1606 raw = orig_termios; /* modify the original mode */
1607 /* input modes: no break, no CR to NL, no parity check, no strip char,
1608 * no start/stop output control. */
1609 raw.c_iflag &= ~(BRKINT | ICRNL | INPCK | ISTRIP | IXON);
1610 /* output modes - disable post processing */
1611 raw.c_oflag &= ~(OPOST);
1612 /* control modes - set 8 bit chars */
1613 raw.c_cflag |= (CS8);
1614 /* local modes - choing off, canonical off, no extended functions,
1615 * no signal chars (^Z,^C) */
1616 raw.c_lflag &= ~(ECHO | ICANON | IEXTEN | ISIG);
1617 /* control chars - set return condition: min number of bytes and timer.
1618 * We want read to return every single byte, without timeout. */
1619 raw.c_cc[VMIN] = 1; raw.c_cc[VTIME] = 0; /* 1 byte, no timer */
1620
1621 /* put terminal in raw mode after flushing */
1622 if (tcsetattr(fd,TCSAFLUSH,&raw) < 0) goto fatal;
1623 rawmode = true;
1624#else
1625 if (!atexit_registered) {
1626 /* Cleanup them at exit */
1627 atexit(linenoiseAtExit);
1628 atexit_registered = true;
1629
1630 /* Init windows console handles only once */
1631 hOut = GetStdHandle(STD_OUTPUT_HANDLE);
1632 if (hOut==INVALID_HANDLE_VALUE) goto fatal;
1633 }
1634
1635 DWORD consolemodeOut;
1636 if (!GetConsoleMode(hOut, &consolemodeOut)) {
1637 CloseHandle(hOut);
1638 errno = ENOTTY;
1639 return false;
1640 };
1641
1642 hIn = GetStdHandle(STD_INPUT_HANDLE);
1643 if (hIn == INVALID_HANDLE_VALUE) {
1644 CloseHandle(hOut);
1645 errno = ENOTTY;
1646 return false;
1647 }
1648
1649 GetConsoleMode(hIn, &consolemodeIn);
1650 SetConsoleMode(hIn, ENABLE_PROCESSED_INPUT);
1651
1652 rawmode = true;
1653#endif
1654 return true;
1655
1656fatal:
1657 errno = ENOTTY;
1658 return false;
1659}
1660
1661inline void disableRawMode(int fd) {
1662#ifdef _WIN32
1663 if (consolemodeIn) {
1664 SetConsoleMode(hIn, consolemodeIn);
1665 consolemodeIn = 0;
1666 }
1667 rawmode = false;
1668#else
1669 /* Don't even check the return value as it's too late. */
1670 if (rawmode && tcsetattr(fd,TCSAFLUSH,&orig_termios) != -1)
1671 rawmode = false;
1672#endif
1673}
1674
1675/* Use the ESC [6n escape sequence to query the horizontal cursor position
1676 * and return it. On error -1 is returned, on success the position of the
1677 * cursor. */
1678inline int getCursorPosition(int ifd, int ofd) {
1679 char buf[32];
1680 int cols, rows;
1681 unsigned int i = 0;
1682
1683 /* Report cursor location */
1684 if (write(ofd, "\x1b[6n", 4) != 4) return -1;
1685
1686 /* Read the response: ESC [ rows ; cols R */
1687 while (i < sizeof(buf)-1) {
1688 if (read(ifd,buf+i,1) != 1) break;
1689 if (buf[i] == 'R') break;
1690 i++;
1691 }
1692 buf[i] = '\0';
1693
1694 /* Parse it. */
1695 if (buf[0] != ESC || buf[1] != '[') return -1;
1696 if (sscanf(buf+2,"%d;%d",&rows,&cols) != 2) return -1;
1697 return cols;
1698}
1699
1700/* Try to get the number of columns in the current terminal, or assume 80
1701 * if it fails. */
1702inline int getColumns(int ifd, int ofd) {
1703#ifdef _WIN32
1704 CONSOLE_SCREEN_BUFFER_INFO b;
1705
1706 if (!GetConsoleScreenBufferInfo(hOut, &b)) return 80;
1707 return b.srWindow.Right - b.srWindow.Left;
1708#else
1709 struct winsize ws;
1710
1711 if (ioctl(1, TIOCGWINSZ, &ws) == -1 || ws.ws_col == 0) {
1712 /* ioctl() failed. Try to query the terminal itself. */
1713 int start, cols;
1714
1715 /* Get the initial position so we can restore it later. */
1716 start = getCursorPosition(ifd,ofd);
1717 if (start == -1) goto failed;
1718
1719 /* Go to right margin and get position. */
1720 if (write(ofd,"\x1b[999C",6) != 6) goto failed;
1721 cols = getCursorPosition(ifd,ofd);
1722 if (cols == -1) goto failed;
1723
1724 /* Restore position. */
1725 if (cols > start) {
1726 char seq[32];
1727 snprintf(seq,32,"\x1b[%dD",cols-start);
1728 if (write(ofd,seq,strlen(seq)) == -1) {
1729 /* Can't recover... */
1730 }
1731 }
1732 return cols;
1733 } else {
1734 return ws.ws_col;
1735 }
1736
1737failed:
1738 return 80;
1739#endif
1740}
1741
1742/* Clear the screen. Used to handle ctrl+l */
1743inline void linenoiseClearScreen(void) {
1744 if (write(STDOUT_FILENO,"\x1b[H\x1b[2J",7) <= 0) {
1745 /* nothing to do, just to avoid warning. */
1746 }
1747}
1748
1749/* Beep, used for completion when there is nothing to complete or when all
1750 * the choices were already shown. */
1751inline void linenoiseBeep(void) {
1752 fprintf(stderr, "\x7");
1753 fflush(stderr);
1754}
1755
1756/* ============================== Completion ================================ */
1757
1758/* This is an helper function for linenoiseEdit() and is called when the
1759 * user types the <tab> key in order to complete the string currently in the
1760 * input.
1761 *
1762 * The state of the editing is encapsulated into the pointed linenoiseState
1763 * structure as described in the structure definition. */
1764inline int completeLine(struct linenoiseState *ls, char *cbuf, int *c) {
1765 std::vector<std::string> lc;
1766 int nread = 0, nwritten;
1767 *c = 0;
1768
1769 completionCallback(ls->buf,lc);
1770 if (lc.empty()) {
1771 linenoiseBeep();
1772 } else {
1773 int stop = 0, i = 0;
1774
1775 while(!stop) {
1776 /* Show completion or original buffer */
1777 if (i < static_cast<int>(lc.size())) {
1778 struct linenoiseState saved = *ls;
1779
1780 ls->len = ls->pos = static_cast<int>(lc[i].size());
1781 ls->buf = &lc[i][0];
1782 refreshLine(ls);
1783 ls->len = saved.len;
1784 ls->pos = saved.pos;
1785 ls->buf = saved.buf;
1786 } else {
1787 refreshLine(ls);
1788 }
1789
1790 //nread = read(ls->ifd,&c,1);
1791#ifdef _WIN32
1792 nread = win32read(c);
1793 if (nread == 1) {
1794 cbuf[0] = *c;
1795 }
1796#else
1797 nread = unicodeReadUTF8Char(ls->ifd,cbuf,c);
1798#endif
1799 if (nread <= 0) {
1800 *c = -1;
1801 return nread;
1802 }
1803
1804 switch(*c) {
1805 case 9: /* tab */
1806 i = (i+1) % (lc.size()+1);
1807 if (i == lc.size()) linenoiseBeep();
1808 break;
1809 case 27: /* escape */
1810 /* Re-show original buffer */
1811 if (i < static_cast<int>(lc.size())) refreshLine(ls);
1812 stop = 1;
1813 break;
1814 default:
1815 /* Update buffer and return */
1816 if (i < static_cast<int>(lc.size())) {
1817 nwritten = snprintf(ls->buf,ls->buflen,"%s",&lc[i][0]);
1818 ls->len = ls->pos = nwritten;
1819 }
1820 stop = 1;
1821 break;
1822 }
1823 }
1824 }
1825
1826 return nread;
1827}
1828
1829/* Register a callback function to be called for tab-completion. */
1830static void SetCompletionCallback(CompletionCallback fn) {
1831 completionCallback = fn;
1832}
1833
1834/* =========================== Line editing ================================= */
1835
1836/* Single line low level line refresh.
1837 *
1838 * Rewrite the currently edited line accordingly to the buffer content,
1839 * cursor position, and number of columns of the terminal. */
1840inline void refreshSingleLine(struct linenoiseState *l) {
1841 char seq[64];
1842 int pcolwid = unicodeColumnPos(l->prompt.c_str(), static_cast<int>(l->prompt.length()));
1843 int fd = l->ofd;
1844 char *buf = l->buf;
1845 int len = l->len;
1846 int pos = l->pos;
1847 std::string ab;
1848
1849 while((pcolwid+unicodeColumnPos(buf, pos)) >= l->cols) {
1850 int glen = unicodeGraphemeLen(buf, len, 0);
1851 buf += glen;
1852 len -= glen;
1853 pos -= glen;
1854 }
1855 while (pcolwid+unicodeColumnPos(buf, len) > l->cols) {
1856 len -= unicodePrevGraphemeLen(buf, len);
1857 }
1858
1859 /* Cursor to left edge */
1860 snprintf(seq,64,"\r");
1861 ab += seq;
1862 /* Write the prompt and the current buffer content */
1863 ab += l->prompt;
1864 ab.append(buf, len);
1865 /* Erase to right */
1866 snprintf(seq,64,"\x1b[0K");
1867 ab += seq;
1868 /* Move cursor to original position. */
1869 snprintf(seq,64,"\r\x1b[%dC", (int)(unicodeColumnPos(buf, pos)+pcolwid));
1870 ab += seq;
1871 if (write(fd,ab.c_str(), static_cast<int>(ab.length())) == -1) {} /* Can't recover from write error. */
1872}
1873
1874/* Multi line low level line refresh.
1875 *
1876 * Rewrite the currently edited line accordingly to the buffer content,
1877 * cursor position, and number of columns of the terminal. */
1878inline void refreshMultiLine(struct linenoiseState *l) {
1879 char seq[64];
1880 int pcolwid = unicodeColumnPos(l->prompt.c_str(), static_cast<int>(l->prompt.length()));
1881 int colpos = unicodeColumnPosForMultiLine(l->buf, l->len, l->len, l->cols, pcolwid);
1882 int colpos2; /* cursor column position. */
1883 int rows = (pcolwid+colpos+l->cols-1)/l->cols; /* rows used by current buf. */
1884 int rpos = (pcolwid+l->oldcolpos+l->cols)/l->cols; /* cursor relative row. */
1885 int rpos2; /* rpos after refresh. */
1886 int col; /* colum position, zero-based. */
1887 int old_rows = (int)l->maxrows;
1888 int fd = l->ofd, j;
1889 std::string ab;
1890
1891 /* Update maxrows if needed. */
1892 if (rows > (int)l->maxrows) l->maxrows = rows;
1893
1894 /* First step: clear all the lines used before. To do so start by
1895 * going to the last row. */
1896 if (old_rows-rpos > 0) {
1897 snprintf(seq,64,"\x1b[%dB", old_rows-rpos);
1898 ab += seq;
1899 }
1900
1901 /* Now for every row clear it, go up. */
1902 for (j = 0; j < old_rows-1; j++) {
1903 snprintf(seq,64,"\r\x1b[0K\x1b[1A");
1904 ab += seq;
1905 }
1906
1907 /* Clean the top line. */
1908 snprintf(seq,64,"\r\x1b[0K");
1909 ab += seq;
1910
1911 /* Write the prompt and the current buffer content */
1912 ab += l->prompt;
1913 ab.append(l->buf, l->len);
1914
1915 /* Get text width to cursor position */
1916 colpos2 = unicodeColumnPosForMultiLine(l->buf, l->len, l->pos, l->cols, pcolwid);
1917
1918 /* If we are at the very end of the screen with our prompt, we need to
1919 * emit a newline and move the prompt to the first column. */
1920 if (l->pos &&
1921 l->pos == l->len &&
1922 (colpos2+pcolwid) % l->cols == 0)
1923 {
1924 ab += "\n";
1925 snprintf(seq,64,"\r");
1926 ab += seq;
1927 rows++;
1928 if (rows > (int)l->maxrows) l->maxrows = rows;
1929 }
1930
1931 /* Move cursor to right position. */
1932 rpos2 = (pcolwid+colpos2+l->cols)/l->cols; /* current cursor relative row. */
1933
1934 /* Go up till we reach the expected positon. */
1935 if (rows-rpos2 > 0) {
1936 snprintf(seq,64,"\x1b[%dA", rows-rpos2);
1937 ab += seq;
1938 }
1939
1940 /* Set column. */
1941 col = (pcolwid + colpos2) % l->cols;
1942 if (col)
1943 snprintf(seq,64,"\r\x1b[%dC", col);
1944 else
1945 snprintf(seq,64,"\r");
1946 ab += seq;
1947
1948 l->oldcolpos = colpos2;
1949
1950 if (write(fd,ab.c_str(), static_cast<int>(ab.length())) == -1) {} /* Can't recover from write error. */
1951}
1952
1953/* Calls the two low level functions refreshSingleLine() or
1954 * refreshMultiLine() according to the selected mode. */
1955inline void refreshLine(struct linenoiseState *l) {
1956 if (mlmode)
1957 refreshMultiLine(l);
1958 else
1959 refreshSingleLine(l);
1960}
1961
1962/* Insert the character 'c' at cursor current position.
1963 *
1964 * On error writing to the terminal -1 is returned, otherwise 0. */
1965inline int linenoiseEditInsert(struct linenoiseState *l, const char* cbuf, int clen) {
1966 if (l->len < l->buflen) {
1967 if (l->len == l->pos) {
1968 memcpy(&l->buf[l->pos],cbuf,clen);
1969 l->pos+=clen;
1970 l->len+=clen;;
1971 l->buf[l->len] = '\0';
1972 if ((!mlmode && unicodeColumnPos(l->prompt.c_str(), static_cast<int>(l->prompt.length()))+unicodeColumnPos(l->buf,l->len) < l->cols) /* || mlmode */) {
1973 /* Avoid a full update of the line in the
1974 * trivial case. */
1975 if (write(l->ofd,cbuf,clen) == -1) return -1;
1976 } else {
1977 refreshLine(l);
1978 }
1979 } else {
1980 memmove(l->buf+l->pos+clen,l->buf+l->pos,l->len-l->pos);
1981 memcpy(&l->buf[l->pos],cbuf,clen);
1982 l->pos+=clen;
1983 l->len+=clen;
1984 l->buf[l->len] = '\0';
1985 refreshLine(l);
1986 }
1987 }
1988 return 0;
1989}
1990
1991/* Move cursor on the left. */
1992inline void linenoiseEditMoveLeft(struct linenoiseState *l) {
1993 if (l->pos > 0) {
1994 l->pos -= unicodePrevGraphemeLen(l->buf, l->pos);
1995 refreshLine(l);
1996 }
1997}
1998
1999/* Move cursor on the right. */
2000inline void linenoiseEditMoveRight(struct linenoiseState *l) {
2001 if (l->pos != l->len) {
2002 l->pos += unicodeGraphemeLen(l->buf, l->len, l->pos);
2003 refreshLine(l);
2004 }
2005}
2006
2007/* Move cursor to the start of the line. */
2008inline void linenoiseEditMoveHome(struct linenoiseState *l) {
2009 if (l->pos != 0) {
2010 l->pos = 0;
2011 refreshLine(l);
2012 }
2013}
2014
2015/* Move cursor to the end of the line. */
2016inline void linenoiseEditMoveEnd(struct linenoiseState *l) {
2017 if (l->pos != l->len) {
2018 l->pos = l->len;
2019 refreshLine(l);
2020 }
2021}
2022
2023/* Substitute the currently edited line with the next or previous history
2024 * entry as specified by 'dir'. */
2025#define LINENOISE_HISTORY_NEXT 0
2026#define LINENOISE_HISTORY_PREV 1
2027inline void linenoiseEditHistoryNext(struct linenoiseState *l, int dir) {
2028 if (history.size() > 1) {
2029 /* Update the current history entry before to
2030 * overwrite it with the next one. */
2031 history[history.size() - 1 - l->history_index] = l->buf;
2032 /* Show the new entry */
2033 l->history_index += (dir == LINENOISE_HISTORY_PREV) ? 1 : -1;
2034 if (l->history_index < 0) {
2035 l->history_index = 0;
2036 return;
2037 } else if (l->history_index >= (int)history.size()) {
2038 l->history_index = static_cast<int>(history.size())-1;
2039 return;
2040 }
2041 memset(l->buf, 0, l->buflen);
2042 strcpy(l->buf,history[history.size() - 1 - l->history_index].c_str());
2043 l->len = l->pos = static_cast<int>(strlen(l->buf));
2044 refreshLine(l);
2045 }
2046}
2047
2048/* Delete the character at the right of the cursor without altering the cursor
2049 * position. Basically this is what happens with the "Delete" keyboard key. */
2050inline void linenoiseEditDelete(struct linenoiseState *l) {
2051 if (l->len > 0 && l->pos < l->len) {
2052 int glen = unicodeGraphemeLen(l->buf,l->len,l->pos);
2053 memmove(l->buf+l->pos,l->buf+l->pos+glen,l->len-l->pos-glen);
2054 l->len-=glen;
2055 l->buf[l->len] = '\0';
2056 refreshLine(l);
2057 }
2058}
2059
2060/* Backspace implementation. */
2061inline void linenoiseEditBackspace(struct linenoiseState *l) {
2062 if (l->pos > 0 && l->len > 0) {
2063 int glen = unicodePrevGraphemeLen(l->buf,l->pos);
2064 memmove(l->buf+l->pos-glen,l->buf+l->pos,l->len-l->pos);
2065 l->pos-=glen;
2066 l->len-=glen;
2067 l->buf[l->len] = '\0';
2068 refreshLine(l);
2069 }
2070}
2071
2072/* Delete the previosu word, maintaining the cursor at the start of the
2073 * current word. */
2074inline void linenoiseEditDeletePrevWord(struct linenoiseState *l) {
2075 int old_pos = l->pos;
2076 int diff;
2077
2078 while (l->pos > 0 && l->buf[l->pos-1] == ' ')
2079 l->pos--;
2080 while (l->pos > 0 && l->buf[l->pos-1] != ' ')
2081 l->pos--;
2082 diff = old_pos - l->pos;
2083 memmove(l->buf+l->pos,l->buf+old_pos,l->len-old_pos+1);
2084 l->len -= diff;
2085 refreshLine(l);
2086}
2087
2088/* This function is the core of the line editing capability of linenoise.
2089 * It expects 'fd' to be already in "raw mode" so that every key pressed
2090 * will be returned ASAP to read().
2091 *
2092 * The resulting string is put into 'buf' when the user type enter, or
2093 * when ctrl+d is typed.
2094 *
2095 * The function returns the length of the current buffer. */
2096inline int linenoiseEdit(int stdin_fd, int stdout_fd, char *buf, int buflen, const char *prompt)
2097{
2098 struct linenoiseState l;
2099
2100 /* Populate the linenoise state that we pass to functions implementing
2101 * specific editing functionalities. */
2102 l.ifd = stdin_fd;
2103 l.ofd = stdout_fd;
2104 l.buf = buf;
2105 l.buflen = buflen;
2106 l.prompt = prompt;
2107 l.oldcolpos = l.pos = 0;
2108 l.len = 0;
2109 l.cols = getColumns(stdin_fd, stdout_fd);
2110 l.maxrows = 0;
2111 l.history_index = 0;
2112
2113 /* Buffer starts empty. */
2114 l.buf[0] = '\0';
2115 l.buflen--; /* Make sure there is always space for the nulterm */
2116
2117 /* The latest history entry is always our current buffer, that
2118 * initially is just an empty string. */
2119 AddHistory("");
2120
2121 if (write(l.ofd,prompt, static_cast<int>(l.prompt.length())) == -1) return -1;
2122 while(1) {
2123 int c;
2124 char cbuf[4];
2125 int nread;
2126 char seq[3];
2127
2128#ifdef _WIN32
2129 nread = win32read(&c);
2130 if (nread == 1) {
2131 cbuf[0] = c;
2132 }
2133#else
2134 nread = unicodeReadUTF8Char(l.ifd,cbuf,&c);
2135#endif
2136 if (nread <= 0) return (int)l.len;
2137
2138 /* Only autocomplete when the callback is set. It returns < 0 when
2139 * there was an error reading from fd. Otherwise it will return the
2140 * character that should be handled next. */
2141 if (c == 9 && completionCallback != NULL) {
2142 nread = completeLine(&l,cbuf,&c);
2143 /* Return on errors */
2144 if (c < 0) return l.len;
2145 /* Read next character when 0 */
2146 if (c == 0) continue;
2147 }
2148
2149 switch(c) {
2150 case ENTER: /* enter */
2151 if (!history.empty()) history.pop_back();
2152 if (mlmode) linenoiseEditMoveEnd(&l);
2153 return (int)l.len;
2154 case CTRL_C: /* ctrl-c */
2155 errno = EAGAIN;
2156 return -1;
2157 case BACKSPACE: /* backspace */
2158 case 8: /* ctrl-h */
2159 linenoiseEditBackspace(&l);
2160 break;
2161 case CTRL_D: /* ctrl-d, remove char at right of cursor, or if the
2162 line is empty, act as end-of-file. */
2163 if (l.len > 0) {
2164 linenoiseEditDelete(&l);
2165 } else {
2166 history.pop_back();
2167 return -1;
2168 }
2169 break;
2170 case CTRL_T: /* ctrl-t, swaps current character with previous. */
2171 if (l.pos > 0 && l.pos < l.len) {
2172 int aux = buf[l.pos-1];
2173 buf[l.pos-1] = buf[l.pos];
2174 buf[l.pos] = aux;
2175 if (l.pos != l.len-1) l.pos++;
2176 refreshLine(&l);
2177 }
2178 break;
2179 case CTRL_B: /* ctrl-b */
2180 linenoiseEditMoveLeft(&l);
2181 break;
2182 case CTRL_F: /* ctrl-f */
2183 linenoiseEditMoveRight(&l);
2184 break;
2185 case CTRL_P: /* ctrl-p */
2186 linenoiseEditHistoryNext(&l, LINENOISE_HISTORY_PREV);
2187 break;
2188 case CTRL_N: /* ctrl-n */
2189 linenoiseEditHistoryNext(&l, LINENOISE_HISTORY_NEXT);
2190 break;
2191 case ESC: /* escape sequence */
2192 /* Read the next two bytes representing the escape sequence.
2193 * Use two calls to handle slow terminals returning the two
2194 * chars at different times. */
2195 if (read(l.ifd,seq,1) == -1) break;
2196 if (read(l.ifd,seq+1,1) == -1) break;
2197
2198 /* ESC [ sequences. */
2199 if (seq[0] == '[') {
2200 if (seq[1] >= '0' && seq[1] <= '9') {
2201 /* Extended escape, read additional byte. */
2202 if (read(l.ifd,seq+2,1) == -1) break;
2203 if (seq[2] == '~') {
2204 switch(seq[1]) {
2205 case '3': /* Delete key. */
2206 linenoiseEditDelete(&l);
2207 break;
2208 }
2209 }
2210 } else {
2211 switch(seq[1]) {
2212 case 'A': /* Up */
2213 linenoiseEditHistoryNext(&l, LINENOISE_HISTORY_PREV);
2214 break;
2215 case 'B': /* Down */
2216 linenoiseEditHistoryNext(&l, LINENOISE_HISTORY_NEXT);
2217 break;
2218 case 'C': /* Right */
2219 linenoiseEditMoveRight(&l);
2220 break;
2221 case 'D': /* Left */
2222 linenoiseEditMoveLeft(&l);
2223 break;
2224 case 'H': /* Home */
2225 linenoiseEditMoveHome(&l);
2226 break;
2227 case 'F': /* End*/
2228 linenoiseEditMoveEnd(&l);
2229 break;
2230 }
2231 }
2232 }
2233
2234 /* ESC O sequences. */
2235 else if (seq[0] == 'O') {
2236 switch(seq[1]) {
2237 case 'H': /* Home */
2238 linenoiseEditMoveHome(&l);
2239 break;
2240 case 'F': /* End*/
2241 linenoiseEditMoveEnd(&l);
2242 break;
2243 }
2244 }
2245 break;
2246 default:
2247 if (linenoiseEditInsert(&l,cbuf,nread)) return -1;
2248 break;
2249 case CTRL_U: /* Ctrl+u, delete the whole line. */
2250 buf[0] = '\0';
2251 l.pos = l.len = 0;
2252 refreshLine(&l);
2253 break;
2254 case CTRL_K: /* Ctrl+k, delete from current to end of line. */
2255 buf[l.pos] = '\0';
2256 l.len = l.pos;
2257 refreshLine(&l);
2258 break;
2259 case CTRL_A: /* Ctrl+a, go to the start of the line */
2260 linenoiseEditMoveHome(&l);
2261 break;
2262 case CTRL_E: /* ctrl+e, go to the end of the line */
2263 linenoiseEditMoveEnd(&l);
2264 break;
2265 case CTRL_L: /* ctrl+l, clear screen */
2266 linenoiseClearScreen();
2267 refreshLine(&l);
2268 break;
2269 case CTRL_W: /* ctrl+w, delete previous word */
2270 linenoiseEditDeletePrevWord(&l);
2271 break;
2272 }
2273 }
2274 return l.len;
2275}
2276
2277/* This function calls the line editing function linenoiseEdit() using
2278 * the STDIN file descriptor set in raw mode. */
2279inline bool linenoiseRaw(const char *prompt, std::string& line) {
2280 bool quit = false;
2281
2282 if (!isatty(STDIN_FILENO)) {
2283 /* Not a tty: read from file / pipe. */
2284 std::getline(std::cin, line);
2285 } else {
2286 /* Interactive editing. */
2287 if (enableRawMode(STDIN_FILENO) == false) {
2288 return quit;
2289 }
2290
2291 char buf[LINENOISE_MAX_LINE];
2292 auto count = linenoiseEdit(STDIN_FILENO, STDOUT_FILENO, buf, LINENOISE_MAX_LINE, prompt);
2293 if (count == -1) {
2294 quit = true;
2295 } else {
2296 line.assign(buf, count);
2297 }
2298
2299 disableRawMode(STDIN_FILENO);
2300 printf("\n");
2301 }
2302 return quit;
2303}
2304
2305/* The high level function that is the main API of the linenoise library.
2306 * This function checks if the terminal has basic capabilities, just checking
2307 * for a blacklist of stupid terminals, and later either calls the line
2308 * editing function or uses dummy fgets() so that you will be able to type
2309 * something even in the most desperate of the conditions. */
2310inline bool Readline(const char *prompt, std::string& line) {
2311 if (isUnsupportedTerm()) {
2312 printf("%s",prompt);
2313 fflush(stdout);
2314 std::getline(std::cin, line);
2315 return false;
2316 } else {
2317 return linenoiseRaw(prompt, line);
2318 }
2319}
2320
2321inline std::string Readline(const char *prompt, bool& quit) {
2322 std::string line;
2323 quit = Readline(prompt, line);
2324 return line;
2325}
2326
2327inline std::string Readline(const char *prompt) {
2328 bool quit; // dummy
2329 return Readline(prompt, quit);
2330}
2331
2332/* ================================ History ================================= */
2333
2334/* At exit we'll try to fix the terminal to the initial conditions. */
2335inline void linenoiseAtExit(void) {
2336 disableRawMode(STDIN_FILENO);
2337}
2338
2339/* This is the API call to add a new entry in the linenoise history.
2340 * It uses a fixed array of char pointers that are shifted (memmoved)
2341 * when the history max length is reached in order to remove the older
2342 * entry and make room for the new one, so it is not exactly suitable for huge
2343 * histories, but will work well for a few hundred of entries.
2344 *
2345 * Using a circular buffer is smarter, but a bit more complex to handle. */
2346inline bool AddHistory(const char* line) {
2347 if (history_max_len == 0) return false;
2348
2349 /* Don't add duplicated lines. */
2350 if (!history.empty() && history.back() == line) return false;
2351
2352 /* If we reached the max length, remove the older line. */
2353 if (history.size() == history_max_len) {
2354 history.erase(history.begin());
2355 }
2356 history.push_back(line);
2357
2358 return true;
2359}
2360
2361/* Set the maximum length for the history. This function can be called even
2362 * if there is already some history, the function will make sure to retain
2363 * just the latest 'len' elements if the new history length value is smaller
2364 * than the amount of items already inside the history. */
2365inline bool SetHistoryMaxLen(size_t len) {
2366 if (len < 1) return false;
2367 history_max_len = len;
2368 if (len < history.size()) {
2369 history.resize(len);
2370 }
2371 return true;
2372}
2373
2374/* Save the history in the specified file. On success *true* is returned
2375 * otherwise *false* is returned. */
2376inline bool SaveHistory(const char* path) {
2377 std::ofstream f(path); // TODO: need 'std::ios::binary'?
2378 if (!f) return false;
2379 for (const auto& h: history) {
2380 f << h << std::endl;
2381 }
2382 return true;
2383}
2384
2385/* Load the history from the specified file. If the file does not exist
2386 * zero is returned and no operation is performed.
2387 *
2388 * If the file exists and the operation succeeded *true* is returned, otherwise
2389 * on error *false* is returned. */
2390inline bool LoadHistory(const char* path) {
2391 std::ifstream f(path);
2392 if (!f) return false;
2393 std::string line;
2394 while (std::getline(f, line)) {
2395 AddHistory(line.c_str());
2396 }
2397 return true;
2398}
2399
2400inline const std::vector<std::string>& GetHistory() {
2401 return history;
2402}
2403
2404} // namespace linenoise
2405
2406#ifdef _WIN32
2407#undef isatty
2408#undef write
2409#undef read
2410#endif
2411
2412#endif /* __LINENOISE_HPP */